]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BaseLib/X64/Thunk16.nasm
MdePkg BaseLib NASM Thunk16: Initialize _16GdtrBase to 0
[mirror_edk2.git] / MdePkg / Library / BaseLib / X64 / Thunk16.nasm
1
2 #include "BaseLibInternals.h"
3
4 ;------------------------------------------------------------------------------
5 ;
6 ; Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
7 ; This program and the accompanying materials
8 ; are licensed and made available under the terms and conditions of the BSD License
9 ; which accompanies this distribution. The full text of the license may be found at
10 ; http://opensource.org/licenses/bsd-license.php.
11 ;
12 ; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 ; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 ;
15 ; Module Name:
16 ;
17 ; Thunk.asm
18 ;
19 ; Abstract:
20 ;
21 ; Real mode thunk
22 ;
23 ;------------------------------------------------------------------------------
24
25 global ASM_PFX(m16Size)
26 global ASM_PFX(mThunk16Attr)
27 global ASM_PFX(m16Gdt)
28 global ASM_PFX(m16GdtrBase)
29 global ASM_PFX(mTransition)
30 global ASM_PFX(m16Start)
31
32 struc IA32_REGS
33
34 ._EDI: resd 1
35 ._ESI: resd 1
36 ._EBP: resd 1
37 ._ESP: resd 1
38 ._EBX: resd 1
39 ._EDX: resd 1
40 ._ECX: resd 1
41 ._EAX: resd 1
42 ._DS: resw 1
43 ._ES: resw 1
44 ._FS: resw 1
45 ._GS: resw 1
46 ._EFLAGS: resq 1
47 ._EIP: resd 1
48 ._CS: resw 1
49 ._SS: resw 1
50 .size:
51
52 endstruc
53
54 SECTION .data
55
56 ;
57 ; These are global constant to convey information to C code.
58 ;
59 ASM_PFX(m16Size) DW InternalAsmThunk16 - ASM_PFX(m16Start)
60 ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttrEnd - 4 - ASM_PFX(m16Start)
61 ASM_PFX(m16Gdt) DW _NullSeg - ASM_PFX(m16Start)
62 ASM_PFX(m16GdtrBase) DW _16GdtrBase - ASM_PFX(m16Start)
63 ASM_PFX(mTransition) DW _EntryPoint - ASM_PFX(m16Start)
64
65 SECTION .text
66
67 ASM_PFX(m16Start):
68
69 SavedGdt:
70 dw 0
71 dq 0
72
73 ;------------------------------------------------------------------------------
74 ; _BackFromUserCode() takes control in real mode after 'retf' has been executed
75 ; by user code. It will be shadowed to somewhere in memory below 1MB.
76 ;------------------------------------------------------------------------------
77 _BackFromUserCode:
78 ;
79 ; The order of saved registers on the stack matches the order they appears
80 ; in IA32_REGS structure. This facilitates wrapper function to extract them
81 ; into that structure.
82 ;
83 BITS 16
84 push ss
85 push cs
86 o32 call dword .Base ; push eip
87 .Base:
88 push dword 0 ; reserved high order 32 bits of EFlags
89 pushfd
90 cli ; disable interrupts
91 push gs
92 push fs
93 push es
94 push ds
95 pushad
96 mov edx, strict dword 0
97 .ThunkAttrEnd:
98 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
99 jz .1
100 mov ax, 2401h
101 int 15h
102 cli ; disable interrupts
103 jnc .2
104 .1:
105 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
106 jz .2
107 in al, 92h
108 or al, 2
109 out 92h, al ; deactivate A20M#
110 .2:
111 xor eax, eax
112 mov ax, ss
113 lea ebp, [esp + IA32_REGS.size]
114 mov [bp - IA32_REGS.size + IA32_REGS._ESP], ebp
115 mov ebx, [bp - IA32_REGS.size + IA32_REGS._EIP]
116 shl eax, 4 ; shl eax, 4
117 add ebp, eax ; add ebp, eax
118 mov eax, cs
119 shl eax, 4
120 lea eax, [eax + ebx + (.X64JmpEnd - .Base)]
121 mov [cs:bx + (.X64JmpEnd - 6 - .Base)], eax
122 mov eax, strict dword 0
123 .SavedCr4End:
124 mov cr4, eax
125 o32 lgdt [cs:bx + (SavedGdt - .Base)]
126 mov ecx, 0c0000080h
127 rdmsr
128 or ah, 1
129 wrmsr
130 mov eax, strict dword 0
131 .SavedCr0End:
132 mov cr0, eax
133 jmp 0:strict dword 0
134 .X64JmpEnd:
135 BITS 64
136 nop
137 mov rsp, strict qword 0
138 .SavedSpEnd:
139 nop
140 ret
141
142 _EntryPoint:
143 DD _ToUserCode - ASM_PFX(m16Start)
144 DW CODE16
145 _16Gdtr:
146 DW GDT_SIZE - 1
147 _16GdtrBase:
148 DQ 0
149 _16Idtr:
150 DW (1 << 10) - 1
151 DD 0
152
153 ;------------------------------------------------------------------------------
154 ; _ToUserCode() takes control in real mode before passing control to user code.
155 ; It will be shadowed to somewhere in memory below 1MB.
156 ;------------------------------------------------------------------------------
157 _ToUserCode:
158 BITS 16
159 mov ss, dx ; set new segment selectors
160 mov ds, dx
161 mov es, dx
162 mov fs, dx
163 mov gs, dx
164 mov ecx, 0c0000080h
165 mov cr0, eax ; real mode starts at next instruction
166 rdmsr
167 and ah, ~1
168 wrmsr
169 mov cr4, ebp
170 mov ss, si ; set up 16-bit stack segment
171 mov esp, ebx ; set up 16-bit stack pointer
172 call dword .Base ; push eip
173 .Base:
174 pop ebp ; ebp <- address of .Base
175 push word [dword esp + IA32_REGS.size + 2]
176 lea ax, [bp + (.RealMode - .Base)]
177 push ax
178 retf ; execution begins at next instruction
179 .RealMode:
180
181 o32 lidt [cs:bp + (_16Idtr - .Base)]
182
183 popad
184 pop ds
185 pop es
186 pop fs
187 pop gs
188 popfd
189 lea esp, [esp + 4] ; skip high order 32 bits of EFlags
190
191 o32 retf ; transfer control to user code
192
193 ALIGN 8
194
195 CODE16 equ _16Code - $
196 DATA16 equ _16Data - $
197 DATA32 equ _32Data - $
198
199 _NullSeg DQ 0
200 _16Code:
201 DW -1
202 DW 0
203 DB 0
204 DB 9bh
205 DB 8fh ; 16-bit segment, 4GB limit
206 DB 0
207 _16Data:
208 DW -1
209 DW 0
210 DB 0
211 DB 93h
212 DB 8fh ; 16-bit segment, 4GB limit
213 DB 0
214 _32Data:
215 DW -1
216 DW 0
217 DB 0
218 DB 93h
219 DB 0cfh ; 16-bit segment, 4GB limit
220 DB 0
221
222 GDT_SIZE equ $ - _NullSeg
223
224 ;------------------------------------------------------------------------------
225 ; IA32_REGISTER_SET *
226 ; EFIAPI
227 ; InternalAsmThunk16 (
228 ; IN IA32_REGISTER_SET *RegisterSet,
229 ; IN OUT VOID *Transition
230 ; );
231 ;------------------------------------------------------------------------------
232 global ASM_PFX(InternalAsmThunk16)
233 ASM_PFX(InternalAsmThunk16):
234 BITS 64
235 push rbp
236 push rbx
237 push rsi
238 push rdi
239
240 mov ebx, ds
241 push rbx ; Save ds segment register on the stack
242 mov ebx, es
243 push rbx ; Save es segment register on the stack
244 mov ebx, ss
245 push rbx ; Save ss segment register on the stack
246
247 push fs
248 push gs
249 mov rsi, rcx
250 movzx r8d, word [rsi + IA32_REGS._SS]
251 mov edi, [rsi + IA32_REGS._ESP]
252 lea rdi, [edi - (IA32_REGS.size + 4)]
253 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16
254 mov ebx, edi ; ebx <- stack for 16-bit code
255 push IA32_REGS.size / 4
256 add edi, eax ; edi <- linear address of 16-bit stack
257 pop rcx
258 rep movsd ; copy RegSet
259 lea ecx, [rdx + (_BackFromUserCode.SavedCr4End - ASM_PFX(m16Start))]
260 mov eax, edx ; eax <- transition code address
261 and edx, 0fh
262 shl eax, 12 ; segment address in high order 16 bits
263 lea ax, [rdx + (_BackFromUserCode - ASM_PFX(m16Start))] ; offset address
264 stosd ; [edi] <- return address of user code
265
266 sgdt [rsp + 60h] ; save GDT stack in argument space
267 movzx r10, word [rsp + 60h] ; r10 <- GDT limit
268 lea r11, [rcx + (InternalAsmThunk16 - _BackFromUserCode.SavedCr4End) + 0xf]
269 and r11, ~0xf ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer
270
271 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4End)], r10w ; save the limit of shadowed GDT table
272 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4End) + 2], r11 ; save the base address of shadowed GDT table
273
274 mov rsi, [rsp + 62h] ; rsi <- the original GDT base address
275 xchg rcx, r10 ; save rcx to r10 and initialize rcx to be the limit of GDT table
276 inc rcx ; rcx <- the size of memory to copy
277 xchg rdi, r11 ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table
278 rep movsb ; perform memory copy to shadow GDT table
279 mov rcx, r10 ; restore the orignal rcx before memory copy
280 mov rdi, r11 ; restore the original rdi before memory copy
281
282 sidt [rsp + 50h] ; save IDT stack in argument space
283 mov rax, cr0
284 mov [rcx + (_BackFromUserCode.SavedCr0End - 4 - _BackFromUserCode.SavedCr4End)], eax
285 and eax, 7ffffffeh ; clear PE, PG bits
286 mov rbp, cr4
287 mov [rcx - 4], ebp ; save CR4 in _BackFromUserCode.SavedCr4End - 4
288 and ebp, ~30h ; clear PAE, PSE bits
289 mov esi, r8d ; esi <- 16-bit stack segment
290 push DATA32
291 pop rdx ; rdx <- 32-bit data segment selector
292 lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4End)]
293 mov ss, edx
294 pushfq
295 lea edx, [rdx + DATA16 - DATA32]
296 lea r8, [REL .RetFromRealMode]
297 push r8
298 mov r8d, cs
299 mov [rcx + (_BackFromUserCode.X64JmpEnd - 2 - _BackFromUserCode.SavedCr4End)], r8w
300 mov [rcx + (_BackFromUserCode.SavedSpEnd - 8 - _BackFromUserCode.SavedCr4End)], rsp
301 jmp dword far [rcx + (_EntryPoint - _BackFromUserCode.SavedCr4End)]
302 .RetFromRealMode:
303 popfq
304 lgdt [rsp + 60h] ; restore protected mode GDTR
305 lidt [rsp + 50h] ; restore protected mode IDTR
306 lea eax, [rbp - IA32_REGS.size]
307 pop gs
308 pop fs
309 pop rbx
310 mov ss, ebx
311 pop rbx
312 mov es, ebx
313 pop rbx
314 mov ds, ebx
315
316 pop rdi
317 pop rsi
318 pop rbx
319 pop rbp
320
321 ret