]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BaseLib/X64/Thunk16.nasm
MdePkg BaseLib NASM Thunk16: Use NASM local labels
[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
a8458d6c 60ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttr - 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
83 ; Some instructions for manipulation of segment registers have to be written\r
84 ; in opcode since 64-bit MASM prevents accesses to those registers.\r
85 ;\r
86 DB 16h ; push ss\r
87 DB 0eh ; push cs\r
88 DB 66h\r
a8458d6c
JJ
89 call .Base ; push eip\r
90.Base:\r
fbb5393c
JJ
91 DB 66h\r
92 push 0 ; reserved high order 32 bits of EFlags\r
93 pushfw ; pushfd actually\r
94 cli ; disable interrupts\r
95 push gs\r
96 push fs\r
97 DB 6 ; push es\r
98 DB 1eh ; push ds\r
99 DB 66h, 60h ; pushad\r
100 DB 66h, 0bah ; mov edx, imm32\r
a8458d6c 101.ThunkAttr: dd 0\r
fbb5393c 102 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15\r
a8458d6c 103 jz .1\r
fbb5393c
JJ
104 mov eax, 15cd2401h ; mov ax, 2401h & int 15h\r
105 cli ; disable interrupts\r
a8458d6c
JJ
106 jnc .2\r
107.1:\r
fbb5393c 108 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL\r
a8458d6c 109 jz .2\r
fbb5393c
JJ
110 in al, 92h\r
111 or al, 2\r
112 out 92h, al ; deactivate A20M#\r
a8458d6c 113.2:\r
fbb5393c
JJ
114 xor ax, ax ; xor eax, eax\r
115 mov eax, ss ; mov ax, ss\r
116 lea bp, [esp + IA32_REGS.size]\r
117 ;\r
118 ; rsi in the following 2 instructions is indeed bp in 16-bit code\r
119 ;\r
120 mov [rsi - IA32_REGS.size + IA32_REGS._ESP], bp\r
121 DB 66h\r
122 mov ebx, [rsi - IA32_REGS.size + IA32_REGS._EIP]\r
123 shl ax, 4 ; shl eax, 4\r
124 add bp, ax ; add ebp, eax\r
125 mov ax, cs\r
126 shl ax, 4\r
a8458d6c
JJ
127 lea ax, [eax + ebx + (.64BitCode - .Base)]\r
128 DB 66h, 2eh, 89h, 87h ; mov cs:[bx + (.64Eip - .Base)], eax\r
129 DW .64Eip - .Base\r
fbb5393c 130 DB 66h, 0b8h ; mov eax, imm32\r
a8458d6c 131.SavedCr4: DD 0\r
fbb5393c
JJ
132 mov cr4, rax\r
133 ;\r
134 ; rdi in the instruction below is indeed bx in 16-bit code\r
135 ;\r
136 DB 66h, 2eh ; 2eh is "cs:" segment override\r
a8458d6c 137 lgdt [rdi + (SavedGdt - .Base)]\r
fbb5393c
JJ
138 DB 66h\r
139 mov ecx, 0c0000080h\r
140 rdmsr\r
141 or ah, 1\r
142 wrmsr\r
143 DB 66h, 0b8h ; mov eax, imm32\r
a8458d6c 144.SavedCr0: DD 0\r
fbb5393c 145 mov cr0, rax\r
a8458d6c
JJ
146 DB 66h, 0eah ; jmp far cs:.64Bit\r
147.64Eip: DD 0\r
148.SavedCs: DW 0\r
149.64BitCode:\r
fbb5393c
JJ
150 db 090h \r
151 db 048h, 0bch ; mov rsp, imm64\r
a8458d6c 152.SavedSp: DQ 0 ; restore stack\r
fbb5393c
JJ
153 nop\r
154 ret\r
155\r
156_EntryPoint:\r
157 DD _ToUserCode - ASM_PFX(m16Start)\r
158 DW CODE16\r
159_16Gdtr:\r
160 DW GDT_SIZE - 1\r
161_16GdtrBase:\r
162 DQ _NullSeg\r
163_16Idtr:\r
164 DW (1 << 10) - 1\r
165 DD 0\r
166\r
167;------------------------------------------------------------------------------\r
168; _ToUserCode() takes control in real mode before passing control to user code.\r
169; It will be shadowed to somewhere in memory below 1MB.\r
170;------------------------------------------------------------------------------\r
171_ToUserCode:\r
172 mov ss, edx ; set new segment selectors\r
173 mov ds, edx\r
174 mov es, edx\r
175 mov fs, edx\r
176 mov gs, edx\r
177 DB 66h\r
178 mov ecx, 0c0000080h\r
179 mov cr0, rax ; real mode starts at next instruction\r
180 rdmsr\r
181 and ah, ~1\r
182 wrmsr\r
183 mov cr4, rbp\r
184 mov ss, esi ; set up 16-bit stack segment\r
185 mov sp, bx ; set up 16-bit stack pointer\r
186 DB 66h ; make the following call 32-bit\r
a8458d6c
JJ
187 call .Base ; push eip\r
188.Base:\r
189 pop bp ; ebp <- address of .Base\r
fbb5393c 190 push qword [esp + IA32_REGS.size + 2]\r
a8458d6c 191 lea eax, [rsi + (.RealMode - .Base)] ; rsi is "bp" in 16-bit code\r
fbb5393c
JJ
192 push rax\r
193 retf ; execution begins at next instruction\r
a8458d6c 194.RealMode:\r
fbb5393c 195 DB 66h, 2eh ; CS and operand size override\r
a8458d6c 196 lidt [rsi + (_16Idtr - .Base)]\r
fbb5393c
JJ
197 DB 66h, 61h ; popad\r
198 DB 1fh ; pop ds\r
199 DB 07h ; pop es\r
200 pop fs\r
201 pop gs\r
202 popfw ; popfd\r
203 lea sp, [esp + 4] ; skip high order 32 bits of EFlags\r
204 DB 66h ; make the following retf 32-bit\r
205 retf ; transfer control to user code\r
206\r
207ALIGN 8\r
208\r
209CODE16 equ _16Code - $\r
210DATA16 equ _16Data - $\r
211DATA32 equ _32Data - $\r
212\r
213_NullSeg DQ 0\r
214_16Code:\r
215 DW -1\r
216 DW 0\r
217 DB 0\r
218 DB 9bh\r
219 DB 8fh ; 16-bit segment, 4GB limit\r
220 DB 0\r
221_16Data:\r
222 DW -1\r
223 DW 0\r
224 DB 0\r
225 DB 93h\r
226 DB 8fh ; 16-bit segment, 4GB limit\r
227 DB 0\r
228_32Data:\r
229 DW -1\r
230 DW 0\r
231 DB 0\r
232 DB 93h\r
233 DB 0cfh ; 16-bit segment, 4GB limit\r
234 DB 0\r
235\r
236GDT_SIZE equ $ - _NullSeg\r
237\r
238;------------------------------------------------------------------------------\r
239; IA32_REGISTER_SET *\r
240; EFIAPI\r
241; InternalAsmThunk16 (\r
242; IN IA32_REGISTER_SET *RegisterSet,\r
243; IN OUT VOID *Transition\r
244; );\r
245;------------------------------------------------------------------------------\r
246global ASM_PFX(InternalAsmThunk16)\r
247ASM_PFX(InternalAsmThunk16):\r
248 push rbp\r
249 push rbx\r
250 push rsi\r
251 push rdi\r
252 \r
253 mov ebx, ds\r
254 push rbx ; Save ds segment register on the stack\r
255 mov ebx, es\r
256 push rbx ; Save es segment register on the stack\r
257 mov ebx, ss\r
258 push rbx ; Save ss segment register on the stack\r
259 \r
260 push fs\r
261 push gs\r
262 mov rsi, rcx\r
263 movzx r8d, word [rsi + IA32_REGS._SS]\r
264 mov edi, [rsi + IA32_REGS._ESP]\r
265 lea rdi, [edi - (IA32_REGS.size + 4)]\r
266 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16\r
267 mov ebx, edi ; ebx <- stack for 16-bit code\r
268 push IA32_REGS.size / 4\r
269 add edi, eax ; edi <- linear address of 16-bit stack\r
270 pop rcx\r
271 rep movsd ; copy RegSet\r
a8458d6c 272 lea ecx, [rdx + (_BackFromUserCode.SavedCr4 - ASM_PFX(m16Start))]\r
fbb5393c
JJ
273 mov eax, edx ; eax <- transition code address\r
274 and edx, 0fh\r
275 shl eax, 12 ; segment address in high order 16 bits\r
276 lea ax, [rdx + (_BackFromUserCode - ASM_PFX(m16Start))] ; offset address\r
277 stosd ; [edi] <- return address of user code\r
278 \r
279 sgdt [rsp + 60h] ; save GDT stack in argument space\r
280 movzx r10, word [rsp + 60h] ; r10 <- GDT limit \r
a8458d6c 281 lea r11, [rcx + (InternalAsmThunk16 - _BackFromUserCode.SavedCr4) + 0xf]\r
fbb5393c
JJ
282 and r11, ~0xf ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer\r
283 \r
a8458d6c
JJ
284 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4)], r10w ; save the limit of shadowed GDT table\r
285 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4) + 2], r11 ; save the base address of shadowed GDT table\r
fbb5393c
JJ
286 \r
287 mov rsi, [rsp + 62h] ; rsi <- the original GDT base address\r
288 xchg rcx, r10 ; save rcx to r10 and initialize rcx to be the limit of GDT table\r
289 inc rcx ; rcx <- the size of memory to copy\r
290 xchg rdi, r11 ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table\r
291 rep movsb ; perform memory copy to shadow GDT table\r
292 mov rcx, r10 ; restore the orignal rcx before memory copy\r
293 mov rdi, r11 ; restore the original rdi before memory copy\r
294 \r
295 sidt [rsp + 50h] ; save IDT stack in argument space\r
296 mov rax, cr0\r
a8458d6c 297 mov [rcx + (_BackFromUserCode.SavedCr0 - _BackFromUserCode.SavedCr4)], eax\r
fbb5393c
JJ
298 and eax, 7ffffffeh ; clear PE, PG bits\r
299 mov rbp, cr4\r
a8458d6c 300 mov [rcx], ebp ; save CR4 in _BackFromUserCode.SavedCr4\r
fbb5393c
JJ
301 and ebp, ~30h ; clear PAE, PSE bits\r
302 mov esi, r8d ; esi <- 16-bit stack segment\r
303 DB 6ah, DATA32 ; push DATA32\r
304 pop rdx ; rdx <- 32-bit data segment selector\r
a8458d6c 305 lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4)]\r
fbb5393c
JJ
306 mov ss, edx\r
307 pushfq\r
308 lea edx, [rdx + DATA16 - DATA32]\r
a8458d6c 309 lea r8, [REL .RetFromRealMode]\r
fbb5393c
JJ
310 push r8\r
311 mov r8d, cs\r
a8458d6c
JJ
312 mov [rcx + (_BackFromUserCode.SavedCs - _BackFromUserCode.SavedCr4)], r8w\r
313 mov [rcx + (_BackFromUserCode.SavedSp - _BackFromUserCode.SavedCr4)], rsp\r
314 jmp dword far [rcx + (_EntryPoint - _BackFromUserCode.SavedCr4)]\r
315.RetFromRealMode:\r
fbb5393c
JJ
316 popfq\r
317 lgdt [rsp + 60h] ; restore protected mode GDTR\r
318 lidt [rsp + 50h] ; restore protected mode IDTR\r
319 lea eax, [rbp - IA32_REGS.size]\r
320 pop gs\r
321 pop fs\r
322 pop rbx\r
323 mov ss, ebx\r
324 pop rbx\r
325 mov es, ebx\r
326 pop rbx\r
327 mov ds, ebx\r
328\r
329 pop rdi\r
330 pop rsi\r
331 pop rbx\r
332 pop rbp\r
333\r
334 ret\r