]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdePkg/Library/BaseLib/Ia32/Thunk16.nasm
MdePkg/BaseLib: Support IA32 processors without CLFLUSH
[mirror_edk2.git] / MdePkg / Library / BaseLib / Ia32 / Thunk16.nasm
... / ...
CommitLineData
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 ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start)\r
62ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttrEnd - 4 - ASM_PFX(m16Start)\r
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
85BITS 16\r
86 push ss\r
87 push cs\r
88 ;\r
89 ; Note: We can't use o32 on the next instruction because of a bug\r
90 ; in NASM 2.09.04 through 2.10rc1.\r
91 ;\r
92 call dword .Base ; push eip\r
93.Base:\r
94 pushfd\r
95 cli ; disable interrupts\r
96 push gs\r
97 push fs\r
98 push es\r
99 push ds\r
100 pushad\r
101 mov edx, strict dword 0\r
102.ThunkAttrEnd:\r
103 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15\r
104 jz .1\r
105 mov ax, 2401h\r
106 int 15h\r
107 cli ; disable interrupts\r
108 jnc .2\r
109.1:\r
110 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL\r
111 jz .2\r
112 in al, 92h\r
113 or al, 2\r
114 out 92h, al ; deactivate A20M#\r
115.2:\r
116 xor eax, eax\r
117 mov ax, ss\r
118 lea ebp, [esp + IA32_REGS.size]\r
119 mov [bp - IA32_REGS.size + IA32_REGS._ESP], ebp\r
120 mov bx, [bp - IA32_REGS.size + IA32_REGS._EIP]\r
121 shl eax, 4 ; shl eax, 4\r
122 add ebp, eax ; add ebp, eax\r
123 mov eax, strict dword 0\r
124.SavedCr4End:\r
125 mov cr4, eax\r
126o32 lgdt [cs:bx + (SavedGdt - .Base)]\r
127 mov eax, strict dword 0\r
128.SavedCr0End:\r
129 mov cr0, eax\r
130 mov ax, strict word 0\r
131.SavedSsEnd:\r
132 mov ss, eax\r
133 mov esp, strict dword 0\r
134.SavedEspEnd:\r
135o32 retf ; return to protected mode\r
136\r
137_EntryPoint:\r
138 DD _ToUserCode - ASM_PFX(m16Start)\r
139 DW 8h\r
140_16Idtr:\r
141 DW (1 << 10) - 1\r
142 DD 0\r
143_16Gdtr:\r
144 DW GdtEnd - _NullSegDesc - 1\r
145_16GdtrBase:\r
146 DD 0\r
147\r
148;------------------------------------------------------------------------------\r
149; _ToUserCode() takes control in real mode before passing control to user code.\r
150; It will be shadowed to somewhere in memory below 1MB.\r
151;------------------------------------------------------------------------------\r
152_ToUserCode:\r
153BITS 16\r
154 mov dx, ss\r
155 mov ss, cx ; set new segment selectors\r
156 mov ds, cx\r
157 mov es, cx\r
158 mov fs, cx\r
159 mov gs, cx\r
160 mov cr0, eax ; real mode starts at next instruction\r
161 ; which (per SDM) *must* be a far JMP.\r
162 jmp 0:strict word 0\r
163.RealAddrEnd:\r
164 mov cr4, ebp\r
165 mov ss, si ; set up 16-bit stack segment\r
166 xchg esp, ebx ; set up 16-bit stack pointer\r
167 mov bp, [esp + IA32_REGS.size]\r
168 mov [cs:bp + (_BackFromUserCode.SavedSsEnd - 2 - _BackFromUserCode)], dx\r
169 mov [cs:bp + (_BackFromUserCode.SavedEspEnd - 4 - _BackFromUserCode)], ebx\r
170 lidt [cs:bp + (_16Idtr - _BackFromUserCode)]\r
171\r
172 popad\r
173 pop ds\r
174 pop es\r
175 pop fs\r
176 pop gs\r
177 popfd\r
178\r
179o32 retf ; transfer control to user code\r
180\r
181ALIGN 16\r
182_NullSegDesc DQ 0\r
183_16CsDesc:\r
184 DW -1\r
185 DW 0\r
186 DB 0\r
187 DB 9bh\r
188 DB 8fh ; 16-bit segment, 4GB limit\r
189 DB 0\r
190_16DsDesc:\r
191 DW -1\r
192 DW 0\r
193 DB 0\r
194 DB 93h\r
195 DB 8fh ; 16-bit segment, 4GB limit\r
196 DB 0\r
197GdtEnd:\r
198\r
199;------------------------------------------------------------------------------\r
200; IA32_REGISTER_SET *\r
201; EFIAPI\r
202; InternalAsmThunk16 (\r
203; IN IA32_REGISTER_SET *RegisterSet,\r
204; IN OUT VOID *Transition\r
205; );\r
206;------------------------------------------------------------------------------\r
207global ASM_PFX(InternalAsmThunk16)\r
208ASM_PFX(InternalAsmThunk16):\r
209BITS 32\r
210 push ebp\r
211 push ebx\r
212 push esi\r
213 push edi\r
214 push ds\r
215 push es\r
216 push fs\r
217 push gs\r
218 mov esi, [esp + 36] ; esi <- RegSet, the 1st parameter\r
219 movzx edx, word [esi + IA32_REGS._SS]\r
220 mov edi, [esi + IA32_REGS._ESP]\r
221 add edi, - (IA32_REGS.size + 4) ; reserve stack space\r
222 mov ebx, edi ; ebx <- stack offset\r
223 imul eax, edx, 16 ; eax <- edx * 16\r
224 push IA32_REGS.size / 4\r
225 add edi, eax ; edi <- linear address of 16-bit stack\r
226 pop ecx\r
227 rep movsd ; copy RegSet\r
228 mov eax, [esp + 40] ; eax <- address of transition code\r
229 mov esi, edx ; esi <- 16-bit stack segment\r
230 lea edx, [eax + (_BackFromUserCode.SavedCr0End - ASM_PFX(m16Start))]\r
231 mov ecx, eax\r
232 and ecx, 0fh\r
233 shl eax, 12\r
234 lea ecx, [ecx + (_BackFromUserCode - ASM_PFX(m16Start))]\r
235 mov ax, cx\r
236 stosd ; [edi] <- return address of user code\r
237 add eax, _ToUserCode.RealAddrEnd - _BackFromUserCode\r
238 mov [edx + (_ToUserCode.RealAddrEnd - 4 - _BackFromUserCode.SavedCr0End)], eax\r
239 sgdt [edx + (SavedGdt - _BackFromUserCode.SavedCr0End)]\r
240 sidt [esp + 36] ; save IDT stack in argument space\r
241 mov eax, cr0\r
242 mov [edx - 4], eax ; save CR0 in _BackFromUserCode.SavedCr0End - 4\r
243 and eax, 7ffffffeh ; clear PE, PG bits\r
244 mov ebp, cr4\r
245 mov [edx + (_BackFromUserCode.SavedCr4End - 4 - _BackFromUserCode.SavedCr0End)], ebp\r
246 and ebp, ~30h ; clear PAE, PSE bits\r
247 push 10h\r
248 pop ecx ; ecx <- selector for data segments\r
249 lgdt [edx + (_16Gdtr - _BackFromUserCode.SavedCr0End)]\r
250 pushfd ; Save df/if indeed\r
251 call dword far [edx + (_EntryPoint - _BackFromUserCode.SavedCr0End)]\r
252 popfd\r
253 lidt [esp + 36] ; restore protected mode IDTR\r
254 lea eax, [ebp - IA32_REGS.size] ; eax <- the address of IA32_REGS\r
255 pop gs\r
256 pop fs\r
257 pop es\r
258 pop ds\r
259 pop edi\r
260 pop esi\r
261 pop ebx\r
262 pop ebp\r
263 ret\r