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