2 #include "BaseLibInternals.h"
4 ;------------------------------------------------------------------------------
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.
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.
23 ;------------------------------------------------------------------------------
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)
57 ; These are global constant to convey information to C code.
59 ASM_PFX(m16Size) DW InternalAsmThunk16 - ASM_PFX(m16Start)
60 ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttr - 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)
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 ;------------------------------------------------------------------------------
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.
86 o32 call dword .Base ; push eip
88 push dword 0 ; reserved high order 32 bits of EFlags
90 cli ; disable interrupts
96 DB 66h, 0bah ; mov edx, imm32
98 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
102 cli ; disable interrupts
105 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
109 out 92h, al ; deactivate A20M#
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
120 lea eax, [eax + ebx + (.64BitCode - .Base)]
121 mov [cs:bx + (.64Eip - .Base)], eax
122 DB 66h, 0b8h ; mov eax, imm32
125 o32 lgdt [cs:bx + (SavedGdt - .Base)]
130 DB 66h, 0b8h ; mov eax, imm32
133 DB 66h, 0eah ; jmp far cs:.64Bit
139 db 048h, 0bch ; mov rsp, imm64
140 .SavedSp: DQ 0 ; restore stack
145 DD _ToUserCode - ASM_PFX(m16Start)
155 ;------------------------------------------------------------------------------
156 ; _ToUserCode() takes control in real mode before passing control to user code.
157 ; It will be shadowed to somewhere in memory below 1MB.
158 ;------------------------------------------------------------------------------
161 mov ss, dx ; set new segment selectors
167 mov cr0, eax ; real mode starts at next instruction
172 mov ss, si ; set up 16-bit stack segment
173 mov esp, ebx ; set up 16-bit stack pointer
174 call dword .Base ; push eip
176 pop ebp ; ebp <- address of .Base
177 push word [dword esp + IA32_REGS.size + 2]
178 lea ax, [bp + (.RealMode - .Base)]
180 retf ; execution begins at next instruction
183 o32 lidt [cs:bp + (_16Idtr - .Base)]
191 lea esp, [esp + 4] ; skip high order 32 bits of EFlags
193 o32 retf ; transfer control to user code
197 CODE16 equ _16Code - $
198 DATA16 equ _16Data - $
199 DATA32 equ _32Data - $
207 DB 8fh ; 16-bit segment, 4GB limit
214 DB 8fh ; 16-bit segment, 4GB limit
221 DB 0cfh ; 16-bit segment, 4GB limit
224 GDT_SIZE equ $ - _NullSeg
226 ;------------------------------------------------------------------------------
227 ; IA32_REGISTER_SET *
229 ; InternalAsmThunk16 (
230 ; IN IA32_REGISTER_SET *RegisterSet,
231 ; IN OUT VOID *Transition
233 ;------------------------------------------------------------------------------
234 global ASM_PFX(InternalAsmThunk16)
235 ASM_PFX(InternalAsmThunk16):
243 push rbx ; Save ds segment register on the stack
245 push rbx ; Save es segment register on the stack
247 push rbx ; Save ss segment register on the stack
252 movzx r8d, word [rsi + IA32_REGS._SS]
253 mov edi, [rsi + IA32_REGS._ESP]
254 lea rdi, [edi - (IA32_REGS.size + 4)]
255 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16
256 mov ebx, edi ; ebx <- stack for 16-bit code
257 push IA32_REGS.size / 4
258 add edi, eax ; edi <- linear address of 16-bit stack
260 rep movsd ; copy RegSet
261 lea ecx, [rdx + (_BackFromUserCode.SavedCr4 - ASM_PFX(m16Start))]
262 mov eax, edx ; eax <- transition code address
264 shl eax, 12 ; segment address in high order 16 bits
265 lea ax, [rdx + (_BackFromUserCode - ASM_PFX(m16Start))] ; offset address
266 stosd ; [edi] <- return address of user code
268 sgdt [rsp + 60h] ; save GDT stack in argument space
269 movzx r10, word [rsp + 60h] ; r10 <- GDT limit
270 lea r11, [rcx + (InternalAsmThunk16 - _BackFromUserCode.SavedCr4) + 0xf]
271 and r11, ~0xf ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer
273 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4)], r10w ; save the limit of shadowed GDT table
274 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4) + 2], r11 ; save the base address of shadowed GDT table
276 mov rsi, [rsp + 62h] ; rsi <- the original GDT base address
277 xchg rcx, r10 ; save rcx to r10 and initialize rcx to be the limit of GDT table
278 inc rcx ; rcx <- the size of memory to copy
279 xchg rdi, r11 ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table
280 rep movsb ; perform memory copy to shadow GDT table
281 mov rcx, r10 ; restore the orignal rcx before memory copy
282 mov rdi, r11 ; restore the original rdi before memory copy
284 sidt [rsp + 50h] ; save IDT stack in argument space
286 mov [rcx + (_BackFromUserCode.SavedCr0 - _BackFromUserCode.SavedCr4)], eax
287 and eax, 7ffffffeh ; clear PE, PG bits
289 mov [rcx], ebp ; save CR4 in _BackFromUserCode.SavedCr4
290 and ebp, ~30h ; clear PAE, PSE bits
291 mov esi, r8d ; esi <- 16-bit stack segment
293 pop rdx ; rdx <- 32-bit data segment selector
294 lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4)]
297 lea edx, [rdx + DATA16 - DATA32]
298 lea r8, [REL .RetFromRealMode]
301 mov [rcx + (_BackFromUserCode.SavedCs - _BackFromUserCode.SavedCr4)], r8w
302 mov [rcx + (_BackFromUserCode.SavedSp - _BackFromUserCode.SavedCr4)], rsp
303 jmp dword far [rcx + (_EntryPoint - _BackFromUserCode.SavedCr4)]
306 lgdt [rsp + 60h] ; restore protected mode GDTR
307 lidt [rsp + 50h] ; restore protected mode IDTR
308 lea eax, [rbp - IA32_REGS.size]