summaryrefslogtreecommitdiff
path: root/ReferenceCode/Haswell/CpuInit/Dxe/MpCommon.c
diff options
context:
space:
mode:
Diffstat (limited to 'ReferenceCode/Haswell/CpuInit/Dxe/MpCommon.c')
-rw-r--r--ReferenceCode/Haswell/CpuInit/Dxe/MpCommon.c1186
1 files changed, 1186 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/CpuInit/Dxe/MpCommon.c b/ReferenceCode/Haswell/CpuInit/Dxe/MpCommon.c
new file mode 100644
index 0000000..dd9a55e
--- /dev/null
+++ b/ReferenceCode/Haswell/CpuInit/Dxe/MpCommon.c
@@ -0,0 +1,1186 @@
+/** @file
+ Code which support multi-processor
+
+@copyright
+ Copyright (c) 1999 - 2012 Intel Corporation. All rights reserved
+ This software and associated documentation (if any) is furnished
+ under a license and may only be used or copied in accordance
+ with the terms of the license. Except as permitted by such
+ license, no part of this software or documentation may be
+ reproduced, stored in a retrieval system, or transmitted in any
+ form or by any means without the express written consent of
+ Intel Corporation.
+
+ This file contains an 'Intel Peripheral Driver' and uniquely
+ identified as "Intel Reference Module" and is
+ licensed for Intel CPUs and chipsets under the terms of your
+ license agreement with Intel or your vendor. This file may
+ be modified by the user, subject to additional terms of the
+ license agreement
+
+**/
+#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000)
+#include "EdkIIGlueDxe.h"
+#include "MpCommon.h"
+#include "CpuInitDxe.h"
+#include "Features.h"
+#include EFI_PROTOCOL_DEFINITION (ExitPmAuth)
+#endif
+
+extern MP_SYSTEM_DATA *mMPSystemData;
+
+extern EFI_PHYSICAL_ADDRESS mOriginalBuffer;
+extern EFI_PHYSICAL_ADDRESS mBackupBuffer;
+extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
+extern DXE_CPU_PLATFORM_POLICY_PROTOCOL *mPlatformCpu;
+volatile UINTN mSwitchToLegacyRegionCount = 0;
+
+EFI_PHYSICAL_ADDRESS mLegacyRegion;
+//(AMI_CHG+)>
+#if (REQUEST_EBDA_SIZE != 0x1000)
+UINTN mEbdaOffset = 0;
+#endif
+//<(AMI_CHG+)
+
+/**
+ Check if X2APIC is enabled
+
+ @retval TRUE if enabled
+ @retval FALSE if not enabled
+**/
+BOOLEAN
+IsXapicEnabled (
+ VOID
+ )
+{
+ UINT64 MsrValue;
+
+ MsrValue = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ if (MsrValue & B_MSR_IA32_APIC_BASE_G_XAPIC) {
+ if (MsrValue & B_MSR_IA32_APIC_BASE_M_XAPIC) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Function to get APIC register from MSR or MMIO
+
+ @param[in] XapicEnabled - x2APIC enabled or not
+ @param[in] MsrIndex - MSR index of APIC register
+ @param[in] MemoryMappedIo - MMIO address for APIC register
+
+ @retval The value of APIC register
+**/
+UINT64
+ReadApicMsrOrMemory (
+ BOOLEAN XapicEnabled,
+ UINT32 MsrIndex,
+ UINT64 MemoryMappedIo
+ )
+{
+ UINT64 Value;
+
+ if (XapicEnabled) {
+ Value = AsmReadMsr64 (MsrIndex);
+ } else {
+ Value = (UINT64) *(volatile UINT32 *) (UINTN) MemoryMappedIo;
+ }
+
+ return Value;
+}
+
+/**
+ Function to write APIC register by MSR or MMIO
+
+ @param[in] XapicEnabled - x2APIC enabled or not
+ @param[in] MsrIndex - MSR index of APIC register
+ @param[in] MemoryMappedIo - MMIO address for APIC register
+ @param[in] Value - Value that will be written to APIC register
+**/
+VOID
+WriteApicMsrOrMemory (
+ BOOLEAN XapicEnabled,
+ UINT32 MsrIndex,
+ UINT64 MemoryMappedIo,
+ UINT64 Value
+ )
+{
+ if (XapicEnabled) {
+ AsmWriteMsr64 (MsrIndex, Value);
+ } else {
+ if (MsrIndex == EXT_XAPIC_ICR) {
+ *(volatile UINT32 *) (UINTN) (MemoryMappedIo - APIC_REGISTER_ICR_LOW_OFFSET + APIC_REGISTER_ICR_HIGH_OFFSET) = (UINT32) (Value >> 32);
+ }
+ *(volatile UINT32 *) (UINTN) MemoryMappedIo = (UINT32) Value;
+ }
+}
+
+/**
+ Send interrupt to CPU
+
+ @param[in] BroadcastMode - Interrupt broadcast mode
+ @param[in] ApicID - APIC ID for sending interrupt
+ @param[in] VectorNumber - Vector number
+ @param[in] DeliveryMode - Interrupt delivery mode
+ @param[in] TriggerMode - Interrupt trigger mode
+ @param[in] Assert - Interrupt pin polarity
+
+ @retval EFI_INVALID_PARAMETER - Input parameter not correct
+ @retval EFI_NOT_READY - There was a pending interrupt
+ @retval EFI_SUCCESS - Interrupt sent successfully
+**/
+EFI_STATUS
+SendInterrupt (
+ IN UINT32 BroadcastMode,
+ IN UINT32 ApicID,
+ IN UINT32 VectorNumber,
+ IN UINT32 DeliveryMode,
+ IN UINT32 TriggerMode,
+ IN BOOLEAN Assert
+ )
+{
+ UINT64 ApicBaseReg;
+ EFI_PHYSICAL_ADDRESS ApicBase;
+ UINT32 ICRLow;
+ UINT32 ICRHigh;
+ BOOLEAN XapicEnabled;
+
+ ///
+ /// Initialze ICR high dword, since P6 family processor needs
+ /// the destination field to be 0x0F when it is a broadcast
+ ///
+ ICRHigh = 0x0f000000;
+ ICRLow = VectorNumber | (DeliveryMode << 8);
+
+ if (TriggerMode == TRIGGER_MODE_LEVEL) {
+ ICRLow |= 0x8000;
+ }
+
+ if (Assert) {
+ ICRLow |= 0x4000;
+ }
+
+ XapicEnabled = IsXapicEnabled ();
+
+ switch (BroadcastMode) {
+ case BROADCAST_MODE_SPECIFY_CPU:
+ if (XapicEnabled) {
+ ICRHigh = (UINT32) ApicID;
+ } else {
+ ICRHigh = ApicID << 24;
+ }
+ break;
+
+ case BROADCAST_MODE_ALL_INCLUDING_SELF:
+ ICRLow |= 0x80000;
+ break;
+
+ case BROADCAST_MODE_ALL_EXCLUDING_SELF:
+ ICRLow |= 0xC0000;
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBase = ApicBaseReg & 0xffffff000;
+
+ ///
+ /// According Nehalem BWG, if Extended XAPIC Mode is enabled,
+ /// legacy xAPIC is no longer working.
+ /// So, previous MMIO offset must be transferred to MSR offset R/W.
+ /// ----------------------------------------------------------------
+ /// MMIO Offset MSR Offset Register Name
+ /// ----------------------------------------------------------------
+ /// 300h-310h 830h Interrupt Command Register [63:0]
+ /// 831h [Reserved]
+ /// ----------------------------------------------------------------
+ ///
+ WriteApicMsrOrMemory (
+ XapicEnabled,
+ EXT_XAPIC_ICR,
+ ApicBase + APIC_REGISTER_ICR_LOW_OFFSET,
+ (((UINT64) ICRHigh << 32) | (UINT64) ICRLow)
+ );
+
+ gBS->Stall (10);
+
+ ICRLow = (UINT32) ReadApicMsrOrMemory (XapicEnabled, EXT_XAPIC_ICR, ApicBase + APIC_REGISTER_ICR_LOW_OFFSET);
+
+ if (ICRLow & BIT12) {
+ return EFI_NOT_READY;
+ }
+
+ gBS->Stall (100);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check number of cores in the package.
+
+ @retval Number of cores in the package.
+**/
+UINT8
+GetCoreNumber (
+ VOID
+ )
+{
+ EFI_CPUID_REGISTER Cpuid;
+ AsmCpuidEx (
+ 4,
+ 0,
+ &Cpuid.RegEax,
+ NULL,
+ NULL,
+ NULL
+ );
+ return (UINT8)(RShiftU64 (Cpuid.RegEax, 26) & 0x3f) + 1;
+}
+
+/**
+ Get APIC ID of processor
+
+ @param[in] ApicBase - APIC base
+ @param[in] ApicVersion - APIC version
+
+ @retval APIC ID of processor
+**/
+UINT32
+GetApicID (
+ OUT EFI_PHYSICAL_ADDRESS *ApicBase OPTIONAL,
+ OUT UINT32 *ApicVersion OPTIONAL
+ )
+{
+ UINT64 ApicBaseReg;
+ UINT32 ApicID;
+ UINT32 LocalApicVersion;
+ UINT64 LocalApicBase;
+ UINTN MsrValue;
+ BOOLEAN XapicEnabled;
+
+ XapicEnabled = IsXapicEnabled ();
+
+ if (XapicEnabled) {
+ ///
+ /// According Nehalem BWG, if Extended XAPIC Mode
+ /// is enabled, legacy xAPIC is no longer working.
+ /// So, previous MMIO offset must be transfered
+ /// to MSR offset R/W.
+ /// MMIO Offset MSR Offset Register Name
+ /// 020h 802h EXT_XAPIC_LOGICAL_APIC_ID
+ /// 030h 803h EXT_XAPIC_VERSION
+ ///
+ MsrValue = (UINTN) AsmReadMsr64 (EXT_XAPIC_VERSION);
+ *ApicVersion = (UINT32) (MsrValue & 0xff);
+ *ApicBase = 0;
+
+ MsrValue = (UINTN) AsmReadMsr64 (EXT_XAPIC_LOGICAL_APIC_ID);
+ ApicID = (UINT32) MsrValue;
+ return ApicID;
+ }
+
+ ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ LocalApicBase = ApicBaseReg & 0xffffff000;
+ if (ApicBase) {
+ *ApicBase = LocalApicBase;
+ }
+
+ ///
+ /// if Apic is not enabled yet, enable it here
+ ///
+ if ((ApicBaseReg & 0x800) == 0) {
+ ApicBaseReg |= 0x800;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseReg);
+ }
+
+ if (ApicVersion) {
+ LocalApicVersion = *(volatile UINT32 *) (UINTN) (LocalApicBase + APIC_REGISTER_APIC_VERSION_OFFSET);
+ *ApicVersion = LocalApicVersion & 0xff;
+ }
+
+ ApicID = *(volatile UINT32 *) (UINTN) (LocalApicBase + APIC_REGISTER_LOCAL_ID_OFFSET);
+ return (ApicID >> 24) & 0x0ff;
+}
+
+/**
+ Programs Local APIC registers.
+
+ @param[in] BSP - Is this BSP?
+**/
+VOID
+ProgramXApic (
+ BOOLEAN BSP
+ )
+{
+ UINT64 ApicBaseReg;
+ EFI_PHYSICAL_ADDRESS ApicBase;
+ UINT64 EntryValue;
+ BOOLEAN XapicEnabled;
+
+ ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBase = ApicBaseReg & 0xffffff000;
+
+ XapicEnabled = IsXapicEnabled ();
+
+ ///
+ /// Program the Spurious Vector entry if XAPIC is enabled
+ ///
+ EntryValue = ReadApicMsrOrMemory (XapicEnabled, EXT_XAPIC_SVR, ApicBase + APIC_REGISTER_SPURIOUS_VECTOR_OFFSET);
+ EntryValue &= 0xFFFFFD0F;
+ EntryValue |= 0x10F;
+ WriteApicMsrOrMemory (XapicEnabled, EXT_XAPIC_SVR, ApicBase + APIC_REGISTER_SPURIOUS_VECTOR_OFFSET, EntryValue);
+
+ ///
+ /// Double check if it is BSP
+ ///
+ if (!BSP) {
+ CpuDisableInterrupt ();
+ }
+
+ ///
+ /// Program the LINT0 vector entry as EntInt
+ ///
+ EntryValue = ReadApicMsrOrMemory (XapicEnabled, EXT_XAPIC_LVT_LINT0, ApicBase + APIC_REGISTER_LINT0_VECTOR_OFFSET);
+ if (BSP) {
+ EntryValue &= 0xFFFE00FF;
+ EntryValue |= 0x700;
+ } else {
+ EntryValue |= 0x10000;
+ ///
+ /// set bit 16 as mask for LINT0
+ ///
+ }
+
+ WriteApicMsrOrMemory (XapicEnabled, EXT_XAPIC_LVT_LINT0, ApicBase + APIC_REGISTER_LINT0_VECTOR_OFFSET, EntryValue);
+
+ ///
+ /// Program the LINT1 vector entry as NMI
+ ///
+ EntryValue = ReadApicMsrOrMemory (XapicEnabled, EXT_XAPIC_LVT_LINT1, ApicBase + APIC_REGISTER_LINT1_VECTOR_OFFSET);
+ EntryValue &= 0xFFFE00FF;
+ if (BSP) {
+ EntryValue |= 0x400;
+ } else {
+ EntryValue |= 0x10400;
+ }
+
+ WriteApicMsrOrMemory (XapicEnabled, EXT_XAPIC_LVT_LINT1, ApicBase + APIC_REGISTER_LINT1_VECTOR_OFFSET, EntryValue);
+
+}
+
+/**
+ Allocate a temporary memory under 1MB for MP Init to perform INIT-SIPI.
+ This buffer also provides memory for stack/data for MP running
+
+ @param[in] WakeUpBuffer - Return buffer location
+
+ @retval EFI_SUCCESS if ok to get a memory under 1MB for MP running.
+**/
+EFI_STATUS
+AllocateWakeUpBuffer (
+ OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ for (*WakeUpBuffer = 0x58000; *WakeUpBuffer >= 0x2000; *WakeUpBuffer -= 0x1000) {
+ Status = (gBS->AllocatePages)(AllocateAddress, EfiReservedMemoryType, 1, WakeUpBuffer);
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Allocate Reserved Memory
+
+ @param[in] Size - Memory Size
+ @param[in] Alignment - Alignment size
+ @param[in] Pointer - return memory location
+
+ @retval EFI_SUCCESS - Allocate a reserved memory successfully
+**/
+EFI_STATUS
+AllocateAlignedReservedMemory (
+ IN UINTN Size,
+ IN UINTN Alignment,
+ OUT VOID **Pointer
+ )
+{
+ EFI_STATUS Status;
+ UINTN PointerValue;
+
+ Status = AllocateReservedMemoryBelow4G (
+ Size + Alignment - 1,
+ Pointer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PointerValue = (UINTN) *Pointer;
+ PointerValue = (PointerValue + Alignment - 1) / Alignment * Alignment;
+
+ *Pointer = (VOID *) PointerValue;
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill in the CPU location information
+
+ @param[in] Location - CPU location information
+
+ @retval EFI_SUCCESS - always return success
+**/
+EFI_STATUS
+FillInCpuLocation (
+ IN CPU_PHYSICAL_LOCATION *Location
+ )
+{
+ UINT32 ApicId;
+ EFI_CPUID_REGISTER RegsInfo;
+ UINT32 LevelType;
+ UINT32 LevelBits;
+ UINT8 Shift;
+ UINT8 Bits;
+ UINT32 Mask;
+ BOOLEAN HyperThreadingEnabled;
+
+ AsmCpuid (CPUID_VERSION_INFO, &RegsInfo.RegEax, &RegsInfo.RegEbx, &RegsInfo.RegEcx, &RegsInfo.RegEdx);
+ ApicId = (RegsInfo.RegEbx >> 24);
+
+ AsmCpuid (CPUID_SIGNATURE, &RegsInfo.RegEax, &RegsInfo.RegEbx, &RegsInfo.RegEcx, &RegsInfo.RegEdx);
+ if (RegsInfo.RegEax >= CPUID_CORE_TOPOLOGY) {
+ LevelBits = 0;
+ LevelType = 0;
+ do {
+ AsmCpuidEx (
+ CPUID_CORE_TOPOLOGY,
+ LevelType,
+ &RegsInfo.RegEax,
+ &RegsInfo.RegEbx,
+ &RegsInfo.RegEcx,
+ &RegsInfo.RegEdx
+ );
+ LevelType = ((RegsInfo.RegEcx >> 8) & 0xFF);
+ switch (LevelType) {
+ case 1:
+ ///
+ /// Thread
+ ///
+ Location->Thread = ApicId & ((1 << (RegsInfo.RegEax & 0x0F)) - 1);
+ LevelBits = RegsInfo.RegEax & 0x0F;
+ break;
+
+ case 2:
+ ///
+ /// Core
+ ///
+ Location->Core = ApicId >> LevelBits;
+ LevelBits = RegsInfo.RegEax & 0x0F;
+ break;
+
+ default:
+ ///
+ /// End of Level
+ ///
+ Location->Die = 0;
+ Location->Package = ApicId >> LevelBits;
+ break;
+ }
+ } while (!(RegsInfo.RegEax == 0 && RegsInfo.RegEbx == 0));
+ } else {
+
+ AsmCpuid (CPUID_VERSION_INFO, &RegsInfo.RegEax, &RegsInfo.RegEbx, &RegsInfo.RegEcx, &RegsInfo.RegEdx);
+ Bits = 0;
+ Shift = (UINT8) ((RegsInfo.RegEbx >> 16) & 0xFF);
+
+ Mask = Shift - 1;
+ while (Shift > 1) {
+ Shift >>= 1;
+ Bits++;
+ }
+
+ HyperThreadingEnabled = FALSE;
+ AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &RegsInfo.RegEax, &RegsInfo.RegEbx, &RegsInfo.RegEcx, &RegsInfo.RegEdx);
+ if (Mask > (RegsInfo.RegEax >> 26)) {
+ HyperThreadingEnabled = TRUE;
+ }
+
+ Location->Package = (ApicId >> Bits);
+ Location->Die = 0;
+ if (HyperThreadingEnabled) {
+ Location->Core = (ApicId & Mask) >> 1;
+ Location->Thread = (ApicId & Mask) & 1;
+ } else {
+ Location->Core = (ApicId & Mask);
+ Location->Thread = 0;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill in CPU relevant information into data hub
+
+ @param[in] CpuNumber - CPU number
+ @param[in] CpuDataforDatahub - pointer to data hub that will be updated
+
+ @retval EFI_SUCCESS - always return success
+**/
+EFI_STATUS
+FillinDataforDataHub (
+ IN UINTN CpuNumber,
+ OUT CPU_DATA_FOR_DATAHUB *CpuDataforDatahub
+ )
+{
+ ZeroMem (CpuDataforDatahub, sizeof (*CpuDataforDatahub));
+
+ ///
+ /// Read Cpu Frequency from MSR instead
+ ///
+ CpuDataforDatahub->IntendCoreFrequency =
+ (
+ 100 *
+ (((UINT32) EfiReadMsr (MSR_IA32_PERF_STS) >> N_IA32_PERF_STSP_STATE_TARGET) & B_IA32_PERF_STSP_STATE_MASK)
+ );
+
+ GetProcessorVersion (&CpuDataforDatahub->Version);
+ CpuDataforDatahub->Manufacturer = GetProcessorManufacturer ();
+
+ EfiCpuid (CPUID_VERSION_INFO, (EFI_CPUID_REGISTER *) &CpuDataforDatahub->CpuidData);
+
+ CpuDataforDatahub->Family = GetProcessorFamily ();
+ CpuDataforDatahub->Voltage = GetProcessorVoltage ();
+ CpuDataforDatahub->ApicID = GetApicID (
+ &CpuDataforDatahub->ApicBase,
+ &CpuDataforDatahub->ApicVersion
+ );
+
+ CpuDataforDatahub->MicrocodeRevision = GetCpuUcodeRevision ();
+ EfiCpuid (CPUID_CACHE_INFO, CpuDataforDatahub->CacheInformation);
+
+ ///
+ /// Status field will be updated later, after calling CpuPlatformPolicy protocol to override
+ ///
+ CpuDataforDatahub->Status = GetProcessorStatus (CpuNumber);;
+
+ FillInCpuLocation (&CpuDataforDatahub->Location);
+
+ ///
+ /// Health field will be filled in else where
+ ///
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocate EfiReservedMemoryType below 4G memory address.
+
+ @param[in] Size - Size of memory to allocate.
+ @param[in] Buffer - Allocated address for output.
+
+ @retval EFI_SUCCESS - Memory successfully allocated.
+ @retval Other - Other errors occur.
+**/
+EFI_STATUS
+AllocateReservedMemoryBelow4G (
+ IN UINTN Size,
+ OUT VOID **Buffer
+ )
+{
+ UINTN Pages;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+
+ Pages = EFI_SIZE_TO_PAGES (Size);
+ Address = 0xffffffff;
+
+ Status = (gBS->AllocatePages)(AllocateMaxAddress, EfiReservedMemoryType, Pages, &Address);
+
+ *Buffer = (VOID *) (UINTN) Address;
+
+ return Status;
+}
+
+/**
+ This function is invoked when SMM_BASE protocol is installed, then we
+ allocate SMRAM and save all information there.
+
+ @param[in] Event - The triggered event.
+ @param[in] Context - Context for this event.
+**/
+VOID
+EFIAPI
+InitializeSmramDataContent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_SMM_BASE_PROTOCOL *SmmBase;
+ SMRAM_CPU_DATA SmramCpuDataTemplate;
+ UINTN LockBoxSize;
+ UINT8 *LockBoxData;
+ PSEUDO_DESCRIPTOR *Idtr;
+ PSEUDO_DESCRIPTOR *Gdtr;
+ UINTN MicrocodeSize;
+ EFI_CPU_MICROCODE_HEADER **Microcode;
+ UINT8 *LockBoxMicrocode;
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_SMM_CONTROL_PROTOCOL *SmmControl;
+ UINT8 *SmramCpuData;
+ UINTN VarSize;
+ SMRAM_CPU_DATA_ADDRESS SmramCpuDataAddr;
+ UINTN ArgBufferSize;
+ UINT8 ArgBuffer;
+ EFI_SMM_CONTROL_REGISTER SmiRegister;
+
+ DEBUG ((EFI_D_INFO, "InitializeSmramDataContent\n"));
+
+ Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &SmmBase);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiSmmControlProtocolGuid, NULL, (VOID **) &SmmControl);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Init
+ ///
+ CopyMem (&SmramCpuDataTemplate.HeaderGuid, &gSmramCpuDataHeaderGuid, sizeof (EFI_GUID));
+ SmramCpuDataTemplate.AcpiCpuPointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiCpuData;
+ CopyMem (&SmramCpuDataTemplate.AcpiCpuData, mAcpiCpuData, sizeof (ACPI_CPU_DATA));
+
+ ///
+ /// Calculate size
+ ///
+ SmramCpuDataTemplate.GdtrProfileSize = sizeof (PSEUDO_DESCRIPTOR);
+ Gdtr = (PSEUDO_DESCRIPTOR *) (UINTN) mAcpiCpuData->GdtrProfile;
+ SmramCpuDataTemplate.GdtSize = Gdtr->Limit + 1;
+ SmramCpuDataTemplate.IdtrProfileSize = sizeof (PSEUDO_DESCRIPTOR);
+ Idtr = (PSEUDO_DESCRIPTOR *) (UINTN) mAcpiCpuData->GdtrProfile;
+ SmramCpuDataTemplate.IdtSize = Idtr->Limit + 1;
+ SmramCpuDataTemplate.CpuPrivateDataSize = sizeof (MP_CPU_S3_DATA_POINTER);
+ SmramCpuDataTemplate.S3BootScriptTableSize = sizeof (mMPSystemData->S3BootScriptTable);
+ SmramCpuDataTemplate.S3BspMtrrTableSize = sizeof (mMPSystemData->S3BspMtrrTable);
+ ///
+ /// Record best match for each CPU Microcode and NULL for end
+ ///
+ SmramCpuDataTemplate.MicrocodePointerBufferSize = sizeof (UINT32) * (mAcpiCpuData->NumberOfCpus + 1);
+ ///
+ /// Calculate Microcode DataSize
+ ///
+ SmramCpuDataTemplate.MicrocodeDataBufferSize = 0;
+ Microcode = (VOID *) (UINTN) mAcpiCpuData->MicrocodePointerBuffer;
+ if (Microcode != NULL) {
+ Index = 0;
+ MicrocodeSize = 0;
+ while (Microcode[Index] != NULL) {
+ if (Microcode[Index]->DataSize == 0) {
+ MicrocodeSize = 2048;
+ } else {
+ MicrocodeSize = Microcode[Index]->TotalSize;
+ }
+
+ SmramCpuDataTemplate.MicrocodeDataBufferSize += (UINT32) MicrocodeSize;
+ Index++;
+ }
+ }
+
+ SmramCpuDataTemplate.GdtrProfileOffset = sizeof (SMRAM_CPU_DATA);
+ SmramCpuDataTemplate.GdtOffset = SmramCpuDataTemplate.GdtrProfileOffset + SmramCpuDataTemplate.GdtrProfileSize;
+ SmramCpuDataTemplate.IdtrProfileOffset = SmramCpuDataTemplate.GdtOffset + SmramCpuDataTemplate.GdtSize;
+ SmramCpuDataTemplate.IdtOffset = SmramCpuDataTemplate.IdtrProfileOffset + SmramCpuDataTemplate.IdtrProfileSize;
+ SmramCpuDataTemplate.CpuPrivateDataOffset = SmramCpuDataTemplate.IdtOffset + SmramCpuDataTemplate.IdtSize;
+ SmramCpuDataTemplate.S3BootScriptTableOffset = SmramCpuDataTemplate.CpuPrivateDataOffset + SmramCpuDataTemplate.CpuPrivateDataSize;
+ SmramCpuDataTemplate.S3BspMtrrTableOffset = SmramCpuDataTemplate.S3BootScriptTableOffset + SmramCpuDataTemplate.S3BootScriptTableSize;
+ SmramCpuDataTemplate.MicrocodePointerBufferOffset = SmramCpuDataTemplate.S3BspMtrrTableOffset + SmramCpuDataTemplate.S3BspMtrrTableSize;
+ SmramCpuDataTemplate.MicrocodeDataBufferOffset = SmramCpuDataTemplate.MicrocodePointerBufferOffset + SmramCpuDataTemplate.MicrocodePointerBufferSize;
+
+ LockBoxSize = sizeof (SMRAM_CPU_DATA) +
+ SmramCpuDataTemplate.GdtrProfileSize +
+ SmramCpuDataTemplate.GdtSize +
+ SmramCpuDataTemplate.IdtrProfileSize +
+ SmramCpuDataTemplate.IdtSize +
+ SmramCpuDataTemplate.CpuPrivateDataSize +
+ SmramCpuDataTemplate.S3BootScriptTableSize +
+ SmramCpuDataTemplate.S3BspMtrrTableSize +
+ SmramCpuDataTemplate.MicrocodePointerBufferSize +
+ SmramCpuDataTemplate.MicrocodeDataBufferSize;
+
+ DEBUG ((EFI_D_INFO, "LockBoxSize - %x\n", LockBoxSize));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.GdtrProfileSize - %x\n", SmramCpuDataTemplate.GdtrProfileSize));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.GdtSize - %x\n", SmramCpuDataTemplate.GdtSize));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.IdtrProfileSize - %x\n", SmramCpuDataTemplate.IdtrProfileSize));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.IdtSize - %x\n", SmramCpuDataTemplate.IdtSize));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.CpuPrivateDataSize - %x\n", SmramCpuDataTemplate.CpuPrivateDataSize));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.S3BootScriptTableSize - %x\n", SmramCpuDataTemplate.S3BootScriptTableSize));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.S3BspMtrrTableSize - %x\n", SmramCpuDataTemplate.S3BspMtrrTableSize));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.MicrocodePointerBufferSize - %x\n", SmramCpuDataTemplate.MicrocodePointerBufferSize));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.MicrocodeDataBufferSize - %x\n", SmramCpuDataTemplate.MicrocodeDataBufferSize));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.GdtrProfileOffset - %x\n", SmramCpuDataTemplate.GdtrProfileOffset));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.GdtOffset - %x\n", SmramCpuDataTemplate.GdtOffset));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.IdtrProfileOffset - %x\n", SmramCpuDataTemplate.IdtrProfileOffset));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.IdtOffset - %x\n", SmramCpuDataTemplate.IdtOffset));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.CpuPrivateDataOffset - %x\n", SmramCpuDataTemplate.CpuPrivateDataOffset));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.S3BootScriptTableOffset - %x\n", SmramCpuDataTemplate.S3BootScriptTableOffset));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.S3BspMtrrTableOffset - %x\n", SmramCpuDataTemplate.S3BspMtrrTableOffset));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.MicrocodePointerBufferOffset - %x\n", SmramCpuDataTemplate.MicrocodePointerBufferOffset));
+ DEBUG ((EFI_D_INFO, "SmramCpuData.MicrocodeDataBufferOffset - %x\n", SmramCpuDataTemplate.MicrocodeDataBufferOffset));
+
+ ///
+ /// Allocate Normal Memory
+ ///
+ Status = (gBS->AllocatePool)(EfiBootServicesData, LockBoxSize, &SmramCpuData);
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Allocate SMRAM
+ ///
+ Status = SmmBase->SmmAllocatePool (
+ SmmBase,
+ EfiRuntimeServicesData,
+ LockBoxSize + EFI_PAGE_SIZE,
+ &LockBoxData
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Let it page aligned
+ ///
+ LockBoxData = (UINT8 *) (((UINTN) LockBoxData + EFI_PAGE_SIZE - 1) &~(EFI_PAGE_SIZE - 1));
+ DEBUG ((EFI_D_INFO, "CPU SMRAM NVS Data - %x\n", LockBoxData));
+
+ ///
+ /// Copy data buffer
+ ///
+ CopyMem (SmramCpuData, &SmramCpuDataTemplate, sizeof (SmramCpuDataTemplate));
+
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.GdtrProfileOffset,
+ (VOID *) (UINTN) mAcpiCpuData->GdtrProfile,
+ SmramCpuDataTemplate.GdtrProfileSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.GdtOffset,
+ (VOID *) (UINTN) Gdtr->Base,
+ SmramCpuDataTemplate.GdtSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.IdtrProfileOffset,
+ (VOID *) (UINTN) mAcpiCpuData->IdtrProfile,
+ SmramCpuDataTemplate.IdtrProfileSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.IdtOffset,
+ (VOID *) (UINTN) Idtr->Base,
+ SmramCpuDataTemplate.IdtSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.CpuPrivateDataOffset,
+ (VOID *) (UINTN) mAcpiCpuData->CpuPrivateData,
+ SmramCpuDataTemplate.CpuPrivateDataSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.S3BootScriptTableOffset,
+ (VOID *) (UINTN) mMPSystemData->S3DataPointer.S3BootScriptTable,
+ SmramCpuDataTemplate.S3BootScriptTableSize
+ );
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.S3BspMtrrTableOffset,
+ (VOID *) (UINTN) mMPSystemData->S3DataPointer.S3BspMtrrTable,
+ SmramCpuDataTemplate.S3BspMtrrTableSize
+ );
+ Microcode = (VOID *) (UINTN) mAcpiCpuData->MicrocodePointerBuffer;
+ if (Microcode != NULL) {
+ ///
+ /// Copy Microcode Pointer Buffer
+ ///
+ CopyMem (
+ SmramCpuData + SmramCpuDataTemplate.MicrocodePointerBufferOffset,
+ Microcode,
+ SmramCpuDataTemplate.MicrocodePointerBufferSize
+ );
+ ///
+ /// Copy Microcode Data
+ ///
+ Index = 0;
+ MicrocodeSize = 0;
+ LockBoxMicrocode = SmramCpuData + SmramCpuDataTemplate.MicrocodeDataBufferOffset;
+ while (Microcode[Index] != NULL) {
+ if (Microcode[Index]->DataSize == 0) {
+ MicrocodeSize = 2048;
+ } else {
+ MicrocodeSize = Microcode[Index]->TotalSize;
+ }
+
+ CopyMem (LockBoxMicrocode, Microcode[Index], MicrocodeSize);
+ LockBoxMicrocode += MicrocodeSize;
+ Index++;
+ }
+ }
+
+ ///
+ /// Copy to SMRAM
+ ///
+ ///
+ /// We have to use SMI to copy SMRAM, because we can not access SMRAM after SMRR enabled.
+ /// SMM_ACCESS.Open () takes no effect.
+ ///
+ VarSize = sizeof (SmramCpuDataAddr);
+ SmramCpuDataAddr.LockBoxData = (UINT64) (UINTN) LockBoxData;
+ SmramCpuDataAddr.SmramCpuData = (UINT64) (UINTN) SmramCpuData;
+ SmramCpuDataAddr.LockBoxSize = (UINT64) LockBoxSize;
+
+ Status = gRT->SetVariable (
+ SMRAM_CPU_DATA_VARIABLE,
+ &gSmramCpuDataVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ VarSize,
+ &SmramCpuDataAddr
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Fill SMI data port
+ ///
+ Status = SmmControl->GetRegisterInfo (SmmControl, &SmiRegister);
+ ASSERT_EFI_ERROR (Status);
+ IoWrite8 (SmiRegister.SmiDataRegister, SMM_FROM_CPU_DRIVER_SAVE_INFO);
+
+ ///
+ /// Trigger SMI
+ ///
+ ArgBufferSize = sizeof (ArgBuffer);
+ ArgBuffer = mSmmbaseSwSmiNumber;
+ Status = SmmControl->Trigger (SmmControl, (INT8 *) &ArgBuffer, &ArgBufferSize, FALSE, 0);
+ Status = SmmControl->Clear (SmmControl, 0);
+ return;
+}
+
+/**
+ This function is invoked when LegacyBios protocol is installed, we must
+ allocate reserved memory under 1M for AP.
+
+ @param[in] Event - The triggered event.
+ @param[in] Context - Context for this event.
+**/
+VOID
+EFIAPI
+ReAllocateEbdaMemoryForAP (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_PHYSICAL_ADDRESS EbdaOld;
+ EFI_PHYSICAL_ADDRESS EbdaNew;
+ UINTN EbdaSize;
+ EFI_STATUS Status;
+
+ ///
+ /// Check whether this is real LegacyBios notification
+ ///
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ ///
+ /// PLEASE NOTE:
+ /// For legacy implementation, we have reserved 0x9F000 to 0x9FFFF for S3 usage in CSM,
+ /// No don't need to allocate it again
+ /// This range will be used for MpS3 driver and S3Resume driver on S3 boot path
+ /// The base needs to be aligned to 4K to satisfy the AP vector requirement
+ /// The original implementation requires 8K from legacy memory form E/F segment,
+ /// which needs lock/unlock and makes lots of code chipset dependent on S3 boot path
+ /// Here we just use normal low memory to eliminate the dependency
+ /// In this case, EBDA will start from 0x9F000 - sizeof (EBDA) in CSM definition
+ /// CSM EBDA base and memory size in BDA area needs to be consistent with this
+ ///
+ ///
+ /// Get EDBA address/length and turn it into the S3 reserved address
+ /// The length of this range is limited so we need to keep the real mode code small
+ ///
+ EbdaOld = (EFI_PHYSICAL_ADDRESS) (*(UINT16 *) (UINTN) 0x40E) << 4;;
+ EbdaSize = (UINTN) (*((UINT8 *) (UINTN) EbdaOld));
+
+//(AMI_CHG+)>
+#if (REQUEST_EBDA_SIZE == 0x1000)
+ mLegacyRegion = EbdaOld + (EbdaSize << 10);
+ mLegacyRegion = (mLegacyRegion - 0x1000) & 0xFFFFF000;
+ EbdaNew = mLegacyRegion - (EbdaSize << 10);
+#else
+ *(UINT8 *) ((UINTN) EbdaOld) = (UINT8)(EbdaSize + 8);
+ mLegacyRegion = EbdaOld + (EbdaSize << 10);
+ mLegacyRegion = (mLegacyRegion - REQUEST_EBDA_SIZE) & 0xFFFFF000;
+ EbdaNew = mLegacyRegion - (EbdaSize << 10);
+ mEbdaOffset = EbdaSize << 10;
+#endif
+//<(AMI_CHG+)
+
+ (*(UINT16 *) (UINTN) 0x40E) = (UINT16) (EbdaNew >> 4);
+ CopyMem ((VOID *) (UINTN) EbdaNew, (VOID *) (UINTN) EbdaOld, EbdaSize << 10);
+
+ ///
+ /// Update 40:13 with the new size of available base memory
+ ///
+ *(UINT16 *) (UINTN) 0x413 = (*(UINT16 *) (UINTN) 0x413) - (UINT16) (((EbdaOld - EbdaNew) >> 10));
+
+ ///
+ /// Free the Wake-up buffer and re-declare it as Reserved Memory
+ ///
+ DEBUG ((EFI_D_INFO, "Legacy region freed before re-allocation: %X\n", mLegacyRegion));
+ Status = (gBS->FreePages) (mLegacyRegion, 1);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "Allocate and reserve the 4K buffer for Legacy Region\n"));
+ Status = (gBS->AllocatePages)(AllocateAddress, EfiReservedMemoryType, 1, &mLegacyRegion);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "mLegacyRegion CSM - %x\n", mLegacyRegion));
+}
+
+/**
+ This function is invoked when LegacyBios protocol is installed, we must
+ allocate reserved memory under 1M for AP.
+
+ @param[in] Event - The triggered event.
+ @param[in] Context - Context for this event.
+**/
+VOID
+EFIAPI
+ReAllocateMemoryForAP (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS LegacyRegion;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ MONITOR_MWAIT_DATA *MonitorAddr;
+ UINTN Index;
+ UINT64 MaxCstate;
+ UINT64 CStateLimit;
+ UINT32 SubStates;
+ EFI_CPUID_REGISTER MwaitInfo;
+ BOOLEAN HasCsm;
+ EFI_MP_SERVICES_PROTOCOL *MpService;
+
+ VOID *ExitPmAuth;
+ STATIC BOOLEAN InitDone = FALSE;
+
+ ///
+ /// Check whether this is real ExitPmAuth notification
+ ///
+ Status = gBS->LocateProtocol (&gExitPmAuthProtocolGuid, NULL, &ExitPmAuth);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ ///
+ /// Make sure it is invoked only once.
+ ///
+ if (InitDone) {
+ return;
+ }
+
+ InitDone = TRUE;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ HasCsm = FALSE;
+ } else {
+ HasCsm = TRUE;
+ }
+
+ while (ApRunning ()) {
+ CpuPause ();
+ }
+ ///
+ /// Re-load microcode patch here!!!
+ ///
+ ReLoadMicrocodeBeforeBoot ();
+
+ if (HasCsm) {
+//(AMI_CHG+)>
+#if (REQUEST_EBDA_SIZE == 0x1000)
+ LegacyRegion = mLegacyRegion;
+#else
+ EFI_PHYSICAL_ADDRESS CurEbda;
+
+ CurEbda = (EFI_PHYSICAL_ADDRESS) (*(UINT16 *) (UINTN) 0x40E) << 4;
+ LegacyRegion = (EFI_PHYSICAL_ADDRESS) ((UINTN)CurEbda + mEbdaOffset);
+ LegacyRegion += 0x1000;
+ LegacyRegion &= 0xffff000;
+#endif
+//<(AMI_CHG+)
+ DEBUG ((EFI_D_INFO, "Using LegacyRegion CSM - %x\n", LegacyRegion));
+ } else {
+ ///
+ /// The BackBuffer is 4k. Allocate 0x2000 bytes from below 640K memory to ensure 4k aligned spaces of 0x1000 bytes,
+ /// since Alignment argument does not work.
+ ///
+ LegacyRegion = 0x9FFFF;
+ Status = (gBS->AllocatePages)(AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (0x2000), &LegacyRegion);
+ ASSERT_EFI_ERROR (Status);
+ DEBUG ((EFI_D_INFO, "LegacyRegion NonCSM - %x\n", LegacyRegion));
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+ }
+ ///
+ /// This address should be less than A seg.
+ /// And it should be aligned to 4K
+ ///
+ ASSERT (!((UINTN) LegacyRegion & 0x0FFF) && ((UINTN) LegacyRegion < 0xA0000));
+
+ mAcpiCpuData->WakeUpBuffer = (EFI_PHYSICAL_ADDRESS) LegacyRegion;
+ mAcpiCpuData->WakeUpBuffer = (mAcpiCpuData->WakeUpBuffer + 0x0fff) & 0x0fffff000;
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mBackupBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ ExchangeInfo->BufferStart = (UINT32) mAcpiCpuData->WakeUpBuffer;
+ CopyMem (
+ (VOID *) (UINTN) mAcpiCpuData->WakeUpBuffer,
+ (VOID *) (UINTN) mBackupBuffer,
+ EFI_PAGE_SIZE
+ );
+ RedirectFarJump ();
+
+ if (HasCsm) {
+ Status = LegacyBios->CopyLegacyRegion (
+ LegacyBios,
+ sizeof (MP_CPU_EXCHANGE_INFO),
+ (VOID *) (UINTN) (mAcpiCpuData->WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET),
+ (VOID *) (UINTN) (mBackupBuffer + MP_CPU_EXCHANGE_INFO_OFFSET)
+ );
+ }
+
+ ///
+ /// Set all APs to deepest C-State before ready to boot for better power saving,
+ /// if boot to DOS/EFI_SHARE or any operating system that running only single thread.
+ ///
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mAcpiCpuData->WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ if (mPlatformCpu->CpuConfig->ApHandoffManner != WakeUpApPerHltLoop) {
+ ///
+ /// Based on HSW BWG 17.2.7, BIOS should use CPUID.(EAX=5) Monitor/Mwait Leaf and also check MSR E2h[3:0] Package C-state limit to determine
+ /// if the processor supports MONITOR/MWAIT extensions for various Haswell specific C-states and sub C-states.
+ ///
+ CStateLimit = AsmReadMsr64 (MSR_PMG_CST_CONFIG) & B_PACKAGE_C_STATE_LIMIT;
+ AsmCpuid (5, &MwaitInfo.RegEax, &MwaitInfo.RegEbx, &MwaitInfo.RegEcx, &MwaitInfo.RegEdx);
+ MaxCstate = 0;
+ SubStates = 0;
+ if (MwaitInfo.RegEcx & BIT0) {
+ switch (CStateLimit) {
+ case V_CSTATE_LIMIT_C10:
+ SubStates = (MwaitInfo.RegEdx & (BIT31 | BIT30 | BIT29 | BIT28)) >> 28;
+ MaxCstate = 0x60 | (SubStates - 1);
+ break;
+
+ case V_CSTATE_LIMIT_C9:
+ SubStates = (MwaitInfo.RegEdx & (BIT27 | BIT26 | BIT25 | BIT24)) >> 24;
+ MaxCstate = 0x50 | (SubStates - 1);
+ break;
+
+ case V_CSTATE_LIMIT_C8:
+ SubStates = (MwaitInfo.RegEdx & (BIT23 | BIT22 | BIT21 | BIT20)) >> 20;
+ MaxCstate = 0x40 | (SubStates - 1);
+ break;
+
+ case V_CSTATE_LIMIT_C7S:
+ SubStates = (MwaitInfo.RegEdx & (BIT19 | BIT18 | BIT17 | BIT16)) >> 16;
+ MaxCstate = 0x30 | (SubStates - 1);
+ break;
+
+ case V_CSTATE_LIMIT_C7:
+ SubStates = (MwaitInfo.RegEdx & (BIT19 | BIT18 | BIT17 | BIT16)) >> 16;
+ MaxCstate = 0x30 | (SubStates - 1);
+ break;
+
+ case V_CSTATE_LIMIT_C6:
+ SubStates = (MwaitInfo.RegEdx & (BIT15 | BIT14 | BIT13 | BIT12)) >> 12;
+ MaxCstate = 0x20 | (SubStates - 1);
+ break;
+
+ case V_CSTATE_LIMIT_C3:
+ SubStates = (MwaitInfo.RegEdx & (BIT11 | BIT10 | BIT9 | BIT8)) >> 8;
+ MaxCstate = 0x10 | (SubStates - 1);
+ break;
+
+ case V_CSTATE_LIMIT_C1:
+ SubStates = (MwaitInfo.RegEdx & (BIT7 | BIT6 | BIT5 | BIT4)) >> 4;
+ MaxCstate = 0x00 | (SubStates - 1);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ ///
+ /// Use WakeUpApPerMwaitLoop32 if CR4 paging table entities are not allocated as RESERVED MEMORY TYPE in 64-bits mode.
+ ///
+ ExchangeInfo->WakeUpApManner = WakeUpApPerMwaitLoop32;
+ for (Index = 0; Index < mMPSystemData->NumberOfCpus; Index++) {
+ MonitorAddr = (MONITOR_MWAIT_DATA *) ((UINT8 *) ExchangeInfo->StackStart + (Index + 1) * ExchangeInfo->StackSize - MONITOR_FILTER_SIZE);
+ MonitorAddr->WakeUpApVectorChangeFlag = TRUE;
+ MonitorAddr->MwaitTargetCstate = MaxCstate;
+ }
+ } else {
+ ExchangeInfo->WakeUpApManner = WakeUpApPerHltLoop;
+ }
+
+ ///
+ /// Locate MpServices protocol
+ ///
+ Status = gBS->LocateProtocol (
+ &gEfiMpServiceProtocolGuid,
+ NULL,
+ (VOID **) &MpService
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ///
+ /// Move Limit CPUID Maxval configuration here to not impact the BOOT
+ /// After setting this, no code can execute CPUID function > 3.
+ ///
+ ProgramCpuidLimit (MpService);
+ Status = MpService->StartupAllAPs (
+ MpService,
+ ProgramCpuidLimit,
+ FALSE,
+ NULL,
+ 0,
+ MpService,
+ NULL
+ );
+
+ ///
+ /// Invoke the InitializeSmram directly, since it is in ExitPmAuth event.
+ ///
+ InitializeSmramDataContent (NULL, NULL);
+}
+
+/**
+ This function is invoked by EFI_EVENT_SIGNAL_LEGACY_BOOT.
+ Before booting to legacy OS, reset AP's wakeup buffer address,
+ preparing for S3 usage.
+
+ @param[in] Event - The triggered event.
+ @param[in] Context - Context for this event.
+**/
+VOID
+ResetAPs (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ return;
+}