]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BaseLib/X64/Thunk16.asm
Use #include "XXX.h" for module internal header files.
[mirror_edk2.git] / MdePkg / Library / BaseLib / X64 / Thunk16.asm
CommitLineData
1efcc4ae 1\r
47fc17d8 2#include "BaseLibInternals.h"\r
f1baef62 3\r
4;------------------------------------------------------------------------------\r
5;\r
6; Copyright (c) 2006, Intel Corporation\r
7; All rights reserved. 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
25EXTERNDEF m16Start:BYTE\r
26EXTERNDEF m16Size:WORD\r
27EXTERNDEF mThunk16Attr:WORD\r
28EXTERNDEF m16Gdt:WORD\r
29EXTERNDEF m16GdtrBase:WORD\r
30EXTERNDEF mTransition:WORD\r
31\r
32IA32_REGS STRUC 4t\r
33_EDI DD ?\r
34_ESI DD ?\r
35_EBP DD ?\r
36_ESP DD ?\r
37_EBX DD ?\r
38_EDX DD ?\r
39_ECX DD ?\r
40_EAX DD ?\r
41_DS DW ?\r
42_ES DW ?\r
43_FS DW ?\r
44_GS DW ?\r
45_EFLAGS DQ ?\r
46_EIP DD ?\r
47_CS DW ?\r
48_SS DW ?\r
49IA32_REGS ENDS\r
50\r
51 .const\r
52\r
53m16Size DW InternalAsmThunk16 - m16Start\r
54mThunk16Attr DW _ThunkAttr - m16Start\r
55m16Gdt DW _NullSeg - m16Start\r
56m16GdtrBase DW _16GdtrBase - m16Start\r
57mTransition DW _EntryPoint - m16Start\r
58\r
59 .code\r
60\r
61m16Start LABEL BYTE\r
62\r
63SavedGdt LABEL FWORD\r
64 DW ?\r
65 DQ ?\r
66\r
67;------------------------------------------------------------------------------\r
68; _BackFromUserCode() takes control in real mode after 'retf' has been executed\r
69; by user code. It will be shadowed to somewhere in memory below 1MB.\r
70;------------------------------------------------------------------------------\r
71_BackFromUserCode PROC\r
72 ;\r
73 ; The order of saved registers on the stack matches the order they appears\r
74 ; in IA32_REGS structure. This facilitates wrapper function to extract them\r
75 ; into that structure.\r
76 ;\r
77 ; Some instructions for manipulation of segment registers have to be written\r
78 ; in opcode since 64-bit MASM prevents accesses to those registers.\r
79 ;\r
80 DB 16h ; push ss\r
81 DB 0eh ; push cs\r
82 DB 66h\r
83 call @Base ; push eip\r
84@Base:\r
85 DB 66h\r
86 push 0 ; reserved high order 32 bits of EFlags\r
87 pushf ; pushfd actually\r
88 cli ; disable interrupts\r
89 push gs\r
90 push fs\r
91 DB 6 ; push es\r
92 DB 1eh ; push ds\r
93 DB 66h, 60h ; pushad\r
94 DB 66h, 0bah ; mov edx, imm32\r
95_ThunkAttr DD ?\r
96 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15\r
97 jz @1\r
98 mov eax, 15cd2401h ; mov ax, 2401h & int 15h\r
99 cli ; disable interrupts\r
100 jnc @2\r
101@1:\r
102 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL\r
103 jz @2\r
104 in al, 92h\r
105 or al, 2\r
106 out 92h, al ; deactivate A20M#\r
107@2:\r
108 mov eax, ss\r
109 lea bp, [esp + sizeof (IA32_REGS)]\r
110 ;\r
111 ; rsi in the following 2 instructions is indeed bp in 16-bit code\r
112 ;\r
113 mov word ptr (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._ESP, bp\r
114 DB 66h\r
115 mov ebx, (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._EIP\r
116 shl ax, 4 ; shl eax, 4\r
117 add bp, ax ; add ebp, eax\r
118 mov ax, cs\r
119 shl ax, 4\r
120 lea ax, [eax + ebx + (@64BitCode - @Base)]\r
121 DB 66h, 2eh, 89h, 87h ; mov cs:[bx + (@64Eip - @Base)], eax\r
122 DW @64Eip - @Base\r
123 DB 66h, 0b8h ; mov eax, imm32\r
124SavedCr4 DD ?\r
125 mov cr4, rax\r
126 ;\r
127 ; rdi in the instruction below is indeed bx in 16-bit code\r
128 ;\r
129 DB 66h, 2eh ; 2eh is "cs:" segment override\r
130 lgdt fword ptr [rdi + (SavedGdt - @Base)]\r
131 DB 66h\r
132 mov ecx, 0c0000080h\r
133 rdmsr\r
134 or ah, 1\r
135 wrmsr\r
136 DB 66h, 0b8h ; mov eax, imm32\r
137SavedCr0 DD ?\r
138 mov cr0, rax\r
139 DB 66h, 0eah ; jmp far cs:@64Bit\r
140@64Eip DD ?\r
141SavedCs DW ?\r
142@64BitCode:\r
143 mov rsp, r8 ; restore stack\r
144 ret\r
145_BackFromUserCode ENDP\r
146\r
147_EntryPoint DD _ToUserCode - m16Start\r
148 DW CODE16\r
149_16Gdtr LABEL FWORD\r
150 DW GDT_SIZE - 1\r
151_16GdtrBase DQ _NullSeg\r
152_16Idtr FWORD (1 SHL 10) - 1\r
153\r
154;------------------------------------------------------------------------------\r
155; _ToUserCode() takes control in real mode before passing control to user code.\r
156; It will be shadowed to somewhere in memory below 1MB.\r
157;------------------------------------------------------------------------------\r
158_ToUserCode PROC\r
159 mov ss, edx ; set new segment selectors\r
160 mov ds, edx\r
161 mov es, edx\r
162 mov fs, edx\r
163 mov gs, edx\r
164 DB 66h\r
165 mov ecx, 0c0000080h\r
166 mov cr0, rax ; real mode starts at next instruction\r
167 rdmsr\r
168 and ah, NOT 1\r
169 wrmsr\r
170 mov cr4, rbp\r
171 mov ss, esi ; set up 16-bit stack segment\r
172 mov sp, bx ; set up 16-bit stack pointer\r
173 DB 66h ; make the following call 32-bit\r
174 call @Base ; push eip\r
175@Base:\r
176 pop bp ; ebp <- address of @Base\r
177 push [esp + sizeof (IA32_REGS) + 2]\r
178 lea eax, [rsi + (@RealMode - @Base)] ; rsi is "bp" in 16-bit code\r
179 push rax\r
180 retf ; execution begins at next instruction\r
181@RealMode:\r
182 DB 66h, 2eh ; CS and operand size override\r
183 lidt fword ptr [rsi + (_16Idtr - @Base)]\r
184 DB 66h, 61h ; popad\r
185 DB 1fh ; pop ds\r
186 DB 07h ; pop es\r
187 pop fs\r
188 pop gs\r
189 popf ; popfd\r
190 lea sp, [esp + 4] ; skip high order 32 bits of EFlags\r
191 DB 66h ; make the following retf 32-bit\r
192 retf ; transfer control to user code\r
193_ToUserCode ENDP\r
194\r
195CODE16 = _16Code - $\r
196DATA16 = _16Data - $\r
197DATA32 = _32Data - $\r
198\r
199_NullSeg DQ 0\r
200_16Code LABEL QWORD\r
201 DW -1\r
202 DW 0\r
203 DB 0\r
204 DB 9bh\r
205 DB 8fh ; 16-bit segment, 4GB limit\r
206 DB 0\r
207_16Data LABEL QWORD\r
208 DW -1\r
209 DW 0\r
210 DB 0\r
211 DB 93h\r
212 DB 8fh ; 16-bit segment, 4GB limit\r
213 DB 0\r
214_32Data LABEL QWORD\r
215 DW -1\r
216 DW 0\r
217 DB 0\r
218 DB 93h\r
219 DB 0cfh ; 16-bit segment, 4GB limit\r
220 DB 0\r
221\r
222GDT_SIZE = $ - _NullSeg\r
223\r
224;------------------------------------------------------------------------------\r
225; IA32_REGISTER_SET *\r
226; EFIAPI\r
227; InternalAsmThunk16 (\r
228; IN IA32_REGISTER_SET *RegisterSet,\r
229; IN OUT VOID *Transition\r
230; );\r
231;------------------------------------------------------------------------------\r
232InternalAsmThunk16 PROC USES rbp rbx rsi rdi\r
233 mov r10d, ds ; r9 ~ r11 are not accessible in 16-bit\r
234 mov r11d, es ; so use them for saving seg registers\r
235 mov r9d, ss\r
236 push fs\r
237 push gs\r
238 mov rsi, rcx\r
239 movzx r8d, (IA32_REGS ptr [rsi])._SS\r
240 mov edi, (IA32_REGS ptr [rsi])._ESP\r
241 lea rdi, [edi - (sizeof (IA32_REGS) + 4)]\r
242 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16\r
243 mov ebx, edi ; ebx <- stack for 16-bit code\r
244 push sizeof (IA32_REGS) / 4\r
245 add edi, eax ; edi <- linear address of 16-bit stack\r
246 pop rcx\r
247 rep movsd ; copy RegSet\r
248 lea ecx, [rdx + (SavedCr4 - m16Start)]\r
249 mov eax, edx ; eax <- transition code address\r
250 and edx, 0fh\r
251 shl eax, 12 ; segment address in high order 16 bits\r
252 lea ax, [rdx + (_BackFromUserCode - m16Start)] ; offset address\r
253 stosd ; [edi] <- return address of user code\r
254 sgdt fword ptr [rcx + (SavedGdt - SavedCr4)]\r
255 sidt fword ptr [rsp + 38h] ; save IDT stack in argument space\r
256 mov rax, cr0\r
257 mov [rcx + (SavedCr0 - SavedCr4)], eax\r
258 and eax, 7ffffffeh ; clear PE, PG bits\r
259 mov rbp, cr4\r
260 mov [rcx], ebp ; save CR4 in SavedCr4\r
261 and ebp, 300h ; clear all but PCE and OSFXSR bits\r
262 mov esi, r8d ; esi <- 16-bit stack segment\r
263 DB 6ah, DATA32 ; push DATA32\r
264 pop rdx ; rdx <- 32-bit data segment selector\r
265 lgdt fword ptr [rcx + (_16Gdtr - SavedCr4)]\r
266 mov ss, edx\r
267 pushfq\r
268 lea edx, [rdx + DATA16 - DATA32]\r
269 lea r8, @RetFromRealMode\r
270 push r8\r
271 mov r8d, cs\r
272 mov [rcx + (SavedCs - SavedCr4)], r8w\r
273 mov r8, rsp\r
274 jmp fword ptr [rcx + (_EntryPoint - SavedCr4)]\r
275@RetFromRealMode:\r
276 popfq\r
277 lidt fword ptr [rsp + 38h] ; restore protected mode IDTR\r
278 lea eax, [rbp - sizeof (IA32_REGS)]\r
279 pop gs\r
280 pop fs\r
281 mov ss, r9d\r
282 mov es, r11d\r
283 mov ds, r10d\r
284 ret\r
285InternalAsmThunk16 ENDP\r
286\r
287 END\r