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