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