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 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) 31 32 struc 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 52 endstruc 53 54 ;; .const 55 56 SECTION .data 57 58 ; 59 ; These are global constant to convey information to C code. 60 ; 61 ASM_PFX(m16Size) DW ASM_PFX(InternalAsmThunk16) - ASM_PFX(m16Start) 62 ASM_PFX(mThunk16Attr) DW _BackFromUserCode.ThunkAttrEnd - 4 - ASM_PFX(m16Start) 63 ASM_PFX(m16Gdt) DW _NullSegDesc - ASM_PFX(m16Start) 64 ASM_PFX(m16GdtrBase) DW _16GdtrBase - ASM_PFX(m16Start) 65 ASM_PFX(mTransition) DW _EntryPoint - ASM_PFX(m16Start) 66 67 SECTION .text 68 69 ASM_PFX(m16Start): 70 71 SavedGdt: 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 ; 85 BITS 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 126 o32 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: 135 o32 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: 153 BITS 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 179 o32 retf ; transfer control to user code 180 181 ALIGN 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 197 GdtEnd: 198 199 ;------------------------------------------------------------------------------ 200 ; IA32_REGISTER_SET * 201 ; EFIAPI 202 ; InternalAsmThunk16 ( 203 ; IN IA32_REGISTER_SET *RegisterSet, 204 ; IN OUT VOID *Transition 205 ; ); 206 ;------------------------------------------------------------------------------ 207 global ASM_PFX(InternalAsmThunk16) 208 ASM_PFX(InternalAsmThunk16): 209 BITS 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