]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdePkg/Library/BaseLib/X64/Thunk16.nasm
MdePkg/BaseLib: Support IA32 processors without CMOVx
[mirror_edk2.git] / MdePkg / Library / BaseLib / X64 / Thunk16.nasm
... / ...
CommitLineData
1\r
2#include "BaseLibInternals.h"\r
3\r
4;------------------------------------------------------------------------------\r
5;\r
6; Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
7; This program and the accompanying materials\r
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
10; http://opensource.org/licenses/bsd-license.php.\r
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
25global ASM_PFX(m16Size)\r
26global ASM_PFX(mThunk16Attr)\r
27global ASM_PFX(m16Gdt)\r
28global ASM_PFX(m16GdtrBase)\r
29global ASM_PFX(mTransition)\r
30global ASM_PFX(m16Start)\r
31\r
32struc IA32_REGS\r
33\r
34 ._EDI: resd 1\r
35 ._ESI: resd 1\r
36 ._EBP: resd 1\r
37 ._ESP: resd 1\r
38 ._EBX: resd 1\r
39 ._EDX: resd 1\r
40 ._ECX: resd 1\r
41 ._EAX: resd 1\r
42 ._DS: resw 1\r
43 ._ES: resw 1\r
44 ._FS: resw 1\r
45 ._GS: resw 1\r
46 ._EFLAGS: resq 1\r
47 ._EIP: resd 1\r
48 ._CS: resw 1\r
49 ._SS: resw 1\r
50 .size:\r
51\r
52endstruc\r
53\r
54SECTION .data\r
55\r
56;\r
57; These are global constant to convey information to C code.\r
58;\r
59ASM_PFX(m16Size) DW ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start)\r
60ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttrEnd - 4 - ASM_PFX(m16Start)\r
61ASM_PFX(m16Gdt) DW _NullSeg - ASM_PFX(m16Start)\r
62ASM_PFX(m16GdtrBase) DW _16GdtrBase - ASM_PFX(m16Start)\r
63ASM_PFX(mTransition) DW _EntryPoint - ASM_PFX(m16Start)\r
64\r
65SECTION .text\r
66\r
67ASM_PFX(m16Start):\r
68\r
69SavedGdt:\r
70 dw 0\r
71 dq 0\r
72\r
73;------------------------------------------------------------------------------\r
74; _BackFromUserCode() takes control in real mode after 'retf' has been executed\r
75; by user code. It will be shadowed to somewhere in memory below 1MB.\r
76;------------------------------------------------------------------------------\r
77_BackFromUserCode:\r
78 ;\r
79 ; The order of saved registers on the stack matches the order they appears\r
80 ; in IA32_REGS structure. This facilitates wrapper function to extract them\r
81 ; into that structure.\r
82 ;\r
83BITS 16\r
84 push ss\r
85 push cs\r
86 ;\r
87 ; Note: We can't use o32 on the next instruction because of a bug\r
88 ; in NASM 2.09.04 through 2.10rc1.\r
89 ;\r
90 call dword .Base ; push eip\r
91.Base:\r
92 push dword 0 ; reserved high order 32 bits of EFlags\r
93 pushfd\r
94 cli ; disable interrupts\r
95 push gs\r
96 push fs\r
97 push es\r
98 push ds\r
99 pushad\r
100 mov edx, strict dword 0\r
101.ThunkAttrEnd:\r
102 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15\r
103 jz .1\r
104 mov ax, 2401h\r
105 int 15h\r
106 cli ; disable interrupts\r
107 jnc .2\r
108.1:\r
109 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL\r
110 jz .2\r
111 in al, 92h\r
112 or al, 2\r
113 out 92h, al ; deactivate A20M#\r
114.2:\r
115 xor eax, eax\r
116 mov ax, ss\r
117 lea ebp, [esp + IA32_REGS.size]\r
118 mov [bp - IA32_REGS.size + IA32_REGS._ESP], ebp\r
119 mov ebx, [bp - IA32_REGS.size + IA32_REGS._EIP]\r
120 shl eax, 4 ; shl eax, 4\r
121 add ebp, eax ; add ebp, eax\r
122 mov eax, cs\r
123 shl eax, 4\r
124 lea eax, [eax + ebx + (.X64JmpEnd - .Base)]\r
125 mov [cs:bx + (.X64JmpEnd - 6 - .Base)], eax\r
126 mov eax, strict dword 0\r
127.SavedCr4End:\r
128 mov cr4, eax\r
129o32 lgdt [cs:bx + (SavedGdt - .Base)]\r
130 mov ecx, 0c0000080h\r
131 rdmsr\r
132 or ah, 1\r
133 wrmsr\r
134 mov eax, strict dword 0\r
135.SavedCr0End:\r
136 mov cr0, eax\r
137 jmp 0:strict dword 0\r
138.X64JmpEnd:\r
139BITS 64\r
140 nop\r
141 mov rsp, strict qword 0\r
142.SavedSpEnd:\r
143 nop\r
144 ret\r
145\r
146_EntryPoint:\r
147 DD _ToUserCode - ASM_PFX(m16Start)\r
148 DW CODE16\r
149_16Gdtr:\r
150 DW GDT_SIZE - 1\r
151_16GdtrBase:\r
152 DQ 0\r
153_16Idtr:\r
154 DW (1 << 10) - 1\r
155 DD 0\r
156\r
157;------------------------------------------------------------------------------\r
158; _ToUserCode() takes control in real mode before passing control to user code.\r
159; It will be shadowed to somewhere in memory below 1MB.\r
160;------------------------------------------------------------------------------\r
161_ToUserCode:\r
162BITS 16\r
163 mov ss, dx ; set new segment selectors\r
164 mov ds, dx\r
165 mov es, dx\r
166 mov fs, dx\r
167 mov gs, dx\r
168 mov ecx, 0c0000080h\r
169 mov cr0, eax ; real mode starts at next instruction\r
170 rdmsr\r
171 and ah, ~1\r
172 wrmsr\r
173 mov cr4, ebp\r
174 mov ss, si ; set up 16-bit stack segment\r
175 mov esp, ebx ; set up 16-bit stack pointer\r
176 call dword .Base ; push eip\r
177.Base:\r
178 pop ebp ; ebp <- address of .Base\r
179 push word [dword esp + IA32_REGS.size + 2]\r
180 lea ax, [bp + (.RealMode - .Base)]\r
181 push ax\r
182 retf ; execution begins at next instruction\r
183.RealMode:\r
184\r
185o32 lidt [cs:bp + (_16Idtr - .Base)]\r
186\r
187 popad\r
188 pop ds\r
189 pop es\r
190 pop fs\r
191 pop gs\r
192 popfd\r
193 lea esp, [esp + 4] ; skip high order 32 bits of EFlags\r
194\r
195o32 retf ; transfer control to user code\r
196\r
197ALIGN 8\r
198\r
199CODE16 equ _16Code - $\r
200DATA16 equ _16Data - $\r
201DATA32 equ _32Data - $\r
202\r
203_NullSeg DQ 0\r
204_16Code:\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:\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:\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 equ $ - _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
236global ASM_PFX(InternalAsmThunk16)\r
237ASM_PFX(InternalAsmThunk16):\r
238BITS 64\r
239 push rbp\r
240 push rbx\r
241 push rsi\r
242 push rdi\r
243 \r
244 mov ebx, ds\r
245 push rbx ; Save ds segment register on the stack\r
246 mov ebx, es\r
247 push rbx ; Save es segment register on the stack\r
248 mov ebx, ss\r
249 push rbx ; Save ss segment register on the stack\r
250 \r
251 push fs\r
252 push gs\r
253 mov rsi, rcx\r
254 movzx r8d, word [rsi + IA32_REGS._SS]\r
255 mov edi, [rsi + IA32_REGS._ESP]\r
256 lea rdi, [edi - (IA32_REGS.size + 4)]\r
257 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16\r
258 mov ebx, edi ; ebx <- stack for 16-bit code\r
259 push IA32_REGS.size / 4\r
260 add edi, eax ; edi <- linear address of 16-bit stack\r
261 pop rcx\r
262 rep movsd ; copy RegSet\r
263 lea ecx, [rdx + (_BackFromUserCode.SavedCr4End - ASM_PFX(m16Start))]\r
264 mov eax, edx ; eax <- transition code address\r
265 and edx, 0fh\r
266 shl eax, 12 ; segment address in high order 16 bits\r
267 lea ax, [rdx + (_BackFromUserCode - ASM_PFX(m16Start))] ; offset address\r
268 stosd ; [edi] <- return address of user code\r
269 \r
270 sgdt [rsp + 60h] ; save GDT stack in argument space\r
271 movzx r10, word [rsp + 60h] ; r10 <- GDT limit \r
272 lea r11, [rcx + (ASM_PFX(InternalAsmThunk16) - _BackFromUserCode.SavedCr4End) + 0xf]\r
273 and r11, ~0xf ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer\r
274 \r
275 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4End)], r10w ; save the limit of shadowed GDT table\r
276 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4End) + 2], r11 ; save the base address of shadowed GDT table\r
277 \r
278 mov rsi, [rsp + 62h] ; rsi <- the original GDT base address\r
279 xchg rcx, r10 ; save rcx to r10 and initialize rcx to be the limit of GDT table\r
280 inc rcx ; rcx <- the size of memory to copy\r
281 xchg rdi, r11 ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table\r
282 rep movsb ; perform memory copy to shadow GDT table\r
283 mov rcx, r10 ; restore the orignal rcx before memory copy\r
284 mov rdi, r11 ; restore the original rdi before memory copy\r
285 \r
286 sidt [rsp + 50h] ; save IDT stack in argument space\r
287 mov rax, cr0\r
288 mov [rcx + (_BackFromUserCode.SavedCr0End - 4 - _BackFromUserCode.SavedCr4End)], eax\r
289 and eax, 7ffffffeh ; clear PE, PG bits\r
290 mov rbp, cr4\r
291 mov [rcx - 4], ebp ; save CR4 in _BackFromUserCode.SavedCr4End - 4\r
292 and ebp, ~30h ; clear PAE, PSE bits\r
293 mov esi, r8d ; esi <- 16-bit stack segment\r
294 push DATA32\r
295 pop rdx ; rdx <- 32-bit data segment selector\r
296 lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4End)]\r
297 mov ss, edx\r
298 pushfq\r
299 lea edx, [rdx + DATA16 - DATA32]\r
300 lea r8, [REL .RetFromRealMode]\r
301 push r8\r
302 mov r8d, cs\r
303 mov [rcx + (_BackFromUserCode.X64JmpEnd - 2 - _BackFromUserCode.SavedCr4End)], r8w\r
304 mov [rcx + (_BackFromUserCode.SavedSpEnd - 8 - _BackFromUserCode.SavedCr4End)], rsp\r
305 jmp dword far [rcx + (_EntryPoint - _BackFromUserCode.SavedCr4End)]\r
306.RetFromRealMode:\r
307 popfq\r
308 lgdt [rsp + 60h] ; restore protected mode GDTR\r
309 lidt [rsp + 50h] ; restore protected mode IDTR\r
310 lea eax, [rbp - IA32_REGS.size]\r
311 pop gs\r
312 pop fs\r
313 pop rbx\r
314 mov ss, ebx\r
315 pop rbx\r
316 mov es, ebx\r
317 pop rbx\r
318 mov ds, ebx\r
319\r
320 pop rdi\r
321 pop rsi\r
322 pop rbx\r
323 pop rbp\r
324\r
325 ret\r