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