1 2#include "BaseLibInternals.h" 3 4;------------------------------------------------------------------------------ 5; 6; Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR> 7; SPDX-License-Identifier: BSD-2-Clause-Patent 8; 9; Module Name: 10; 11; Thunk.asm 12; 13; Abstract: 14; 15; Real mode thunk 16; 17;------------------------------------------------------------------------------ 18 19global ASM_PFX(m16Size) 20global ASM_PFX(mThunk16Attr) 21global ASM_PFX(m16Gdt) 22global ASM_PFX(m16GdtrBase) 23global ASM_PFX(mTransition) 24global ASM_PFX(m16Start) 25 26struc IA32_REGS 27 28 ._EDI: resd 1 29 ._ESI: resd 1 30 ._EBP: resd 1 31 ._ESP: resd 1 32 ._EBX: resd 1 33 ._EDX: resd 1 34 ._ECX: resd 1 35 ._EAX: resd 1 36 ._DS: resw 1 37 ._ES: resw 1 38 ._FS: resw 1 39 ._GS: resw 1 40 ._EFLAGS: resd 1 41 ._EIP: resd 1 42 ._CS: resw 1 43 ._SS: resw 1 44 .size: 45 46endstruc 47 48;; .const 49 50SECTION .data 51 52; 53; These are global constant to convey information to C code. 54; 55ASM_PFX(m16Size) DW ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start) 56ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttrEnd - 4 - ASM_PFX(m16Start) 57ASM_PFX(m16Gdt) DW _NullSegDesc - ASM_PFX(m16Start) 58ASM_PFX(m16GdtrBase) DW _16GdtrBase - ASM_PFX(m16Start) 59ASM_PFX(mTransition) DW _EntryPoint - ASM_PFX(m16Start) 60 61SECTION .text 62 63ASM_PFX(m16Start): 64 65SavedGdt: 66 dw 0 67 dd 0 68 69;------------------------------------------------------------------------------ 70; _BackFromUserCode() takes control in real mode after 'retf' has been executed 71; by user code. It will be shadowed to somewhere in memory below 1MB. 72;------------------------------------------------------------------------------ 73_BackFromUserCode: 74 ; 75 ; The order of saved registers on the stack matches the order they appears 76 ; in IA32_REGS structure. This facilitates wrapper function to extract them 77 ; into that structure. 78 ; 79BITS 16 80 push ss 81 push cs 82 ; 83 ; Note: We can't use o32 on the next instruction because of a bug 84 ; in NASM 2.09.04 through 2.10rc1. 85 ; 86 call dword .Base ; push eip 87.Base: 88 pushfd 89 cli ; disable interrupts 90 push gs 91 push fs 92 push es 93 push ds 94 pushad 95 mov edx, strict dword 0 96.ThunkAttrEnd: 97 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 98 jz .1 99 mov ax, 2401h 100 int 15h 101 cli ; disable interrupts 102 jnc .2 103.1: 104 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL 105 jz .2 106 in al, 92h 107 or al, 2 108 out 92h, al ; deactivate A20M# 109.2: 110 xor eax, eax 111 mov ax, ss 112 lea ebp, [esp + IA32_REGS.size] 113 mov [bp - IA32_REGS.size + IA32_REGS._ESP], ebp 114 mov bx, [bp - IA32_REGS.size + IA32_REGS._EIP] 115 shl eax, 4 ; shl eax, 4 116 add ebp, eax ; add ebp, eax 117 mov eax, strict dword 0 118.SavedCr4End: 119 mov cr4, eax 120o32 lgdt [cs:bx + (SavedGdt - .Base)] 121 mov eax, strict dword 0 122.SavedCr0End: 123 mov cr0, eax 124 mov ax, strict word 0 125.SavedSsEnd: 126 mov ss, eax 127 mov esp, strict dword 0 128.SavedEspEnd: 129o32 retf ; return to protected mode 130 131_EntryPoint: 132 DD _ToUserCode - ASM_PFX(m16Start) 133 DW 8h 134_16Idtr: 135 DW (1 << 10) - 1 136 DD 0 137_16Gdtr: 138 DW GdtEnd - _NullSegDesc - 1 139_16GdtrBase: 140 DD 0 141 142;------------------------------------------------------------------------------ 143; _ToUserCode() takes control in real mode before passing control to user code. 144; It will be shadowed to somewhere in memory below 1MB. 145;------------------------------------------------------------------------------ 146_ToUserCode: 147BITS 16 148 mov dx, ss 149 mov ss, cx ; set new segment selectors 150 mov ds, cx 151 mov es, cx 152 mov fs, cx 153 mov gs, cx 154 mov cr0, eax ; real mode starts at next instruction 155 ; which (per SDM) *must* be a far JMP. 156 jmp 0:strict word 0 157.RealAddrEnd: 158 mov cr4, ebp 159 mov ss, si ; set up 16-bit stack segment 160 xchg esp, ebx ; set up 16-bit stack pointer 161 mov bp, [esp + IA32_REGS.size] 162 mov [cs:bp + (_BackFromUserCode.SavedSsEnd - 2 - _BackFromUserCode)], dx 163 mov [cs:bp + (_BackFromUserCode.SavedEspEnd - 4 - _BackFromUserCode)], ebx 164 lidt [cs:bp + (_16Idtr - _BackFromUserCode)] 165 166 popad 167 pop ds 168 pop es 169 pop fs 170 pop gs 171 popfd 172 173o32 retf ; transfer control to user code 174 175ALIGN 16 176_NullSegDesc DQ 0 177_16CsDesc: 178 DW -1 179 DW 0 180 DB 0 181 DB 9bh 182 DB 8fh ; 16-bit segment, 4GB limit 183 DB 0 184_16DsDesc: 185 DW -1 186 DW 0 187 DB 0 188 DB 93h 189 DB 8fh ; 16-bit segment, 4GB limit 190 DB 0 191GdtEnd: 192 193;------------------------------------------------------------------------------ 194; IA32_REGISTER_SET * 195; EFIAPI 196; InternalAsmThunk16 ( 197; IN IA32_REGISTER_SET *RegisterSet, 198; IN OUT VOID *Transition 199; ); 200;------------------------------------------------------------------------------ 201global ASM_PFX(InternalAsmThunk16) 202ASM_PFX(InternalAsmThunk16): 203BITS 32 204 push ebp 205 push ebx 206 push esi 207 push edi 208 push ds 209 push es 210 push fs 211 push gs 212 mov esi, [esp + 36] ; esi <- RegSet, the 1st parameter 213 movzx edx, word [esi + IA32_REGS._SS] 214 mov edi, [esi + IA32_REGS._ESP] 215 add edi, - (IA32_REGS.size + 4) ; reserve stack space 216 mov ebx, edi ; ebx <- stack offset 217 imul eax, edx, 16 ; eax <- edx * 16 218 push IA32_REGS.size / 4 219 add edi, eax ; edi <- linear address of 16-bit stack 220 pop ecx 221 rep movsd ; copy RegSet 222 mov eax, [esp + 40] ; eax <- address of transition code 223 mov esi, edx ; esi <- 16-bit stack segment 224 lea edx, [eax + (_BackFromUserCode.SavedCr0End - ASM_PFX(m16Start))] 225 mov ecx, eax 226 and ecx, 0fh 227 shl eax, 12 228 lea ecx, [ecx + (_BackFromUserCode - ASM_PFX(m16Start))] 229 mov ax, cx 230 stosd ; [edi] <- return address of user code 231 add eax, _ToUserCode.RealAddrEnd - _BackFromUserCode 232 mov [edx + (_ToUserCode.RealAddrEnd - 4 - _BackFromUserCode.SavedCr0End)], eax 233 sgdt [edx + (SavedGdt - _BackFromUserCode.SavedCr0End)] 234 sidt [esp + 36] ; save IDT stack in argument space 235 mov eax, cr0 236 mov [edx - 4], eax ; save CR0 in _BackFromUserCode.SavedCr0End - 4 237 and eax, 7ffffffeh ; clear PE, PG bits 238 mov ebp, cr4 239 mov [edx + (_BackFromUserCode.SavedCr4End - 4 - _BackFromUserCode.SavedCr0End)], ebp 240 and ebp, ~30h ; clear PAE, PSE bits 241 push 10h 242 pop ecx ; ecx <- selector for data segments 243 lgdt [edx + (_16Gdtr - _BackFromUserCode.SavedCr0End)] 244 pushfd ; Save df/if indeed 245 call dword far [edx + (_EntryPoint - _BackFromUserCode.SavedCr0End)] 246 popfd 247 lidt [esp + 36] ; restore protected mode IDTR 248 lea eax, [ebp - IA32_REGS.size] ; eax <- the address of IA32_REGS 249 pop gs 250 pop fs 251 pop es 252 pop ds 253 pop edi 254 pop esi 255 pop ebx 256 pop ebp 257 ret 258