]> git.proxmox.com Git - mirror_edk2.git/blame - EdkCompatibilityPkg/Foundation/Library/EdkIIGlueLib/Library/BaseLib/X64/Thunk16.asm
Maintainers.txt: Remove EdkCompatibilityPkg information
[mirror_edk2.git] / EdkCompatibilityPkg / Foundation / Library / EdkIIGlueLib / Library / BaseLib / X64 / Thunk16.asm
CommitLineData
0249feb8 1; Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>\r
2c7e5c2f 2; This program and the accompanying materials \r
3eb9473e 3; are licensed and made available under the terms and conditions of the BSD License \r
4; which accompanies this distribution. The full text of the license may be found at \r
5; http://opensource.org/licenses/bsd-license.php \r
6; \r
7; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
8; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
9;\r
10; Module Name:\r
11;\r
12; Thunk.asm\r
13;\r
14; Abstract:\r
15;\r
16; Real mode thunk\r
17;\r
18;------------------------------------------------------------------------------\r
19\r
20EXTERNDEF m16Start:BYTE\r
21EXTERNDEF m16Size:WORD\r
22EXTERNDEF mThunk16Attr:WORD\r
23EXTERNDEF m16Gdt:WORD\r
24EXTERNDEF m16GdtrBase:WORD\r
25EXTERNDEF mTransition:WORD\r
26\r
27THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 EQU 2\r
28THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL EQU 4\r
29\r
30IA32_REGS STRUC 4t\r
31_EDI DD ?\r
32_ESI DD ?\r
33_EBP DD ?\r
34_ESP DD ?\r
35_EBX DD ?\r
36_EDX DD ?\r
37_ECX DD ?\r
38_EAX DD ?\r
39_DS DW ?\r
40_ES DW ?\r
41_FS DW ?\r
42_GS DW ?\r
43_EFLAGS DQ ?\r
44_EIP DD ?\r
45_CS DW ?\r
46_SS DW ?\r
47IA32_REGS ENDS\r
48\r
49 .const\r
50\r
51m16Size DW InternalAsmThunk16 - m16Start\r
52mThunk16Attr DW _ThunkAttr - m16Start\r
53m16Gdt DW _NullSeg - m16Start\r
54m16GdtrBase DW _16GdtrBase - m16Start\r
55mTransition DW _EntryPoint - m16Start\r
56\r
57 .code\r
58\r
59m16Start LABEL BYTE\r
60\r
61SavedGdt LABEL FWORD\r
62 DW ?\r
63 DQ ?\r
64\r
65;------------------------------------------------------------------------------\r
66; _BackFromUserCode() takes control in real mode after 'retf' has been executed\r
67; by user code. It will be shadowed to somewhere in memory below 1MB.\r
68;------------------------------------------------------------------------------\r
69_BackFromUserCode PROC\r
70 ;\r
71 ; The order of saved registers on the stack matches the order they appears\r
72 ; in IA32_REGS structure. This facilitates wrapper function to extract them\r
73 ; into that structure.\r
74 ;\r
75 ; Some instructions for manipulation of segment registers have to be written\r
76 ; in opcode since 64-bit MASM prevents accesses to those registers.\r
77 ;\r
78 DB 16h ; push ss\r
79 DB 0eh ; push cs\r
80 DB 66h\r
81 call @Base ; push eip\r
82@Base:\r
83 DB 66h\r
84 push 0 ; reserved high order 32 bits of EFlags\r
85 pushf ; pushfd actually\r
86 cli ; disable interrupts\r
87 push gs\r
88 push fs\r
89 DB 6 ; push es\r
90 DB 1eh ; push ds\r
91 DB 66h, 60h ; pushad\r
92 DB 66h, 0bah ; mov edx, imm32\r
93_ThunkAttr DD ?\r
94 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15\r
95 jz @1\r
96 mov eax, 15cd2401h ; mov ax, 2401h & int 15h\r
97 cli ; disable interrupts\r
98 jnc @2\r
99@1:\r
100 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL\r
101 jz @2\r
102 in al, 92h\r
103 or al, 2\r
104 out 92h, al ; deactivate A20M#\r
105@2:\r
0249feb8
LG
106 xor ax, ax ; xor eax, eax\r
107 mov eax, ss ; mov ax, ss\r
3eb9473e 108 lea bp, [esp + sizeof (IA32_REGS)]\r
109 ;\r
110 ; rsi in the following 2 instructions is indeed bp in 16-bit code\r
111 ;\r
112 mov word ptr (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._ESP, bp\r
113 DB 66h\r
114 mov ebx, (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._EIP\r
115 shl ax, 4 ; shl eax, 4\r
116 add bp, ax ; add ebp, eax\r
117 mov ax, cs\r
118 shl ax, 4\r
119 lea ax, [eax + ebx + (@64BitCode - @Base)]\r
120 DB 66h, 2eh, 89h, 87h ; mov cs:[bx + (@64Eip - @Base)], eax\r
121 DW @64Eip - @Base\r
122 DB 66h, 0b8h ; mov eax, imm32\r
123SavedCr4 DD ?\r
124 mov cr4, rax\r
125 ;\r
126 ; rdi in the instruction below is indeed bx in 16-bit code\r
127 ;\r
128 DB 66h, 2eh ; 2eh is "cs:" segment override\r
129 lgdt fword ptr [rdi + (SavedGdt - @Base)]\r
130 DB 66h\r
131 mov ecx, 0c0000080h\r
132 rdmsr\r
133 or ah, 1\r
134 wrmsr\r
135 DB 66h, 0b8h ; mov eax, imm32\r
136SavedCr0 DD ?\r
137 mov cr0, rax\r
138 DB 66h, 0eah ; jmp far cs:@64Bit\r
139@64Eip DD ?\r
140SavedCs DW ?\r
141@64BitCode:\r
1e437167 142 db 090h \r
143 db 067h, 0bch ; mov esp, imm32\r
144SavedSp DD ? ; restore stack\r
145 nop\r
3eb9473e 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
1e437167 235 mov rbx, ds\r
236 push rbx ; Save ds segment register on the stack\r
237 mov rbx, es\r
238 push rbx ; Save es segment register on the stack\r
239 mov rbx, ss\r
240 push rbx ; Save ss segment register on the stack\r
241 \r
3eb9473e 242 push fs\r
243 push gs\r
244 mov rsi, rcx\r
245 movzx r8d, (IA32_REGS ptr [rsi])._SS\r
246 mov edi, (IA32_REGS ptr [rsi])._ESP\r
247 lea rdi, [edi - (sizeof (IA32_REGS) + 4)]\r
248 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16\r
249 mov ebx, edi ; ebx <- stack for 16-bit code\r
250 push sizeof (IA32_REGS) / 4\r
251 add edi, eax ; edi <- linear address of 16-bit stack\r
252 pop rcx\r
253 rep movsd ; copy RegSet\r
254 lea ecx, [rdx + (SavedCr4 - m16Start)]\r
255 mov eax, edx ; eax <- transition code address\r
256 and edx, 0fh\r
257 shl eax, 12 ; segment address in high order 16 bits\r
258 lea ax, [rdx + (_BackFromUserCode - m16Start)] ; offset address\r
259 stosd ; [edi] <- return address of user code\r
260 sgdt fword ptr [rcx + (SavedGdt - SavedCr4)]\r
1e437167 261 sidt fword ptr [rsp + 50h] ; save IDT stack in argument space\r
3eb9473e 262 mov rax, cr0\r
263 mov [rcx + (SavedCr0 - SavedCr4)], eax\r
264 and eax, 7ffffffeh ; clear PE, PG bits\r
265 mov rbp, cr4\r
266 mov [rcx], ebp ; save CR4 in SavedCr4\r
267 and ebp, 300h ; clear all but PCE and OSFXSR bits\r
268 mov esi, r8d ; esi <- 16-bit stack segment\r
269 DB 6ah, DATA32 ; push DATA32\r
270 pop rdx ; rdx <- 32-bit data segment selector\r
271 lgdt fword ptr [rcx + (_16Gdtr - SavedCr4)]\r
272 mov ss, edx\r
273 pushfq\r
274 lea edx, [rdx + DATA16 - DATA32]\r
275 lea r8, @RetFromRealMode\r
276 push r8\r
277 mov r8d, cs\r
278 mov [rcx + (SavedCs - SavedCr4)], r8w\r
1e437167 279 mov [rcx + (SavedSp - SavedCr4)], esp\r
3eb9473e 280 jmp fword ptr [rcx + (_EntryPoint - SavedCr4)]\r
281@RetFromRealMode:\r
282 popfq\r
1e437167 283 lidt fword ptr [rsp + 50h] ; restore protected mode IDTR\r
3eb9473e 284 lea eax, [rbp - sizeof (IA32_REGS)]\r
285 pop gs\r
286 pop fs\r
1e437167 287 pop rbx\r
288 mov ss, rbx\r
289 pop rbx\r
290 mov es, rbx\r
291 pop rbx\r
292 mov ds, rbx\r
3eb9473e 293 ret\r
294InternalAsmThunk16 ENDP\r
295\r
296 END\r