From d914e15e11f386c0c1751f7ea4c5871c5286eab8 Mon Sep 17 00:00:00 2001 From: vanjeff Date: Thu, 25 Sep 2008 02:29:34 +0000 Subject: Change name. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@5977 6f19259b-4bc3-4df7-8a09-765794883524 --- MdePkg/Library/BaseLib/X86Thunk.c | 245 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 MdePkg/Library/BaseLib/X86Thunk.c (limited to 'MdePkg/Library/BaseLib/X86Thunk.c') diff --git a/MdePkg/Library/BaseLib/X86Thunk.c b/MdePkg/Library/BaseLib/X86Thunk.c new file mode 100644 index 0000000000..c982ee3e06 --- /dev/null +++ b/MdePkg/Library/BaseLib/X86Thunk.c @@ -0,0 +1,245 @@ +/** @file + Real Mode Thunk Functions for IA32 and X64. + + 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. + +**/ + + +#include + + +// +// 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. + + This function transfers control to the 16-bit code specified by CS:EIP using + the stack specified by SS:ESP in RegisterSet. The updated registers are saved + 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 Transition Pointer to the transition code under 1MB. + + @return The pointer to a IA32_REGISTER_SET structure containing the updated + register values. + +**/ +IA32_REGISTER_SET * +EFIAPI +InternalAsmThunk16 ( + IN IA32_REGISTER_SET *RegisterSet, + 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; + + // + // Extra 4 bytes for return address, and another 4 bytes for mode transition + // + *ExtraStackSize = sizeof (IA32_DWORD_REGS) + 8; +} + +/** + Prepares all structures a code required to use AsmThunk16(). + + Prepares all structures and code required to use AsmThunk16(). + + If ThunkContext is NULL, then ASSERT(). + + @param ThunkContext A pointer to the context structure that describes the + 16-bit real mode code to call. + +**/ +VOID +EFIAPI +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); + + 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; +} + +/** + Transfers control to a 16-bit real mode entry point and returns the results. + + Transfers control to a 16-bit real mode entry point and returns the results. + AsmPrepareThunk16() must be called with ThunkContext before this function is + used. This function must be called with interrupts disabled. + + If ThunkContext is NULL, then ASSERT(). + If AsmPrepareThunk16() was not previously called with ThunkContext, then ASSERT(). + + @param ThunkContext A pointer to the context structure that describes the + 16-bit real mode code to call. + +**/ +VOID +EFIAPI +AsmThunk16 ( + IN OUT THUNK_CONTEXT *ThunkContext + ) +{ + IA32_REGISTER_SET *UpdatedRegs; + + ASSERT (ThunkContext != NULL); + ASSERT ((UINTN)ThunkContext->RealModeBuffer < 0x100000); + ASSERT (ThunkContext->RealModeBufferSize >= m16Size); + ASSERT ((UINTN)ThunkContext->RealModeBuffer + m16Size <= 0x100000); + + UpdatedRegs = InternalAsmThunk16 ( + ThunkContext->RealModeState, + ThunkContext->RealModeBuffer + ); + + CopyMem (ThunkContext->RealModeState, UpdatedRegs, sizeof (*UpdatedRegs)); +} + +/** + Prepares all structures and code for a 16-bit real mode thunk, transfers + control to a 16-bit real mode entry point, and returns the results. + + Prepares all structures and code for a 16-bit real mode thunk, transfers + control to a 16-bit real mode entry point, and returns the results. If the + caller only need to perform a single 16-bit real mode thunk, then this + service should be used. If the caller intends to make more than one 16-bit + real mode thunk, then it is more efficient if AsmPrepareThunk16() is called + once and AsmThunk16() can be called for each 16-bit real mode thunk. This + function must be called with interrupts disabled. + + If ThunkContext is NULL, then ASSERT(). + + @param ThunkContext A pointer to the context structure that describes the + 16-bit real mode code to call. + +**/ +VOID +EFIAPI +AsmPrepareAndThunk16 ( + IN OUT THUNK_CONTEXT *ThunkContext + ) +{ + AsmPrepareThunk16 (ThunkContext); + AsmThunk16 (ThunkContext); +} -- cgit v1.2.3