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