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