]> git.proxmox.com Git - mirror_edk2.git/blame - MdePkg/Library/BaseLib/Ia32/Thunk16.nasm
MdePkg BaseLib NASM Thunk16: Use NASM local labels
[mirror_edk2.git] / MdePkg / Library / BaseLib / Ia32 / Thunk16.nasm
CommitLineData
6dab5c8a
JJ
1\r
2#include "BaseLibInternals.h"\r
3\r
4;------------------------------------------------------------------------------\r
5;\r
6; Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
7; 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
25global ASM_PFX(m16Size)\r
26global ASM_PFX(mThunk16Attr)\r
27global ASM_PFX(m16Gdt)\r
28global ASM_PFX(m16GdtrBase)\r
29global ASM_PFX(mTransition)\r
30global ASM_PFX(m16Start)\r
31\r
32struc IA32_REGS\r
33\r
34 ._EDI: resd 1\r
35 ._ESI: resd 1\r
36 ._EBP: resd 1\r
37 ._ESP: resd 1\r
38 ._EBX: resd 1\r
39 ._EDX: resd 1\r
40 ._ECX: resd 1\r
41 ._EAX: resd 1\r
42 ._DS: resw 1\r
43 ._ES: resw 1\r
44 ._FS: resw 1\r
45 ._GS: resw 1\r
46 ._EFLAGS: resd 1\r
47 ._EIP: resd 1\r
48 ._CS: resw 1\r
49 ._SS: resw 1\r
50 .size:\r
51\r
52endstruc\r
53\r
54;; .const\r
55\r
56SECTION .data\r
57\r
58;\r
59; These are global constant to convey information to C code.\r
60;\r
61ASM_PFX(m16Size) DW InternalAsmThunk16 - ASM_PFX(m16Start)\r
a8458d6c 62ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttr - ASM_PFX(m16Start)\r
6dab5c8a
JJ
63ASM_PFX(m16Gdt) DW _NullSegDesc - ASM_PFX(m16Start)\r
64ASM_PFX(m16GdtrBase) DW _16GdtrBase - ASM_PFX(m16Start)\r
65ASM_PFX(mTransition) DW _EntryPoint - ASM_PFX(m16Start)\r
66\r
67SECTION .text\r
68\r
69ASM_PFX(m16Start):\r
70\r
71SavedGdt:\r
72 dw 0\r
73 dd 0\r
74\r
75;------------------------------------------------------------------------------\r
76; _BackFromUserCode() takes control in real mode after 'retf' has been executed\r
77; by user code. It will be shadowed to somewhere in memory below 1MB.\r
78;------------------------------------------------------------------------------\r
79_BackFromUserCode:\r
80 ;\r
81 ; The order of saved registers on the stack matches the order they appears\r
82 ; in IA32_REGS structure. This facilitates wrapper function to extract them\r
83 ; into that structure.\r
84 ;\r
85 push ss\r
86 push cs\r
87 DB 66h\r
a8458d6c
JJ
88 call .Base ; push eip\r
89.Base:\r
6dab5c8a
JJ
90 pushfw ; pushfd actually\r
91 cli ; disable interrupts\r
92 push gs\r
93 push fs\r
94 push es\r
95 push ds\r
96 pushaw ; pushad actually\r
97 DB 66h, 0bah ; mov edx, imm32\r
a8458d6c 98.ThunkAttr: dd 0\r
6dab5c8a 99 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15\r
a8458d6c 100 jz .1\r
6dab5c8a
JJ
101 mov eax, 15cd2401h ; mov ax, 2401h & int 15h\r
102 cli ; disable interrupts\r
a8458d6c
JJ
103 jnc .2\r
104.1:\r
6dab5c8a 105 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL\r
a8458d6c 106 jz .2\r
6dab5c8a
JJ
107 in al, 92h\r
108 or al, 2\r
109 out 92h, al ; deactivate A20M#\r
a8458d6c 110.2:\r
6dab5c8a
JJ
111 xor ax, ax ; xor eax, eax\r
112 mov eax, ss ; mov ax, ss\r
113 DB 67h\r
114 lea bp, [esp + IA32_REGS.size]\r
115 ;\r
116 ; esi's in the following 2 instructions are indeed bp in 16-bit code. Fact\r
117 ; is "esi" in 32-bit addressing mode has the same encoding of "bp" in 16-\r
118 ; bit addressing mode.\r
119 ;\r
120 mov [esi - IA32_REGS.size + IA32_REGS._ESP], bp\r
121 mov ebx, [esi - IA32_REGS.size + IA32_REGS._EIP]\r
122 shl ax, 4 ; shl eax, 4\r
123 add bp, ax ; add ebp, eax\r
124 DB 66h, 0b8h ; mov eax, imm32\r
a8458d6c 125.SavedCr4: DD 0\r
6dab5c8a
JJ
126 mov cr4, eax\r
127 DB 66h\r
a8458d6c 128 lgdt [cs:edi + (SavedGdt - .Base)]\r
6dab5c8a 129 DB 66h, 0b8h ; mov eax, imm32\r
a8458d6c 130.SavedCr0: DD 0\r
6dab5c8a
JJ
131 mov cr0, eax\r
132 DB 0b8h ; mov ax, imm16\r
a8458d6c 133.SavedSs DW 0\r
6dab5c8a
JJ
134 mov ss, eax\r
135 DB 66h, 0bch ; mov esp, imm32\r
a8458d6c 136.SavedEsp DD 0\r
6dab5c8a
JJ
137 DB 66h\r
138 retf ; return to protected mode\r
139\r
140_EntryPoint:\r
141 DD _ToUserCode - ASM_PFX(m16Start)\r
142 DW 8h\r
143_16Idtr:\r
144 DW (1 << 10) - 1\r
145 DD 0\r
146_16Gdtr:\r
147 DW GdtEnd - _NullSegDesc - 1\r
148_16GdtrBase:\r
149 DD _NullSegDesc\r
150\r
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
155_ToUserCode:\r
156 mov edx, ss\r
157 mov ss, ecx ; set new segment selectors\r
158 mov ds, ecx\r
159 mov es, ecx\r
160 mov fs, ecx\r
161 mov gs, ecx\r
162 mov cr0, eax ; real mode starts at next instruction\r
163 ; which (per SDM) *must* be a far JMP.\r
164 DB 0eah\r
a8458d6c 165.RealAddr: DW 0, 0\r
6dab5c8a
JJ
166\r
167 mov cr4, ebp\r
168 mov ss, esi ; set up 16-bit stack segment\r
169 xchg sp, bx ; set up 16-bit stack pointer\r
170\r
171; mov bp, [esp + sizeof(IA32_REGS)\r
172 DB 67h\r
173 mov ebp, [esp + IA32_REGS.size] ; BackFromUserCode address from stack\r
174\r
a8458d6c
JJ
175; mov cs:[bp + (_BackFromUserCode.SavedSs - _BackFromUserCode)], dx\r
176 mov [cs:esi + (_BackFromUserCode.SavedSs - _BackFromUserCode)], edx\r
6dab5c8a 177\r
a8458d6c 178; mov cs:[bp + (_BackFromUserCode.SavedEsp - _BackFromUserCode)], ebx\r
6dab5c8a 179 DB 2eh, 66h, 89h, 9eh\r
a8458d6c 180 DW _BackFromUserCode.SavedEsp - _BackFromUserCode\r
6dab5c8a
JJ
181\r
182; lidt cs:[bp + (_16Idtr - _BackFromUserCode)]\r
183 DB 2eh, 66h, 0fh, 01h, 9eh\r
184 DW _16Idtr - _BackFromUserCode\r
185\r
186 popaw ; popad actually\r
187 pop ds\r
188 pop es\r
189 pop fs\r
190 pop gs\r
191 popfw ; popfd\r
192\r
193 DB 66h ; Use 32-bit addressing for "retf" below\r
194 retf ; transfer control to user code\r
195\r
196ALIGN 16\r
197_NullSegDesc DQ 0\r
198_16CsDesc:\r
199 DW -1\r
200 DW 0\r
201 DB 0\r
202 DB 9bh\r
203 DB 8fh ; 16-bit segment, 4GB limit\r
204 DB 0\r
205_16DsDesc:\r
206 DW -1\r
207 DW 0\r
208 DB 0\r
209 DB 93h\r
210 DB 8fh ; 16-bit segment, 4GB limit\r
211 DB 0\r
212GdtEnd:\r
213\r
214;------------------------------------------------------------------------------\r
215; IA32_REGISTER_SET *\r
216; EFIAPI\r
217; InternalAsmThunk16 (\r
218; IN IA32_REGISTER_SET *RegisterSet,\r
219; IN OUT VOID *Transition\r
220; );\r
221;------------------------------------------------------------------------------\r
222global ASM_PFX(InternalAsmThunk16)\r
223ASM_PFX(InternalAsmThunk16):\r
224 push ebp\r
225 push ebx\r
226 push esi\r
227 push edi\r
228 push ds\r
229 push es\r
230 push fs\r
231 push gs\r
232 mov esi, [esp + 36] ; esi <- RegSet, the 1st parameter\r
233 movzx edx, word [esi + IA32_REGS._SS]\r
234 mov edi, [esi + IA32_REGS._ESP]\r
235 add edi, - (IA32_REGS.size + 4) ; reserve stack space\r
236 mov ebx, edi ; ebx <- stack offset\r
237 imul eax, edx, 16 ; eax <- edx * 16\r
238 push IA32_REGS.size / 4\r
239 add edi, eax ; edi <- linear address of 16-bit stack\r
240 pop ecx\r
241 rep movsd ; copy RegSet\r
242 mov eax, [esp + 40] ; eax <- address of transition code\r
243 mov esi, edx ; esi <- 16-bit stack segment\r
a8458d6c 244 lea edx, [eax + (_BackFromUserCode.SavedCr0 - ASM_PFX(m16Start))]\r
6dab5c8a
JJ
245 mov ecx, eax\r
246 and ecx, 0fh\r
247 shl eax, 12\r
248 lea ecx, [ecx + (_BackFromUserCode - ASM_PFX(m16Start))]\r
249 mov ax, cx\r
250 stosd ; [edi] <- return address of user code\r
a8458d6c
JJ
251 add eax, _ToUserCode.RealAddr + 4 - _BackFromUserCode\r
252 mov [edx + (_ToUserCode.RealAddr - _BackFromUserCode.SavedCr0)], eax\r
253 sgdt [edx + (SavedGdt - _BackFromUserCode.SavedCr0)]\r
6dab5c8a
JJ
254 sidt [esp + 36] ; save IDT stack in argument space\r
255 mov eax, cr0\r
a8458d6c 256 mov [edx], eax ; save CR0 in _BackFromUserCode.SavedCr0\r
6dab5c8a
JJ
257 and eax, 7ffffffeh ; clear PE, PG bits\r
258 mov ebp, cr4\r
a8458d6c 259 mov [edx + (_BackFromUserCode.SavedCr4 - _BackFromUserCode.SavedCr0)], ebp\r
6dab5c8a
JJ
260 and ebp, ~30h ; clear PAE, PSE bits\r
261 push 10h\r
262 pop ecx ; ecx <- selector for data segments\r
a8458d6c 263 lgdt [edx + (_16Gdtr - _BackFromUserCode.SavedCr0)]\r
6dab5c8a 264 pushfd ; Save df/if indeed\r
a8458d6c 265 call dword far [edx + (_EntryPoint - _BackFromUserCode.SavedCr0)]\r
6dab5c8a
JJ
266 popfd\r
267 lidt [esp + 36] ; restore protected mode IDTR\r
268 lea eax, [ebp - IA32_REGS.size] ; eax <- the address of IA32_REGS\r
269 pop gs\r
270 pop fs\r
271 pop es\r
272 pop ds\r
273 pop edi\r
274 pop esi\r
275 pop ebx\r
276 pop ebp\r
277 ret\r