--- /dev/null
+\r
+#include "BaseLibInternals.h"\r
+\r
+;------------------------------------------------------------------------------\r
+;\r
+; Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
+; This program and the accompanying materials\r
+; are licensed and made available under the terms and conditions of the BSD License\r
+; which accompanies this distribution. The full text of the license may be found at\r
+; http://opensource.org/licenses/bsd-license.php.\r
+;\r
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+;\r
+; Module Name:\r
+;\r
+; Thunk.asm\r
+;\r
+; Abstract:\r
+;\r
+; Real mode thunk\r
+;\r
+;------------------------------------------------------------------------------\r
+\r
+global ASM_PFX(m16Size)\r
+global ASM_PFX(mThunk16Attr)\r
+global ASM_PFX(m16Gdt)\r
+global ASM_PFX(m16GdtrBase)\r
+global ASM_PFX(mTransition)\r
+global ASM_PFX(m16Start)\r
+\r
+struc IA32_REGS\r
+\r
+ ._EDI: resd 1\r
+ ._ESI: resd 1\r
+ ._EBP: resd 1\r
+ ._ESP: resd 1\r
+ ._EBX: resd 1\r
+ ._EDX: resd 1\r
+ ._ECX: resd 1\r
+ ._EAX: resd 1\r
+ ._DS: resw 1\r
+ ._ES: resw 1\r
+ ._FS: resw 1\r
+ ._GS: resw 1\r
+ ._EFLAGS: resq 1\r
+ ._EIP: resd 1\r
+ ._CS: resw 1\r
+ ._SS: resw 1\r
+ .size:\r
+\r
+endstruc\r
+\r
+SECTION .data\r
+\r
+;\r
+; These are global constant to convey information to C code.\r
+;\r
+ASM_PFX(m16Size) DW InternalAsmThunk16 - ASM_PFX(m16Start)\r
+ASM_PFX(mThunk16Attr) DW _ThunkAttr - ASM_PFX(m16Start)\r
+ASM_PFX(m16Gdt) DW _NullSeg - ASM_PFX(m16Start)\r
+ASM_PFX(m16GdtrBase) DW _16GdtrBase - ASM_PFX(m16Start)\r
+ASM_PFX(mTransition) DW _EntryPoint - ASM_PFX(m16Start)\r
+\r
+SECTION .text\r
+\r
+ASM_PFX(m16Start):\r
+\r
+SavedGdt:\r
+ dw 0\r
+ dq 0\r
+\r
+;------------------------------------------------------------------------------\r
+; _BackFromUserCode() takes control in real mode after 'retf' has been executed\r
+; by user code. It will be shadowed to somewhere in memory below 1MB.\r
+;------------------------------------------------------------------------------\r
+_BackFromUserCode:\r
+ ;\r
+ ; The order of saved registers on the stack matches the order they appears\r
+ ; in IA32_REGS structure. This facilitates wrapper function to extract them\r
+ ; into that structure.\r
+ ;\r
+ ; Some instructions for manipulation of segment registers have to be written\r
+ ; in opcode since 64-bit MASM prevents accesses to those registers.\r
+ ;\r
+ DB 16h ; push ss\r
+ DB 0eh ; push cs\r
+ DB 66h\r
+ call @Base ; push eip\r
+@Base:\r
+ DB 66h\r
+ push 0 ; reserved high order 32 bits of EFlags\r
+ pushfw ; pushfd actually\r
+ cli ; disable interrupts\r
+ push gs\r
+ push fs\r
+ DB 6 ; push es\r
+ DB 1eh ; push ds\r
+ DB 66h, 60h ; pushad\r
+ DB 66h, 0bah ; mov edx, imm32\r
+_ThunkAttr: dd 0\r
+ test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15\r
+ jz @1\r
+ mov eax, 15cd2401h ; mov ax, 2401h & int 15h\r
+ cli ; disable interrupts\r
+ jnc @2\r
+@1:\r
+ test dl, THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL\r
+ jz @2\r
+ in al, 92h\r
+ or al, 2\r
+ out 92h, al ; deactivate A20M#\r
+@2:\r
+ xor ax, ax ; xor eax, eax\r
+ mov eax, ss ; mov ax, ss\r
+ lea bp, [esp + IA32_REGS.size]\r
+ ;\r
+ ; rsi in the following 2 instructions is indeed bp in 16-bit code\r
+ ;\r
+ mov [rsi - IA32_REGS.size + IA32_REGS._ESP], bp\r
+ DB 66h\r
+ mov ebx, [rsi - IA32_REGS.size + IA32_REGS._EIP]\r
+ shl ax, 4 ; shl eax, 4\r
+ add bp, ax ; add ebp, eax\r
+ mov ax, cs\r
+ shl ax, 4\r
+ lea ax, [eax + ebx + (@64BitCode - @Base)]\r
+ DB 66h, 2eh, 89h, 87h ; mov cs:[bx + (@64Eip - @Base)], eax\r
+ DW @64Eip - @Base\r
+ DB 66h, 0b8h ; mov eax, imm32\r
+SavedCr4: DD 0\r
+ mov cr4, rax\r
+ ;\r
+ ; rdi in the instruction below is indeed bx in 16-bit code\r
+ ;\r
+ DB 66h, 2eh ; 2eh is "cs:" segment override\r
+ lgdt [rdi + (SavedGdt - @Base)]\r
+ DB 66h\r
+ mov ecx, 0c0000080h\r
+ rdmsr\r
+ or ah, 1\r
+ wrmsr\r
+ DB 66h, 0b8h ; mov eax, imm32\r
+SavedCr0: DD 0\r
+ mov cr0, rax\r
+ DB 66h, 0eah ; jmp far cs:@64Bit\r
+@64Eip: DD 0\r
+SavedCs: DW 0\r
+@64BitCode:\r
+ db 090h \r
+ db 048h, 0bch ; mov rsp, imm64\r
+SavedSp: DQ 0 ; restore stack\r
+ nop\r
+ ret\r
+\r
+_EntryPoint:\r
+ DD _ToUserCode - ASM_PFX(m16Start)\r
+ DW CODE16\r
+_16Gdtr:\r
+ DW GDT_SIZE - 1\r
+_16GdtrBase:\r
+ DQ _NullSeg\r
+_16Idtr:\r
+ DW (1 << 10) - 1\r
+ DD 0\r
+\r
+;------------------------------------------------------------------------------\r
+; _ToUserCode() takes control in real mode before passing control to user code.\r
+; It will be shadowed to somewhere in memory below 1MB.\r
+;------------------------------------------------------------------------------\r
+_ToUserCode:\r
+ mov ss, edx ; set new segment selectors\r
+ mov ds, edx\r
+ mov es, edx\r
+ mov fs, edx\r
+ mov gs, edx\r
+ DB 66h\r
+ mov ecx, 0c0000080h\r
+ mov cr0, rax ; real mode starts at next instruction\r
+ rdmsr\r
+ and ah, ~1\r
+ wrmsr\r
+ mov cr4, rbp\r
+ mov ss, esi ; set up 16-bit stack segment\r
+ mov sp, bx ; set up 16-bit stack pointer\r
+ DB 66h ; make the following call 32-bit\r
+ call @ToUserCodeBase ; push eip\r
+@ToUserCodeBase:\r
+ pop bp ; ebp <- address of @ToUserCodeBase\r
+ push qword [esp + IA32_REGS.size + 2]\r
+ lea eax, [rsi + (@RealMode - @ToUserCodeBase)] ; rsi is "bp" in 16-bit code\r
+ push rax\r
+ retf ; execution begins at next instruction\r
+@RealMode:\r
+ DB 66h, 2eh ; CS and operand size override\r
+ lidt [rsi + (_16Idtr - @ToUserCodeBase)]\r
+ DB 66h, 61h ; popad\r
+ DB 1fh ; pop ds\r
+ DB 07h ; pop es\r
+ pop fs\r
+ pop gs\r
+ popfw ; popfd\r
+ lea sp, [esp + 4] ; skip high order 32 bits of EFlags\r
+ DB 66h ; make the following retf 32-bit\r
+ retf ; transfer control to user code\r
+\r
+ALIGN 8\r
+\r
+CODE16 equ _16Code - $\r
+DATA16 equ _16Data - $\r
+DATA32 equ _32Data - $\r
+\r
+_NullSeg DQ 0\r
+_16Code:\r
+ DW -1\r
+ DW 0\r
+ DB 0\r
+ DB 9bh\r
+ DB 8fh ; 16-bit segment, 4GB limit\r
+ DB 0\r
+_16Data:\r
+ DW -1\r
+ DW 0\r
+ DB 0\r
+ DB 93h\r
+ DB 8fh ; 16-bit segment, 4GB limit\r
+ DB 0\r
+_32Data:\r
+ DW -1\r
+ DW 0\r
+ DB 0\r
+ DB 93h\r
+ DB 0cfh ; 16-bit segment, 4GB limit\r
+ DB 0\r
+\r
+GDT_SIZE equ $ - _NullSeg\r
+\r
+;------------------------------------------------------------------------------\r
+; IA32_REGISTER_SET *\r
+; EFIAPI\r
+; InternalAsmThunk16 (\r
+; IN IA32_REGISTER_SET *RegisterSet,\r
+; IN OUT VOID *Transition\r
+; );\r
+;------------------------------------------------------------------------------\r
+global ASM_PFX(InternalAsmThunk16)\r
+ASM_PFX(InternalAsmThunk16):\r
+ push rbp\r
+ push rbx\r
+ push rsi\r
+ push rdi\r
+ \r
+ mov ebx, ds\r
+ push rbx ; Save ds segment register on the stack\r
+ mov ebx, es\r
+ push rbx ; Save es segment register on the stack\r
+ mov ebx, ss\r
+ push rbx ; Save ss segment register on the stack\r
+ \r
+ push fs\r
+ push gs\r
+ mov rsi, rcx\r
+ movzx r8d, word [rsi + IA32_REGS._SS]\r
+ mov edi, [rsi + IA32_REGS._ESP]\r
+ lea rdi, [edi - (IA32_REGS.size + 4)]\r
+ imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16\r
+ mov ebx, edi ; ebx <- stack for 16-bit code\r
+ push IA32_REGS.size / 4\r
+ add edi, eax ; edi <- linear address of 16-bit stack\r
+ pop rcx\r
+ rep movsd ; copy RegSet\r
+ lea ecx, [rdx + (SavedCr4 - ASM_PFX(m16Start))]\r
+ mov eax, edx ; eax <- transition code address\r
+ and edx, 0fh\r
+ shl eax, 12 ; segment address in high order 16 bits\r
+ lea ax, [rdx + (_BackFromUserCode - ASM_PFX(m16Start))] ; offset address\r
+ stosd ; [edi] <- return address of user code\r
+ \r
+ sgdt [rsp + 60h] ; save GDT stack in argument space\r
+ movzx r10, word [rsp + 60h] ; r10 <- GDT limit \r
+ lea r11, [rcx + (InternalAsmThunk16 - SavedCr4) + 0xf]\r
+ and r11, ~0xf ; r11 <- 16-byte aligned shadowed GDT table in real mode buffer\r
+ \r
+ mov [rcx + (SavedGdt - SavedCr4)], r10w ; save the limit of shadowed GDT table\r
+ mov [rcx + (SavedGdt - SavedCr4) + 2], r11 ; save the base address of shadowed GDT table\r
+ \r
+ mov rsi, [rsp + 62h] ; rsi <- the original GDT base address\r
+ xchg rcx, r10 ; save rcx to r10 and initialize rcx to be the limit of GDT table\r
+ inc rcx ; rcx <- the size of memory to copy\r
+ xchg rdi, r11 ; save rdi to r11 and initialize rdi to the base address of shadowed GDT table\r
+ rep movsb ; perform memory copy to shadow GDT table\r
+ mov rcx, r10 ; restore the orignal rcx before memory copy\r
+ mov rdi, r11 ; restore the original rdi before memory copy\r
+ \r
+ sidt [rsp + 50h] ; save IDT stack in argument space\r
+ mov rax, cr0\r
+ mov [rcx + (SavedCr0 - SavedCr4)], eax\r
+ and eax, 7ffffffeh ; clear PE, PG bits\r
+ mov rbp, cr4\r
+ mov [rcx], ebp ; save CR4 in SavedCr4\r
+ and ebp, ~30h ; clear PAE, PSE bits\r
+ mov esi, r8d ; esi <- 16-bit stack segment\r
+ DB 6ah, DATA32 ; push DATA32\r
+ pop rdx ; rdx <- 32-bit data segment selector\r
+ lgdt [rcx + (_16Gdtr - SavedCr4)]\r
+ mov ss, edx\r
+ pushfq\r
+ lea edx, [rdx + DATA16 - DATA32]\r
+ lea r8, [REL @RetFromRealMode]\r
+ push r8\r
+ mov r8d, cs\r
+ mov [rcx + (SavedCs - SavedCr4)], r8w\r
+ mov [rcx + (SavedSp - SavedCr4)], rsp\r
+ jmp dword far [rcx + (_EntryPoint - SavedCr4)]\r
+@RetFromRealMode:\r
+ popfq\r
+ lgdt [rsp + 60h] ; restore protected mode GDTR\r
+ lidt [rsp + 50h] ; restore protected mode IDTR\r
+ lea eax, [rbp - IA32_REGS.size]\r
+ pop gs\r
+ pop fs\r
+ pop rbx\r
+ mov ss, ebx\r
+ pop rbx\r
+ mov es, ebx\r
+ pop rbx\r
+ mov ds, ebx\r
+\r
+ pop rdi\r
+ pop rsi\r
+ pop rbx\r
+ pop rbp\r
+\r
+ ret\r