From 97d92bdaf05d9307d494444cead97c41272eca62 Mon Sep 17 00:00:00 2001 From: bxing Date: Mon, 15 May 2006 11:14:20 +0000 Subject: [PATCH] Updated BaseLib for THUNK functions and some CPU functions git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@158 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Include/Library/BaseLib.h | 41 ++- MdePkg/Library/BaseLib/BaseLib.msa | 4 +- MdePkg/Library/BaseLib/Ebc/CpuBreakpoint.c | 64 ++++ MdePkg/Library/BaseLib/Ebc/Synchronization.c | 57 ++++ MdePkg/Library/BaseLib/Ia32/Thunk16.asm | 260 +++++++++------- MdePkg/Library/BaseLib/Ipf/CpuBreakpoint.c | 18 ++ MdePkg/Library/BaseLib/Ipf/CpuPause.s | 25 ++ MdePkg/Library/BaseLib/X64/Thunk16.asm | 298 +++++++++++-------- MdePkg/Library/BaseLib/x86Thunk.c | 153 ++++++++-- 9 files changed, 664 insertions(+), 256 deletions(-) create mode 100644 MdePkg/Library/BaseLib/Ebc/Synchronization.c create mode 100644 MdePkg/Library/BaseLib/Ipf/CpuPause.s diff --git a/MdePkg/Include/Library/BaseLib.h b/MdePkg/Include/Library/BaseLib.h index ff663c91b7..7fb2e64dfb 100644 --- a/MdePkg/Include/Library/BaseLib.h +++ b/MdePkg/Include/Library/BaseLib.h @@ -2969,15 +2969,16 @@ typedef union { // Byte packed structure for an 16-bit real mode thunks // typedef struct { - IA32_REGISTER_SET RealModeState; + IA32_REGISTER_SET *RealModeState; VOID *RealModeBuffer; - UINTN RealModeBufferSize; - VOID *CallStack; - UINTN CallStackSize; - VOID *RealModeCode; - UINTN RealModeCodeSize; + UINT32 RealModeBufferSize; + UINT32 ThunkAttributes; } THUNK_CONTEXT; +#define THUNK_ATTRIBUTE_BIG_REAL_MODE 0x00000001 +#define THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 0x00000002 +#define THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL 0x00000004 + /** Retrieves CPUID information. @@ -4798,6 +4799,34 @@ AsmDisablePaging64 ( // 16-bit thunking services // +/** + Retrieves the properties for 16-bit thunk functions. + + Computes the size of the buffer and stack below 1MB required to use the + AsmPrepareThunk16(), AsmThunk16() and AsmPrepareAndThunk16() functions. This + buffer size is returned in RealModeBufferSize, and the stack size is returned + in ExtraStackSize. If parameters are passed to the 16-bit real mode code, + then the actual minimum stack size is ExtraStackSize plus the maximum number + of bytes that need to be passed to the 16-bit real mode code. + + If RealModeBufferSize is NULL, then ASSERT(). + If ExtraStackSize is NULL, then ASSERT(). + + @param RealModeBufferSize A pointer to the size of the buffer below 1MB + required to use the 16-bit thunk functions. + @param ExtraStackSize A pointer to the extra size of stack below 1MB + that the 16-bit thunk functions require for + temporary storage in the transition to and from + 16-bit real mode. + +**/ +VOID +EFIAPI +AsmGetThunk16Properties ( + OUT UINT32 *RealModeBufferSize, + OUT UINT32 *ExtraStackSize + ); + /** Prepares all structures a code required to use AsmThunk16(). diff --git a/MdePkg/Library/BaseLib/BaseLib.msa b/MdePkg/Library/BaseLib/BaseLib.msa index a64eea5071..380674a835 100644 --- a/MdePkg/Library/BaseLib/BaseLib.msa +++ b/MdePkg/Library/BaseLib/BaseLib.msa @@ -272,6 +272,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Ipf/InterlockedCompareExchange32.s Ipf/InterlockedCompareExchange64.s Ipf/Synchronization.c + Ipf/CpuPause.s Math64.c @@ -279,9 +280,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. SetJumpLongJump.c Unaligned.c Ebc/CpuBreakpoint.c + Ebc/Synchronization.c - + MdePkg diff --git a/MdePkg/Library/BaseLib/Ebc/CpuBreakpoint.c b/MdePkg/Library/BaseLib/Ebc/CpuBreakpoint.c index b0b262f367..352e1c7c1f 100644 --- a/MdePkg/Library/BaseLib/Ebc/CpuBreakpoint.c +++ b/MdePkg/Library/BaseLib/Ebc/CpuBreakpoint.c @@ -98,3 +98,67 @@ GetInterruptState ( ASSERT (FALSE); return FALSE; } + +/** + Enables CPU interrupts for the smallest window required to capture any + pending interrupts. + + Enables CPU interrupts for the smallest window required to capture any + pending interrupts. + +**/ +VOID +EFIAPI +EnableDisableInterrupts ( + VOID + ) +{ + EnableInterrupts (); + DisableInterrupts (); +} + +/** + Requests CPU to pause for a short period of time. + + Requests CPU to pause for a short period of time. Typically used in MP + systems to prevent memory starvation while waiting for a spin lock. + +**/ +VOID +EFIAPI +CpuPause ( + VOID + ) +{ +} + +/** + Flushes all the Translation Lookaside Buffers(TLB) entries in a CPU. + + Flushes all the Translation Lookaside Buffers(TLB) entries in a CPU. + +**/ +VOID +EFIAPI +CpuFlushTlb ( + VOID + ) +{ + ASSERT (FALSE); +} + +/** + Places the CPU in a sleep state until an interrupt is received. + + Places the CPU in a sleep state until an interrupt is received. If interrupts + are disabled prior to calling this function, then the CPU will be placed in a + sleep state indefinitely. + +**/ +VOID +EFIAPI +CpuSleep ( + VOID + ) +{ +} diff --git a/MdePkg/Library/BaseLib/Ebc/Synchronization.c b/MdePkg/Library/BaseLib/Ebc/Synchronization.c new file mode 100644 index 0000000000..df591b287a --- /dev/null +++ b/MdePkg/Library/BaseLib/Ebc/Synchronization.c @@ -0,0 +1,57 @@ +/** @file + Implementation of synchronization functions on EBC. + + Copyright (c) 2006, 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: Synchronization.c + +**/ + +UINT32 +EFIAPI +InternalSyncCompareExchange32 ( + IN volatile UINT32 *Value, + IN UINT32 CompareValue, + IN UINT32 ExchangeValue + ) +{ + return *Value != CompareValue ? *Value : + ((*Value = ExchangeValue), CompareValue); +} + +UINT64 +EFIAPI +InternalSyncCompareExchange64 ( + IN volatile UINT64 *Value, + IN UINT64 CompareValue, + IN UINT64 ExchangeValue + ) +{ + return *Value != CompareValue ? *Value : + ((*Value = ExchangeValue), CompareValue); +} + +UINT32 +EFIAPI +InternalSyncIncrement ( + IN volatile UINT32 *Value + ) +{ + return ++*Value; +} + +UINT32 +EFIAPI +InternalSyncDecrement ( + IN volatile UINT32 *Value + ) +{ + return --*Value; +} diff --git a/MdePkg/Library/BaseLib/Ia32/Thunk16.asm b/MdePkg/Library/BaseLib/Ia32/Thunk16.asm index 2d62d72aef..89d4f679b6 100644 --- a/MdePkg/Library/BaseLib/Ia32/Thunk16.asm +++ b/MdePkg/Library/BaseLib/Ia32/Thunk16.asm @@ -22,34 +22,16 @@ .686p .model flat,C - .data +EXTERNDEF C m16Start:BYTE +EXTERNDEF C m16Size:WORD +EXTERNDEF C mThunk16Attr:WORD +EXTERNDEF C m16Gdt:WORD +EXTERNDEF C m16GdtrBase:WORD +EXTERNDEF C mTransition:WORD -NullSegSel DQ 0 -_16BitCsSel LABEL QWORD - DW -1 - DW 0 - DB 0 - DB 9bh - DB 8fh ; 16-bit segment - DB 0 -_16BitDsSel LABEL QWORD - DW -1 - DW 0 - DB 0 - DB 93h - DB 8fh ; 16-bit segment - DB 0 -GdtEnd LABEL QWORD - - .const - -_16Gdtr LABEL FWORD - DW offset GdtEnd - offset NullSegSel - 1 - DD offset NullSegSel - -_16Idtr FWORD (1 SHL 10) - 1 - - .code +THUNK_ATTRIBUTE_BIG_REAL_MODE EQU 1 +THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 EQU 2 +THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL EQU 4 IA32_REGS STRUC 4t _EDI DD ? @@ -70,93 +52,165 @@ _CS DW ? _SS DW ? IA32_REGS ENDS -InternalAsmThunk16 PROC USES ebp ebx esi edi ds es fs gs - mov esi, [esp + 36] ; esi <- RegSet - push sizeof (IA32_REGS) - pop ecx - movzx edx, (IA32_REGS ptr [esi])._SS - mov edi, (IA32_REGS ptr [esi])._ESP - sub edi, ecx ; reserve space on realmode stack - push edi ; save stack offset - imul eax, edx, 16 ; eax <- edx * 16 - add edi, eax ; edi <- linear address of 16-bit stack - rep movsb ; copy RegSet - mov esi, edx ; esi <- 16-bit stack segment - pop ebx ; ebx <- 16-bit stack offset - mov edi, [esp + 40] ; edi <- realmode patch - push cs ; save CS segment selector - push offset @BackToThunk ; offset to back from real mode - mov eax, offset @16Return - stosd - xor eax, eax - stosw ; set CS base to 0 - mov eax, esp - stosd - mov eax, ss - stosd - mov eax, cr0 - mov ecx, eax ; ecx <- CR0 - and ecx, 7ffffffeh ; clear PE, PG bits - stosd - mov eax, cr4 - mov ebp, eax - and ebp, 300h ; clear all but PCE and OSFXSR bits - stosd - sidt fword ptr [esp + 44] ; use parameter space to save IDTR - sgdt fword ptr [edi] - lidt _16Idtr - push 10h - pop eax - push 8 - push offset @16Start - lgdt _16Gdtr - retf -@16Start: ; 16-bit starts here - mov ss, eax ; set SS to be a 16-bit segment - mov cr0, ecx - mov cr4, ebp - mov ss, esi ; set up 16-bit stack - mov sp, bx ; mov esp, ebx actually - popaw ; popad actually - pop ds - pop es - pop fs - pop gs - add sp, 4 ; skip _EFLAGS + .const + +m16Size DW offset InternalAsmThunk16 - offset m16Start +mThunk16Attr DW offset _ThunkAttr - offset m16Start +m16Gdt DW offset _NullSegDesc - offset m16Start +m16GdtrBase DW offset _16GdtrBase - offset m16Start +mTransition DW offset _EntryPoint - offset m16Start + + .code + +m16Start LABEL BYTE + +SavedGdt LABEL FWORD + DW ? + DD ? + +_BackFromUserCode PROC + push ss + push cs DB 66h - retf ; transfer control to 16-bit code -@16Return: + call @Base ; push eip +@Base: pushf ; pushfd actually + cli ; disable interrupts push gs push fs push es push ds pushaw ; pushad actually - DB 67h, 66h - lds esi, fword ptr (IA32_REGS ptr [esp])._EIP - DB 67h, 66h - mov eax, [esi + 12] - mov cr4, eax ; restore CR4 - DB 67h, 66h - lgdt fword ptr [esi + 16] - DB 67h, 66h - mov eax, [esi + 8] - mov cr0, eax ; restore CR0 - xor ax, ax ; xor eax, eax actually + DB 66h, 0bah ; mov edx, imm32 +_ThunkAttr DD ? + 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: mov eax, ss DB 67h - mov dword ptr (IA32_REGS ptr [esp])._SS, eax - shl ax, 4 ; shl eax, 4 actually - add ax, sp ; add eax, esp actually - add sp, sizeof (IA32_REGS) ; add esp, sizeof (IA32_REGS) - DB 67h, 66h - mov dword ptr (IA32_REGS ptr [esp - sizeof (IA32_REGS)])._ESP, esp - DB 67h, 66h - lss esp, fword ptr [esi] ; restore protected mode stack + lea bp, [esp + sizeof (IA32_REGS)] + mov word ptr (IA32_REGS ptr [esi - sizeof (IA32_REGS)])._ESP, bp + mov ebx, (IA32_REGS ptr [esi - sizeof (IA32_REGS)])._EIP + shl ax, 4 ; shl eax, 4 + add bp, ax ; add ebp, eax + DB 66h, 0b8h ; mov eax, imm32 +SavedCr4 DD ? + mov cr4, eax DB 66h - retf ; go back to protected mode -@BackToThunk: + lgdt fword ptr cs:[edi + (offset SavedGdt - offset @Base)] + DB 66h, 0b8h ; mov eax, imm32 +SavedCr0 DD ? + mov cr0, eax + DB 0b8h ; mov ax, imm16 +SavedSs DW ? + mov ss, eax + DB 66h, 0bch ; mov esp, imm32 +SavedEsp DD ? + DB 66h + retf ; return to protected mode +_BackFromUserCode ENDP + +_EntryPoint DD offset _ToUserCode - offset m16Start + DW 8h +_16Idtr FWORD (1 SHL 10) - 1 +_16Gdtr LABEL FWORD + DW offset GdtEnd - offset _NullSegDesc - 1 +_16GdtrBase DD offset _NullSegDesc + +_ToUserCode PROC + mov edx, ss + mov ss, ecx ; set new segment selectors + mov ds, ecx + mov es, ecx + mov fs, ecx + mov gs, ecx + mov cr0, eax + mov cr4, ebp ; real mode starts at next instruction + mov ss, esi ; set up 16-bit stack segment + xchg sp, bx ; set up 16-bit stack pointer + DB 66h + call @Base ; push eip +@Base: + pop bp ; ebp <- offset @Base + mov cs:[esi + (offset SavedSs - offset @Base)], edx + mov cs:[esi + (offset SavedEsp - offset @Base)], bx + DB 66h + lidt fword ptr cs:[esi + (offset _16Idtr - offset @Base)] + popaw ; popad actually + pop ds + pop es + pop fs + pop gs + popf ; popfd + DB 66h + retf ; transfer control to user code +_ToUserCode ENDP + +_NullSegDesc DQ 0 +_16CsDesc LABEL QWORD + DW -1 + DW 0 + DB 0 + DB 9bh + DB 8fh ; 16-bit segment, 4GB limit + DB 0 +_16DsDesc LABEL QWORD + DW -1 + DW 0 + DB 0 + DB 93h + DB 8fh ; 16-bit segment, 4GB limit + DB 0 +GdtEnd LABEL QWORD + +; +; @param RegSet Pointer to a IA32_DWORD_REGS structure +; @param Transition Pointer to the transition code +; @return The address of the 16-bit stack after returning from user code +; +InternalAsmThunk16 PROC USES ebp ebx esi edi ds es fs gs + mov esi, [esp + 36] ; esi <- RegSet + movzx edx, (IA32_REGS ptr [esi])._SS + mov edi, (IA32_REGS ptr [esi])._ESP + add edi, - (sizeof (IA32_REGS) + 4) ; reserve stack space + mov ebx, edi ; ebx <- stack offset + imul eax, edx, 16 ; eax <- edx * 16 + push sizeof (IA32_REGS) / 4 + add edi, eax ; edi <- linear address of 16-bit stack + pop ecx + rep movsd ; copy RegSet + mov eax, [esp + 40] ; eax <- address of transition code + mov esi, edx ; esi <- 16-bit stack segment + lea edx, [eax + (offset SavedCr0 - offset m16Start)] + mov ecx, eax + and ecx, 0fh + shl eax, 12 + lea ecx, [ecx + (offset _BackFromUserCode - offset m16Start)] + mov ax, cx + stosd ; [edi] <- return address of user code + sgdt fword ptr [edx + (offset SavedGdt - offset SavedCr0)] + sidt fword ptr [esp + 36] ; save IDT stack in argument space + mov eax, cr0 + mov [edx], eax ; save CR0 in SavedCr0 + and eax, 7ffffffeh ; clear PE, PG bits + mov ebp, cr4 + mov [edx + (offset SavedCr4 - offset SavedCr0)], ebp + and ebp, 300h ; clear all but PCE and OSFXSR bits + push 10h + pop ecx ; ecx <- selector for data segments + lgdt fword ptr [edx + (offset _16Gdtr - offset SavedCr0)] + call fword ptr [edx + (offset _EntryPoint - offset SavedCr0)] lidt fword ptr [esp + 36] ; restore protected mode IDTR + lea eax, [ebp - sizeof (IA32_REGS)] ret InternalAsmThunk16 ENDP diff --git a/MdePkg/Library/BaseLib/Ipf/CpuBreakpoint.c b/MdePkg/Library/BaseLib/Ipf/CpuBreakpoint.c index 987fc9c846..7923e92fa9 100644 --- a/MdePkg/Library/BaseLib/Ipf/CpuBreakpoint.c +++ b/MdePkg/Library/BaseLib/Ipf/CpuBreakpoint.c @@ -99,3 +99,21 @@ GetInterruptState ( { return FALSE; } + +/** + Enables CPU interrupts for the smallest window required to capture any + pending interrupts. + + Enables CPU interrupts for the smallest window required to capture any + pending interrupts. + +**/ +VOID +EFIAPI +EnableDisableInterrupts ( + VOID + ) +{ + EnableInterrupts (); + DisableInterrupts (); +} diff --git a/MdePkg/Library/BaseLib/Ipf/CpuPause.s b/MdePkg/Library/BaseLib/Ipf/CpuPause.s new file mode 100644 index 0000000000..f52692f438 --- /dev/null +++ b/MdePkg/Library/BaseLib/Ipf/CpuPause.s @@ -0,0 +1,25 @@ +/// @file +/// CpuPause() function for Itanium-based architecture. +/// +/// Copyright (c) 2006, 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: CpuPause.s +/// +/// + +.auto +.text + +.proc CpuPause +.type CpuPause, @function +CpuPause:: + hint @pause + br.ret.sptk.many b0 +.endp diff --git a/MdePkg/Library/BaseLib/X64/Thunk16.asm b/MdePkg/Library/BaseLib/X64/Thunk16.asm index f3e80840b3..15aaa80090 100644 --- a/MdePkg/Library/BaseLib/X64/Thunk16.asm +++ b/MdePkg/Library/BaseLib/X64/Thunk16.asm @@ -19,34 +19,16 @@ ; ;------------------------------------------------------------------------------ - .data +EXTERNDEF m16Start:BYTE +EXTERNDEF m16Size:WORD +EXTERNDEF mThunk16Attr:WORD +EXTERNDEF m16Gdt:WORD +EXTERNDEF m16GdtrBase:WORD +EXTERNDEF mTransition:WORD -NullSegSel DQ 0 -_16CsSegSel LABEL QWORD - DW -1 - DW 0 - DB 0 - DB 9bh - DB 8fh ; 16-bit segment - DB 0 -_16BitDsSel LABEL QWORD - DW -1 - DW 0 - DB 0 - DB 93h - DB 8fh ; 16-bit segment - DB 0 -GdtEnd LABEL QWORD - - .const - -_16Gdtr LABEL FWORD - DW offset GdtEnd - offset NullSegSel - 1 - DQ offset NullSegSel - -_16Idtr FWORD (1 SHL 10) - 1 - - .code +THUNK_ATTRIBUTE_BIG_REAL_MODE EQU 1 +THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 EQU 2 +THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL EQU 4 IA32_REGS STRUC 4t _EDI DD ? @@ -61,128 +43,192 @@ _DS DW ? _ES DW ? _FS DW ? _GS DW ? -_RFLAGS DQ ? +_EFLAGS DQ ? _EIP DD ? _CS DW ? _SS DW ? IA32_REGS ENDS -InternalAsmThunk16 PROC USES rbp rbx rsi rdi r12 r13 r14 r15 - mov eax, ds - push rax - mov eax, es - push rax - push fs - push gs - mov rsi, rcx ; rsi <- RegSet - push sizeof (IA32_REGS) - pop rcx - movzx r8, (IA32_REGS ptr [rsi])._SS - xor rdi, rdi - mov edi, (IA32_REGS ptr [rsi])._ESP - sub rdi, rcx ; reserve space on realmode stack - push rdi ; save stack offset - imul rax, r8, 16 - add rdi, rax ; rdi <- linear address of 16-bit stack - rep movsb ; copy RegSet - mov rsi, r8 ; si <- 16-bit stack segment - pop rbx ; rbx <- 16-bit stack offset - mov rdi, rdx ; rdi <- realmode patch - lea eax, @BackToThunk ; rax <- address to back from real mode - push rax ; use in a far return - mov eax, cs - mov [rsp + 4], eax ; save CS - lea eax, @16Return ; thus @Return must < 4GB - stosd ; set ret address offset - xor eax, eax - stosw ; set ret CS base to 0 - mov eax, esp - stosd ; rsp must < 4GB - mov eax, ss - stosd - mov rax, cr0 - mov ecx, eax ; ecx <- CR0 - and ecx, 7ffffffeh ; clear PE, PG bits - stosd - mov rax, cr4 - mov ebp, eax - and ebp, 300h ; clear all but PCE and OSFXSR bits - stosd - sidt fword ptr [rsp + 70h] ; use parameter space to save IDTR - sgdt fword ptr [rdi] - lea edi, _16Idtr - lea eax, @16Start ; rax <- seg:offset of @16Start - push rax - mov dword ptr [rsp + 4], 8 - push 10h - pop rax ; rax <- 10h as dataseg selector - lgdt _16Gdtr - retf -@16Start: ; 16-bit starts here - mov ss, eax ; set SS to be a 16-bit segment - mov cr0, rcx ; disable protected mode - mov cr4, rbp + .const + +m16Size DW offset InternalAsmThunk16 - offset m16Start +mThunk16Attr DW offset _ThunkAttr - offset m16Start +m16Gdt DW offset _NullSegDesc - offset m16Start +m16GdtrBase DW offset _16GdtrBase - offset m16Start +mTransition DW offset _EntryPoint - offset m16Start + + .code + +m16Start LABEL BYTE + +SavedGdt LABEL FWORD + DW ? + DQ ? + +_BackFromUserCode PROC + DB 16h ; push ss + DB 0eh ; push cs DB 66h - mov ecx, 0c0000080h - rdmsr - and ah, NOT 1 ; clear LME - wrmsr - mov ss, esi ; set up 16-bit stack - mov sp, bx ; mov esp, ebx actually - lidt fword ptr [edi] - DB 66h, 61h ; popad - DB 1fh ; pop ds - DB 7 ; pop es - pop fs - pop gs - add sp, 8 ; skip _RFLAGS + call @Base ; push eip +@Base: DB 66h - retf ; transfer control to 16-bit code -@16Return: - DB 66h - push 0 ; high order 32 bits of rflags + push 0 ; reserved high order 32 bits of EFlags pushf ; pushfd actually + cli ; disable interrupts push gs push fs DB 6 ; push es DB 1eh ; push ds DB 66h, 60h ; pushad - DB 67h, 66h, 0c5h, 74h, 24h, 30h ; lds esi, [esp + 12*4] - DB 66h - mov eax, [esi + 12] - mov cr4, rax ; restore CR4 - DB 66h - lgdt fword ptr [esi + 16] + DB 66h, 0bah ; mov edx, imm32 +_ThunkAttr DD ? + 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: + mov eax, ss + lea bp, [esp + sizeof (IA32_REGS)] + mov word ptr (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._ESP, bp + mov ebx, (IA32_REGS ptr [rsi - sizeof (IA32_REGS)])._EIP + shl ax, 4 ; shl eax, 4 + add bp, ax ; add ebp, eax + DB 66h, 0b8h ; mov eax, imm32 +SavedCr4 DD ? + mov cr4, rax + DB 66h, 2eh + lgdt fword ptr [rdi + (offset SavedGdt - offset @Base)] DB 66h mov ecx, 0c0000080h rdmsr - or ah, 1 ; set LME + or ah, 1 wrmsr + DB 66h, 0b8h ; mov eax, imm32 +SavedCr0 DD ? + mov cr0, rax + DB 0b8h ; mov ax, imm16 +SavedSs DW ? + mov ss, eax + DB 66h, 0bch ; mov esp, imm32 +SavedEsp DD ? DB 66h - mov eax, [esi + 8] - mov cr0, rax ; restore CR0 - xor ax, ax ; xor eax, eax actually - mov eax, ss - mov dword ptr (IA32_REGS ptr [esp])._SS, eax - shl ax, 4 ; shl eax, 4 actually - add ax, sp ; add eax, esp actually - add sp, sizeof (IA32_REGS) ; add esp, sizeof (IA32_REGS) + retf ; return to protected mode +_BackFromUserCode ENDP + +_EntryPoint DD offset _ToUserCode - offset m16Start + DW 8h +_16Gdtr LABEL FWORD + DW offset GdtEnd - offset _NullSegDesc - 1 +_16GdtrBase DQ offset _NullSegDesc +_16Idtr FWORD (1 SHL 10) - 1 + +_ToUserCode PROC + mov edi, ss + mov ss, edx ; set new segment selectors + mov ds, edx + mov es, edx + mov fs, edx + mov gs, edx DB 66h - mov dword ptr (IA32_REGS ptr [esp - sizeof (IA32_REGS)])._ESP, esp + mov ecx, 0c0000080h + mov cr0, rax ; real mode starts at next instruction + rdmsr + and ah, NOT 1 + wrmsr + mov cr4, rbp + mov ss, esi ; set up 16-bit stack segment + xchg sp, bx ; set up 16-bit stack pointer DB 66h - lss esp, fword ptr [esi] ; restore protected mode stack + call @Base ; push eip +@Base: + pop bp ; ebp <- offset @Base + DB 2eh ; cs: + mov [rsi + (offset SavedSs - offset @Base)], edi + DB 2eh ; cs: + mov [rsi + (offset SavedEsp - offset @Base)], bx + DB 66h, 2eh ; CS and operand size override + lidt fword ptr [rsi + (offset _16Idtr - offset @Base)] + DB 66h, 61h ; popad + DB 1fh ; pop ds + DB 07h ; pop es + pop fs + pop gs + popf ; popfd + lea sp, [esp + 4] ; skip high order 32 bits of EFlags DB 66h - retf ; go back to protected mode -@BackToThunk: - lidt fword ptr [rsp + 68h] ; restore protected mode IDTR - shl rax, 32 - shr rax, 32 ; clear high order 32 bits of RAX + retf ; transfer control to user code +_ToUserCode ENDP + +_NullSegDesc DQ 0 +_16CsDesc LABEL QWORD + DW -1 + DW 0 + DB 0 + DB 9bh + DB 8fh ; 16-bit segment, 4GB limit + DB 0 +_16DsDesc LABEL QWORD + DW -1 + DW 0 + DB 0 + DB 93h + DB 8fh ; 16-bit segment, 4GB limit + DB 0 +GdtEnd LABEL QWORD + +; +; @param RegSet Pointer to a IA32_DWORD_REGS structure +; @param Transition Pointer to the transition code +; @return The address of the 16-bit stack after returning from user code +; +InternalAsmThunk16 PROC USES rbp rbx rsi rdi + mov r10d, ds + mov r11d, es + push fs + push gs + mov rsi, rcx + movzx r8d, (IA32_REGS ptr [rsi])._SS + mov edi, (IA32_REGS ptr [rsi])._ESP + lea rdi, [edi - (sizeof (IA32_REGS) + 4)] + imul eax, r8d, 16 ; eax <- r8d(stack segment) * 16 + mov ebx, edi ; ebx <- stack offset for 16-bit code + push sizeof (IA32_REGS) / 4 + add edi, eax ; edi <- linear address of 16-bit stack + pop rcx + rep movsd ; copy RegSet + lea ecx, [rdx + (offset SavedCr4 - offset m16Start)] + mov eax, edx ; eax <- transition code address + and edx, 0fh + shl eax, 12 + lea edx, [rdx + (offset _BackFromUserCode - offset m16Start)] + mov ax, dx + stosd ; [edi] <- return address of user code + sgdt fword ptr [rcx + (offset SavedGdt - offset SavedCr4)] + sidt fword ptr [rsp + 38h] ; save IDT stack in argument space + mov rax, cr0 + mov [rcx + (offset SavedCr0 - offset SavedCr4)], eax + and eax, 7ffffffeh ; clear PE, PG bits + mov rbp, cr4 + mov [rcx], ebp ; save CR4 in SavedCr4 + and ebp, 300h ; clear all but PCE and OSFXSR bits + mov esi, r8d ; esi <- 16-bit stack segment + push 10h + pop rdx ; rdx <- selector for data segments + lgdt fword ptr [rcx + (offset _16Gdtr - offset SavedCr4)] + call fword ptr [rcx + (offset _EntryPoint - offset SavedCr4)] + lidt fword ptr [rsp + 38h] ; restore protected mode IDTR + lea eax, [rbp - sizeof (IA32_REGS)] pop gs pop fs - pop rcx - mov es, ecx - pop rcx - mov ds, ecx + mov es, r11d + mov ds, r10d ret InternalAsmThunk16 ENDP diff --git a/MdePkg/Library/BaseLib/x86Thunk.c b/MdePkg/Library/BaseLib/x86Thunk.c index 8cb5f4f8bd..7045924014 100644 --- a/MdePkg/Library/BaseLib/x86Thunk.c +++ b/MdePkg/Library/BaseLib/x86Thunk.c @@ -14,6 +14,35 @@ **/ +// +// Byte packed structure for a segment descriptor in a GDT/LDT +// +typedef union { + struct { + UINT32 LimitLow:16; + UINT32 BaseLow:16; + UINT32 BaseMid:8; + UINT32 Type:4; + UINT32 S:1; + UINT32 DPL:2; + UINT32 P:1; + UINT32 LimitHigh:4; + UINT32 AVL:1; + UINT32 L:1; + UINT32 DB:1; + UINT32 G:1; + UINT32 BaseHigh:8; + } Bits; + UINT64 Uint64; +} IA32_SEGMENT_DESCRIPTOR; + +extern CONST UINT8 m16Start; +extern CONST UINT16 m16Size; +extern CONST UINT16 mThunk16Attr; +extern CONST UINT16 m16Gdt; +extern CONST UINT16 m16GdtrBase; +extern CONST UINT16 mTransition; + /** Invokes 16-bit code in big real mode and returns the updated register set. @@ -22,7 +51,7 @@ on the real mode stack and the starting address of the save area is returned. @param RegisterSet Values of registers before invocation of 16-bit code. - @param Patch Pointer to the area following the 16-bit code. + @param Transition Pointer to the transition code under 1MB. @return The pointer to a IA32_REGISTER_SET structure containing the updated register values. @@ -31,9 +60,44 @@ IA32_REGISTER_SET * InternalAsmThunk16 ( IN IA32_REGISTER_SET *RegisterSet, - IN OUT VOID *Patch + IN OUT VOID *Transition ); +/** + Retrieves the properties for 16-bit thunk functions. + + Computes the size of the buffer and stack below 1MB required to use the + AsmPrepareThunk16(), AsmThunk16() and AsmPrepareAndThunk16() functions. This + buffer size is returned in RealModeBufferSize, and the stack size is returned + in ExtraStackSize. If parameters are passed to the 16-bit real mode code, + then the actual minimum stack size is ExtraStackSize plus the maximum number + of bytes that need to be passed to the 16-bit real mode code. + + If RealModeBufferSize is NULL, then ASSERT(). + If ExtraStackSize is NULL, then ASSERT(). + + @param RealModeBufferSize A pointer to the size of the buffer below 1MB + required to use the 16-bit thunk functions. + @param ExtraStackSize A pointer to the extra size of stack below 1MB + that the 16-bit thunk functions require for + temporary storage in the transition to and from + 16-bit real mode. + +**/ +VOID +EFIAPI +AsmGetThunk16Properties ( + OUT UINT32 *RealModeBufferSize, + OUT UINT32 *ExtraStackSize + ) +{ + ASSERT (RealModeBufferSize != NULL); + ASSERT (ExtraStackSize != NULL); + + *RealModeBufferSize = m16Size; + *ExtraStackSize = sizeof (IA32_DWORD_REGS) + 8; +} + /** Prepares all structures a code required to use AsmThunk16(). @@ -51,7 +115,64 @@ AsmPrepareThunk16 ( OUT THUNK_CONTEXT *ThunkContext ) { + IA32_SEGMENT_DESCRIPTOR *RealModeGdt; + ASSERT (ThunkContext != NULL); + ASSERT ((UINTN)ThunkContext->RealModeBuffer < 0x100000); + ASSERT (ThunkContext->RealModeBufferSize >= m16Size); + ASSERT ((UINTN)ThunkContext->RealModeBuffer + m16Size <= 0x100000); + ASSERT (((UINTN)ThunkContext->RealModeBuffer & 0x0f) == 0); + + CopyMem (ThunkContext->RealModeBuffer, &m16Start, m16Size); + + // + // Point RealModeGdt to the GDT to be used in transition + // + // RealModeGdt[0]: Reserved as NULL descriptor + // RealModeGdt[1]: Code Segment + // RealModeGdt[2]: Data Segment + // RealModeGdt[3]: Call Gate + // + RealModeGdt = (IA32_SEGMENT_DESCRIPTOR*)( + (UINTN)ThunkContext->RealModeBuffer + m16Gdt); + + // + // Update Code & Data Segment Descriptor + // + RealModeGdt[1].Bits.BaseLow = + (UINT32)(UINTN)ThunkContext->RealModeBuffer & ~0xf; + RealModeGdt[1].Bits.BaseMid = + (UINT32)(UINTN)ThunkContext->RealModeBuffer >> 16; + + // + // Update transition code entry point offset + // + *(UINT32*)((UINTN)ThunkContext->RealModeBuffer + mTransition) += + (UINT32)(UINTN)ThunkContext->RealModeBuffer & 0xf; + + // + // Update Segment Limits for both Code and Data Segment Descriptors + // + if ((ThunkContext->ThunkAttributes & THUNK_ATTRIBUTE_BIG_REAL_MODE) == 0) { + // + // Set segment limits to 64KB + // + RealModeGdt[1].Bits.LimitHigh = 0; + RealModeGdt[1].Bits.G = 0; + RealModeGdt[2].Bits.LimitHigh = 0; + RealModeGdt[2].Bits.G = 0; + } + + // + // Update GDTBASE for this thunk context + // + *(VOID**)((UINTN)ThunkContext->RealModeBuffer + m16GdtrBase) = RealModeGdt; + + // + // Update Thunk Attributes + // + *(UINT32*)((UINTN)ThunkContext->RealModeBuffer + mThunk16Attr) = + ThunkContext->ThunkAttributes; } /** @@ -74,28 +195,20 @@ AsmThunk16 ( IN OUT THUNK_CONTEXT *ThunkContext ) { - UINT16 *Patch; + IA32_REGISTER_SET *UpdatedRegs; ASSERT (ThunkContext != NULL); + ASSERT ((UINTN)ThunkContext->RealModeBuffer < 0x100000); + ASSERT (ThunkContext->RealModeBufferSize >= m16Size); + ASSERT ((UINTN)ThunkContext->RealModeBuffer + m16Size <= 0x100000); + ASSERT (((UINTN)ThunkContext->RealModeBuffer & 0x0f) == 0); - Patch = (UINT16*)( - (UINTN)ThunkContext->RealModeCode + - ThunkContext->RealModeCodeSize - ); + UpdatedRegs = InternalAsmThunk16 ( + ThunkContext->RealModeState, + ThunkContext->RealModeBuffer + ); - // - // 0x9a66 is the OpCode of far call with an operand size override. - // - *Patch = 0x9a66; - - // - // CopyMem() here copies the updated register values back to RealModeState - // - CopyMem ( - &ThunkContext->RealModeState, - InternalAsmThunk16 (&ThunkContext->RealModeState, Patch + 1), - sizeof (ThunkContext->RealModeState) - ); + CopyMem (ThunkContext->RealModeState, UpdatedRegs, sizeof (*UpdatedRegs)); } /**