mirror of https://review.coreboot.org/STM.git
830 lines
23 KiB
C
830 lines
23 KiB
C
/** @file
|
|
|
|
Copyright (c) 2015, 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 <Base.h>
|
|
#include "FrmInit.h"
|
|
#include "Dce.h"
|
|
#include <Library\PcdLib.h>
|
|
|
|
FRM_COMMUNICATION_DATA mCommunicationData;
|
|
|
|
FRM_HOST_CONTEXT_COMMON mHostContextCommon;
|
|
FRM_GUEST_CONTEXT_COMMON mGuestContextCommon;
|
|
|
|
|
|
BASE_LIBRARY_JUMP_BUFFER mGuestJumpBuffer;
|
|
|
|
volatile BOOLEAN *mApFinished;
|
|
volatile BOOLEAN mApLaunch = FALSE;
|
|
|
|
UINT32 mBspIndex;
|
|
|
|
extern UINT32 mExceptionHandlerLength;
|
|
extern UINTN mApicIdList;
|
|
|
|
BASE_LIBRARY_JUMP_BUFFER mDlmeJumpBuffer;
|
|
|
|
/**
|
|
|
|
This is AP wakeup 32bit entrypoint.
|
|
|
|
**/
|
|
VOID
|
|
AsmApWakeup32 (
|
|
VOID
|
|
);
|
|
|
|
#ifdef MDE_CPU_X64
|
|
extern UINT32 mLongModeEntry;
|
|
#endif
|
|
|
|
/**
|
|
|
|
This function is main function and it will jump back accrording to DLME argument.
|
|
|
|
@param DlmeArgs A pointer to the Args of DLME
|
|
**/
|
|
VOID
|
|
DlmeMain (
|
|
IN VOID *DlmeArgs
|
|
)
|
|
{
|
|
LongJump (DlmeArgs, (UINTN)-1);
|
|
CpuDeadLoop ();
|
|
}
|
|
|
|
/**
|
|
|
|
This function run DRTM DL_Entry.
|
|
|
|
**/
|
|
VOID
|
|
DlEntry (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Flag;
|
|
VOID *StackBase;
|
|
VOID *StackTop;
|
|
UINT32 Ret;
|
|
|
|
StackBase = AllocatePages (1);
|
|
StackTop = (UINT8 *)StackBase + EFI_PAGES_TO_SIZE(1);
|
|
|
|
Flag = SetJump (&mDlmeJumpBuffer);
|
|
if (Flag != 0) {
|
|
DEBUG ((EFI_D_INFO, "(TXT) !!!Great! Entre DLME!!!\n"));
|
|
return ;
|
|
}
|
|
|
|
Ret = DL_Entry ((UINTN)DlmeMain, &mDlmeJumpBuffer, StackTop);
|
|
|
|
DEBUG ((EFI_D_INFO, "(TXT) !!!DlEntry fail - 0x%x!!!\n", Ret));
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize FRM heap.
|
|
|
|
**/
|
|
VOID
|
|
InitHeap (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Get memory from HighMemory
|
|
// Should not use AllocatePages here, since it is chicken-egg problem
|
|
//
|
|
mHostContextCommon.HeapBottom = mCommunicationData.HighMemoryBase;
|
|
mHostContextCommon.HeapTop = mCommunicationData.HighMemoryBase + mCommunicationData.HighMemorySize;
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize timer for FRM.
|
|
|
|
**/
|
|
VOID
|
|
InitializeTimer (
|
|
VOID
|
|
)
|
|
{
|
|
mHostContextCommon.AcpiTimerIoPortBaseAddress = GetAcpiTimerPort(&mHostContextCommon.AcpiTimerWidth);
|
|
PcdSet16(PcdAcpiTimerIoPortBaseAddress, mHostContextCommon.AcpiTimerIoPortBaseAddress);
|
|
PcdSet8(PcdAcpiTimerWidth, mHostContextCommon.AcpiTimerWidth);
|
|
if (mHostContextCommon.AcpiTimerIoPortBaseAddress == 0) {
|
|
CpuDeadLoop();
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize basic context for FRM.
|
|
|
|
**/
|
|
VOID
|
|
InitBasicContext (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 RegEax;
|
|
|
|
mHostContextCommon.CpuNum = GetCpuNumFromAcpi ();
|
|
|
|
GetPciExpressInfoFromAcpi (&mHostContextCommon.PciExpressBaseAddress, &mHostContextCommon.PciExpressLength);
|
|
PcdSet64 (PcdPciExpressBaseAddress, mHostContextCommon.PciExpressBaseAddress);
|
|
if (mHostContextCommon.PciExpressBaseAddress == 0) {
|
|
CpuDeadLoop ();
|
|
}
|
|
|
|
mHostContextCommon.ResetIoPortBaseAddress = GetAcpiResetPort ();
|
|
|
|
mHostContextCommon.AcpiPmControlIoPortBaseAddress = GetAcpiPmControlPort ();
|
|
if (mHostContextCommon.AcpiPmControlIoPortBaseAddress == 0) {
|
|
CpuDeadLoop ();
|
|
}
|
|
|
|
mHostContextCommon.HostContextPerCpu = AllocatePages (FRM_SIZE_TO_PAGES(sizeof(FRM_HOST_CONTEXT_PER_CPU)) * mHostContextCommon.CpuNum);
|
|
mGuestContextCommon.GuestContextPerCpu = AllocatePages (FRM_SIZE_TO_PAGES(sizeof(FRM_GUEST_CONTEXT_PER_CPU)) * mHostContextCommon.CpuNum);
|
|
|
|
mHostContextCommon.LowMemoryBase = mCommunicationData.LowMemoryBase;
|
|
mHostContextCommon.LowMemorySize = mCommunicationData.LowMemorySize;
|
|
mHostContextCommon.LowMemoryBackupBase = (UINT64)(UINTN)AllocatePages (FRM_SIZE_TO_PAGES ((UINTN)mCommunicationData.LowMemorySize));
|
|
|
|
//
|
|
// Save current context
|
|
//
|
|
mBspIndex = ApicToIndex (ReadLocalApicId ());
|
|
mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr0 = AsmReadCr0 ();
|
|
mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr3 = AsmReadCr3 ();
|
|
mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr4 = AsmReadCr4 ();
|
|
AsmReadGdtr (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr);
|
|
AsmReadIdtr (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Idtr);
|
|
|
|
AsmCpuid (CPUID_EXTENDED_INFORMATION, &RegEax, NULL, NULL, NULL);
|
|
if (RegEax >= CPUID_EXTENDED_ADDRESS_SIZE) {
|
|
AsmCpuid (CPUID_EXTENDED_ADDRESS_SIZE, &RegEax, NULL, NULL, NULL);
|
|
mHostContextCommon.PhysicalAddressBits = (UINT8)RegEax;
|
|
} else {
|
|
mHostContextCommon.PhysicalAddressBits = 36;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Host related init
|
|
//
|
|
|
|
/**
|
|
|
|
This function initialize host VMCS.
|
|
|
|
**/
|
|
VOID
|
|
InitHostVmcs (
|
|
UINTN Index
|
|
)
|
|
{
|
|
UINT64 Data64;
|
|
UINTN Size;
|
|
|
|
//
|
|
// VMCS size
|
|
//
|
|
Data64 = AsmReadMsr64 (IA32_VMX_BASIC_MSR_INDEX);
|
|
Size = (UINTN)(RShiftU64 (Data64, 32) & 0xFFFF);
|
|
|
|
//
|
|
// Allocate
|
|
//
|
|
mHostContextCommon.HostContextPerCpu[Index].Vmcs = (UINT64)(UINTN)AllocatePages (FRM_SIZE_TO_PAGES(Size));
|
|
|
|
//
|
|
// Set RevisionIdentifier
|
|
//
|
|
*(UINT32 *)(UINTN)mHostContextCommon.HostContextPerCpu[Index].Vmcs = (UINT32)Data64;
|
|
|
|
return ;
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize host common context.
|
|
|
|
**/
|
|
VOID
|
|
InitHostContextCommon (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
INTERRUPT_GATE_DESCRIPTOR *IdtGate;
|
|
|
|
//
|
|
// PageTable
|
|
//
|
|
mHostContextCommon.PageTable = CreatePageTable ();
|
|
|
|
mHostContextCommon.Gdtr.Limit = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr.Limit;
|
|
mHostContextCommon.Gdtr.Base = (UINTN)AllocatePages (FRM_SIZE_TO_PAGES (mHostContextCommon.Gdtr.Limit + 1));
|
|
CopyMem ((VOID *)mHostContextCommon.Gdtr.Base, (VOID *)mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr.Base, mHostContextCommon.Gdtr.Limit + 1);
|
|
AsmWriteGdtr (&mHostContextCommon.Gdtr);
|
|
|
|
mHostContextCommon.Idtr.Limit = 0x100 * sizeof (INTERRUPT_GATE_DESCRIPTOR) - 1;
|
|
mHostContextCommon.Idtr.Base = (UINTN)AllocatePages (FRM_SIZE_TO_PAGES (mHostContextCommon.Idtr.Limit + 1));
|
|
CopyMem ((VOID *)mHostContextCommon.Idtr.Base, (VOID *)mGuestContextCommon.GuestContextPerCpu[mBspIndex].Idtr.Base, mHostContextCommon.Idtr.Limit + 1);
|
|
IdtGate = (INTERRUPT_GATE_DESCRIPTOR *)mHostContextCommon.Idtr.Base;
|
|
for (Index = 0; Index < 0x100; Index++) {
|
|
IdtGate[Index].Offset15To0 = (UINT16)((UINTN)AsmExceptionHandlers + Index * mExceptionHandlerLength);
|
|
IdtGate[Index].Offset31To16 = (UINT16)(((UINTN)AsmExceptionHandlers + Index * mExceptionHandlerLength) >> 16);
|
|
#ifdef MDE_CPU_X64
|
|
IdtGate[Index].Offset63To32 = (UINT32)(((UINTN)AsmExceptionHandlers + Index * mExceptionHandlerLength) >> 32);
|
|
#endif
|
|
}
|
|
//
|
|
// Special for NMI
|
|
//
|
|
IdtGate[2].Offset15To0 = (UINT16)((UINTN)AsmNmiExceptionHandler);
|
|
IdtGate[2].Offset31To16 = (UINT16)(((UINTN)AsmNmiExceptionHandler) >> 16);
|
|
#ifdef MDE_CPU_X64
|
|
IdtGate[2].Offset63To32 = (UINT32)(((UINTN)AsmNmiExceptionHandler) >> 32);
|
|
#endif
|
|
|
|
//
|
|
// VmExitHandler
|
|
//
|
|
InitFrmHandler ();
|
|
mTeardownFinished = AllocatePages (FRM_SIZE_TO_PAGES (mHostContextCommon.CpuNum));
|
|
|
|
//
|
|
// Init HostContextPerCpu
|
|
//
|
|
mApicIdList = (UINTN)AllocatePages (FRM_SIZE_TO_PAGES (sizeof(UINT32) * mHostContextCommon.CpuNum));
|
|
GetApicIdListFromAcpi ((UINT32 *)mApicIdList);
|
|
|
|
for (Index = 0; Index < mHostContextCommon.CpuNum; Index++) {
|
|
mHostContextCommon.HostContextPerCpu[Index].Index = Index;
|
|
mHostContextCommon.HostContextPerCpu[Index].ApicId = *((UINT32 *)mApicIdList + Index);
|
|
|
|
mHostContextCommon.HostContextPerCpu[Index].Stack = (UINTN)AllocatePages (32);
|
|
mHostContextCommon.HostContextPerCpu[Index].Stack += FRM_PAGES_TO_SIZE (32);
|
|
|
|
InitHostVmcs (Index);
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize host context per CPU.
|
|
|
|
@param Index CPU Index
|
|
|
|
**/
|
|
VOID
|
|
InitHostContextPerCpu (
|
|
IN UINT32 Index
|
|
)
|
|
{
|
|
//
|
|
// VmxOn for this CPU
|
|
//
|
|
AsmWbinvd ();
|
|
AsmWriteCr3 (mHostContextCommon.PageTable);
|
|
AsmWriteCr4 (AsmReadCr4 () | CR4_PAE | ((UINTN)AsmReadMsr64 (IA32_VMX_CR4_FIXED0_MSR_INDEX) & (UINTN)AsmReadMsr64 (IA32_VMX_CR4_FIXED1_MSR_INDEX)));
|
|
AsmWriteCr0 (AsmReadCr0 () | ((UINTN)AsmReadMsr64 (IA32_VMX_CR0_FIXED0_MSR_INDEX) & (UINTN)AsmReadMsr64 (IA32_VMX_CR0_FIXED1_MSR_INDEX)));
|
|
AsmVmxOn (&mHostContextCommon.HostContextPerCpu[Index].Vmcs);
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize host context.
|
|
|
|
**/
|
|
VOID
|
|
InitHostContext (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
//
|
|
// Set up common data structure
|
|
//
|
|
InitHostContextCommon ();
|
|
|
|
//
|
|
// Init BSP
|
|
//
|
|
InitHostContextPerCpu (mBspIndex);
|
|
|
|
// Backup
|
|
CopyMem ((VOID *)(UINTN)mHostContextCommon.LowMemoryBackupBase, (VOID *)(UINTN)mHostContextCommon.LowMemoryBase, (UINTN)mHostContextCommon.LowMemorySize);
|
|
|
|
//
|
|
// Wakeup AP for init, because we need AP run VMXON instruction
|
|
//
|
|
mApFinished = AllocatePages (FRM_SIZE_TO_PAGES (mHostContextCommon.CpuNum));
|
|
mApFinished[mBspIndex] = TRUE;
|
|
InitAllAps ();
|
|
|
|
if (IsMleLaunched()) {
|
|
DEBUG((EFI_D_INFO, "(TXT) TxtWakeUpRlps ...\n"));
|
|
#ifdef MDE_CPU_X64
|
|
TxtWakeUpRlps((UINT32)((UINTN)AsmApWakeup32 + mLongModeEntry));
|
|
#else
|
|
TxtWakeUpRlps((UINT32)((UINTN)AsmApWakeup32));
|
|
#endif
|
|
} else {
|
|
DEBUG((EFI_D_INFO, "(FRM) WakeupAllAps ...\n"));
|
|
WakeupAllAps();
|
|
}
|
|
|
|
// Wait
|
|
for (Index = 0; Index < mHostContextCommon.CpuNum; Index++) {
|
|
while (!mApFinished[Index]) {
|
|
; // WAIT
|
|
}
|
|
}
|
|
DEBUG((EFI_D_INFO, "(FRM) mApFinished\n"));
|
|
|
|
// OK All AP finished
|
|
|
|
// Restore
|
|
CopyMem ((VOID *)(UINTN)mHostContextCommon.LowMemoryBase, (VOID *)(UINTN)mHostContextCommon.LowMemoryBackupBase, (UINTN)mHostContextCommon.LowMemorySize);
|
|
}
|
|
|
|
//
|
|
// Guest related init
|
|
//
|
|
|
|
/**
|
|
|
|
This function is guest entrypoint during initialization.
|
|
|
|
**/
|
|
VOID
|
|
GuestEntrypoint (
|
|
VOID
|
|
)
|
|
{
|
|
DEBUG ((EFI_D_INFO, "(FRM) !!!Entry Guest!!!\n"));
|
|
LongJump (&mGuestJumpBuffer, (UINTN)-1);
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize guest VMCS.
|
|
|
|
**/
|
|
VOID
|
|
InitGuestVmcs (
|
|
IN UINT32 Index
|
|
)
|
|
{
|
|
IA32_VMX_BASIC_MSR VmxBasicMsr;
|
|
|
|
//
|
|
// VMCS size
|
|
//
|
|
VmxBasicMsr.Uint64 = AsmReadMsr64 (IA32_VMX_BASIC_MSR_INDEX);
|
|
|
|
//
|
|
// Allocate
|
|
//
|
|
mGuestContextCommon.GuestContextPerCpu[Index].Vmcs = (UINT64)(UINTN)AllocatePages (FRM_SIZE_TO_PAGES((UINTN)VmxBasicMsr.Bits.VmcsRegionSize));
|
|
|
|
//
|
|
// Set RevisionIdentifier
|
|
//
|
|
*(UINT32 *)(UINTN)mGuestContextCommon.GuestContextPerCpu[Index].Vmcs = (UINT32)VmxBasicMsr.Bits.RevisionIdentifier;
|
|
|
|
return ;
|
|
}
|
|
|
|
#define MSR_READ 1
|
|
#define MSR_WRITE 2
|
|
|
|
VOID
|
|
EnableMsrInterception (
|
|
UINT8 *bitmap, UINT32 msr_arg, UINT8 mode
|
|
)
|
|
{
|
|
UINT8 *read_map;
|
|
UINT8 *write_map;
|
|
UINT32 msr = msr_arg;
|
|
UINT8 msr_bit;
|
|
UINT32 msr_index;
|
|
/* low MSR */
|
|
if (msr < 0x1FFFU) {
|
|
read_map = bitmap;
|
|
write_map = bitmap + 2048;
|
|
} else if ((msr >= 0xc0000000U) && (msr <= 0xc0001fffU)) {
|
|
read_map = bitmap + 1024;
|
|
write_map = bitmap + 3072;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
msr &= 0x1FFFU;
|
|
msr_bit = 1U << (msr & 0x7U);
|
|
msr_index = msr >> 3U;
|
|
|
|
if ((mode & MSR_READ) == MSR_READ) {
|
|
read_map[msr_index] |= msr_bit;
|
|
} else {
|
|
read_map[msr_index] &= ~msr_bit;
|
|
}
|
|
|
|
if ((mode & MSR_WRITE) == MSR_WRITE) {
|
|
write_map[msr_index] |= msr_bit;
|
|
} else {
|
|
write_map[msr_index] &= ~msr_bit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize guest common context.
|
|
|
|
**/
|
|
VOID
|
|
InitGuestContextCommon (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
//
|
|
// CompatiblePageTable for IA32 flat mode only
|
|
//
|
|
mGuestContextCommon.CompatiblePageTable = CreateCompatiblePageTable ();
|
|
mGuestContextCommon.CompatiblePageTablePae = CreateCompatiblePageTablePae ();
|
|
|
|
mGuestContextCommon.MsrBitmap = (UINT64)(UINTN)AllocatePages (1);
|
|
EnableMsrInterception( (UINT8*)mGuestContextCommon.MsrBitmap, IA32_EFER_MSR_INDEX, MSR_WRITE|MSR_READ);
|
|
EnableMsrInterception( (UINT8*)mGuestContextCommon.MsrBitmap, IA32_SYSENTER_CS_MSR_INDEX, MSR_WRITE|MSR_READ);
|
|
EnableMsrInterception( (UINT8*)mGuestContextCommon.MsrBitmap, IA32_SYSENTER_ESP_MSR_INDEX, MSR_WRITE|MSR_READ);
|
|
EnableMsrInterception( (UINT8*)mGuestContextCommon.MsrBitmap, IA32_SYSENTER_EIP_MSR_INDEX, MSR_WRITE|MSR_READ);
|
|
EnableMsrInterception( (UINT8*)mGuestContextCommon.MsrBitmap, IA32_FS_BASE_MSR_INDEX, MSR_WRITE|MSR_READ);
|
|
EnableMsrInterception( (UINT8*)mGuestContextCommon.MsrBitmap, IA32_GS_BASE_MSR_INDEX, MSR_WRITE|MSR_READ);
|
|
EnableMsrInterception( (UINT8*)mGuestContextCommon.MsrBitmap, IA32_BIOS_UPDT_TRIG_MSR_INDEX, MSR_WRITE);
|
|
|
|
EptInit ();
|
|
|
|
IoInit ();
|
|
|
|
VmxTimerInit ();
|
|
|
|
//
|
|
// Init GuestContextPerCpu
|
|
//
|
|
for (Index = 0; Index < mHostContextCommon.CpuNum; Index++) {
|
|
mGuestContextCommon.GuestContextPerCpu[Index].Stack = (UINTN)AllocatePages (1);
|
|
mGuestContextCommon.GuestContextPerCpu[Index].Stack += FRM_PAGES_TO_SIZE (1);
|
|
|
|
mGuestContextCommon.GuestContextPerCpu[Index].Cr0 = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr0;
|
|
mGuestContextCommon.GuestContextPerCpu[Index].Cr3 = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr3;
|
|
mGuestContextCommon.GuestContextPerCpu[Index].Cr4 = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr4;
|
|
CopyMem (&mGuestContextCommon.GuestContextPerCpu[Index].Gdtr, &mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr, sizeof(IA32_DESCRIPTOR));
|
|
CopyMem (&mGuestContextCommon.GuestContextPerCpu[Index].Idtr, &mGuestContextCommon.GuestContextPerCpu[mBspIndex].Idtr, sizeof(IA32_DESCRIPTOR));
|
|
|
|
mGuestContextCommon.GuestContextPerCpu[Index].VmExitMsrStore = (UINT64)(UINTN)AllocatePages (1);
|
|
mGuestContextCommon.GuestContextPerCpu[Index].VmExitMsrLoad = (UINT64)(UINTN)AllocatePages (1);
|
|
mGuestContextCommon.GuestContextPerCpu[Index].VmEnterMsrLoad = (UINT64)(UINTN)AllocatePages (1);
|
|
|
|
//
|
|
// Allocate GuestVmcs
|
|
//
|
|
InitGuestVmcs (Index);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize guest context per CPU.
|
|
|
|
@param Index CPU Index
|
|
|
|
**/
|
|
VOID
|
|
InitGuestContextPerCpu (
|
|
IN UINT32 Index
|
|
)
|
|
{
|
|
mGuestContextCommon.GuestContextPerCpu[Index].EFER = AsmReadMsr64 (IA32_EFER_MSR_INDEX);
|
|
|
|
//
|
|
// Load current VMCS, after that we can access VMCS region
|
|
//
|
|
AsmVmClear (&mGuestContextCommon.GuestContextPerCpu[Index].Vmcs);
|
|
AsmVmPtrLoad (&mGuestContextCommon.GuestContextPerCpu[Index].Vmcs);
|
|
|
|
SetVmcsHostField (Index);
|
|
SetVmcsGuestField (Index);
|
|
SetVmcsControlField (Index);
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize guest context.
|
|
|
|
**/
|
|
VOID
|
|
InitGuestContext (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Setup common data structure
|
|
//
|
|
InitGuestContextCommon ();
|
|
|
|
InitGuestContextPerCpu (mBspIndex);
|
|
}
|
|
|
|
/**
|
|
|
|
This function launch guest BSP.
|
|
|
|
**/
|
|
VOID
|
|
LaunchGuestBsp (
|
|
VOID
|
|
)
|
|
{
|
|
UINTN Flag;
|
|
UINTN Rflags;
|
|
|
|
Flag = SetJump (&mGuestJumpBuffer);
|
|
if (Flag != 0) {
|
|
DEBUG ((EFI_D_INFO, "(FRM) !!!Guest JumpBack to EFI!!!\n"));
|
|
// Run successfully
|
|
return ;
|
|
}
|
|
|
|
AsmVmPtrLoad (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Vmcs);
|
|
|
|
//
|
|
// Launch STM
|
|
//
|
|
LaunchStm (mBspIndex);
|
|
|
|
AsmVmPtrLoad (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Vmcs);
|
|
|
|
AcquireSpinLock (&mHostContextCommon.DebugLock);
|
|
DumpVmcsAllField ();
|
|
ReleaseSpinLock (&mHostContextCommon.DebugLock);
|
|
|
|
AsmWbinvd ();
|
|
|
|
Rflags = AsmVmLaunch (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Register);
|
|
DEBUG ((EFI_D_ERROR, "(FRM) !!!LaunchGuestBsp FAIL!!!\n"));
|
|
DEBUG ((EFI_D_ERROR, "(FRM) Rflags: %08x\n", Rflags));
|
|
DEBUG ((EFI_D_ERROR, "(FRM) VMCS_32_RO_VM_INSTRUCTION_ERROR: %08x\n", (UINTN)VmRead32 (VMCS_32_RO_VM_INSTRUCTION_ERROR_INDEX)));
|
|
|
|
CpuDeadLoop ();
|
|
}
|
|
|
|
/**
|
|
|
|
This function launch guest AP.
|
|
|
|
**/
|
|
VOID
|
|
LaunchGuestAp (
|
|
VOID
|
|
)
|
|
{
|
|
mApLaunch = TRUE;
|
|
}
|
|
|
|
/**
|
|
|
|
This function launch guest.
|
|
|
|
**/
|
|
VOID
|
|
LauchGuest (
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// For AP, deadloop
|
|
//
|
|
LaunchGuestAp ();
|
|
|
|
//
|
|
// For BSP, long jump back
|
|
//
|
|
LaunchGuestBsp ();
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize guest BSP in S3.
|
|
|
|
**/
|
|
VOID
|
|
BspS3Init (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr0 = AsmReadCr0 ();
|
|
mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr3 = AsmReadCr3 ();
|
|
mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr4 = AsmReadCr4 ();
|
|
AsmReadGdtr (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr);
|
|
AsmReadIdtr (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Idtr);
|
|
|
|
InitHostContextPerCpu (mBspIndex);
|
|
|
|
for (Index = 0; Index < mHostContextCommon.CpuNum; Index++) {
|
|
mGuestContextCommon.GuestContextPerCpu[Index].Cr0 = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr0;
|
|
mGuestContextCommon.GuestContextPerCpu[Index].Cr3 = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr3;
|
|
mGuestContextCommon.GuestContextPerCpu[Index].Cr4 = mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr4;
|
|
CopyMem (&mGuestContextCommon.GuestContextPerCpu[Index].Gdtr, &mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr, sizeof(IA32_DESCRIPTOR));
|
|
}
|
|
InitGuestContextPerCpu (mBspIndex);
|
|
}
|
|
|
|
/**
|
|
|
|
This function initialize guest AP in S3.
|
|
|
|
**/
|
|
VOID
|
|
ApS3Init (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 Index;
|
|
|
|
// Backup
|
|
CopyMem ((VOID *)(UINTN)mHostContextCommon.LowMemoryBackupBase, (VOID *)(UINTN)mHostContextCommon.LowMemoryBase, (UINTN)mHostContextCommon.LowMemorySize);
|
|
|
|
//
|
|
// Init env
|
|
//
|
|
mApLaunch = FALSE;
|
|
for (Index = 0; Index < mHostContextCommon.CpuNum; Index++) {
|
|
mApFinished[Index] = FALSE;
|
|
}
|
|
|
|
mApFinished[mBspIndex] = TRUE;
|
|
WakeupAllAps ();
|
|
|
|
// Wait
|
|
for (Index = 0; Index < mHostContextCommon.CpuNum; Index++) {
|
|
while (!mApFinished[Index]) {
|
|
; // WAIT
|
|
}
|
|
}
|
|
|
|
// Restore
|
|
CopyMem ((VOID *)(UINTN)mHostContextCommon.LowMemoryBase, (VOID *)(UINTN)mHostContextCommon.LowMemoryBackupBase, (UINTN)mHostContextCommon.LowMemorySize);
|
|
}
|
|
|
|
|
|
BOOLEAN mAlreadyEntered = FALSE;
|
|
|
|
/**
|
|
|
|
This is FRM entrypoint in S3.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
FrmS3Entrypoint (
|
|
VOID
|
|
)
|
|
{
|
|
DEBUG ((EFI_D_INFO, "(FRM) !!!FrmS3Entrypoint!!!\n"));
|
|
DEBUG ((EFI_D_INFO, "(FRM) !!!FRM build time - %a %a!!!\n", (CHAR8 *)__DATE__, (CHAR8 *)__TIME__));
|
|
|
|
BspS3Init ();
|
|
ApS3Init ();
|
|
|
|
LauchGuest ();
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
This is FRM module entrypoint.
|
|
|
|
@param CommunicationData FRM communication data.
|
|
|
|
@retval RETURN_SUCCESS FRM is launched.
|
|
@retval RETURN_UNSUPPORTED FRM is unsupproted.
|
|
|
|
**/
|
|
RETURN_STATUS
|
|
_ModuleEntryPoint (
|
|
IN FRM_COMMUNICATION_DATA *CommunicationData
|
|
)
|
|
{
|
|
BOOLEAN InterruptEnabled;
|
|
RETURN_STATUS Status;
|
|
|
|
if ((AsmReadMsr64 (IA32_FEATURE_CONTROL_MSR_INDEX) & IA32_FEATURE_CONTROL_VMX) == 0) {
|
|
DEBUG ((EFI_D_ERROR, "(FRM) !!!VMX not enabled!\n"));
|
|
return RETURN_UNSUPPORTED;
|
|
}
|
|
|
|
if (mAlreadyEntered) {
|
|
return FrmS3Entrypoint ();
|
|
}
|
|
|
|
InterruptEnabled = SaveAndDisableInterrupts ();
|
|
|
|
if (sizeof(UINTN) == sizeof(UINT32)) {
|
|
DEBUG ((EFI_D_INFO, "(FRM) !!!FrmEntrypoint32!!!\n"));
|
|
} else {
|
|
DEBUG ((EFI_D_INFO, "(FRM) !!!FrmEntrypoint64!!!\n"));
|
|
}
|
|
DEBUG ((EFI_D_INFO, "(FRM) !!!FRM build time - %a %a!!!\n", (CHAR8 *)__DATE__, (CHAR8 *)__TIME__));
|
|
|
|
CopyMem (&mCommunicationData, CommunicationData, sizeof(mCommunicationData));
|
|
|
|
DumpVmxCapabillityMsr ();
|
|
|
|
DEBUG ((EFI_D_INFO, "(FRM) HighMemoryBase - %016lx\n", mCommunicationData.HighMemoryBase));
|
|
DEBUG ((EFI_D_INFO, "(FRM) HighMemorySize - %016lx\n", mCommunicationData.HighMemorySize));
|
|
DEBUG ((EFI_D_INFO, "(FRM) LowMemoryBase - %016lx\n", mCommunicationData.LowMemoryBase));
|
|
DEBUG ((EFI_D_INFO, "(FRM) LowMemorySize - %016lx\n", mCommunicationData.LowMemorySize));
|
|
DEBUG ((EFI_D_INFO, "(FRM) ImageBase - %016lx\n", mCommunicationData.ImageBase));
|
|
DEBUG ((EFI_D_INFO, "(FRM) ImageSize - %016lx\n", mCommunicationData.ImageSize));
|
|
DEBUG ((EFI_D_INFO, "(FRM) TimerPeriod - %016lx\n", mCommunicationData.TimerPeriod));
|
|
DEBUG ((EFI_D_INFO, "(FRM) AcpiRsdp - %016lx\n", mCommunicationData.AcpiRsdp));
|
|
DEBUG ((EFI_D_INFO, "(FRM) SmMonitorService - %016lx\n", mCommunicationData.SmMonitorServiceProtocol));
|
|
DEBUG ((EFI_D_INFO, "(FRM) SmMonitorBase - %016lx\n", mCommunicationData.SmMonitorServiceImageBase));
|
|
DEBUG ((EFI_D_INFO, "(FRM) SmMonitorSize - %016lx\n", mCommunicationData.SmMonitorServiceImageSize));
|
|
DEBUG ((EFI_D_INFO, "(TXT) MeasuredImageSize - %016lx\n", mCommunicationData.MeasuredImageSize));
|
|
DEBUG ((EFI_D_INFO, "(TXT) SinitAcmBase - %016lx\n", mCommunicationData.SinitAcmBase));
|
|
DEBUG ((EFI_D_INFO, "(TXT) SinitAcmSize - %016lx\n", mCommunicationData.SinitAcmSize));
|
|
DEBUG ((EFI_D_INFO, "(TXT) LcpPoBase - %016lx\n", mCommunicationData.LcpPoBase));
|
|
DEBUG ((EFI_D_INFO, "(TXT) LcpPoSize - %016lx\n", mCommunicationData.LcpPoSize));
|
|
DEBUG ((EFI_D_INFO, "(TXT) EventLogBase - %016lx\n", mCommunicationData.EventLogBase));
|
|
DEBUG ((EFI_D_INFO, "(TXT) EventLogSize - %016lx\n", mCommunicationData.EventLogSize));
|
|
DEBUG ((EFI_D_INFO, "(TXT) DprBase - %016lx\n", mCommunicationData.DprBase));
|
|
DEBUG ((EFI_D_INFO, "(TXT) DprSize - %016lx\n", mCommunicationData.DprSize));
|
|
DEBUG ((EFI_D_INFO, "(TXT) PmrLowBase - %016lx\n", mCommunicationData.PmrLowBase));
|
|
DEBUG ((EFI_D_INFO, "(TXT) PmrLowSize - %016lx\n", mCommunicationData.PmrLowSize));
|
|
DEBUG ((EFI_D_INFO, "(TXT) PmrHighBase - %016lx\n", mCommunicationData.PmrLowBase));
|
|
DEBUG ((EFI_D_INFO, "(TXT) PmrHighSize - %016lx\n", mCommunicationData.PmrLowSize));
|
|
DEBUG ((EFI_D_INFO, "(TXT) TpmType - %08x\n", mCommunicationData.TpmType));
|
|
DEBUG ((EFI_D_INFO, "(TXT) ActivePcrBanks - %08x\n", mCommunicationData.TpmType));
|
|
|
|
mHostContextCommon.ImageBase = mCommunicationData.ImageBase;
|
|
mHostContextCommon.ImageSize = mCommunicationData.ImageSize;
|
|
|
|
//
|
|
// Prepare heap, then we can use memory service
|
|
//
|
|
InitHeap ();
|
|
// after that we can use mHostContextCommon
|
|
|
|
InitializeSpinLock (&mHostContextCommon.DebugLock);
|
|
// after that we can use AcquireSpinLock/ReleaseSpinLock (&mHostContextCommon.DebugLock) to control block level debug.
|
|
|
|
InitializeSpinLock (&mHostContextCommon.MemoryLock);
|
|
// after that we can use MemoryServices
|
|
|
|
InitializeTimer();
|
|
// after that we can use MicroSecondDelay()
|
|
|
|
Status = DceLoaderEntrypoint();
|
|
if (!EFI_ERROR(Status)) {
|
|
DlEntry();
|
|
}
|
|
|
|
InitBasicContext ();
|
|
|
|
InitHostContext ();
|
|
|
|
InitGuestContext ();
|
|
|
|
LauchGuest ();
|
|
|
|
mAlreadyEntered = TRUE;
|
|
|
|
if (InterruptEnabled) {
|
|
EnableInterrupts();
|
|
}
|
|
return RETURN_SUCCESS;
|
|
}
|
|
|