STM/Stm/StmPkg/Core/Init/StmInit.c

1341 lines
51 KiB
C

/** @file
STM initialization
Copyright (c) 2015 - 2016, 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 "StmInit.h"
#include "PeStm.h"
#include <Library/PcdLib.h>
#include <string.h>
extern PE_SMI_CONTROL PeSmiControl;
extern void InitPe();
STM_HOST_CONTEXT_COMMON mHostContextCommon;
STM_GUEST_CONTEXT_COMMON mGuestContextCommonSmi;
STM_GUEST_CONTEXT_COMMON mGuestContextCommonSmm[NUM_PE_TYPE];
static SPIN_LOCK CpuReadyCountLock;
static unsigned int CpuReadyCount = 0;
void CpuReadySync(UINT32 Index);
VOID InitCpuReadySync();
volatile BOOLEAN mIsBspInitialized;
extern volatile BOOLEAN *mCpuInitStatus;
/*++
STM runtime:
+------------+
| SMM handler|
+-------+ +------------+
| Guest | -- ^ |
+-------+ | (2)VMResume| |(3)RSM
|(1) SMI | v
+-------+ |-----------> +------------+
| | |(4) VMResume |SMI-H SMM-H|
| MVMM | -<----------- | STM |
| | (0) Init |STM-Init |
+-------+ -------------> +------------+
Memory layout:
+--------------------+ --
| SMM VMCS | |
+--------------------+ |-> Per-Processor VMCS
| SMI VMCS | |
+--------------------+ --
| SMM VMCS | |
+--------------------+ |-> Per-Processor VMCS
| SMI VMCS | |
+--------------------+ --
| Stack | |-> Per-Processor Dynamic
+--------------------+ --
| Stack | |-> Per-Processor Dynamic
RSP-> +--------------------+ --
| Heap | |
+--------------------+ |-> Additional Dynamic
| Page Table (24K) | |
CR3-> +--------------------+ --
RIP-> | STM Code | |
+--------------------+ |
| GDT (4K) | |-> Static Image
GDT-> +--------------------+ |
| STM Header (4K) | |
MSEG-> +--------------------+ --
--*/
/**
This function return 4K page aligned VMCS size.
@return 4K page aligned VMCS size
**/
UINT32
GetVmcsSize (
VOID
)
{
UINT64 Data64;
UINT32 VmcsSize;
Data64 = AsmReadMsr64 (IA32_VMX_BASIC_MSR_INDEX);
VmcsSize = (UINT32)(RShiftU64 (Data64, 32) & 0xFFFF);
VmcsSize = STM_PAGES_TO_SIZE (STM_SIZE_TO_PAGES (VmcsSize));
return VmcsSize;
}
/**
This function return if Senter executed.
@retval TRUE Senter executed
@retval FALSE Sexit not executed
**/
BOOLEAN
IsSentryEnabled (
VOID
)
{
UINT32 TxtStatus;
TxtStatus = TxtPubRead32 (TXT_STS);
if (((TxtStatus & TXT_STS_SENTER_DONE) != 0) &&
((TxtStatus & TXT_STS_SEXIT_DONE) == 0)) {
return TRUE;
} else {
return FALSE;
}
}
/**
This function get CPU number in TXT heap region.
@return CPU number in TXT heap region
**/
UINT32
GetCpuNumFromTxt (
VOID
)
{
TXT_BIOS_TO_OS_DATA *BiosToOsData;
BiosToOsData = GetTxtBiosToOsData ();
return BiosToOsData->NumLogProcs;
}
/**
This function return PCI Express information in TXT heap region.
Only one segment information is returned.
@param PciExpressBaseAddress PCI Express base address
@param PciExpressLength PCI Express length
@return PciExpressBaseAddress
**/
UINT64
GetPciExpressInfoFromTxt (
OUT UINT64 *PciExpressBaseAddress,
OUT UINT64 *PciExpressLength
)
{
TXT_SINIT_TO_MLE_DATA *SinitToMleData;
TXT_SINIT_MEMORY_DESCRIPTOR_RECORD *SinitMemoryDescriptor;
UINTN Index;
SinitToMleData = GetTxtSinitToMleData ();
SinitMemoryDescriptor = (TXT_SINIT_MEMORY_DESCRIPTOR_RECORD *)((UINTN)SinitToMleData - sizeof(UINT64) + SinitToMleData->SinitMdrTableOffset);
for (Index = 0; Index < SinitToMleData->NumberOfSinitMdrs; Index++) {
if (SinitMemoryDescriptor[Index].Type == TXT_SINIT_MDR_TYPE_PCIE) {
*PciExpressBaseAddress = SinitMemoryDescriptor[Index].Address;
*PciExpressLength = SinitMemoryDescriptor[Index].Length;
return SinitMemoryDescriptor[Index].Address;
}
}
*PciExpressBaseAddress = 0;
*PciExpressLength = 0;
return 0;
}
#define EBDA_BASE_ADDRESS 0x40E
/**
This function find ACPI RSDPTR in TXT heap region.
@return ACPI RSDPTR in TXT heap region
**/
VOID *
FindTxtAcpiRsdPtr (
VOID
)
{
TXT_OS_TO_SINIT_DATA *OsSinitData;
OsSinitData = GetTxtOsToSinitData ();
if (OsSinitData->Version < 5) {
return NULL;
}
return (VOID *)(UINTN)OsSinitData->RsdpPtr;
}
/**
This function find ACPI RSDPTR in UEFI or legacy region.
@return ACPI RSDPTR in UEFI or legacy region
**/
VOID *
FindAcpiRsdPtr (
VOID
)
{
if (mHostContextCommon.AcpiRsdp != 0) {
DEBUG((EFI_D_INFO, "RSDP found in mHostContextCommon.AcpiRsdp 0x%016llx\n", mHostContextCommon.AcpiRsdp));
return (VOID *)(UINTN)mHostContextCommon.AcpiRsdp;
} else {
UINTN Address;
DEBUG((EFI_D_INFO, "Searching for RSDP\n"));
//
// Search EBDA
//
Address = (*(UINT16 *)(UINTN)(EBDA_BASE_ADDRESS)) << 4;
for (; Address < 0xA0000 ; Address += 0x10) {
if (*(UINT64 *)(Address) == EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE) {
DEBUG((EFI_D_INFO, "RSDP found\n"));
mHostContextCommon.AcpiRsdp = Address; // save having to keep looking for it
AsmWbinvd (); // let everone see it
return (VOID *)(Address);
}
}
//
// First Seach 0x0e0000 - 0x0fffff for RSD Ptr
//
for (Address = 0xe0000; Address < 0xfffff; Address += 0x10) {
//DEBUG((EFI_D_INFO, "0x%08lx 0x%016llx 0x%016llx - ", Address, *(UINT64 *)(Address), EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE));
if (*(UINT64 *)(Address) == EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE) {
DEBUG((EFI_D_INFO, "RSDP found\n"));
mHostContextCommon.AcpiRsdp = Address; // save having to keep looking for it
AsmWbinvd ();
return (VOID *)Address;
}
}
//
// Not found
//
return NULL;
}
}
/**
This function scan ACPI table in RSDT.
@param Rsdt ACPI RSDT
@param Signature ACPI table signature
@return ACPI table
**/
VOID *
ScanTableInRSDT (
IN EFI_ACPI_DESCRIPTION_HEADER *Rsdt,
IN UINT32 Signature
)
{
UINTN Index;
UINT32 EntryCount;
UINT32 *EntryPtr;
EFI_ACPI_DESCRIPTION_HEADER *Table;
EntryCount = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
EntryPtr = (UINT32 *)(Rsdt + 1);
for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));
if (Table->Signature == Signature) {
return Table;
}
}
return NULL;
}
/**
This function scan ACPI table in XSDT.
@param Xsdt ACPI XSDT
@param Signature ACPI table signature
@return ACPI table
**/
VOID *
ScanTableInXSDT (
IN EFI_ACPI_DESCRIPTION_HEADER *Xsdt,
IN UINT32 Signature
)
{
UINTN Index;
UINT32 EntryCount;
UINT64 EntryPtr;
UINTN BasePtr;
EFI_ACPI_DESCRIPTION_HEADER *Table;
EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
BasePtr = (UINTN)(Xsdt + 1);
for (Index = 0; Index < EntryCount; Index ++) {
CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(EntryPtr));
if (Table->Signature == Signature) {
return Table;
}
}
return NULL;
}
/**
This function find ACPI table according to signature.
@param RsdPtr ACPI RSDPTR
@param Signature ACPI table signature
@return ACPI table
**/
VOID *
FindAcpiPtr (
VOID *RsdPtr,
UINT32 Signature
)
{
EFI_ACPI_DESCRIPTION_HEADER *AcpiTable;
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
if (RsdPtr == NULL) {
return NULL;
}
AcpiTable = NULL;
Rsdp = (EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)RsdPtr;
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->RsdtAddress;
Xsdt = NULL;
if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) {
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->XsdtAddress;
}
//
// Check Xsdt
//
if (Xsdt != NULL) {
AcpiTable = ScanTableInXSDT (Xsdt, Signature);
}
//
// Check Rsdt
//
if ((AcpiTable == NULL) && (Rsdt != NULL)) {
AcpiTable = ScanTableInRSDT (Rsdt, Signature);
}
return AcpiTable;
}
/**
This function return CPU number from MADT.
@return CPU number
**/
UINT32
GetCpuNumFromAcpi (
VOID
)
{
UINT32 Index;
EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *Madt;
UINTN Length;
EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApic;
Madt = FindAcpiPtr (FindAcpiRsdPtr (), EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE);
if (Madt == NULL) {
return 1;
}
Index = 0;
Length = Madt->Header.Length;
LocalApic = (EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE *)(Madt + 1);
while ((UINTN)LocalApic < (UINTN)Madt + Length) {
if (LocalApic->Type == EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC) {
if ((LocalApic->Flags & EFI_ACPI_2_0_LOCAL_APIC_ENABLED) != 0) {
Index++;
}
} else if (LocalApic->Type == EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC) {
if ((((EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE *)LocalApic)->Flags & EFI_ACPI_4_0_LOCAL_APIC_ENABLED) != 0) {
Index++;
}
}
LocalApic = (EFI_ACPI_2_0_PROCESSOR_LOCAL_APIC_STRUCTURE *)((UINTN)LocalApic + LocalApic->Length);
}
return Index;
}
/**
This function return PCI Express information from MCFG.
Only one segment information is returned.
@param PciExpressBaseAddress PCI Express base address
@param PciExpressLength PCI Express length
@return PciExpressBaseAddress
**/
UINT64
GetPciExpressInfoFromAcpi (
OUT UINT64 *PciExpressBaseAddress,
OUT UINT64 *PciExpressLength
)
{
EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER *Mcfg;
UINTN Length;
EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE *McfgStruct;
Mcfg = FindAcpiPtr (FindAcpiRsdPtr (), EFI_ACPI_2_0_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_SIGNATURE);
if (Mcfg == NULL) {
*PciExpressBaseAddress = 0;
*PciExpressLength = 0;
return 0;
}
Length = Mcfg->Header.Length;
McfgStruct = (EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE *)(Mcfg + 1);
while ((UINTN)McfgStruct < (UINTN)Mcfg + Length) {
if ((McfgStruct->PciSegmentGroupNumber == 0) && (McfgStruct->StartBusNumber == 0)) {
*PciExpressBaseAddress = McfgStruct->BaseAddress;
*PciExpressLength = (McfgStruct->EndBusNumber + 1) * SIZE_1MB;
return McfgStruct->BaseAddress;
}
McfgStruct ++;
}
*PciExpressBaseAddress = 0;
*PciExpressLength = 0;
return 0;
}
/**
This function return minimal MSEG size required by STM.
@param StmHeader Stm header
@return minimal MSEG size
**/
UINTN
GetMinMsegSize (
IN STM_HEADER *StmHeader
)
{
UINTN MinMsegSize;
//MinMsegSize = (STM_PAGES_TO_SIZE (STM_SIZE_TO_PAGES (StmHeader->SwStmHdr.StaticImageSize)) +
/* we use the page table offset in this calculation because the static memory size does
not account for the data and bss locations which come before the page tables and
are cleared by sinit */
MinMsegSize = StmHeader->HwStmHdr.Cr3Offset +
StmHeader->SwStmHdr.AdditionalDynamicMemorySize +
((StmHeader->SwStmHdr.PerProcDynamicMemorySize + GetVmcsSize () * 2) * mHostContextCommon.CpuNum);
return MinMsegSize;
}
/**
This function return the index of CPU according to stack.
@param Register stack value of this CPU
@return CPU index
**/
UINT32
GetIndexFromStack (
IN X86_REGISTER *Register
)
{
STM_HEADER *StmHeader;
UINTN ThisStackTop;
UINTN StackBottom;
UINTN Index;
StmHeader = (STM_HEADER *)(UINTN)((UINT32)AsmReadMsr64(IA32_SMM_MONITOR_CTL_MSR_INDEX) & 0xFFFFF000);
//
// Stack top of this CPU
//
ThisStackTop = ((UINTN)Register + SIZE_4KB - 1) & ~(SIZE_4KB - 1);
//
// EspOffset pointer to bottom of 1st CPU
//
StackBottom = (UINTN)StmHeader + StmHeader->HwStmHdr.EspOffset;
Index = (ThisStackTop - StackBottom) / StmHeader->SwStmHdr.PerProcDynamicMemorySize;
//
// Need minus one for 0-based CPU index
//
return (UINT32)(Index - 1);
}
UINT64
GetMsegInfoFromTxt (
OUT UINT64 *MsegBase,
OUT UINT64 *MsegLength
)
{
*MsegBase = TxtPubRead64(TXT_MSEG_BASE);
*MsegLength = TxtPubRead64(TXT_MSEG_SIZE);
return 0;
}
/**
This function return MSEG information from MSR.
@param MsegBase MSEG base address
@param
MSEG length
@return MsegBase
**/
extern MRTT_INFO mMtrrInfo;
UINT64
GetMsegInfoFromMsr (
OUT UINT64 *MsegBase,
OUT UINT64 *MsegLength
)
{
UINT32 SmrrBase;
UINT32 SmrrLength;
SmrrBase = (UINT32)mMtrrInfo.SmrrBase & (UINT32)mMtrrInfo.SmrrMask & 0xFFFFF000;
SmrrLength = (UINT32)mMtrrInfo.SmrrMask & 0xFFFFF000;
SmrrLength = ~SmrrLength + 1;
*MsegBase = (UINT64)((UINT32)AsmReadMsr64(IA32_SMM_MONITOR_CTL_MSR_INDEX) & 0xFFFFF000);
*MsegLength = SmrrLength - (*MsegBase - SmrrBase);
return *MsegLength;
}
/**
This function initialize STM heap.
@param StmHeader MSEG STM header
**/
VOID
InitHeap (
IN STM_HEADER *StmHeader
)
{
HEAP_HEADER *HeaderPointer;
UINT64 MsegBase;
UINT64 MsegLength;
if (IsSentryEnabled()) {
GetMsegInfoFromTxt (&MsegBase, &MsegLength);
DEBUG ((EFI_D_INFO, "TXT MsegBase- %08x\n", (UINTN)MsegBase));
DEBUG ((EFI_D_INFO, "TXT MsegLength - %08x\n", (UINTN)MsegLength));
} else {
GetMsegInfoFromMsr (&MsegBase, &MsegLength);
}
DEBUG ((EFI_D_INFO, "MsegBase (MSR) - %08x\n", (UINTN)MsegBase));
DEBUG ((EFI_D_INFO, "MsegLength (end of TSEG) - %08x\n", (UINTN)MsegLength));
if (MsegBase == 0) {
DEBUG ((EFI_D_ERROR, "MsegBase == 0\n"));
CpuDeadLoop ();
}
DEBUG ((EFI_D_INFO, "Cr30Offset - %08x\n", StmHeader->HwStmHdr.Cr3Offset));
DEBUG ((EFI_D_INFO, "Page Table Start - %08x\n", MsegBase + StmHeader->HwStmHdr.Cr3Offset));
// make sure that the tseg size was set correctly
// right now we will assume a max size of 3mb for mseg, bug, bug
mHostContextCommon.HeapBottom = (UINT64)((UINTN)StmHeader +
StmHeader->HwStmHdr.Cr3Offset +
STM_PAGES_TO_SIZE(6)); // reserve 6 page for page table
mHostContextCommon.HeapTop = (UINT64)((UINTN)StmHeader +
STM_PAGES_TO_SIZE (STM_SIZE_TO_PAGES (StmHeader->SwStmHdr.StaticImageSize)) +
StmHeader->SwStmHdr.AdditionalDynamicMemorySize);
mHostContextCommon.HeapFree = mHostContextCommon.HeapBottom;
HeaderPointer = (HEAP_HEADER *)((UINTN) mHostContextCommon.HeapFree);
HeaderPointer->NextBlock = 0L;
HeaderPointer->BlockLength = (mHostContextCommon.HeapTop - mHostContextCommon.HeapBottom) >> 12;
}
/**
This function initialize basic context for STM.
**/
VOID
InitBasicContext (
VOID
)
{
mHostContextCommon.HostContextPerCpu = (STM_HOST_CONTEXT_PER_CPU *)AllocatePages (STM_SIZE_TO_PAGES(sizeof(STM_HOST_CONTEXT_PER_CPU)) * mHostContextCommon.CpuNum);
mGuestContextCommonSmi.GuestContextPerCpu = (STM_GUEST_CONTEXT_PER_CPU *) AllocatePages (STM_SIZE_TO_PAGES(sizeof(STM_GUEST_CONTEXT_PER_CPU)) * mHostContextCommon.CpuNum);
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu = AllocatePages (STM_SIZE_TO_PAGES(sizeof(STM_GUEST_CONTEXT_PER_CPU)) * mHostContextCommon.CpuNum);
}
extern void GetMtrr(); // found in eptinit.c...
/**
This function initialize BSP.
@param Register X86 register context
**/
VOID
BspInit (
IN X86_REGISTER *Register
)
{
STM_HEADER *StmHeader;
UINTN VmcsDatabasePage;
VMCS_RECORD_STRUCTURE *VmcsRecord;
TXT_PROCESSOR_SMM_DESCRIPTOR *TxtProcessorSmmDescriptor;
X86_REGISTER *Reg;
IA32_IDT_GATE_DESCRIPTOR *IdtGate;
UINT32 SubIndex;
UINTN XStateSize;
UINT32 RegEax;
IA32_VMX_MISC_MSR VmxMisc;
UINT32 BiosStmVer = 100; // initially assume that the BIOS supports v1.0 of the Intel ref
IA32_DESCRIPTOR IdtrLoad;
GetMtrr(); //Needed in various inits
AsmWbinvd(); // make sure it gets out
StmHeader = (STM_HEADER *)(UINTN)((UINT32)AsmReadMsr64(IA32_SMM_MONITOR_CTL_MSR_INDEX) & 0xFFFFF000);
// on a platform that does not start with TXT, cannot assume the data space has been set to zero
ZeroMem(&mHostContextCommon, sizeof(STM_HOST_CONTEXT_COMMON));
ZeroMem(&mGuestContextCommonSmi, sizeof(STM_HOST_CONTEXT_COMMON));
ZeroMem(&mGuestContextCommonSmm, sizeof(STM_HOST_CONTEXT_COMMON) * NUM_PE_TYPE);
InitHeap (StmHeader);
// after that we can use mHostContextCommon
InitializeSpinLock (&mHostContextCommon.DebugLock);
// after that we can use DEBUG
DEBUG ((EFI_D_INFO, " ********************** STM/PE *********************\n"));
DEBUG ((EFI_D_INFO, "!!!STM build time - %a %a!!!\n", (CHAR8 *)__DATE__, (CHAR8 *)__TIME__));
DEBUG ((EFI_D_INFO, "!!!STM Relocation DONE!!!\n"));
DEBUG ((EFI_D_INFO, "!!!Enter StmInit (BSP)!!! - %d (%x)\n", (UINTN)0, (UINTN)ReadUnaligned32 ((UINT32 *)&Register->Rax)));
// Check Signature and size
VmxMisc.Uint64 = AsmReadMsr64 (IA32_VMX_MISC_MSR_INDEX);
if ((VmxMisc.Uint64 & BIT15) != 0) {
TxtProcessorSmmDescriptor = (TXT_PROCESSOR_SMM_DESCRIPTOR *)(UINTN)(AsmReadMsr64 (IA32_SMBASE_INDEX) + SMM_TXTPSD_OFFSET);
} else {
TxtProcessorSmmDescriptor = (TXT_PROCESSOR_SMM_DESCRIPTOR *)(UINTN)(VmRead32 (VMCS_32_GUEST_SMBASE_INDEX) + SMM_TXTPSD_OFFSET);
}
DEBUG((EFI_D_INFO, "TxtProcessorSmmDescriptor: 0x%016llx\n", TxtProcessorSmmDescriptor));
/*debug - used to make sure that the bios properly sets up the Smm Descriptors*********************debug*/
DEBUG ((EFI_D_INFO, "TxtProcessorSmmDescriptor - %08x\n", (UINTN)TxtProcessorSmmDescriptor));
DEBUG ((EFI_D_INFO, " Signature - %016lx\n", TxtProcessorSmmDescriptor->Signature));
DEBUG ((EFI_D_INFO, " Size - %04x\n", (UINTN)TxtProcessorSmmDescriptor->Size));
DEBUG ((EFI_D_INFO, " SmmDescriptorVerMajor - %02x\n", (UINTN)TxtProcessorSmmDescriptor->SmmDescriptorVerMajor));
DEBUG ((EFI_D_INFO, " SmmDescriptorVerMinor - %02x\n", (UINTN)TxtProcessorSmmDescriptor->SmmDescriptorVerMinor));
DEBUG ((EFI_D_INFO, " LocalApicId - %08x\n", (UINTN)TxtProcessorSmmDescriptor->LocalApicId));
DEBUG ((EFI_D_INFO, " ExecutionDisableOutsideSmrr - %02x\n", (UINTN)TxtProcessorSmmDescriptor->SmmEntryState.ExecutionDisableOutsideSmrr));
DEBUG ((EFI_D_INFO, " Intel64Mode - %02x\n", (UINTN)TxtProcessorSmmDescriptor->SmmEntryState.Intel64Mode));
DEBUG ((EFI_D_INFO, " Cr4Pae - %02x\n", (UINTN)TxtProcessorSmmDescriptor->SmmEntryState.Cr4Pae));
DEBUG ((EFI_D_INFO, " Cr4Pse - %02x\n", (UINTN)TxtProcessorSmmDescriptor->SmmEntryState.Cr4Pse));
DEBUG ((EFI_D_INFO, " SmramToVmcsRestoreRequired - %02x\n", (UINTN)TxtProcessorSmmDescriptor->SmmResumeState.SmramToVmcsRestoreRequired));
DEBUG ((EFI_D_INFO, " ReinitializeVmcsRequired - %02x\n", (UINTN)TxtProcessorSmmDescriptor->SmmResumeState.ReinitializeVmcsRequired));
DEBUG ((EFI_D_INFO, " DomainType - %02x\n", (UINTN)TxtProcessorSmmDescriptor->StmSmmState.DomainType));
DEBUG ((EFI_D_INFO, " XStatePolicy - %02x\n", (UINTN)TxtProcessorSmmDescriptor->StmSmmState.XStatePolicy));
DEBUG ((EFI_D_INFO, " EptEnabled - %02x\n", (UINTN)TxtProcessorSmmDescriptor->StmSmmState.EptEnabled));
DEBUG ((EFI_D_INFO, " SmmCs - %04x\n", (UINTN)TxtProcessorSmmDescriptor->SmmCs));
DEBUG ((EFI_D_INFO, " SmmDs - %04x\n", (UINTN)TxtProcessorSmmDescriptor->SmmDs));
DEBUG ((EFI_D_INFO, " SmmSs - %04x\n", (UINTN)TxtProcessorSmmDescriptor->SmmSs));
DEBUG ((EFI_D_INFO, " SmmOtherSegment - %04x\n", (UINTN)TxtProcessorSmmDescriptor->SmmOtherSegment));
DEBUG ((EFI_D_INFO, " SmmTr - %04x\n", (UINTN)TxtProcessorSmmDescriptor->SmmTr));
DEBUG ((EFI_D_INFO, " SmmCr3 - %016lx\n", TxtProcessorSmmDescriptor->SmmCr3));
DEBUG ((EFI_D_INFO, " SmmStmSetupRip - %016lx\n", TxtProcessorSmmDescriptor->SmmStmSetupRip));
DEBUG ((EFI_D_INFO, " SmmStmTeardownRip - %016lx\n", TxtProcessorSmmDescriptor->SmmStmTeardownRip));
DEBUG ((EFI_D_INFO, " SmmSmiHandlerRip - %016lx\n", TxtProcessorSmmDescriptor->SmmSmiHandlerRip));
DEBUG ((EFI_D_INFO, " SmmSmiHandlerRsp - %016lx\n", TxtProcessorSmmDescriptor->SmmSmiHandlerRsp));
DEBUG ((EFI_D_INFO, " SmmGdtPtr - %016lx\n", TxtProcessorSmmDescriptor->SmmGdtPtr));
DEBUG ((EFI_D_INFO, " SmmGdtSize - %08x\n", (UINTN)TxtProcessorSmmDescriptor->SmmGdtSize));
DEBUG ((EFI_D_INFO, " RequiredStmSmmRevId - %08x\n", (UINTN)TxtProcessorSmmDescriptor->RequiredStmSmmRevId));
DEBUG ((EFI_D_INFO, " StmProtectionExceptionHandler:\n"));
DEBUG ((EFI_D_INFO, " SpeRip - %016lx\n", TxtProcessorSmmDescriptor->StmProtectionExceptionHandler.SpeRip));
DEBUG ((EFI_D_INFO, " SpeRsp - %016lx\n", TxtProcessorSmmDescriptor->StmProtectionExceptionHandler.SpeRsp));
DEBUG ((EFI_D_INFO, " SpeSs - %04x\n", (UINTN)TxtProcessorSmmDescriptor->StmProtectionExceptionHandler.SpeSs));
DEBUG ((EFI_D_INFO, " PageViolationException - %04x\n", (UINTN)TxtProcessorSmmDescriptor->StmProtectionExceptionHandler.PageViolationException));
DEBUG ((EFI_D_INFO, " MsrViolationException - %04x\n", (UINTN)TxtProcessorSmmDescriptor->StmProtectionExceptionHandler.MsrViolationException));
DEBUG ((EFI_D_INFO, " RegisterViolationException- %04x\n", (UINTN)TxtProcessorSmmDescriptor->StmProtectionExceptionHandler.RegisterViolationException));
DEBUG ((EFI_D_INFO, " IoViolationException - %04x\n", (UINTN)TxtProcessorSmmDescriptor->StmProtectionExceptionHandler.IoViolationException));
DEBUG ((EFI_D_INFO, " PciViolationException - %04x\n", (UINTN)TxtProcessorSmmDescriptor->StmProtectionExceptionHandler.PciViolationException));
DEBUG ((EFI_D_INFO, " BiosHwResourceRequirements - %016lx\n", TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr));
DEBUG ((EFI_D_INFO, " AcpiRsdp - %016lx\n", TxtProcessorSmmDescriptor->AcpiRsdp));
DEBUG ((EFI_D_INFO, " PhysicalAddressBits - %02x\n", (UINTN)TxtProcessorSmmDescriptor->PhysicalAddressBits));
/************************************debug**********************************************************************/
// We have to know CpuNum, or we do not know where VMCS will be.
if (IsSentryEnabled ()) {
mHostContextCommon.CpuNum = GetCpuNumFromTxt ();
DEBUG ((EFI_D_INFO, "CpuNumber from TXT Region - %d\n", (UINTN)mHostContextCommon.CpuNum));
} else {
{
EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
mHostContextCommon.AcpiRsdp = TxtProcessorSmmDescriptor->AcpiRsdp;
Rsdp = FindAcpiRsdPtr ();
DEBUG ((EFI_D_INFO, "Rsdp - %08x\n", Rsdp));
if (Rsdp == NULL) {
DEBUG ((EFI_D_INFO, "Null Rsdp - Can not continue\n", Rsdp));
CpuDeadLoop ();
}
Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->RsdtAddress;
DEBUG ((EFI_D_INFO, "Rsdt - %08x\n", Rsdt));
DEBUG ((EFI_D_INFO, "RsdtLen - %08x\n", Rsdt->Length));
if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) {
Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)Rsdp->XsdtAddress;
DEBUG ((EFI_D_INFO, "Xsdt - %016lx\n", Xsdt));
DEBUG ((EFI_D_INFO, "XsdtLen - %08x\n", Xsdt->Length));
}
}
mHostContextCommon.CpuNum = GetCpuNumFromAcpi ();
DEBUG ((EFI_D_INFO, "CpuNumber from ACPI MADT - %d\n", (UINTN)mHostContextCommon.CpuNum));
}
InterlockedIncrement (&mHostContextCommon.JoinedCpuNum);
mHostContextCommon.StmShutdown = 0; // used by Stm/Pe to know when to stop the timer
InitializeSpinLock (&mHostContextCommon.MemoryLock);
InitializeSpinLock (&mHostContextCommon.SmiVmcallLock);
InitializeSpinLock (&mHostContextCommon.PciLock);
DEBUG ((EFI_D_INFO, "HeapBottom - %08x\n", mHostContextCommon.HeapBottom));
DEBUG ((EFI_D_INFO, "HeapTop - %08x\n", mHostContextCommon.HeapTop));
// initialize PE state
PeSmiControl.PeExec = 0;
PeSmiControl.PeNmiBreak = 0;
PeSmiControl.PeCpuIndex = -1;
// Initialize CpuSync
CpuReadyCount = 0;
InitializeSpinLock(&CpuReadyCountLock);
if (TxtProcessorSmmDescriptor->Signature != TXT_PROCESSOR_SMM_DESCRIPTOR_SIGNATURE) {
DEBUG ((EFI_D_INFO, "TXT Descriptor Signature ERROR - %016lx!\n", TxtProcessorSmmDescriptor->Signature));
CpuDeadLoop ();
}
if(TxtProcessorSmmDescriptor->Size == sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR) - 9) // are we dealing with a .99 Bios
{
BiosStmVer = 99; // version .99 has nine less bytes, etc
DEBUG((EFI_D_INFO, "Version .99 Bios detected Found Size: %08x SizeOf %08x\n", TxtProcessorSmmDescriptor->Size, sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR)));
}
else
{
if (TxtProcessorSmmDescriptor->Size != sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR)) {
DEBUG ((EFI_D_INFO, "TXT Descriptor Size ERROR - %08x! Found %08x\n", TxtProcessorSmmDescriptor->Size, sizeof(TXT_PROCESSOR_SMM_DESCRIPTOR) ));
CpuDeadLoop ();
}
}
InitBasicContext ();
DEBUG ((EFI_D_INFO, "Register(%d) - %08x\n", (UINTN)0, Register));
Reg = &mGuestContextCommonSmi.GuestContextPerCpu[0].Register;
Register->Rsp = VmReadN (VMCS_N_GUEST_RSP_INDEX);
CopyMem (Reg, Register, sizeof(X86_REGISTER));
mHostContextCommon.StmHeader = StmHeader;
DEBUG ((EFI_D_INFO, "StmHeader - %08x\n", (UINTN)mHostContextCommon.StmHeader));
DEBUG ((EFI_D_INFO, "Hardware field:\n"));
DEBUG ((EFI_D_INFO, " StmHeaderRevision - %08x\n", (UINTN)StmHeader->HwStmHdr.StmHeaderRevision));
DEBUG ((EFI_D_INFO, " MonitorFeatures - %08x\n", (UINTN)StmHeader->HwStmHdr.MonitorFeatures));
DEBUG ((EFI_D_INFO, " GdtrLimit - %08x\n", (UINTN)StmHeader->HwStmHdr.GdtrLimit));
DEBUG ((EFI_D_INFO, " GdtrBaseOffset - %08x\n", (UINTN)StmHeader->HwStmHdr.GdtrBaseOffset));
DEBUG ((EFI_D_INFO, " CsSelector - %08x\n", (UINTN)StmHeader->HwStmHdr.CsSelector));
DEBUG ((EFI_D_INFO, " EipOffset - %08x\n", (UINTN)StmHeader->HwStmHdr.EipOffset));
DEBUG ((EFI_D_INFO, " EspOffset - %08x\n", (UINTN)StmHeader->HwStmHdr.EspOffset));
DEBUG ((EFI_D_INFO, " Cr3Offset - %08x\n", (UINTN)StmHeader->HwStmHdr.Cr3Offset));
DEBUG ((EFI_D_INFO, "Software field:\n"));
DEBUG ((EFI_D_INFO, " StmSpecVerMajor - %02x\n", (UINTN)StmHeader->SwStmHdr.StmSpecVerMajor));
DEBUG ((EFI_D_INFO, " StmSpecVerMinor - %02x\n", (UINTN)StmHeader->SwStmHdr.StmSpecVerMinor));
DEBUG ((EFI_D_INFO, " StaticImageSize - %08x\n", (UINTN)StmHeader->SwStmHdr.StaticImageSize));
DEBUG ((EFI_D_INFO, " PerProcDynamicMemorySize - %08x\n", (UINTN)StmHeader->SwStmHdr.PerProcDynamicMemorySize));
DEBUG ((EFI_D_INFO, " AdditionalDynamicMemorySize - %08x\n", (UINTN)StmHeader->SwStmHdr.AdditionalDynamicMemorySize));
DEBUG ((EFI_D_INFO, " Intel64ModeSupported - %08x\n", (UINTN)StmHeader->SwStmHdr.StmFeatures.Intel64ModeSupported));
DEBUG ((EFI_D_INFO, " EptSupported - %08x\n", (UINTN)StmHeader->SwStmHdr.StmFeatures.EptSupported));
DEBUG ((EFI_D_INFO, " NumberOfRevIDs - %08x\n", (UINTN)StmHeader->SwStmHdr.NumberOfRevIDs));
for (SubIndex = 0; SubIndex < StmHeader->SwStmHdr.NumberOfRevIDs; SubIndex++) {
DEBUG ((EFI_D_INFO, " StmSmmRevID(%02d) - %08x\n", (UINTN)SubIndex, (UINTN)StmHeader->SwStmHdr.StmSmmRevID[SubIndex]));
}
mHostContextCommon.AcpiRsdp = TxtProcessorSmmDescriptor->AcpiRsdp;
//
// Check MSEG BASE/SIZE in TXT region
//
mHostContextCommon.StmSize = GetMinMsegSize (StmHeader);
{
UINT64 MsegBase, MsegLength;
INT32 AvailMseg;
if (IsSentryEnabled()) {
GetMsegInfoFromTxt (&MsegBase, &MsegLength);
} else {
GetMsegInfoFromMsr (&MsegBase, &MsegLength);
}
AvailMseg = MsegLength - mHostContextCommon.StmSize;
DEBUG ((EFI_D_INFO, "MinMsegSize - 0x%08x MsegLength 0x%08x AvailMseg 0x%08x \n",
(UINTN)mHostContextCommon.StmSize,
MsegLength,
AvailMseg));
}
if(BiosStmVer == 99)
{
mHostContextCommon.PhysicalAddressBits = 36; // for v.99 use this value for now. CPUID value might be too big
}
else
{
mHostContextCommon.PhysicalAddressBits = TxtProcessorSmmDescriptor->PhysicalAddressBits;
}
AsmCpuid(CPUID_EXTENDED_INFORMATION, &RegEax, NULL, NULL, NULL);
if (RegEax >= CPUID_EXTENDED_ADDRESS_SIZE) {
AsmCpuid(CPUID_EXTENDED_ADDRESS_SIZE, &RegEax, NULL, NULL, NULL);
RegEax = (UINT8)RegEax;
DEBUG((EFI_D_INFO, "CPUID - PhysicalAddressBits - 0x%02x\n", (UINT8)RegEax));
} else {
RegEax = 36;
}
if ((mHostContextCommon.PhysicalAddressBits == 0) || (mHostContextCommon.PhysicalAddressBits > (UINT8)RegEax)) {
mHostContextCommon.PhysicalAddressBits = (UINT8)RegEax;
}
if (sizeof(UINTN) == sizeof(UINT32)) {
if (mHostContextCommon.PhysicalAddressBits > 32) {
mHostContextCommon.PhysicalAddressBits = 32;
}
}
mHostContextCommon.MaximumSupportAddress = (LShiftU64(1, mHostContextCommon.PhysicalAddressBits) - 1);
mHostContextCommon.PageTable = AsmReadCr3 ();
AsmReadGdtr (&mHostContextCommon.Gdtr);
//
// Set up STM host IDT to catch exception
//
mHostContextCommon.Idtr.Limit = (UINT16)(STM_MAX_IDT_NUM * sizeof (IA32_IDT_GATE_DESCRIPTOR) - 1);
mHostContextCommon.Idtr.Base = (UINTN)AllocatePages (STM_SIZE_TO_PAGES (mHostContextCommon.Idtr.Limit + 1));
IdtGate = (IA32_IDT_GATE_DESCRIPTOR *)mHostContextCommon.Idtr.Base;
InitializeExternalVectorTablePtr (IdtGate);
//IA32_DESCRIPTOR IdtrLoad;
IdtrLoad = mHostContextCommon.Idtr;
AsmWriteIdtr(&IdtrLoad);
//
// Add more paging for Host CR3.
/////////
//CreateHostPaging ();
// make host paging dynamic to save space for the PE/VMs
SetupStmPageFault();
// VMCS database: One CPU one page should be enough
VmcsDatabasePage = mHostContextCommon.CpuNum;
mHostContextCommon.VmcsDatabase = (UINT64)(UINTN)AllocatePages (VmcsDatabasePage);
// Set last entry
ZeroMem ((VOID *)(UINTN)mHostContextCommon.VmcsDatabase, STM_PAGES_TO_SIZE(VmcsDatabasePage));
VmcsRecord = (VMCS_RECORD_STRUCTURE *)(UINTN)mHostContextCommon.VmcsDatabase;
VmcsRecord[STM_PAGES_TO_SIZE(VmcsDatabasePage) / sizeof(VMCS_RECORD_STRUCTURE) - 1].Type = VMCS_RECORD_LAST;
// DumpVmcsRecord (mHostContextCommon.VmcsDatabase);
// EventLog
InitializeEventLog ();
mCpuInitStatus = AllocatePages (STM_SIZE_TO_PAGES (mHostContextCommon.CpuNum));
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[0].Cr3 = (UINTN)TxtProcessorSmmDescriptor->SmmCr3;
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[0].Actived = FALSE;
//
// CompatiblePageTable for IA32 flat mode only
//
mGuestContextCommonSmm[SMI_HANDLER].CompatiblePageTable = CreateCompatiblePageTable ();
mGuestContextCommonSmm[SMI_HANDLER].CompatiblePaePageTable = CreateCompatiblePaePageTable ();
//
// Allocate XState buffer
//
XStateSize = CalculateXStateSize ();
mGuestContextCommonSmi.ZeroXStateBuffer = (UINTN)AllocatePages (STM_SIZE_TO_PAGES(XStateSize));
for (SubIndex = 0; SubIndex < mHostContextCommon.CpuNum; SubIndex++) {
mGuestContextCommonSmi.GuestContextPerCpu[SubIndex].XStateBuffer = (UINTN)AllocatePages (STM_SIZE_TO_PAGES(XStateSize));
}
EptInit ();
IoInit ();
MsrInit ();
//
// Get PciExpressBaseAddress
//
if (IsSentryEnabled()) {
GetPciExpressInfoFromTxt(&mHostContextCommon.PciExpressBaseAddress, &mHostContextCommon.PciExpressLength);
DEBUG((EFI_D_INFO, "PCIExpressBase from TXT Region - %x\n", (UINTN)mHostContextCommon.PciExpressBaseAddress));
DEBUG((EFI_D_INFO, "PCIExpressLength from TXT Region - %x\n", (UINTN)mHostContextCommon.PciExpressLength));
} else {
GetPciExpressInfoFromAcpi(&mHostContextCommon.PciExpressBaseAddress, &mHostContextCommon.PciExpressLength);
DEBUG((EFI_D_INFO, "PCIExpressBase from ACPI MCFG - %x\n", (UINTN)mHostContextCommon.PciExpressBaseAddress));
DEBUG((EFI_D_INFO, "PCIExpressLength from ACPI MCFG - %x\n", (UINTN)mHostContextCommon.PciExpressLength));
}
if (mHostContextCommon.PciExpressBaseAddress == 0) {
DEBUG((EFI_D_INFO, "mHostContextCommon.PciExpressBaseAddress == 0\n"));
CpuDeadLoop();
}
if ((mHostContextCommon.PciExpressBaseAddress > mHostContextCommon.MaximumSupportAddress) ||
(mHostContextCommon.PciExpressLength > mHostContextCommon.MaximumSupportAddress - mHostContextCommon.PciExpressBaseAddress)) {
DEBUG((EFI_D_INFO, "mHostContextCommon.PciExpressBaseAddress overflow MaximumSupportAddress\n"));
CpuDeadLoop();
}
if (IsOverlap (mHostContextCommon.PciExpressBaseAddress, mHostContextCommon.PciExpressLength, mHostContextCommon.TsegBase, mHostContextCommon.TsegLength)) {
DEBUG((EFI_D_INFO, "mHostContextCommon.PciExpressBaseAddress overlap with TSEG\n"));
CpuDeadLoop();
}
PcdSet64(PcdPciExpressBaseAddress, mHostContextCommon.PciExpressBaseAddress);
for (SubIndex = 0; SubIndex < mHostContextCommon.CpuNum; SubIndex++) {
mHostContextCommon.HostContextPerCpu[SubIndex].HostMsrEntryCount = 1;
mGuestContextCommonSmi.GuestContextPerCpu[SubIndex].GuestMsrEntryCount = 1;
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[SubIndex].GuestMsrEntryCount = 1;
}
mHostContextCommon.HostContextPerCpu[0].HostMsrEntryAddress = (UINT64)(UINTN)AllocatePages (STM_SIZE_TO_PAGES (sizeof(VM_EXIT_MSR_ENTRY) * mHostContextCommon.HostContextPerCpu[0].HostMsrEntryCount * mHostContextCommon.CpuNum));
mGuestContextCommonSmi.GuestContextPerCpu[0].GuestMsrEntryAddress = (UINT64)(UINTN)AllocatePages (STM_SIZE_TO_PAGES (sizeof(VM_EXIT_MSR_ENTRY) * mGuestContextCommonSmi.GuestContextPerCpu[0].GuestMsrEntryCount * mHostContextCommon.CpuNum));
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[SubIndex].GuestMsrEntryAddress = (UINT64)(UINTN)AllocatePages (STM_SIZE_TO_PAGES(sizeof(VM_EXIT_MSR_ENTRY) * mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[0].GuestMsrEntryCount * mHostContextCommon.CpuNum));
for (SubIndex = 0; SubIndex < mHostContextCommon.CpuNum; SubIndex++) {
mHostContextCommon.HostContextPerCpu[SubIndex].HostMsrEntryAddress = mHostContextCommon.HostContextPerCpu[0].HostMsrEntryAddress + sizeof(VM_EXIT_MSR_ENTRY) * mGuestContextCommonSmi.GuestContextPerCpu[0].GuestMsrEntryCount * SubIndex;
mGuestContextCommonSmi.GuestContextPerCpu[SubIndex].GuestMsrEntryAddress = mGuestContextCommonSmi.GuestContextPerCpu[0].GuestMsrEntryAddress + sizeof(VM_EXIT_MSR_ENTRY) * mGuestContextCommonSmi.GuestContextPerCpu[0].GuestMsrEntryCount * SubIndex;
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[SubIndex].GuestMsrEntryAddress = mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[0].GuestMsrEntryAddress + sizeof(VM_EXIT_MSR_ENTRY) * mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[0].GuestMsrEntryCount * SubIndex;
}
DEBUG ((EFI_D_INFO, "DumpStmResource - %x\n", TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr));
DumpStmResource ((STM_RSC *)(UINTN)TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr);
DEBUG ((EFI_D_INFO, "RegisterBiosResource - %x\n", TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr));
RegisterBiosResource ((STM_RSC *)(UINTN)TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr);
InitStmHandlerSmi ();
InitStmHandlerSmm ();
InitPe(); // Initialize protected execution
//STM_PERF_INIT;
//
// Initialization done
//
mIsBspInitialized = TRUE;
AsmWbinvd (); // let everyone else know
return ;
}
/**
This function initialize AP.
@param Index CPU index
@param Register X86 register context
**/
VOID
ApInit (
IN UINT32 Index,
IN X86_REGISTER *Register
)
{
X86_REGISTER *Reg;
IA32_DESCRIPTOR IdtrLoad;
while (!mIsBspInitialized) {
//
// Wait here
//
}
DEBUG ((EFI_D_INFO, "%ld !!!Enter StmInit (AP done)!!! (%x)\n", (UINTN)Index, (UINTN)ReadUnaligned32 ((UINT32 *)&Register->Rax)));
if (Index >= mHostContextCommon.CpuNum) {
DEBUG ((EFI_D_INFO, "%ld !!!Index(0x%x) >= mHostContextCommon.CpuNum(0x%x)\n", Index, (UINTN)Index, (UINTN)mHostContextCommon.CpuNum));
CpuDeadLoop ();
Index = GetIndexFromStack (Register);
}
// do this here to make sure that we can handle a page fault
IdtrLoad = mHostContextCommon.Idtr;
AsmWriteIdtr(&IdtrLoad);
InterlockedIncrement (&mHostContextCommon.JoinedCpuNum);
//DEBUG ((EFI_D_INFO, "%ld Register - %08x\n", (UINTN)Index, Register));
Reg = &mGuestContextCommonSmi.GuestContextPerCpu[Index].Register;
Register->Rsp = VmReadN (VMCS_N_GUEST_RSP_INDEX);
CopyMem (Reg, Register, sizeof(X86_REGISTER));
if (mHostContextCommon.JoinedCpuNum > mHostContextCommon.CpuNum) {
DEBUG ((EFI_D_ERROR, "%ld JoinedCpuNum(%d) > CpuNum(%d)\n", Index, (UINTN)mHostContextCommon.JoinedCpuNum, (UINTN)mHostContextCommon.CpuNum));
// Reset system
CpuDeadLoop ();
}
return ;
}
/**
This function initialize common part for BSP and AP.
@param Index CPU index
**/
VOID
CommonInit (
IN UINT32 Index
)
{
UINTN StackBase;
UINTN StackSize;
STM_HEADER *StmHeader;
UINT32 RegEdx;
IA32_VMX_MISC_MSR VmxMisc;
AsmWriteCr4 (AsmReadCr4 () | CR4_OSFXSR | CR4_OSXMMEXCPT);
if (IsXStateSupoprted()) {
AsmWriteCr4 (AsmReadCr4 () | CR4_OSXSAVE);
}
VmxMisc.Uint64 = AsmReadMsr64 (IA32_VMX_MISC_MSR_INDEX);
RegEdx = ReadUnaligned32 ((UINT32 *)&mGuestContextCommonSmi.GuestContextPerCpu[Index].Register.Rdx);
if ((RegEdx & STM_CONFIG_SMI_UNBLOCKING_BY_VMX_OFF) != 0) {
if (VmxMisc.Bits.VmxOffUnblockSmiSupport != 0) {
AsmWriteMsr64 (IA32_SMM_MONITOR_CTL_MSR_INDEX, AsmReadMsr64(IA32_SMM_MONITOR_CTL_MSR_INDEX) | IA32_SMM_MONITOR_SMI_UNBLOCKING_BY_VMX_OFF);
}
}
mHostContextCommon.HostContextPerCpu[Index].Index = Index;
mHostContextCommon.HostContextPerCpu[Index].ApicId = (UINT8)ReadLocalApicId ();
mHostContextCommon.HostContextPerCpu[Index].Vmxon = VmRead64(VMCS_64_CONTROL_EXECUTIVE_VMCS_PTR_INDEX);
StmHeader = mHostContextCommon.StmHeader;
StackBase = (UINTN)StmHeader +
STM_PAGES_TO_SIZE (STM_SIZE_TO_PAGES (StmHeader->SwStmHdr.StaticImageSize)) +
StmHeader->SwStmHdr.AdditionalDynamicMemorySize;
StackSize = StmHeader->SwStmHdr.PerProcDynamicMemorySize;
mHostContextCommon.HostContextPerCpu[Index].Stack = (UINTN)(StackBase + StackSize * (Index + 1)); // Stack Top
if ((VmxMisc.Uint64 & BIT15) != 0) {
mHostContextCommon.HostContextPerCpu[Index].Smbase = (UINT32)AsmReadMsr64 (IA32_SMBASE_INDEX);
} else {
mHostContextCommon.HostContextPerCpu[Index].Smbase = VmRead32 (VMCS_32_GUEST_SMBASE_INDEX);
}
mHostContextCommon.HostContextPerCpu[Index].TxtProcessorSmmDescriptor = (TXT_PROCESSOR_SMM_DESCRIPTOR *)(UINTN)(mHostContextCommon.HostContextPerCpu[Index].Smbase + SMM_TXTPSD_OFFSET);
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Cr3 = (UINTN)mHostContextCommon.HostContextPerCpu[Index].TxtProcessorSmmDescriptor->SmmCr3;
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Efer = AsmReadMsr64 (IA32_EFER_MSR_INDEX);
mGuestContextCommonSmi.GuestContextPerCpu[Index].Efer = AsmReadMsr64 (IA32_EFER_MSR_INDEX);
}
/**
This function initialize VMCS.
@param Index CPU index
**/
VOID
VmcsInit (
IN UINT32 Index
)
{
UINT64 CurrentVmcs;
UINTN VmcsBase;
UINT32 VmcsSize;
STM_HEADER *StmHeader;
UINTN Rflags;
StmHeader = mHostContextCommon.StmHeader;
/* have to use Cr3Offset because StaticImageSize ignores BSS and Data sections */
VmcsBase = (UINTN)StmHeader +
//STM_PAGES_TO_SIZE (STM_SIZE_TO_PAGES (StmHeader->SwStmHdr.StaticImageSize)) +
StmHeader->HwStmHdr.Cr3Offset +
StmHeader->SwStmHdr.AdditionalDynamicMemorySize +
StmHeader->SwStmHdr.PerProcDynamicMemorySize * mHostContextCommon.CpuNum;
VmcsSize = GetVmcsSize();
mGuestContextCommonSmi.GuestContextPerCpu[Index].Vmcs = (UINT64)(VmcsBase + VmcsSize * (Index * 2));
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Vmcs = (UINT64)(VmcsBase + VmcsSize * (Index * 2 + 1));
DEBUG ((EFI_D_INFO, "%d SmiVmcsPtr - %016lx\n", (UINTN)Index, mGuestContextCommonSmi.GuestContextPerCpu[Index].Vmcs));
DEBUG ((EFI_D_INFO, "%d SmmVmcsPtr - %016lx\n", (UINTN)Index, mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Vmcs));
AsmVmPtrStore (&CurrentVmcs);
DEBUG ((EFI_D_INFO, "%d CurrentVmcs - %016lx VmcsSize %x\n", (UINTN)Index, CurrentVmcs, VmcsSize));
if (IsOverlap (CurrentVmcs, VmcsSize, mHostContextCommon.TsegBase, mHostContextCommon.TsegLength)) {
// Overlap TSEG
DEBUG ((EFI_D_ERROR, "%d CurrentVmcs violation - %016lx\n", (UINTN)Index, CurrentVmcs));
DumpVmcsAllField();
CpuDeadLoop() ;
}
Rflags = AsmVmClear (&CurrentVmcs);
if ((Rflags & (RFLAGS_CF | RFLAGS_ZF)) != 0) {
DEBUG ((EFI_D_ERROR, "%d ERROR: AsmVmClear - %016lx : %08x\n", (UINTN)Index, CurrentVmcs, Rflags));
CpuDeadLoop ();
}
CopyMem (
(VOID *)(UINTN)mGuestContextCommonSmi.GuestContextPerCpu[Index].Vmcs,
(VOID *)(UINTN)CurrentVmcs,
(UINTN)VmcsSize
);
CopyMem (
(VOID *)(UINTN)mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Vmcs,
(VOID *)(UINTN)CurrentVmcs,
(UINTN)VmcsSize
);
*(UINT32 *)(UINTN)mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Vmcs = (UINT32)AsmReadMsr64 (IA32_VMX_BASIC_MSR_INDEX) & 0xFFFFFFFF;
AsmWbinvd ();
Rflags = AsmVmPtrLoad (&mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Vmcs);
if ((Rflags & (RFLAGS_CF | RFLAGS_ZF)) != 0) {
DEBUG ((EFI_D_ERROR, "%d ERROR: AsmVmPtrLoad - %016lx : %08x\n", (UINTN)Index, mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Vmcs, Rflags));
CpuDeadLoop ();
}
InitializeSmmVmcs (Index, &mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Vmcs);
Rflags = AsmVmClear (&mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Vmcs);
if ((Rflags & (RFLAGS_CF | RFLAGS_ZF)) != 0) {
DEBUG ((EFI_D_ERROR, "%d ERROR: AsmVmClear - %016lx : %08x\n", (UINTN)Index, mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Vmcs, Rflags));
CpuDeadLoop ();
}
AsmWbinvd ();
Rflags = AsmVmPtrLoad (&mGuestContextCommonSmi.GuestContextPerCpu[Index].Vmcs);
if ((Rflags & (RFLAGS_CF | RFLAGS_ZF)) != 0) {
DEBUG ((EFI_D_ERROR, "%d ERROR: AsmVmPtrLoad - %016lx : %08x\n", (UINTN)Index, mGuestContextCommonSmi.GuestContextPerCpu[Index].Vmcs, Rflags));
CpuDeadLoop ();
}
InitializeSmiVmcs (Index, &mGuestContextCommonSmi.GuestContextPerCpu[Index].Vmcs);
}
/**
This function launch back to MLE.
@param Index CPU index
**/
VOID
LaunchBack (
IN UINT32 Index
)
{
UINTN Rflags;
X86_REGISTER *Reg;
Reg = &mGuestContextCommonSmi.GuestContextPerCpu[Index].Register;
#if 0
//
// Dump BIOS resource - already dumped
//
if ((Index == 0) && (ReadUnaligned32 ((UINT32 *)&Reg->Rax) == STM_API_INITIALIZE_PROTECTION)) {
DEBUG ((EFI_D_INFO, "BIOS resource:\n"));
DumpStmResource ((STM_RSC *)(UINTN)mHostContextCommon.HostContextPerCpu[0].TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr);
}
#endif
if (ReadUnaligned32 ((UINT32 *)&Reg->Rax) == STM_API_START) {
// We need do additional thing for STM_API_START
mGuestContextCommonSmm[SMI_HANDLER].GuestContextPerCpu[Index].Actived = TRUE;
SmmSetup (Index);
}
if(!IsResourceListValid ((STM_RSC *)(UINTN)mHostContextCommon.HostContextPerCpu[Index].TxtProcessorSmmDescriptor->BiosHwResourceRequirementsPtr, FALSE)) {
DEBUG ((EFI_D_INFO, "%ld LaunchBack - ValidateBiosResourceList fail!\n", Index));
WriteUnaligned32 ((UINT32 *)&Reg->Rax, ERROR_STM_MALFORMED_RESOURCE_LIST);
VmWriteN (VMCS_N_GUEST_RFLAGS_INDEX, VmReadN(VMCS_N_GUEST_RFLAGS_INDEX) | RFLAGS_CF);
} else {
WriteUnaligned32 ((UINT32 *)&Reg->Rax, STM_SUCCESS);
VmWriteN (VMCS_N_GUEST_RFLAGS_INDEX, VmReadN(VMCS_N_GUEST_RFLAGS_INDEX) & ~RFLAGS_CF);
}
WriteUnaligned32 ((UINT32 *)&Reg->Rbx, 0); // Not support STM_RSC_BGM or STM_RSC_BGI or STM_RSC_MSR
DEBUG ((EFI_D_INFO, "%ld !!!LaunchBack!!!\n", (UINTN)Index));
if(Index != 0)
{
// syncs the AP CPUS - all will wait until the BSP has completed setting up the API
CpuReadySync(Index);
}
else
{
// DumpVmcsAllField();
}
AsmWbinvd(); // flush caches
Rflags = AsmVmLaunch (Reg);
AcquireSpinLock (&mHostContextCommon.DebugLock);
DEBUG ((EFI_D_ERROR, "%ld !!!LaunchBack FAIL!!!\n", Index));
DEBUG ((EFI_D_ERROR, "%ld Rflags: %08x\n", Index, Rflags));
DEBUG ((EFI_D_ERROR, "%ld VMCS_32_RO_VM_INSTRUCTION_ERROR: %08x\n", Index, (UINTN)VmRead32 (VMCS_32_RO_VM_INSTRUCTION_ERROR_INDEX)));
ReleaseSpinLock (&mHostContextCommon.DebugLock);
CpuDeadLoop ();
}
/**
This function initialize STM.
@param Register X86 register context
**/
extern void PrintSmiEnRegister(UINT32 Index); // found in PcPciHandler.c
VOID
InitializeSmmMonitor (
IN X86_REGISTER *Register
)
{
UINT32 Index;
Index = GetIndexFromStack (Register);
if (Index == 0) {
// The build process should make sure "virtual address" is same as "file pointer to raw data",
// in final PE/COFF image, so that we can let StmLoad load binrary to memory directly.
// If no, GenStm tool will "load image". So here, we just need "relocate image"
RelocateStmImage (FALSE);
BspInit (Register);
} else {
Index = GetIndexFromStack (Register);
ApInit (Index, Register);
}
//PrintSmiEnRegister(Index); /* debug*/
CommonInit (Index);
VmcsInit (Index);
//
PrintSmiEnRegister(Index); /* DEBUG*/
AsmWbinvd(); // flush caches
LaunchBack (Index);
return ;
}
static unsigned int CpuSynched;
VOID InitCpuReadySync()
{
CpuReadyCount = 0; // count of CPUs waiting in the loop
CpuSynched = 0; // when 0 - not synched yet; when 1 CPUs are synched, but all have not exited the loop
// need to prevent CPUs from entering the loop until all CPUs have exited
AsmWbinvd (); // force it out
}
VOID CpuReadySync(UINT32 Index)
{
while(InterlockedCompareExchange32(&CpuSynched, 1, 1) == 1 /*CpuSynched == 1*/) {} // prevent processors from entering the synch loop until all the previous processors have left
InterlockedIncrement(&CpuReadyCount);
//DEBUG ((EFI_D_ERROR, "%ld CpuReadySync - CpuReadyCount: %d CpuNum %d\n", Index, CpuReadyCount, mHostContextCommon.CpuNum));
while(InterlockedCompareExchange32(&CpuSynched, 0, 0) == 0)//( CpuReadyCount < mHostContextCommon.CpuNum)
{
// spin until all CPUs are synced
if((InterlockedCompareExchange32(&CpuSynched, 0, 0) == 0 /*CpuSynched == 0*/) &&
InterlockedCompareExchange32(&CpuReadyCount, mHostContextCommon.CpuNum, mHostContextCommon.CpuNum)== mHostContextCommon.CpuNum)
{
InterlockedCompareExchange32(&CpuSynched, 0, 1); //CpuSynched = 1;
//DEBUG((EFI_D_ERROR, "%ld CpuReadySync - CpuSynched set to 1\n", Index));
}
}
if(InterlockedDecrement(&CpuReadyCount) == 0)
{
InterlockedCompareExchange32(&CpuSynched, 1, 0); // CpuSynched = 0;
// DEBUG((EFI_D_ERROR, "%ld CpuReadySync - CpuSynched set to 0\n", Index));
}
// DEBUG((EFI_D_ERROR, "%ld CpuReadySync - Cpu Released - CpuReadyCount: %d, \n", Index, CpuReadyCount));//could cause problems
}