]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Foundation/Library/EdkIIGlueLib/Library/BaseLib/X64/Thunk16.asm
Fix the issue that the high 16-bit of EAX may contain invalid data, which cause bad...
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / EdkIIGlueLib / Library / BaseLib / X64 / Thunk16.asm
CommitLineData
be3b67bc 1; Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
2c7e5c2f 2; This program and the accompanying materials \r
3eb9473e 3; are licensed and made available under the terms and conditions of the BSD License \r
4; which accompanies this distribution. The full text of the license may be found at \r
5; http://opensource.org/licenses/bsd-license.php \r
6; \r
7; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
8; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
9;\r
10; Module Name:\r
11;\r
12; Thunk.asm\r
13;\r
14; Abstract:\r
15;\r
16; Real mode thunk\r
17;\r
18;------------------------------------------------------------------------------\r
19\r
20EXTERNDEF m16Start:BYTE\r
21EXTERNDEF m16Size:WORD\r
22EXTERNDEF mThunk16Attr:WORD\r
23EXTERNDEF m16Gdt:WORD\r
24EXTERNDEF m16GdtrBase:WORD\r
25EXTERNDEF mTransition:WORD\r
26\r
27THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 EQU 2\r
28THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL EQU 4\r
29\r
30IA32_REGS STRUC 4t\r
31_EDI DD ?\r
32_ESI DD ?\r
33_EBP DD ?\r
34_ESP DD ?\r
35_EBX DD ?\r
36_EDX DD ?\r
37_ECX DD ?\r
38_EAX DD ?\r
39_DS DW ?\r
40_ES DW ?\r
41_FS DW ?\r
42_GS DW ?\r
43_EFLAGS DQ ?\r
44_EIP DD ?\r
45_CS DW ?\r
46_SS DW ?\r
47IA32_REGS ENDS\r
48\r
49 .const\r
50\r
51m16Size DW InternalAsmThunk16 - m16Start\r
52mThunk16Attr DW _ThunkAttr - m16Start\r
53m16Gdt DW _NullSeg - m16Start\r
54m16GdtrBase DW _16GdtrBase - m16Start\r
55mTransition DW _EntryPoint - m16Start\r
56\r
57 .code\r
58\r
59m16Start LABEL BYTE\r
60\r
61SavedGdt LABEL FWORD\r
62 DW ?\r
63 DQ ?\r
64\r
65;------------------------------------------------------------------------------\r
66; _BackFromUserCode() takes control in real mode after 'retf' has been executed\r
67; by user code. It will be shadowed to somewhere in memory below 1MB.\r
68;------------------------------------------------------------------------------\r
69_BackFromUserCode PROC\r
70 ;\r
71 ; The order of saved registers on the stack matches the order they appears\r
72 ; in IA32_REGS structure. This facilitates wrapper function to extract them\r
73 ; into that structure.\r
74 ;\r
75 ; Some instructions for manipulation of segment registers have to be written\r
76 ; in opcode since 64-bit MASM prevents accesses to those registers.\r
77 ;\r
78 DB 16h ; push ss\r
79 DB 0eh ; push cs\r
80 DB 66h\r
81 call @Base ; push eip\r
82@Base:\r
83 DB 66h\r
84 push 0 ; reserved high order 32 bits of EFlags\r
85 pushf ; pushfd actually\r
86 cli ; disable interrupts\r
87 push gs\r
88 push fs\r
89 DB 6 ; push es\r
90 DB 1eh ; push ds\r
91 DB 66h, 60h ; pushad\r
92 DB 66h, 0bah ; mov edx, imm32\r
93_ThunkAttr DD ?\r
94 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15\r
95 jz @1\r
96 mov eax, 15cd2401h ; mov ax, 2401h & int 15h\r
97 cli ; disable interrupts\r
98 jnc @2\r
99@1:\r
100 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL\r
101 jz @2\r
102 in al, 92h\r
103 or al, 2\r
104 out 92h, al ; deactivate A20M#\r
105@2:\r
be3b67bc 106 mov ax, ss\r
3eb9473e 107 lea bp, [esp + sizeof (IA32_REGS)]\r
108 ;\r
109 ; rsi in the following 2 instructions is indeed bp in 16-bit code\r
110 ;\r
111 mov word ptr (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._ESP, bp\r
112 DB 66h\r
113 mov ebx, (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._EIP\r
114 shl ax, 4 ; shl eax, 4\r
115 add bp, ax ; add ebp, eax\r
116 mov ax, cs\r
117 shl ax, 4\r
118 lea ax, [eax + ebx + (@64BitCode - @Base)]\r
119 DB 66h, 2eh, 89h, 87h ; mov cs:[bx + (@64Eip - @Base)], eax\r
120 DW @64Eip - @Base\r
121 DB 66h, 0b8h ; mov eax, imm32\r
122SavedCr4 DD ?\r
123 mov cr4, rax\r
124 ;\r
125 ; rdi in the instruction below is indeed bx in 16-bit code\r
126 ;\r
127 DB 66h, 2eh ; 2eh is "cs:" segment override\r
128 lgdt fword ptr [rdi + (SavedGdt - @Base)]\r
129 DB 66h\r
130 mov ecx, 0c0000080h\r
131 rdmsr\r
132 or ah, 1\r
133 wrmsr\r
134 DB 66h, 0b8h ; mov eax, imm32\r
135SavedCr0 DD ?\r
136 mov cr0, rax\r
137 DB 66h, 0eah ; jmp far cs:@64Bit\r
138@64Eip DD ?\r
139SavedCs DW ?\r
140@64BitCode:\r
1e437167 141 db 090h \r
142 db 067h, 0bch ; mov esp, imm32\r
143SavedSp DD ? ; restore stack\r
144 nop\r
3eb9473e 145 ret\r
146_BackFromUserCode ENDP\r
147\r
148_EntryPoint DD _ToUserCode - m16Start\r
149 DW CODE16\r
150_16Gdtr LABEL FWORD\r
151 DW GDT_SIZE - 1\r
152_16GdtrBase DQ _NullSeg\r
153_16Idtr FWORD (1 SHL 10) - 1\r
154\r
155;------------------------------------------------------------------------------\r
156; _ToUserCode() takes control in real mode before passing control to user code.\r
157; It will be shadowed to somewhere in memory below 1MB.\r
158;------------------------------------------------------------------------------\r
159_ToUserCode PROC\r
160 mov ss, edx ; set new segment selectors\r
161 mov ds, edx\r
162 mov es, edx\r
163 mov fs, edx\r
164 mov gs, edx\r
165 DB 66h\r
166 mov ecx, 0c0000080h\r
167 mov cr0, rax ; real mode starts at next instruction\r
168 rdmsr\r
169 and ah, NOT 1\r
170 wrmsr\r
171 mov cr4, rbp\r
172 mov ss, esi ; set up 16-bit stack segment\r
173 mov sp, bx ; set up 16-bit stack pointer\r
174 DB 66h ; make the following call 32-bit\r
175 call @Base ; push eip\r
176@Base:\r
177 pop bp ; ebp <- address of @Base\r
178 push [esp + sizeof (IA32_REGS) + 2]\r
179 lea eax, [rsi + (@RealMode - @Base)] ; rsi is "bp" in 16-bit code\r
180 push rax\r
181 retf ; execution begins at next instruction\r
182@RealMode:\r
183 DB 66h, 2eh ; CS and operand size override\r
184 lidt fword ptr [rsi + (_16Idtr - @Base)]\r
185 DB 66h, 61h ; popad\r
186 DB 1fh ; pop ds\r
187 DB 07h ; pop es\r
188 pop fs\r
189 pop gs\r
190 popf ; popfd\r
191 lea sp, [esp + 4] ; skip high order 32 bits of EFlags\r
192 DB 66h ; make the following retf 32-bit\r
193 retf ; transfer control to user code\r
194_ToUserCode ENDP\r
195\r
196CODE16 = _16Code - $\r
197DATA16 = _16Data - $\r
198DATA32 = _32Data - $\r
199\r
200_NullSeg DQ 0\r
201_16Code LABEL QWORD\r
202 DW -1\r
203 DW 0\r
204 DB 0\r
205 DB 9bh\r
206 DB 8fh ; 16-bit segment, 4GB limit\r
207 DB 0\r
208_16Data LABEL QWORD\r
209 DW -1\r
210 DW 0\r
211 DB 0\r
212 DB 93h\r
213 DB 8fh ; 16-bit segment, 4GB limit\r
214 DB 0\r
215_32Data LABEL QWORD\r
216 DW -1\r
217 DW 0\r
218 DB 0\r
219 DB 93h\r
220 DB 0cfh ; 16-bit segment, 4GB limit\r
221 DB 0\r
222\r
223GDT_SIZE = $ - _NullSeg\r
224\r
225;------------------------------------------------------------------------------\r
226; IA32_REGISTER_SET *\r
227; EFIAPI\r
228; InternalAsmThunk16 (\r
229; IN IA32_REGISTER_SET *RegisterSet,\r
230; IN OUT VOID *Transition\r
231; );\r
232;------------------------------------------------------------------------------\r
233InternalAsmThunk16 PROC USES rbp rbx rsi rdi\r
1e437167 234 mov rbx, ds\r
235 push rbx ; Save ds segment register on the stack\r
236 mov rbx, es\r
237 push rbx ; Save es segment register on the stack\r
238 mov rbx, ss\r
239 push rbx ; Save ss segment register on the stack\r
240 \r
3eb9473e 241 push fs\r
242 push gs\r
243 mov rsi, rcx\r
244 movzx r8d, (IA32_REGS ptr [rsi])._SS\r
245 mov edi, (IA32_REGS ptr [rsi])._ESP\r
246 lea rdi, [edi - (sizeof (IA32_REGS) + 4)]\r
247 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16\r
248 mov ebx, edi ; ebx <- stack for 16-bit code\r
249 push sizeof (IA32_REGS) / 4\r
250 add edi, eax ; edi <- linear address of 16-bit stack\r
251 pop rcx\r
252 rep movsd ; copy RegSet\r
253 lea ecx, [rdx + (SavedCr4 - m16Start)]\r
254 mov eax, edx ; eax <- transition code address\r
255 and edx, 0fh\r
256 shl eax, 12 ; segment address in high order 16 bits\r
257 lea ax, [rdx + (_BackFromUserCode - m16Start)] ; offset address\r
258 stosd ; [edi] <- return address of user code\r
259 sgdt fword ptr [rcx + (SavedGdt - SavedCr4)]\r
1e437167 260 sidt fword ptr [rsp + 50h] ; save IDT stack in argument space\r
3eb9473e 261 mov rax, cr0\r
262 mov [rcx + (SavedCr0 - SavedCr4)], eax\r
263 and eax, 7ffffffeh ; clear PE, PG bits\r
264 mov rbp, cr4\r
265 mov [rcx], ebp ; save CR4 in SavedCr4\r
266 and ebp, 300h ; clear all but PCE and OSFXSR bits\r
267 mov esi, r8d ; esi <- 16-bit stack segment\r
268 DB 6ah, DATA32 ; push DATA32\r
269 pop rdx ; rdx <- 32-bit data segment selector\r
270 lgdt fword ptr [rcx + (_16Gdtr - SavedCr4)]\r
271 mov ss, edx\r
272 pushfq\r
273 lea edx, [rdx + DATA16 - DATA32]\r
274 lea r8, @RetFromRealMode\r
275 push r8\r
276 mov r8d, cs\r
277 mov [rcx + (SavedCs - SavedCr4)], r8w\r
1e437167 278 mov [rcx + (SavedSp - SavedCr4)], esp\r
3eb9473e 279 jmp fword ptr [rcx + (_EntryPoint - SavedCr4)]\r
280@RetFromRealMode:\r
281 popfq\r
1e437167 282 lidt fword ptr [rsp + 50h] ; restore protected mode IDTR\r
3eb9473e 283 lea eax, [rbp - sizeof (IA32_REGS)]\r
284 pop gs\r
285 pop fs\r
1e437167 286 pop rbx\r
287 mov ss, rbx\r
288 pop rbx\r
289 mov es, rbx\r
290 pop rbx\r
291 mov ds, rbx\r
3eb9473e 292 ret\r
293InternalAsmThunk16 ENDP\r
294\r
295 END\r