]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - 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
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
60ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttr - 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
86o32 call dword .Base ; push eip\r
87.Base:\r
88 push dword 0 ; reserved high order 32 bits of EFlags\r
89 pushfd\r
90 cli ; disable interrupts\r
91 push gs\r
92 push fs\r
93 push es\r
94 push ds\r
95 pushad\r
96 DB 66h, 0bah ; mov edx, imm32\r
97.ThunkAttr: dd 0\r
98 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15\r
99 jz .1\r
100 mov ax, 2401h\r
101 int 15h\r
102 cli ; disable interrupts\r
103 jnc .2\r
104.1:\r
105 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL\r
106 jz .2\r
107 in al, 92h\r
108 or al, 2\r
109 out 92h, al ; deactivate A20M#\r
110.2:\r
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
122 DB 66h, 0b8h ; mov eax, imm32\r
123.SavedCr4: DD 0\r
124 mov cr4, eax\r
125o32 lgdt [cs:bx + (SavedGdt - .Base)]\r
126 mov ecx, 0c0000080h\r
127 rdmsr\r
128 or ah, 1\r
129 wrmsr\r
130 DB 66h, 0b8h ; mov eax, imm32\r
131.SavedCr0: DD 0\r
132 mov cr0, eax\r
133 DB 66h, 0eah ; jmp far cs:.64Bit\r
134.64Eip: DD 0\r
135.SavedCs: DW 0\r
136.64BitCode:\r
137BITS 64\r
138 nop\r
139 db 048h, 0bch ; mov rsp, imm64\r
140.SavedSp: DQ 0 ; restore stack\r
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
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
166 mov ecx, 0c0000080h\r
167 mov cr0, eax ; real mode starts at next instruction\r
168 rdmsr\r
169 and ah, ~1\r
170 wrmsr\r
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
175.Base:\r
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
180 retf ; execution begins at next instruction\r
181.RealMode:\r
182\r
183o32 lidt [cs:bp + (_16Idtr - .Base)]\r
184\r
185 popad\r
186 pop ds\r
187 pop es\r
188 pop fs\r
189 pop gs\r
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
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
236BITS 64\r
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
261 lea ecx, [rdx + (_BackFromUserCode.SavedCr4 - ASM_PFX(m16Start))]\r
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
270 lea r11, [rcx + (InternalAsmThunk16 - _BackFromUserCode.SavedCr4) + 0xf]\r
271 and r11, ~0xf ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer\r
272 \r
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
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
286 mov [rcx + (_BackFromUserCode.SavedCr0 - _BackFromUserCode.SavedCr4)], eax\r
287 and eax, 7ffffffeh ; clear PE, PG bits\r
288 mov rbp, cr4\r
289 mov [rcx], ebp ; save CR4 in _BackFromUserCode.SavedCr4\r
290 and ebp, ~30h ; clear PAE, PSE bits\r
291 mov esi, r8d ; esi <- 16-bit stack segment\r
292 push DATA32\r
293 pop rdx ; rdx <- 32-bit data segment selector\r
294 lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4)]\r
295 mov ss, edx\r
296 pushfq\r
297 lea edx, [rdx + DATA16 - DATA32]\r
298 lea r8, [REL .RetFromRealMode]\r
299 push r8\r
300 mov r8d, cs\r
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
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