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.
83 ; Some instructions for manipulation of segment registers have to be written
84 ; in opcode since 64-bit MASM prevents accesses to those registers.
92 push 0 ; reserved high order 32 bits of EFlags
93 pushfw ; pushfd actually
94 cli ; disable interrupts
100 DB 66h, 0bah ; mov edx, imm32
102 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
104 mov eax, 15cd2401h ; mov ax, 2401h & int 15h
105 cli ; disable interrupts
108 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
112 out 92h, al ; deactivate A20M#
114 xor ax, ax ; xor eax, eax
115 mov eax, ss ; mov ax, ss
116 lea bp, [esp + IA32_REGS.size]
118 ; rsi in the following 2 instructions is indeed bp in 16-bit code
120 mov [rsi - IA32_REGS.size + IA32_REGS._ESP], bp
122 mov ebx, [rsi - IA32_REGS.size + IA32_REGS._EIP]
123 shl ax, 4 ; shl eax, 4
124 add bp, ax ; add ebp, eax
127 lea ax, [eax + ebx + (.64BitCode - .Base)]
128 DB 66h, 2eh, 89h, 87h ; mov cs:[bx + (.64Eip - .Base)], eax
130 DB 66h, 0b8h ; mov eax, imm32
134 ; rdi in the instruction below is indeed bx in 16-bit code
136 DB 66h, 2eh ; 2eh is "cs:" segment override
137 lgdt [rdi + (SavedGdt - .Base)]
143 DB 66h, 0b8h ; mov eax, imm32
146 DB 66h, 0eah ; jmp far cs:.64Bit
151 db 048h, 0bch ; mov rsp, imm64
152 .SavedSp: DQ 0 ; restore stack
157 DD _ToUserCode - ASM_PFX(m16Start)
167 ;------------------------------------------------------------------------------
168 ; _ToUserCode() takes control in real mode before passing control to user code.
169 ; It will be shadowed to somewhere in memory below 1MB.
170 ;------------------------------------------------------------------------------
172 mov ss, edx ; set new segment selectors
179 mov cr0, rax ; real mode starts at next instruction
184 mov ss, esi ; set up 16-bit stack segment
185 mov sp, bx ; set up 16-bit stack pointer
186 DB 66h ; make the following call 32-bit
187 call .Base ; push eip
189 pop bp ; ebp <- address of .Base
190 push qword [esp + IA32_REGS.size + 2]
191 lea eax, [rsi + (.RealMode - .Base)] ; rsi is "bp" in 16-bit code
193 retf ; execution begins at next instruction
195 DB 66h, 2eh ; CS and operand size override
196 lidt [rsi + (_16Idtr - .Base)]
203 lea sp, [esp + 4] ; skip high order 32 bits of EFlags
204 DB 66h ; make the following retf 32-bit
205 retf ; transfer control to user code
209 CODE16 equ _16Code - $
210 DATA16 equ _16Data - $
211 DATA32 equ _32Data - $
219 DB 8fh ; 16-bit segment, 4GB limit
226 DB 8fh ; 16-bit segment, 4GB limit
233 DB 0cfh ; 16-bit segment, 4GB limit
236 GDT_SIZE equ $ - _NullSeg
238 ;------------------------------------------------------------------------------
239 ; IA32_REGISTER_SET *
241 ; InternalAsmThunk16 (
242 ; IN IA32_REGISTER_SET *RegisterSet,
243 ; IN OUT VOID *Transition
245 ;------------------------------------------------------------------------------
246 global ASM_PFX(InternalAsmThunk16)
247 ASM_PFX(InternalAsmThunk16):
254 push rbx ; Save ds segment register on the stack
256 push rbx ; Save es segment register on the stack
258 push rbx ; Save ss segment register on the stack
263 movzx r8d, word [rsi + IA32_REGS._SS]
264 mov edi, [rsi + IA32_REGS._ESP]
265 lea rdi, [edi - (IA32_REGS.size + 4)]
266 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16
267 mov ebx, edi ; ebx <- stack for 16-bit code
268 push IA32_REGS.size / 4
269 add edi, eax ; edi <- linear address of 16-bit stack
271 rep movsd ; copy RegSet
272 lea ecx, [rdx + (_BackFromUserCode.SavedCr4 - ASM_PFX(m16Start))]
273 mov eax, edx ; eax <- transition code address
275 shl eax, 12 ; segment address in high order 16 bits
276 lea ax, [rdx + (_BackFromUserCode - ASM_PFX(m16Start))] ; offset address
277 stosd ; [edi] <- return address of user code
279 sgdt [rsp + 60h] ; save GDT stack in argument space
280 movzx r10, word [rsp + 60h] ; r10 <- GDT limit
281 lea r11, [rcx + (InternalAsmThunk16 - _BackFromUserCode.SavedCr4) + 0xf]
282 and r11, ~0xf ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer
284 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4)], r10w ; save the limit of shadowed GDT table
285 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4) + 2], r11 ; save the base address of shadowed GDT table
287 mov rsi, [rsp + 62h] ; rsi <- the original GDT base address
288 xchg rcx, r10 ; save rcx to r10 and initialize rcx to be the limit of GDT table
289 inc rcx ; rcx <- the size of memory to copy
290 xchg rdi, r11 ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table
291 rep movsb ; perform memory copy to shadow GDT table
292 mov rcx, r10 ; restore the orignal rcx before memory copy
293 mov rdi, r11 ; restore the original rdi before memory copy
295 sidt [rsp + 50h] ; save IDT stack in argument space
297 mov [rcx + (_BackFromUserCode.SavedCr0 - _BackFromUserCode.SavedCr4)], eax
298 and eax, 7ffffffeh ; clear PE, PG bits
300 mov [rcx], ebp ; save CR4 in _BackFromUserCode.SavedCr4
301 and ebp, ~30h ; clear PAE, PSE bits
302 mov esi, r8d ; esi <- 16-bit stack segment
303 DB 6ah, DATA32 ; push DATA32
304 pop rdx ; rdx <- 32-bit data segment selector
305 lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4)]
308 lea edx, [rdx + DATA16 - DATA32]
309 lea r8, [REL .RetFromRealMode]
312 mov [rcx + (_BackFromUserCode.SavedCs - _BackFromUserCode.SavedCr4)], r8w
313 mov [rcx + (_BackFromUserCode.SavedSp - _BackFromUserCode.SavedCr4)], rsp
314 jmp dword far [rcx + (_EntryPoint - _BackFromUserCode.SavedCr4)]
317 lgdt [rsp + 60h] ; restore protected mode GDTR
318 lidt [rsp + 50h] ; restore protected mode IDTR
319 lea eax, [rbp - IA32_REGS.size]