]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BaseLib/X64/Thunk16.nasm
MdePkg NASM Thunk16: Work around NASM 2.09.04 - 2.10rc1 bug
[mirror_edk2.git] / MdePkg / Library / BaseLib / X64 / Thunk16.nasm
CommitLineData
fbb5393c
JJ
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 InternalAsmThunk16 - ASM_PFX(m16Start)\r
7458df40 60ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttrEnd - 4 - ASM_PFX(m16Start)\r
fbb5393c
JJ
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
f6888eea
JJ
83BITS 16\r
84 push ss\r
85 push cs\r
eabcdf3a
JJ
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
a8458d6c 91.Base:\r
f6888eea
JJ
92 push dword 0 ; reserved high order 32 bits of EFlags\r
93 pushfd\r
fbb5393c
JJ
94 cli ; disable interrupts\r
95 push gs\r
96 push fs\r
f6888eea
JJ
97 push es\r
98 push ds\r
99 pushad\r
7458df40
JJ
100 mov edx, strict dword 0\r
101.ThunkAttrEnd:\r
fbb5393c 102 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15\r
a8458d6c 103 jz .1\r
f6888eea
JJ
104 mov ax, 2401h\r
105 int 15h\r
fbb5393c 106 cli ; disable interrupts\r
a8458d6c
JJ
107 jnc .2\r
108.1:\r
fbb5393c 109 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL\r
a8458d6c 110 jz .2\r
fbb5393c
JJ
111 in al, 92h\r
112 or al, 2\r
113 out 92h, al ; deactivate A20M#\r
a8458d6c 114.2:\r
f6888eea
JJ
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
7458df40
JJ
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
f6888eea
JJ
128 mov cr4, eax\r
129o32 lgdt [cs:bx + (SavedGdt - .Base)]\r
fbb5393c
JJ
130 mov ecx, 0c0000080h\r
131 rdmsr\r
132 or ah, 1\r
133 wrmsr\r
7458df40
JJ
134 mov eax, strict dword 0\r
135.SavedCr0End:\r
f6888eea 136 mov cr0, eax\r
7458df40
JJ
137 jmp 0:strict dword 0\r
138.X64JmpEnd:\r
f6888eea
JJ
139BITS 64\r
140 nop\r
7458df40
JJ
141 mov rsp, strict qword 0\r
142.SavedSpEnd:\r
fbb5393c
JJ
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
03e9db15 152 DQ 0\r
fbb5393c
JJ
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
f6888eea
JJ
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
fbb5393c 168 mov ecx, 0c0000080h\r
f6888eea 169 mov cr0, eax ; real mode starts at next instruction\r
fbb5393c
JJ
170 rdmsr\r
171 and ah, ~1\r
172 wrmsr\r
f6888eea
JJ
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
a8458d6c 177.Base:\r
f6888eea
JJ
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
fbb5393c 182 retf ; execution begins at next instruction\r
a8458d6c 183.RealMode:\r
f6888eea
JJ
184\r
185o32 lidt [cs:bp + (_16Idtr - .Base)]\r
186\r
187 popad\r
188 pop ds\r
189 pop es\r
fbb5393c
JJ
190 pop fs\r
191 pop gs\r
f6888eea
JJ
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
fbb5393c
JJ
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
f6888eea 238BITS 64\r
fbb5393c
JJ
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
7458df40 263 lea ecx, [rdx + (_BackFromUserCode.SavedCr4End - ASM_PFX(m16Start))]\r
fbb5393c
JJ
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
7458df40 272 lea r11, [rcx + (InternalAsmThunk16 - _BackFromUserCode.SavedCr4End) + 0xf]\r
fbb5393c
JJ
273 and r11, ~0xf ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer\r
274 \r
7458df40
JJ
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
fbb5393c
JJ
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
7458df40 288 mov [rcx + (_BackFromUserCode.SavedCr0End - 4 - _BackFromUserCode.SavedCr4End)], eax\r
fbb5393c
JJ
289 and eax, 7ffffffeh ; clear PE, PG bits\r
290 mov rbp, cr4\r
7458df40 291 mov [rcx - 4], ebp ; save CR4 in _BackFromUserCode.SavedCr4End - 4\r
fbb5393c
JJ
292 and ebp, ~30h ; clear PAE, PSE bits\r
293 mov esi, r8d ; esi <- 16-bit stack segment\r
f6888eea 294 push DATA32\r
fbb5393c 295 pop rdx ; rdx <- 32-bit data segment selector\r
7458df40 296 lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4End)]\r
fbb5393c
JJ
297 mov ss, edx\r
298 pushfq\r
299 lea edx, [rdx + DATA16 - DATA32]\r
a8458d6c 300 lea r8, [REL .RetFromRealMode]\r
fbb5393c
JJ
301 push r8\r
302 mov r8d, cs\r
7458df40
JJ
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
a8458d6c 306.RetFromRealMode:\r
fbb5393c
JJ
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