]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BaseLib/X64/Thunk16.asm
Update the copyright notice format
[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
bb817c56
HT
6; Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>\r
7; This program and the accompanying materials\r
f1baef62 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
0fe43214 143 db 090h \r
144 db 067h, 0bch ; mov esp, imm32\r
145SavedSp DD ? ; restore stack\r
146 nop\r
f1baef62 147 ret\r
148_BackFromUserCode ENDP\r
149\r
150_EntryPoint DD _ToUserCode - m16Start\r
151 DW CODE16\r
152_16Gdtr LABEL FWORD\r
153 DW GDT_SIZE - 1\r
154_16GdtrBase DQ _NullSeg\r
155_16Idtr FWORD (1 SHL 10) - 1\r
156\r
157;------------------------------------------------------------------------------\r
158; _ToUserCode() takes control in real mode before passing control to user code.\r
159; It will be shadowed to somewhere in memory below 1MB.\r
160;------------------------------------------------------------------------------\r
161_ToUserCode PROC\r
162 mov ss, edx ; set new segment selectors\r
163 mov ds, edx\r
164 mov es, edx\r
165 mov fs, edx\r
166 mov gs, edx\r
167 DB 66h\r
168 mov ecx, 0c0000080h\r
169 mov cr0, rax ; real mode starts at next instruction\r
170 rdmsr\r
171 and ah, NOT 1\r
172 wrmsr\r
173 mov cr4, rbp\r
174 mov ss, esi ; set up 16-bit stack segment\r
175 mov sp, bx ; set up 16-bit stack pointer\r
176 DB 66h ; make the following call 32-bit\r
177 call @Base ; push eip\r
178@Base:\r
179 pop bp ; ebp <- address of @Base\r
180 push [esp + sizeof (IA32_REGS) + 2]\r
181 lea eax, [rsi + (@RealMode - @Base)] ; rsi is "bp" in 16-bit code\r
182 push rax\r
183 retf ; execution begins at next instruction\r
184@RealMode:\r
185 DB 66h, 2eh ; CS and operand size override\r
186 lidt fword ptr [rsi + (_16Idtr - @Base)]\r
187 DB 66h, 61h ; popad\r
188 DB 1fh ; pop ds\r
189 DB 07h ; pop es\r
190 pop fs\r
191 pop gs\r
192 popf ; popfd\r
193 lea sp, [esp + 4] ; skip high order 32 bits of EFlags\r
194 DB 66h ; make the following retf 32-bit\r
195 retf ; transfer control to user code\r
196_ToUserCode ENDP\r
197\r
198CODE16 = _16Code - $\r
199DATA16 = _16Data - $\r
200DATA32 = _32Data - $\r
201\r
202_NullSeg DQ 0\r
203_16Code LABEL QWORD\r
204 DW -1\r
205 DW 0\r
206 DB 0\r
207 DB 9bh\r
208 DB 8fh ; 16-bit segment, 4GB limit\r
209 DB 0\r
210_16Data LABEL QWORD\r
211 DW -1\r
212 DW 0\r
213 DB 0\r
214 DB 93h\r
215 DB 8fh ; 16-bit segment, 4GB limit\r
216 DB 0\r
217_32Data LABEL QWORD\r
218 DW -1\r
219 DW 0\r
220 DB 0\r
221 DB 93h\r
222 DB 0cfh ; 16-bit segment, 4GB limit\r
223 DB 0\r
224\r
225GDT_SIZE = $ - _NullSeg\r
226\r
227;------------------------------------------------------------------------------\r
228; IA32_REGISTER_SET *\r
229; EFIAPI\r
230; InternalAsmThunk16 (\r
231; IN IA32_REGISTER_SET *RegisterSet,\r
232; IN OUT VOID *Transition\r
233; );\r
234;------------------------------------------------------------------------------\r
235InternalAsmThunk16 PROC USES rbp rbx rsi rdi\r
0fe43214 236 mov rbx, ds\r
237 push rbx ; Save ds segment register on the stack\r
238 mov rbx, es\r
239 push rbx ; Save es segment register on the stack\r
240 mov rbx, ss\r
241 push rbx ; Save ss segment register on the stack\r
242 \r
f1baef62 243 push fs\r
244 push gs\r
245 mov rsi, rcx\r
246 movzx r8d, (IA32_REGS ptr [rsi])._SS\r
247 mov edi, (IA32_REGS ptr [rsi])._ESP\r
248 lea rdi, [edi - (sizeof (IA32_REGS) + 4)]\r
249 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16\r
250 mov ebx, edi ; ebx <- stack for 16-bit code\r
251 push sizeof (IA32_REGS) / 4\r
252 add edi, eax ; edi <- linear address of 16-bit stack\r
253 pop rcx\r
254 rep movsd ; copy RegSet\r
255 lea ecx, [rdx + (SavedCr4 - m16Start)]\r
256 mov eax, edx ; eax <- transition code address\r
257 and edx, 0fh\r
258 shl eax, 12 ; segment address in high order 16 bits\r
259 lea ax, [rdx + (_BackFromUserCode - m16Start)] ; offset address\r
260 stosd ; [edi] <- return address of user code\r
a1487801 261 \r
262 sgdt fword ptr [rsp + 60h] ; save GDT stack in argument space\r
263 movzx r10, word ptr [rsp + 60h] ; r10 <- GDT limit \r
264 lea r11, [rcx + (InternalAsmThunk16 - SavedCr4) + 0xf]\r
265 and r11, 0xfffffff0 ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer\r
266 \r
267 mov word ptr [rcx + (SavedGdt - SavedCr4)], r10w ; save the limit of shadowed GDT table\r
268 mov qword ptr [rcx + (SavedGdt - SavedCr4) + 2], r11 ; save the base address of shadowed GDT table\r
269 \r
270 mov rsi, qword ptr [rsp + 62h] ; rsi <- the original GDT base address\r
271 xchg rcx, r10 ; save rcx to r10 and initialize rcx to be the limit of GDT table\r
272 inc rcx ; rcx <- the size of memory to copy\r
273 xchg rdi, r11 ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table\r
274 rep movsb ; perform memory copy to shadow GDT table\r
275 mov rcx, r10 ; restore the orignal rcx before memory copy\r
276 mov rdi, r11 ; restore the original rdi before memory copy\r
277 \r
0fe43214 278 sidt fword ptr [rsp + 50h] ; save IDT stack in argument space\r
f1baef62 279 mov rax, cr0\r
280 mov [rcx + (SavedCr0 - SavedCr4)], eax\r
281 and eax, 7ffffffeh ; clear PE, PG bits\r
282 mov rbp, cr4\r
283 mov [rcx], ebp ; save CR4 in SavedCr4\r
284 and ebp, 300h ; clear all but PCE and OSFXSR bits\r
285 mov esi, r8d ; esi <- 16-bit stack segment\r
286 DB 6ah, DATA32 ; push DATA32\r
287 pop rdx ; rdx <- 32-bit data segment selector\r
288 lgdt fword ptr [rcx + (_16Gdtr - SavedCr4)]\r
289 mov ss, edx\r
290 pushfq\r
291 lea edx, [rdx + DATA16 - DATA32]\r
292 lea r8, @RetFromRealMode\r
293 push r8\r
294 mov r8d, cs\r
295 mov [rcx + (SavedCs - SavedCr4)], r8w\r
0fe43214 296 mov [rcx + (SavedSp - SavedCr4)], esp\r
f1baef62 297 jmp fword ptr [rcx + (_EntryPoint - SavedCr4)]\r
298@RetFromRealMode:\r
299 popfq\r
a1487801 300 lgdt fword ptr [rsp + 60h] ; restore protected mode GDTR\r
0fe43214 301 lidt fword ptr [rsp + 50h] ; restore protected mode IDTR\r
f1baef62 302 lea eax, [rbp - sizeof (IA32_REGS)]\r
303 pop gs\r
304 pop fs\r
0fe43214 305 pop rbx\r
306 mov ss, rbx\r
307 pop rbx\r
308 mov es, rbx\r
309 pop rbx\r
310 mov ds, rbx\r
f1baef62 311 ret\r
312InternalAsmThunk16 ENDP\r
313\r
314 END\r