2007-06-28 09:00:39 +02:00
|
|
|
/*++
|
|
|
|
|
2011-10-18 04:42:34 +02:00
|
|
|
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
|
2010-04-28 13:56:24 +02:00
|
|
|
This program and the accompanying materials
|
2007-06-28 09:00:39 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
Abstract:
|
|
|
|
|
|
|
|
Real Mode Thunk Functions
|
|
|
|
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#include "Thunk16Lib.h"
|
|
|
|
#include "EfiCommonLib.h"
|
|
|
|
|
|
|
|
extern CONST UINTN mCode16Size;
|
|
|
|
|
|
|
|
extern
|
|
|
|
IA32_REGISTER_SET *
|
2009-02-11 06:50:37 +01:00
|
|
|
EFIAPI
|
2007-06-28 09:00:39 +02:00
|
|
|
_Thunk16 (
|
|
|
|
IN OUT IA32_REGISTER_SET *RegisterSet,
|
|
|
|
IN UINT32 ThunkFlags,
|
|
|
|
IN UINT32 RealModeCs
|
|
|
|
);
|
|
|
|
|
|
|
|
extern
|
|
|
|
VOID
|
2009-02-11 06:50:37 +01:00
|
|
|
EFIAPI
|
2007-06-28 09:00:39 +02:00
|
|
|
_Code16Addr (
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
2009-02-11 06:50:37 +01:00
|
|
|
EFIAPI
|
2007-06-28 09:00:39 +02:00
|
|
|
AsmFxRestore (
|
|
|
|
IN CONST IA32_FX_BUFFER *Buffer
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
2009-02-11 06:50:37 +01:00
|
|
|
EFIAPI
|
2007-06-28 09:00:39 +02:00
|
|
|
AsmFxSave (
|
|
|
|
OUT IA32_FX_BUFFER *Buffer
|
|
|
|
);
|
|
|
|
|
2010-11-26 02:54:49 +01:00
|
|
|
UINTN
|
|
|
|
EFIAPI
|
|
|
|
AsmGetEflags (
|
|
|
|
VOID
|
|
|
|
);
|
|
|
|
|
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
AsmSetEflags (
|
|
|
|
IN UINTN Eflags
|
|
|
|
);
|
|
|
|
|
2007-06-28 09:00:39 +02:00
|
|
|
//
|
|
|
|
// Implementation
|
|
|
|
//
|
|
|
|
STATIC
|
|
|
|
IA32_REGISTER_SET *
|
|
|
|
AsmThunk16 (
|
|
|
|
IN THUNK_CONTEXT *ThunkContext,
|
|
|
|
IN OUT IA32_REGISTER_SET *RegisterSet,
|
|
|
|
IN UINT32 ThunkFlags
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Do the 16-bit thunk code.
|
|
|
|
|
|
|
|
NOTE: This function must be called on TPL_HIGH_LEVEL or with interrupts
|
|
|
|
disabled because of GDTR and IDTR manipulations.
|
|
|
|
This function must be placed in identity mapped pages.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
ThunkContext - Thunk context to use.
|
|
|
|
RegisterSet - CPU registers would be set to the values contained in this
|
|
|
|
structure before making the far call. Then CPU registers are
|
|
|
|
copied back to this structure.
|
|
|
|
SS:ESP points to the real mode stack if THUNK_USER_STACK is
|
|
|
|
set on input, otherwise ignored.
|
|
|
|
EFlages is ignored on input.
|
|
|
|
On output, values of CS, EIP, SS and ESP should be ignored.
|
|
|
|
ThunkFlags - 2 flags have currently been defined, THUNK_SAVE_FP_STATE and
|
|
|
|
THUNK_USER_STACK.
|
|
|
|
THUNK_SAVE_FP_STATE - FPU state would be saved/restored
|
|
|
|
before/after calling real mode code.
|
|
|
|
THUNK_USER_STACK - The stack specified by SS:ESP would be
|
|
|
|
used instead of the default stack.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
RegisterSet is returned.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
IA32_FX_BUFFER *FpSavedState;
|
|
|
|
UINT8 FpBuffer[sizeof (*FpSavedState) + 0x10];
|
2010-11-26 02:54:49 +01:00
|
|
|
UINTN Eflags;
|
2007-06-28 09:00:39 +02:00
|
|
|
|
|
|
|
FpSavedState = (IA32_FX_BUFFER*)(((UINTN)FpBuffer + 0xf) & ~0xf);
|
|
|
|
|
|
|
|
if (!(ThunkFlags & THUNK_USER_STACK)) {
|
|
|
|
RegisterSet->E.ESP = (UINT16)ThunkContext->DefaultStack;
|
|
|
|
RegisterSet->E.SS = (UINT16)((ThunkContext->DefaultStack >> 4) & 0xf000);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ThunkFlags & THUNK_SAVE_FP_STATE) {
|
|
|
|
AsmFxSave (FpSavedState);
|
|
|
|
}
|
|
|
|
|
2010-11-26 02:54:49 +01:00
|
|
|
Eflags = AsmGetEflags ();
|
|
|
|
|
2007-06-28 09:00:39 +02:00
|
|
|
EfiCommonLibCopyMem (
|
|
|
|
RegisterSet,
|
|
|
|
_Thunk16 (
|
|
|
|
RegisterSet,
|
|
|
|
(UINT16)(ThunkFlags >> 16),
|
|
|
|
ThunkContext->RealModeBuffer >> 4
|
|
|
|
),
|
|
|
|
sizeof (*RegisterSet)
|
|
|
|
);
|
|
|
|
|
2010-11-26 02:54:49 +01:00
|
|
|
AsmSetEflags (Eflags);
|
|
|
|
|
2007-06-28 09:00:39 +02:00
|
|
|
if (ThunkFlags & THUNK_SAVE_FP_STATE) {
|
|
|
|
AsmFxRestore (FpSavedState);
|
|
|
|
}
|
|
|
|
|
|
|
|
return RegisterSet;
|
|
|
|
}
|
|
|
|
|
|
|
|
UINTN
|
|
|
|
EFIAPI
|
|
|
|
AsmThunk16GetProperties (
|
|
|
|
OUT UINTN *MinimumStackSize
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Returns the properties of this real mode thunk implementation. Currently
|
|
|
|
there are 2 properties has been defined, the minimum real mode buffer size
|
|
|
|
and the minimum stack size.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
MinimumStackSize - The minimum size required for a 16-bit stack.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
The minimum size of the real mode buffer needed by this thunk implementation
|
|
|
|
is returned.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
|
|
// This size should be large enough to hold the register set as well as saved
|
|
|
|
// CPU contexts including GDTR, CR0 and CR4
|
|
|
|
//
|
|
|
|
if (MinimumStackSize) {
|
|
|
|
*MinimumStackSize = sizeof (IA32_REGISTER_SET) + 0x200;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mCode16Size;
|
|
|
|
}
|
|
|
|
|
|
|
|
THUNK_CONTEXT *
|
|
|
|
EFIAPI
|
|
|
|
AsmThunk16SetProperties (
|
|
|
|
OUT THUNK_CONTEXT *ThunkContext,
|
|
|
|
IN VOID *RealModeBuffer,
|
|
|
|
IN UINTN BufferSize
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Tell this real mode thunk implementation the address and size of the real
|
|
|
|
mode buffer needed.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
ThunkContext - The thunk context whose properties to set.
|
|
|
|
RealModeBuffer - The address of the buffer allocated by caller. It should be
|
|
|
|
aligned on a 16-byte boundary.
|
|
|
|
This buffer must be in identity mapped pages.
|
|
|
|
BufferSize - The size of RealModeBuffer. Must be larger than the minimum
|
|
|
|
size required as returned by AsmThunk16GetProperties().
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
None
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
BufferSize &= ~3;
|
|
|
|
|
|
|
|
ThunkContext->RealModeBuffer = (UINT32)(UINTN)RealModeBuffer;
|
|
|
|
ThunkContext->DefaultStack = (UINT32)(ThunkContext->RealModeBuffer + BufferSize);
|
|
|
|
EfiCommonLibCopyMem (RealModeBuffer, (VOID*)(UINTN)_Code16Addr, mCode16Size);
|
|
|
|
|
|
|
|
return ThunkContext;
|
|
|
|
}
|
|
|
|
|
2010-11-26 02:54:49 +01:00
|
|
|
#pragma pack (1)
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
UINT32 EDI;
|
|
|
|
UINT32 ESI;
|
|
|
|
UINT32 EBP;
|
|
|
|
UINT32 ESP;
|
|
|
|
UINT32 EBX;
|
|
|
|
UINT32 EDX;
|
|
|
|
UINT32 ECX;
|
|
|
|
UINT32 EAX;
|
|
|
|
UINT16 DS;
|
|
|
|
UINT16 ES;
|
|
|
|
UINT16 FS;
|
|
|
|
UINT16 GS;
|
|
|
|
UINTN EFLAGS;
|
|
|
|
UINT32 EIP;
|
|
|
|
UINT16 CS;
|
|
|
|
UINT16 SS;
|
|
|
|
} IA32_REGS;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
UINT16 Limit;
|
|
|
|
UINT32 Base;
|
|
|
|
} IA32_DESC;
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
UINT32 RetEip;
|
|
|
|
UINT16 RetCs;
|
|
|
|
UINT16 ThunkFlags;
|
|
|
|
#ifdef EFI32
|
|
|
|
UINT32 SavedEsp;
|
|
|
|
UINT16 SavedSs;
|
|
|
|
#endif
|
|
|
|
IA32_DESC SavedGdtr;
|
|
|
|
#ifdef EFIX64
|
|
|
|
UINT16 Resvd1;
|
|
|
|
#endif
|
|
|
|
UINT32 SavedCr0;
|
|
|
|
UINT32 SavedCr4;
|
|
|
|
} _STK16;
|
|
|
|
#pragma pack ()
|
|
|
|
|
|
|
|
#define STACK_PARAM_SIZE 16
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
AsmThunk16SetUserStack (
|
|
|
|
IN THUNK_CONTEXT *ThunkContext,
|
|
|
|
IN VOID *Stack,
|
|
|
|
IN UINTN StackSize
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (StackSize > STACK_PARAM_SIZE) {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
EfiCommonLibCopyMem ((VOID *)(UINTN)(ThunkContext->DefaultStack - sizeof(_STK16) - sizeof(IA32_REGS) - STACK_PARAM_SIZE), Stack, StackSize);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-06-28 09:00:39 +02:00
|
|
|
VOID
|
|
|
|
EFIAPI
|
|
|
|
AsmThunk16Destroy (
|
|
|
|
IN OUT THUNK_CONTEXT *ThunkContext
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Reset all internal states to their initial values. The caller should not
|
|
|
|
release the real mode buffer until after a call to this function.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
ThunkContext - The thunk context to destroy.
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
None
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ThunkContext->RealModeBuffer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
IA32_REGISTER_SET *
|
|
|
|
EFIAPI
|
|
|
|
AsmThunk16FarCall86 (
|
|
|
|
IN THUNK_CONTEXT *ThunkContext,
|
|
|
|
IN OUT IA32_REGISTER_SET *RegisterSet,
|
|
|
|
IN UINT32 Flags
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Make a far call to 16-bit code.
|
|
|
|
|
|
|
|
NOTE: This function must be called on TPL_HIGH_LEVEL or with interrupts
|
|
|
|
disabled because of GDTR and IDTR manipulations.
|
|
|
|
This function must be placed in identity mapped pages.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
ThunkContext - Thunk context to use.
|
|
|
|
RegisterSet - CPU registers would be set to the values contained in this
|
|
|
|
structure before making the far call. Then CPU registers are
|
|
|
|
copied back to this structure.
|
|
|
|
CS:EIP points to the real mode code being called on input.
|
|
|
|
SS:ESP points to the real mode stack if THUNK_USER_STACK is
|
|
|
|
set on input, otherwise ignored.
|
|
|
|
EFlages is ignored on input.
|
|
|
|
On output, values of CS, EIP, SS and ESP should be ignored.
|
2010-11-26 02:54:49 +01:00
|
|
|
ThunkFlags - THUNK_USER_STACK: The stack specified by SS:ESP would be
|
|
|
|
used instead of the default stack.
|
2007-06-28 09:00:39 +02:00
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
RegisterSet is returned.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
return AsmThunk16 (ThunkContext, RegisterSet, Flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
IA32_REGISTER_SET *
|
|
|
|
EFIAPI
|
|
|
|
AsmThunk16Int86 (
|
|
|
|
IN THUNK_CONTEXT *ThunkContext,
|
|
|
|
IN UINT8 IntNumber,
|
|
|
|
IN OUT IA32_REGISTER_SET *RegisterSet,
|
|
|
|
IN UINT32 Flags
|
|
|
|
)
|
|
|
|
/*++
|
|
|
|
|
|
|
|
Routine Description:
|
|
|
|
|
|
|
|
Invoke a 16-bit interrupt handler.
|
|
|
|
|
|
|
|
NOTE: This function must be called on TPL_HIGH_LEVEL or with interrupts
|
|
|
|
disabled because of GDTR and IDTR manipulations.
|
|
|
|
This function must be placed in identity mapped pages.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
|
|
ThunkContext - Thunk context to use.
|
|
|
|
IntNumber - The ordinal of the interrupt handler ranging from 0 to 255.
|
|
|
|
RegisterSet - CPU registers would be set to the values contained in this
|
|
|
|
structure before making the far call. Then CPU registers are
|
|
|
|
copied back to this structure.
|
|
|
|
SS:ESP points to the real mode stack if THUNK_USER_STACK is
|
|
|
|
set on input, otherwise ignored.
|
|
|
|
EFlages is ignored on input.
|
|
|
|
On output, values of CS, EIP, SS and ESP should be ignored.
|
2010-11-26 02:54:49 +01:00
|
|
|
ThunkFlags - THUNK_USER_STACK: The stack specified by SS:ESP would be
|
|
|
|
used instead of the default stack.
|
2007-06-28 09:00:39 +02:00
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
|
|
RegisterSet is returned.
|
|
|
|
|
|
|
|
--*/
|
|
|
|
{
|
2011-10-18 04:42:34 +02:00
|
|
|
UINT32 *VectorBase;
|
|
|
|
|
|
|
|
//
|
|
|
|
// The base address of legacy interrupt vector table is 0.
|
|
|
|
// We use this base address to get the legacy interrupt handler.
|
|
|
|
//
|
|
|
|
VectorBase = 0;
|
|
|
|
RegisterSet->E.EIP = (UINT16)(VectorBase)[IntNumber];
|
|
|
|
RegisterSet->E.CS = (UINT16)((VectorBase)[IntNumber] >> 16);
|
2007-06-28 09:00:39 +02:00
|
|
|
|
|
|
|
return AsmThunk16 (ThunkContext, RegisterSet, Flags | THUNK_INTERRUPT);
|
|
|
|
}
|