2 #include "BaseLibInternals.h"
4 ;------------------------------------------------------------------------------
6 ; Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
7 ; SPDX-License-Identifier: BSD-2-Clause-Patent
17 ;------------------------------------------------------------------------------
19 global ASM_PFX(m16Size)
20 global ASM_PFX(mThunk16Attr)
21 global ASM_PFX(m16Gdt)
22 global ASM_PFX(m16GdtrBase)
23 global ASM_PFX(mTransition)
24 global ASM_PFX(m16Start)
51 ; These are global constant to convey information to C code.
53 ASM_PFX(m16Size) DW ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start)
54 ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttrEnd - 4 - ASM_PFX(m16Start)
55 ASM_PFX(m16Gdt) DW _NullSeg - ASM_PFX(m16Start)
56 ASM_PFX(m16GdtrBase) DW _16GdtrBase - ASM_PFX(m16Start)
57 ASM_PFX(mTransition) DW _EntryPoint - ASM_PFX(m16Start)
67 ;------------------------------------------------------------------------------
68 ; _BackFromUserCode() takes control in real mode after 'retf' has been executed
69 ; by user code. It will be shadowed to somewhere in memory below 1MB.
70 ;------------------------------------------------------------------------------
73 ; The order of saved registers on the stack matches the order they appears
74 ; in IA32_REGS structure. This facilitates wrapper function to extract them
75 ; into that structure.
81 ; Note: We can't use o32 on the next instruction because of a bug
82 ; in NASM 2.09.04 through 2.10rc1.
84 call dword .Base ; push eip
86 push dword 0 ; reserved high order 32 bits of EFlags
88 cli ; disable interrupts
94 mov edx, strict dword 0
96 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15
100 cli ; disable interrupts
103 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL
107 out 92h, al ; deactivate A20M#
111 lea ebp, [esp + IA32_REGS.size]
112 mov [bp - IA32_REGS.size + IA32_REGS._ESP], ebp
113 mov ebx, [bp - IA32_REGS.size + IA32_REGS._EIP]
114 shl eax, 4 ; shl eax, 4
115 add ebp, eax ; add ebp, eax
118 lea eax, [eax + ebx + (.X64JmpEnd - .Base)]
119 mov [cs:bx + (.X64JmpEnd - 6 - .Base)], eax
120 mov eax, strict dword 0
123 o32 lgdt [cs:bx + (SavedGdt - .Base)]
128 mov eax, strict dword 0
135 mov rsp, strict qword 0
141 DD _ToUserCode - ASM_PFX(m16Start)
151 ;------------------------------------------------------------------------------
152 ; _ToUserCode() takes control in real mode before passing control to user code.
153 ; It will be shadowed to somewhere in memory below 1MB.
154 ;------------------------------------------------------------------------------
157 mov ss, dx ; set new segment selectors
163 mov cr0, eax ; real mode starts at next instruction
168 mov ss, si ; set up 16-bit stack segment
169 mov esp, ebx ; set up 16-bit stack pointer
170 call dword .Base ; push eip
172 pop ebp ; ebp <- address of .Base
173 push word [dword esp + IA32_REGS.size + 2]
174 lea ax, [bp + (.RealMode - .Base)]
176 retf ; execution begins at next instruction
179 o32 lidt [cs:bp + (_16Idtr - .Base)]
187 lea esp, [esp + 4] ; skip high order 32 bits of EFlags
189 o32 retf ; transfer control to user code
193 CODE16 equ _16Code - $
194 DATA16 equ _16Data - $
195 DATA32 equ _32Data - $
203 DB 8fh ; 16-bit segment, 4GB limit
210 DB 8fh ; 16-bit segment, 4GB limit
217 DB 0cfh ; 16-bit segment, 4GB limit
220 GDT_SIZE equ $ - _NullSeg
222 ;------------------------------------------------------------------------------
223 ; IA32_REGISTER_SET *
225 ; InternalAsmThunk16 (
226 ; IN IA32_REGISTER_SET *RegisterSet,
227 ; IN OUT VOID *Transition
229 ;------------------------------------------------------------------------------
230 global ASM_PFX(InternalAsmThunk16)
231 ASM_PFX(InternalAsmThunk16):
239 push rbx ; Save ds segment register on the stack
241 push rbx ; Save es segment register on the stack
243 push rbx ; Save ss segment register on the stack
248 movzx r8d, word [rsi + IA32_REGS._SS]
249 mov edi, [rsi + IA32_REGS._ESP]
250 lea rdi, [edi - (IA32_REGS.size + 4)]
251 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16
252 mov ebx, edi ; ebx <- stack for 16-bit code
253 push IA32_REGS.size / 4
254 add edi, eax ; edi <- linear address of 16-bit stack
256 rep movsd ; copy RegSet
257 lea ecx, [rdx + (_BackFromUserCode.SavedCr4End - ASM_PFX(m16Start))]
258 mov eax, edx ; eax <- transition code address
260 shl eax, 12 ; segment address in high order 16 bits
261 lea ax, [rdx + (_BackFromUserCode - ASM_PFX(m16Start))] ; offset address
262 stosd ; [edi] <- return address of user code
264 sgdt [rsp + 60h] ; save GDT stack in argument space
265 movzx r10, word [rsp + 60h] ; r10 <- GDT limit
266 lea r11, [rcx + (ASM_PFX(InternalAsmThunk16) - _BackFromUserCode.SavedCr4End) + 0xf]
267 and r11, ~0xf ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer
269 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4End)], r10w ; save the limit of shadowed GDT table
270 mov [rcx + (SavedGdt - _BackFromUserCode.SavedCr4End) + 2], r11 ; save the base address of shadowed GDT table
272 mov rsi, [rsp + 62h] ; rsi <- the original GDT base address
273 xchg rcx, r10 ; save rcx to r10 and initialize rcx to be the limit of GDT table
274 inc rcx ; rcx <- the size of memory to copy
275 xchg rdi, r11 ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table
276 rep movsb ; perform memory copy to shadow GDT table
277 mov rcx, r10 ; restore the orignal rcx before memory copy
278 mov rdi, r11 ; restore the original rdi before memory copy
280 sidt [rsp + 50h] ; save IDT stack in argument space
282 mov [rcx + (_BackFromUserCode.SavedCr0End - 4 - _BackFromUserCode.SavedCr4End)], eax
283 and eax, 7ffffffeh ; clear PE, PG bits
285 mov [rcx - 4], ebp ; save CR4 in _BackFromUserCode.SavedCr4End - 4
286 and ebp, ~30h ; clear PAE, PSE bits
287 mov esi, r8d ; esi <- 16-bit stack segment
289 pop rdx ; rdx <- 32-bit data segment selector
290 lgdt [rcx + (_16Gdtr - _BackFromUserCode.SavedCr4End)]
293 lea edx, [rdx + DATA16 - DATA32]
294 lea r8, [REL .RetFromRealMode]
297 mov [rcx + (_BackFromUserCode.X64JmpEnd - 2 - _BackFromUserCode.SavedCr4End)], r8w
298 mov [rcx + (_BackFromUserCode.SavedSpEnd - 8 - _BackFromUserCode.SavedCr4End)], rsp
299 jmp dword far [rcx + (_EntryPoint - _BackFromUserCode.SavedCr4End)]
302 lgdt [rsp + 60h] ; restore protected mode GDTR
303 lidt [rsp + 50h] ; restore protected mode IDTR
304 lea eax, [rbp - IA32_REGS.size]