/** @file | |
Real Mode Thunk Functions for IA32 and X64. | |
Copyright (c) 2006, Intel Corporation<BR> | |
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: x86Thunk.c | |
**/ | |
// | |
// 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 * | |
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); | |
} |