/** @file | |
Real Mode Thunk Functions for IA32 and x64. | |
Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR> | |
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 "BaseLibInternals.h" | |
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 The 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(). | |
This interface is limited to be used in either physical mode or virtual modes with paging enabled where the | |
virtual to physical mappings for ThunkContext.RealModeBuffer is mapped 1:1. | |
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 ( | |
IN 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. | |
The register state from the RealModeState field of ThunkContext is restored just prior | |
to calling the 16-bit real mode entry point. This includes the EFLAGS field of RealModeState, | |
which is used to set the interrupt state when a 16-bit real mode entry point is called. | |
Control is transferred to the 16-bit real mode entry point specified by the CS and Eip fields of RealModeState. | |
The stack is initialized to the SS and ESP fields of RealModeState. Any parameters passed to | |
the 16-bit real mode code must be populated by the caller at SS:ESP prior to calling this function. | |
The 16-bit real mode entry point is invoked with a 16-bit CALL FAR instruction, | |
so when accessing stack contents, the 16-bit real mode code must account for the 16-bit segment | |
and 16-bit offset of the return address that were pushed onto the stack. The 16-bit real mode entry | |
point must exit with a RETF instruction. The register state is captured into RealModeState immediately | |
after the RETF instruction is executed. | |
If EFLAGS specifies interrupts enabled, or any of the 16-bit real mode code enables interrupts, | |
or any of the 16-bit real mode code makes a SW interrupt, then the caller is responsible for making sure | |
the IDT at address 0 is initialized to handle any HW or SW interrupts that may occur while in 16-bit real mode. | |
If EFLAGS specifies interrupts enabled, or any of the 16-bit real mode code enables interrupts, | |
then the caller is responsible for making sure the 8259 PIC is in a state compatible with 16-bit real mode. | |
This includes the base vectors, the interrupt masks, and the edge/level trigger mode. | |
If THUNK_ATTRIBUTE_BIG_REAL_MODE is set in the ThunkAttributes field of ThunkContext, then the user code | |
is invoked in big real mode. Otherwise, the user code is invoked in 16-bit real mode with 64KB segment limits. | |
If neither THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 nor THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL are set in | |
ThunkAttributes, then it is assumed that the user code did not enable the A20 mask, and no attempt is made to | |
disable the A20 mask. | |
If THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 is set and THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL is clear in | |
ThunkAttributes, then attempt to use the INT 15 service to disable the A20 mask. If this INT 15 call fails, | |
then attempt to disable the A20 mask by directly accessing the 8042 keyboard controller I/O ports. | |
If THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 is clear and THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL is set in | |
ThunkAttributes, then attempt to disable the A20 mask by directly accessing the 8042 keyboard controller I/O ports. | |
If ThunkContext is NULL, then ASSERT(). | |
If AsmPrepareThunk16() was not previously called with ThunkContext, then ASSERT(). | |
If both THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 and THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL are set in | |
ThunkAttributes, then ASSERT(). | |
This interface is limited to be used in either physical mode or virtual modes with paging enabled where the | |
virtual to physical mappings for ThunkContext.RealModeBuffer is mapped 1:1. | |
@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); | |
ASSERT (((ThunkContext->ThunkAttributes & (THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 | THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL)) != \ | |
(THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15 | THUNK_ATTRIBUTE_DISABLE_A20_MASK_KBD_CTRL))); | |
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 interface is limited to be used in either physical mode or virtual modes with paging enabled where the | |
virtual to physical mappings for ThunkContext.RealModeBuffer is mapped 1:1. | |
See AsmPrepareThunk16() and AsmThunk16() for the detailed description and ASSERT() conditions. | |
@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); | |
} |