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 25EXTERNDEF m16Start:BYTE 26EXTERNDEF m16Size:WORD 27EXTERNDEF mThunk16Attr:WORD 28EXTERNDEF m16Gdt:WORD 29EXTERNDEF m16GdtrBase:WORD 30EXTERNDEF mTransition:WORD 31 32IA32_REGS STRUC 4t 33_EDI DD ? 34_ESI DD ? 35_EBP DD ? 36_ESP DD ? 37_EBX DD ? 38_EDX DD ? 39_ECX DD ? 40_EAX DD ? 41_DS DW ? 42_ES DW ? 43_FS DW ? 44_GS DW ? 45_EFLAGS DQ ? 46_EIP DD ? 47_CS DW ? 48_SS DW ? 49IA32_REGS ENDS 50 51 .const 52 53m16Size DW InternalAsmThunk16 - m16Start 54mThunk16Attr DW _ThunkAttr - m16Start 55m16Gdt DW _NullSeg - m16Start 56m16GdtrBase DW _16GdtrBase - m16Start 57mTransition DW _EntryPoint - m16Start 58 59 .code 60 61m16Start LABEL BYTE 62 63SavedGdt LABEL FWORD 64 DW ? 65 DQ ? 66 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;------------------------------------------------------------------------------ 71_BackFromUserCode PROC 72 ; 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. 76 ; 77 ; Some instructions for manipulation of segment registers have to be written 78 ; in opcode since 64-bit MASM prevents accesses to those registers. 79 ; 80 DB 16h ; push ss 81 DB 0eh ; push cs 82 DB 66h 83 call @Base ; push eip 84@Base: 85 DB 66h 86 push 0 ; reserved high order 32 bits of EFlags 87 pushf ; pushfd actually 88 cli ; disable interrupts 89 push gs 90 push fs 91 DB 6 ; push es 92 DB 1eh ; push ds 93 DB 66h, 60h ; pushad 94 DB 66h, 0bah ; mov edx, imm32 95_ThunkAttr DD ? 96 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 97 jz @1 98 mov eax, 15cd2401h ; mov ax, 2401h & int 15h 99 cli ; disable interrupts 100 jnc @2 101@1: 102 test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL 103 jz @2 104 in al, 92h 105 or al, 2 106 out 92h, al ; deactivate A20M# 107@2: 108 xor ax, ax ; xor eax, eax 109 mov eax, ss ; mov ax, ss 110 lea bp, [esp + sizeof (IA32_REGS)] 111 ; 112 ; rsi in the following 2 instructions is indeed bp in 16-bit code 113 ; 114 mov word ptr (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._ESP, bp 115 DB 66h 116 mov ebx, (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._EIP 117 shl ax, 4 ; shl eax, 4 118 add bp, ax ; add ebp, eax 119 mov ax, cs 120 shl ax, 4 121 lea ax, [eax + ebx + (@64BitCode - @Base)] 122 DB 66h, 2eh, 89h, 87h ; mov cs:[bx + (@64Eip - @Base)], eax 123 DW @64Eip - @Base 124 DB 66h, 0b8h ; mov eax, imm32 125SavedCr4 DD ? 126 mov cr4, rax 127 ; 128 ; rdi in the instruction below is indeed bx in 16-bit code 129 ; 130 DB 66h, 2eh ; 2eh is "cs:" segment override 131 lgdt fword ptr [rdi + (SavedGdt - @Base)] 132 DB 66h 133 mov ecx, 0c0000080h 134 rdmsr 135 or ah, 1 136 wrmsr 137 DB 66h, 0b8h ; mov eax, imm32 138SavedCr0 DD ? 139 mov cr0, rax 140 DB 66h, 0eah ; jmp far cs:@64Bit 141@64Eip DD ? 142SavedCs DW ? 143@64BitCode: 144 db 090h 145 db 048h, 0bch ; mov rsp, imm64 146SavedSp DQ ? ; restore stack 147 nop 148 ret 149_BackFromUserCode ENDP 150 151_EntryPoint DD _ToUserCode - m16Start 152 DW CODE16 153_16Gdtr LABEL FWORD 154 DW GDT_SIZE - 1 155_16GdtrBase DQ _NullSeg 156_16Idtr FWORD (1 SHL 10) - 1 157 158;------------------------------------------------------------------------------ 159; _ToUserCode() takes control in real mode before passing control to user code. 160; It will be shadowed to somewhere in memory below 1MB. 161;------------------------------------------------------------------------------ 162_ToUserCode PROC 163 mov ss, edx ; set new segment selectors 164 mov ds, edx 165 mov es, edx 166 mov fs, edx 167 mov gs, edx 168 DB 66h 169 mov ecx, 0c0000080h 170 mov cr0, rax ; real mode starts at next instruction 171 rdmsr 172 and ah, NOT 1 173 wrmsr 174 mov cr4, rbp 175 mov ss, esi ; set up 16-bit stack segment 176 mov sp, bx ; set up 16-bit stack pointer 177 DB 66h ; make the following call 32-bit 178 call @Base ; push eip 179@Base: 180 pop bp ; ebp <- address of @Base 181 push [esp + sizeof (IA32_REGS) + 2] 182 lea eax, [rsi + (@RealMode - @Base)] ; rsi is "bp" in 16-bit code 183 push rax 184 retf ; execution begins at next instruction 185@RealMode: 186 DB 66h, 2eh ; CS and operand size override 187 lidt fword ptr [rsi + (_16Idtr - @Base)] 188 DB 66h, 61h ; popad 189 DB 1fh ; pop ds 190 DB 07h ; pop es 191 pop fs 192 pop gs 193 popf ; popfd 194 lea sp, [esp + 4] ; skip high order 32 bits of EFlags 195 DB 66h ; make the following retf 32-bit 196 retf ; transfer control to user code 197_ToUserCode ENDP 198 199CODE16 = _16Code - $ 200DATA16 = _16Data - $ 201DATA32 = _32Data - $ 202 203_NullSeg DQ 0 204_16Code LABEL QWORD 205 DW -1 206 DW 0 207 DB 0 208 DB 9bh 209 DB 8fh ; 16-bit segment, 4GB limit 210 DB 0 211_16Data LABEL QWORD 212 DW -1 213 DW 0 214 DB 0 215 DB 93h 216 DB 8fh ; 16-bit segment, 4GB limit 217 DB 0 218_32Data LABEL QWORD 219 DW -1 220 DW 0 221 DB 0 222 DB 93h 223 DB 0cfh ; 16-bit segment, 4GB limit 224 DB 0 225 226GDT_SIZE = $ - _NullSeg 227 228;------------------------------------------------------------------------------ 229; IA32_REGISTER_SET * 230; EFIAPI 231; InternalAsmThunk16 ( 232; IN IA32_REGISTER_SET *RegisterSet, 233; IN OUT VOID *Transition 234; ); 235;------------------------------------------------------------------------------ 236InternalAsmThunk16 PROC USES rbp rbx rsi rdi 237 mov rbx, ds 238 push rbx ; Save ds segment register on the stack 239 mov rbx, es 240 push rbx ; Save es segment register on the stack 241 mov rbx, ss 242 push rbx ; Save ss segment register on the stack 243 244 push fs 245 push gs 246 mov rsi, rcx 247 movzx r8d, (IA32_REGS ptr [rsi])._SS 248 mov edi, (IA32_REGS ptr [rsi])._ESP 249 lea rdi, [edi - (sizeof (IA32_REGS) + 4)] 250 imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16 251 mov ebx, edi ; ebx <- stack for 16-bit code 252 push sizeof (IA32_REGS) / 4 253 add edi, eax ; edi <- linear address of 16-bit stack 254 pop rcx 255 rep movsd ; copy RegSet 256 lea ecx, [rdx + (SavedCr4 - m16Start)] 257 mov eax, edx ; eax <- transition code address 258 and edx, 0fh 259 shl eax, 12 ; segment address in high order 16 bits 260 lea ax, [rdx + (_BackFromUserCode - m16Start)] ; offset address 261 stosd ; [edi] <- return address of user code 262 263 sgdt fword ptr [rsp + 60h] ; save GDT stack in argument space 264 movzx r10, word ptr [rsp + 60h] ; r10 <- GDT limit 265 lea r11, [rcx + (InternalAsmThunk16 - SavedCr4) + 0xf] 266 and r11, 0xfffffff0 ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer 267 268 mov word ptr [rcx + (SavedGdt - SavedCr4)], r10w ; save the limit of shadowed GDT table 269 mov qword ptr [rcx + (SavedGdt - SavedCr4) + 2], r11 ; save the base address of shadowed GDT table 270 271 mov rsi, qword ptr [rsp + 62h] ; rsi <- the original GDT base address 272 xchg rcx, r10 ; save rcx to r10 and initialize rcx to be the limit of GDT table 273 inc rcx ; rcx <- the size of memory to copy 274 xchg rdi, r11 ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table 275 rep movsb ; perform memory copy to shadow GDT table 276 mov rcx, r10 ; restore the orignal rcx before memory copy 277 mov rdi, r11 ; restore the original rdi before memory copy 278 279 sidt fword ptr [rsp + 50h] ; save IDT stack in argument space 280 mov rax, cr0 281 mov [rcx + (SavedCr0 - SavedCr4)], eax 282 and eax, 7ffffffeh ; clear PE, PG bits 283 mov rbp, cr4 284 mov [rcx], ebp ; save CR4 in SavedCr4 285 and ebp, NOT 30h ; clear PAE, PSE bits 286 mov esi, r8d ; esi <- 16-bit stack segment 287 DB 6ah, DATA32 ; push DATA32 288 pop rdx ; rdx <- 32-bit data segment selector 289 lgdt fword ptr [rcx + (_16Gdtr - SavedCr4)] 290 mov ss, edx 291 pushfq 292 lea edx, [rdx + DATA16 - DATA32] 293 lea r8, @RetFromRealMode 294 push r8 295 mov r8d, cs 296 mov [rcx + (SavedCs - SavedCr4)], r8w 297 mov [rcx + (SavedSp - SavedCr4)], rsp 298 jmp fword ptr [rcx + (_EntryPoint - SavedCr4)] 299@RetFromRealMode: 300 popfq 301 lgdt fword ptr [rsp + 60h] ; restore protected mode GDTR 302 lidt fword ptr [rsp + 50h] ; restore protected mode IDTR 303 lea eax, [rbp - sizeof (IA32_REGS)] 304 pop gs 305 pop fs 306 pop rbx 307 mov ss, rbx 308 pop rbx 309 mov es, rbx 310 pop rbx 311 mov ds, rbx 312 ret 313InternalAsmThunk16 ENDP 314 315 END 316