diff options
Diffstat (limited to 'ReferenceCode/Haswell/CpuS3/Pei/CpuS3Peim.c')
-rw-r--r-- | ReferenceCode/Haswell/CpuS3/Pei/CpuS3Peim.c | 1035 |
1 files changed, 1035 insertions, 0 deletions
diff --git a/ReferenceCode/Haswell/CpuS3/Pei/CpuS3Peim.c b/ReferenceCode/Haswell/CpuS3/Pei/CpuS3Peim.c new file mode 100644 index 0000000..ddf8ba1 --- /dev/null +++ b/ReferenceCode/Haswell/CpuS3/Pei/CpuS3Peim.c @@ -0,0 +1,1035 @@ +/** @file + Cpu driver running on S3 boot path + +@copyright + Copyright (c) 2005 - 2013 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 a 'Sample Driver' and is licensed as such + under the terms of your license agreement with Intel or your + vendor. This file may be modified by the user, subject to + the additional terms of the license agreement + +**/ + +/// +/// External include files do NOT need to be explicitly specified in real EDKII +/// environment +/// +#if !defined(EDK_RELEASE_VERSION) || (EDK_RELEASE_VERSION < 0x00020000) +#include "EdkIIGluePeim.h" +#include "MpCommon.h" +#include "BootGuardLibrary.h" +#include EFI_PPI_DEFINITION (SmmAccess) +#include EFI_PPI_DEPENDENCY (Stall) +#include EFI_PPI_DEFINITION (CpuPlatformPolicy) + +#include EFI_GUID_DEFINITION (HOB) +#include EFI_GUID_DEFINITION (StatusCodeDataTypeId) +#include EFI_GUID_DEFINITION (SmramCpuDataHeader) +#endif + +#define PEI_ACPI_CPU_DATA_HOB_GUID \ + { 0x7682bbef, 0xb0b6, 0x4939, 0xae, 0x66, 0x1b, 0x3d, 0xf2, 0xf6, 0xaa, 0xf3}; + +EFI_GUID gPeiAcpiCpuDataGuid = PEI_ACPI_CPU_DATA_HOB_GUID; +typedef VOID (*S3_AP_PROCEDURE)( + MP_CPU_EXCHANGE_INFO *ExchangeInfo, + UINT64 *MtrrValues + ); + +/** + This function handles SA S3 resume task + + @param[in] PeiServices - Pointer to PEI Services Table. + @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi - Pointer to the PPI data associated with this function. + + @retval EFI_STATUS - Always return EFI_SUCCESS +**/ +static +EFI_STATUS +CpuS3ResumeAtEndOfPei ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi + ); + +EFI_GUID gEfiPeiEndOfPeiPhasePpiGuid = EFI_PEI_END_OF_PEI_PHASE_PPI_GUID; +STATIC EFI_PEI_NOTIFY_DESCRIPTOR mCpuS3ResumeNotifyDesc = { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), + &gEfiPeiEndOfPeiPhasePpiGuid, + CpuS3ResumeAtEndOfPei +}; + +/** + Get APIC ID of processor + + @retval APIC ID of processor +**/ +UINT32 +GetApicID ( + VOID + ) +{ + EFI_CPUID_REGISTER CpuidRegisters; + + AsmCpuid ( + CPUID_VERSION_INFO, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + return (UINT32) (CpuidRegisters.RegEbx >> 24); +} + +/** + 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 + @param[in] PeiServices - Indirect reference to the PEI Services Table + @param[in] PeiStall - EFI_PEI_STALL_PPI to stall for some interval + + @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, + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_STALL_PPI *PeiStall + ) +{ + UINT64 ApicBaseReg; + EFI_PHYSICAL_ADDRESS ApicBase; + UINT32 ICRLow; + UINT32 ICRHigh; + + /// + /// 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; + } + + switch (BroadcastMode) { + case BROADCAST_MODE_SPECIFY_CPU: + 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 & 0xffffff000ULL; + + *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_HIGH_OFFSET) = ICRHigh; + *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET) = ICRLow; + + PeiStall->Stall ( + PeiServices, + PeiStall, + 10 * STALL_ONE_MICRO_SECOND + ); + + ICRLow = *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET); + if (ICRLow & 0x1000) { + return EFI_NOT_READY; + } + + return EFI_SUCCESS; +} + +/** + Programs XAPIC registers. + + @param[in] BSP - Is this BSP? +**/ +VOID +ProgramXApic ( + BOOLEAN BSP + ) +{ + UINT64 ApicBaseReg; + EFI_PHYSICAL_ADDRESS ApicBase; + volatile UINT32 *EntryAddress; + UINT32 EntryValue; + + ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE); + ApicBase = ApicBaseReg & 0xffffff000ULL; + + /// + /// Program the Spurious Vectore entry + /// + EntryAddress = (UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_SPURIOUS_VECTOR_OFFSET); + EntryValue = *EntryAddress; + EntryValue &= 0xFFFFFD0F; + EntryValue |= 0x10F; + *EntryAddress = EntryValue; + + /// + /// Program the LINT1 vector entry as extINT + /// + EntryAddress = (UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_LINT0_VECTOR_OFFSET); + EntryValue = *EntryAddress; + + if (BSP) { + EntryValue &= 0xFFFE00FF; + EntryValue |= 0x700; + } else { + EntryValue |= 0x10000; + } + + *EntryAddress = EntryValue; + + /// + /// Program the LINT1 vector entry as NMI + /// + EntryAddress = (UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_LINT1_VECTOR_OFFSET); + EntryValue = *EntryAddress; + EntryValue &= 0xFFFE00FF; + if (BSP) { + EntryValue |= 0x400; + } else { + EntryValue |= 0x10400; + } + + *EntryAddress = EntryValue; + +} + +/** + Restore all MSR settings + + @param[in] ScriptTable - contain the MSR settings that will be restored +**/ +VOID +InitializeFeatures ( + IN MP_CPU_S3_SCRIPT_DATA *ScriptTable + ) +{ + EFI_CPUID_REGISTER CpuidRegisters; + UINT32 ApicId; + UINT8 SkipMsr; + /// + /// Restore all the MSRs for processor + /// + AsmCpuid ( + CPUID_VERSION_INFO, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + ApicId = (CpuidRegisters.RegEbx >> 24); + + while (ScriptTable->MsrIndex != 0) { + if (ApicId == ScriptTable->ApicId) { + SkipMsr = 0; + if ((ScriptTable->MsrIndex == MSR_PMG_CST_CONFIG) && (AsmReadMsr64 (MSR_PMG_CST_CONFIG) & B_CST_CONTROL_LOCK)) { + SkipMsr = 1; + } + if (SkipMsr == 0) { + AsmWriteMsr64 (ScriptTable->MsrIndex, ScriptTable->MsrValue); + } + } + ScriptTable++; + } +} + +/** + Restore all MSR settings with debug message output + + @param[in] PeiServices - General purpose services available to every PEIM. + @param[in] ScriptTable - Script table contain all MSR settings that will be restored +**/ +VOID +InitializeFeaturesLog ( + IN EFI_PEI_SERVICES **PeiServices, + IN MP_CPU_S3_SCRIPT_DATA *ScriptTable + ) +{ + EFI_CPUID_REGISTER CpuidRegisters; + UINT32 ApicId; + BOOLEAN SkipMsr; + + /// + /// Restore all the MSRs for processor + /// + AsmCpuid ( + CPUID_VERSION_INFO, + &CpuidRegisters.RegEax, + &CpuidRegisters.RegEbx, + &CpuidRegisters.RegEcx, + &CpuidRegisters.RegEdx + ); + ApicId = (CpuidRegisters.RegEbx >> 24); + + while (ScriptTable->MsrIndex != 0) { + if (ApicId == ScriptTable->ApicId) { + DEBUG ((EFI_D_INFO, "MSR Index - %x, MSR value - %x\n", ScriptTable->MsrIndex, ScriptTable->MsrValue)); + SkipMsr = FALSE; + if ((ScriptTable->MsrIndex == MSR_PMG_CST_CONFIG) && (AsmReadMsr64 (MSR_PMG_CST_CONFIG) & B_CST_CONTROL_LOCK)) { + SkipMsr = TRUE; + } + if (ScriptTable->MsrIndex == MSR_IA32_DEBUG_INTERFACE) { + /* Access to MSR_IA32_DEBUG_INTERFACE is supported on + HSW B0, HSWULT B0 and CRW B0 Stepping + HSW stepping >= C0, HSWULT Stepping >= C0 and CRW stepping >= C0 stepping, if CPUID (EAX=1): ECX[11] = 1 + */ + switch (CpuidRegisters.RegEax) { + case (EnumCpuHsw + EnumHswA0): + DEBUG ((EFI_D_INFO,"MSR_IA32_DEBUG_INTERFACE is not supported on Ax CPU stepping\n")); + break; + case (EnumCpuHsw + EnumHswB0): + case (EnumCpuHswUlt + EnumHswUltB0): + case (EnumCpuCrw + EnumCrwB0): + if ((AsmReadMsr64 (MSR_IA32_DEBUG_INTERFACE) & B_DEBUG_INTERFACE_LOCK)) { + SkipMsr = TRUE; + } + break; + default: + if (CpuidRegisters.RegEcx & BIT11) { + if ((AsmReadMsr64 (MSR_IA32_DEBUG_INTERFACE) & B_DEBUG_INTERFACE_LOCK)) { + SkipMsr = TRUE; + } + } + break; + } + } + if (!SkipMsr) { + AsmWriteMsr64 (ScriptTable->MsrIndex, ScriptTable->MsrValue); + } + } + ScriptTable++; + } +} + +/** + Initialize prefetcher settings + + @param[in] MlcStreamerprefecterEnabled - Enable/Disable MLC streamer prefetcher + @param[in] MlcSpatialPrefetcherEnabled - Enable/Disable MLC spatial prefetcher +**/ +VOID +ProcessorsPrefetcherInitialization ( + IN UINTN MlcStreamerprefecterEnabled, + IN UINTN MlcSpatialPrefetcherEnabled + ) +{ + UINT64 MsrValue; + MsrValue = AsmReadMsr64 (MISC_FEATURE_CONTROL); + + if (MlcStreamerprefecterEnabled == CPU_FEATURE_DISABLE) { + MsrValue |= B_MISC_FEATURE_CONTROL_MLC_STRP; + } + + if (MlcSpatialPrefetcherEnabled == CPU_FEATURE_DISABLE) { + MsrValue |= B_MISC_FEATURE_CONTROL_MLC_SPAP; + } + + if ((MsrValue & (B_MISC_FEATURE_CONTROL_MLC_STRP | B_MISC_FEATURE_CONTROL_MLC_SPAP)) != 0) { + AsmWriteMsr64 (MISC_FEATURE_CONTROL, MsrValue); + } + + return; +} + +/** + AP initialization + + @param[in] ExchangeInfo - Pointer to the exchange info buffer for output. + @param[in] MtrrValues - buffer contains MTRR settings +**/ +VOID +MPRendezvousProcedure ( + MP_CPU_EXCHANGE_INFO *ExchangeInfo, + UINT64 *MtrrValues + ) +{ + UINT32 FailedRevision; + ACPI_CPU_DATA *AcpiCpuData; + EFI_PEI_SERVICES **PeiServices; + EFI_PEI_STALL_PPI *PeiStall; + MP_CPU_S3_DATA_POINTER *CpuS3DataPtr; + + /// + /// Switch AP speed to BSP speed + /// + AsmWriteMsr64 (MSR_IA32_PERF_CTRL, ExchangeInfo->CpuPerfCtrlValue); + + AcpiCpuData = (ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress); + PeiServices = ExchangeInfo->PeiServices; + PeiStall = ExchangeInfo->PeiStall; + + ProgramXApic (FALSE); + + InitializeMicrocode ( + ExchangeInfo, + (EFI_CPU_MICROCODE_HEADER **) (UINTN) ExchangeInfo->MicrocodePointer, + &FailedRevision + ); + + ProcessorsPrefetcherInitialization ( + ExchangeInfo->CpuPlatformPolicyPpi->CpuConfig->MlcStreamerPrefetcher, + ExchangeInfo->CpuPlatformPolicyPpi->CpuConfig->MlcSpatialPrefetcher + ); + + /// + /// wait till all CPUs done the Microcode Load + /// + while (ExchangeInfo->McuLoadCount < AcpiCpuData->NumberOfCpus) { + CpuPause (); + } + + MpMtrrSynchUp (MtrrValues); + + InitializeFeatures (ExchangeInfo->S3BootScriptTable); + + InterlockedIncrement (&(ExchangeInfo->FinishedCount)); + + /// + /// Sempahore check loop executed in memory + /// + (*ExchangeInfo->SemaphoreCheck)(&ExchangeInfo->FinishedCount); + + InterlockedIncrement (&(ExchangeInfo->WakeupCount)); + + /// + /// Restore the MTRR programmed before OS boot + /// + /// MpMtrrSynchUp (MtrrValues); + /// + CpuS3DataPtr = (MP_CPU_S3_DATA_POINTER *) (UINTN) AcpiCpuData->CpuPrivateData; + SetMtrrRegisters (PeiServices, (EFI_MTRR_VALUES *) CpuS3DataPtr->S3BspMtrrTable); + + while (ExchangeInfo->WakeupCount < AcpiCpuData->NumberOfCpus - 1) { + CpuPause (); + } + + InterlockedIncrement (&(ExchangeInfo->FinishedCount)); + +} + +/** + Wake up all the application processors + + @param[in] PeiServices - Indirect reference to the PEI Services Table + @param[in] PeiStall - EFI_PEI_STALL_PPI to stall for some interval + @param[in] AcpiCpuData - pointer to ACPI_CPU_DATA structure + @param[in] MtrrValues - pointer to a buffer which stored MTRR settings + + @retval EFI_SUCCESS - APs are successfully waked up +**/ +EFI_STATUS +WakeUpAPs ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_STALL_PPI *PeiStall, + ACPI_CPU_DATA *AcpiCpuData, + UINT64 *MtrrValues, + S3_AP_PROCEDURE Function + ) +{ + EFI_PHYSICAL_ADDRESS WakeUpBuffer; + MP_CPU_EXCHANGE_INFO *ExchangeInfo; + MP_CPU_S3_DATA_POINTER *CpuS3DataPtr; + UINTN CpuPpiAddrDelta; + PEI_CPU_PLATFORM_POLICY_PPI *CpuPolicyPpi; + + WakeUpBuffer = AcpiCpuData->WakeUpBuffer; + CopyMem ((VOID *) (UINTN) WakeUpBuffer, AsmGetAddressMap (), 0x1000 - 0x200); + + ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + (0x1000 - 0x200)); + + ExchangeInfo->Lock = 0; + ExchangeInfo->StackStart = (UINTN) AcpiCpuData->StackAddress; + ExchangeInfo->StackSize = STACK_SIZE_PER_PROC; + ExchangeInfo->ApFunction = (UINT32) Function; + ExchangeInfo->BufferStart = (UINT32) WakeUpBuffer; + ExchangeInfo->PmodeOffset = (UINT32) (AsmGetPmodeOffset ()); + ExchangeInfo->SemaphoreCheck = (VOID (*)(UINT32 *))(AsmGetSemaphoreCheckOffset () + (UINT32) WakeUpBuffer); + ExchangeInfo->AcpiCpuDataAddress = (UINT32) AcpiCpuData; + ExchangeInfo->MtrrValuesAddress = (UINT32) MtrrValues; + ExchangeInfo->FinishedCount = (UINT32) 0; + ExchangeInfo->SerializeLock = (UINT32) 0; + ExchangeInfo->MicrocodePointer = (UINT32) (UINTN) AcpiCpuData->MicrocodePointerBuffer; + ExchangeInfo->StartState = (UINT32) 0; + + CpuS3DataPtr = (MP_CPU_S3_DATA_POINTER *) (UINTN) AcpiCpuData->CpuPrivateData; + ExchangeInfo->S3BootScriptTable = (MP_CPU_S3_SCRIPT_DATA *) (UINTN) CpuS3DataPtr->S3BootScriptTable; + ExchangeInfo->VirtualWireMode = CpuS3DataPtr->VirtualWireMode; + ExchangeInfo->PeiServices = PeiServices; + ExchangeInfo->PeiStall = PeiStall; + ExchangeInfo->CpuPerfCtrlValue = AsmReadMsr64 (MSR_IA32_PERF_CTRL); + + ExchangeInfo->CpuPlatformPolicyPpi = NULL; + PeiServicesLocatePpi ( + &gPeiCpuPlatformPolicyPpiGuid, + 0, + NULL, + (VOID **) &(ExchangeInfo->CpuPlatformPolicyPpi) + ); + + // + // Calculate delta from cache address to memory address + // + CpuPolicyPpi = ExchangeInfo->CpuPlatformPolicyPpi; + CpuPpiAddrDelta = CpuPolicyPpi->CpuPlatformPpiPtr - (UINTN)(CpuPolicyPpi); + // + // Calculate new address in memory for each pointer in PEI_CPU_PLATFORM_POLICY_PPI + // + CpuPolicyPpi->CpuConfig = (CPU_CONFIG_PPI *)((UINTN)CpuPolicyPpi->CpuConfig - CpuPpiAddrDelta); + CpuPolicyPpi->PowerMgmtConfig = (POWER_MGMT_CONFIG_PPI *)((UINTN)CpuPolicyPpi->PowerMgmtConfig - CpuPpiAddrDelta); + CpuPolicyPpi->SecurityConfig = (SECURITY_CONFIG_PPI *)((UINTN)CpuPolicyPpi->SecurityConfig - CpuPpiAddrDelta); + CpuPolicyPpi->SecurityConfig->PfatConfig = (PFAT_CONFIG *)((UINTN)CpuPolicyPpi->SecurityConfig->PfatConfig - CpuPpiAddrDelta); + CpuPolicyPpi->SecurityConfig->TxtConfig = (TXT_CONFIG *)((UINTN)CpuPolicyPpi->SecurityConfig->TxtConfig - CpuPpiAddrDelta); + CpuPolicyPpi->SecurityConfig->BootGuardConfig = (BOOT_GUARD_CONFIG *)((UINTN)CpuPolicyPpi->SecurityConfig->BootGuardConfig - CpuPpiAddrDelta); + CpuPolicyPpi->OverclockingConfig = (OVERCLOCKING_CONFIG_PPI *)((UINTN)CpuPolicyPpi->OverclockingConfig - CpuPpiAddrDelta); + + CopyMem ( + (VOID *) (UINTN) &ExchangeInfo->GdtrProfile, + (VOID *) (UINTN) AcpiCpuData->GdtrProfile, + sizeof (PSEUDO_DESCRIPTOR) + ); + CopyMem ( + (VOID *) (UINTN) &ExchangeInfo->IdtrProfile, + (VOID *) (UINTN) AcpiCpuData->IdtrProfile, + sizeof (PSEUDO_DESCRIPTOR) + ); + + DEBUG ((EFI_D_INFO, "Cpu S3 Bootscript at %08X\n", (UINT32) ExchangeInfo->S3BootScriptTable)); + +#ifdef BOOT_GUARD_SUPPORT_FLAG +#if BOOT_GUARD_SUPPORT_FLAG == 1 + // + // Disable PBET before send IPI to APs + // + StopPbeTimer (); +#endif +#endif + + /// + /// Don't touch MPCPU private data + /// Here we use ExchangeInfo instead + /// + /// + /// Send INIT IPI - SIPI to all APs + /// + SendInterrupt ( + BROADCAST_MODE_ALL_EXCLUDING_SELF, + 0, + 0, + DELIVERY_MODE_INIT, + TRIGGER_MODE_EDGE, + TRUE, + PeiServices, + PeiStall + ); + + PeiStall->Stall ( + PeiServices, + PeiStall, + 10 * STALL_ONE_MILLI_SECOND ///< 10ms + ); + + SendInterrupt ( + BROADCAST_MODE_ALL_EXCLUDING_SELF, + 0, + (UINT32) RShiftU64 (WakeUpBuffer, + 12), + DELIVERY_MODE_SIPI, + TRIGGER_MODE_EDGE, + TRUE, + PeiServices, + PeiStall + ); + + PeiStall->Stall ( + PeiServices, + PeiStall, + 200 * STALL_ONE_MICRO_SECOND ///< 200us + ); + + SendInterrupt ( + BROADCAST_MODE_ALL_EXCLUDING_SELF, + 0, + (UINT32) RShiftU64 (WakeUpBuffer, + 12), + DELIVERY_MODE_SIPI, + TRIGGER_MODE_EDGE, + TRUE, + PeiServices, + PeiStall + ); + + PeiStall->Stall ( + PeiServices, + PeiStall, + 200 * STALL_ONE_MICRO_SECOND ///< 200us + ); + + return EFI_SUCCESS; +} + +/** + This routine is used to search SMRAM and get SmramCpuData point. + + @param[in] PeiServices - PEI services global pointer + @param[in] SmmAccessPpi - SmmAccess PPI instance + + @retval SmramCpuData - The pointer of CPU information in SMRAM. +**/ +STATIC +SMRAM_CPU_DATA * +GetSmmCpuData ( + IN EFI_PEI_SERVICES **PeiServices, + IN PEI_SMM_ACCESS_PPI *SmmAccessPpi + ) +{ + EFI_SMRAM_DESCRIPTOR *SmramRanges; + UINTN SmramRangeCount; + UINTN Size; + EFI_STATUS Status; + UINT32 Address; + SMRAM_CPU_DATA *SmramCpuData; + + /// + /// Get all SMRAM range + /// + Size = 0; + Status = SmmAccessPpi->GetCapabilities (PeiServices, SmmAccessPpi, &Size, NULL); + ASSERT (Status == EFI_BUFFER_TOO_SMALL); + + Status = PeiServicesAllocatePool ( + Size, + (VOID **) &SmramRanges + ); + ASSERT_EFI_ERROR (Status); + + Status = SmmAccessPpi->GetCapabilities (PeiServices, SmmAccessPpi, &Size, SmramRanges); + ASSERT_EFI_ERROR (Status); + + Size /= sizeof (*SmramRanges); + SmramRangeCount = Size; + + /// + /// BUGBUG: We assume TSEG is the last range of SMRAM in SmramRanges + /// + SmramRanges += SmramRangeCount - 1; + + DEBUG ((EFI_D_INFO, "TsegBase - %x\n", SmramRanges->CpuStart)); + DEBUG ((EFI_D_INFO, "TsegTop - %x\n", SmramRanges->CpuStart + SmramRanges->PhysicalSize)); + + /// + /// Search SMRAM on page alignment for the SMMNVS signature + /// + for (Address = (UINT32) (SmramRanges->CpuStart + SmramRanges->PhysicalSize - EFI_PAGE_SIZE); + Address >= (UINT32) SmramRanges->CpuStart; + Address -= EFI_PAGE_SIZE + ) { + SmramCpuData = (SMRAM_CPU_DATA *) (UINTN) Address; + if (CompareGuid (&SmramCpuData->HeaderGuid, &gSmramCpuDataHeaderGuid) + && SmramCpuData->AcpiCpuData.NumberOfCpus == (UINT32)(AsmReadMsr64(0x35) & 0xffff)) { //(AMI_CHG) + /// + /// Find it + /// + return SmramCpuData; + } + } + + ASSERT (FALSE); + + return NULL; +} + +/** + This routine is restore the CPU information from SMRAM to original reserved memory region. + + @param[in] PeiServices - PEI services global pointer + + @retval AcpiCpuData - The pointer of CPU information in reserved memory. +**/ +ACPI_CPU_DATA * +RestoreSmramCpuData ( + IN EFI_PEI_SERVICES **PeiServices + ) +{ + PEI_SMM_ACCESS_PPI *SmmAccessPpi; + SMRAM_CPU_DATA *SmramCpuData; + EFI_STATUS Status; + ACPI_CPU_DATA *AcpiCpuData; + MP_CPU_S3_DATA_POINTER *CpuS3DataPtr; + PSEUDO_DESCRIPTOR *Idtr; + PSEUDO_DESCRIPTOR *Gdtr; + UINTN MicrocodeSize; + EFI_CPU_MICROCODE_HEADER **Microcode; + EFI_CPU_MICROCODE_HEADER *LockBoxMicrocode; + UINTN Index; + + Status = PeiServicesLocatePpi ( + &gPeiSmmAccessPpiGuid, + 0, + NULL, + (VOID **) &SmmAccessPpi + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Open all SMM regions + /// + Index = 0; + do { + Status = SmmAccessPpi->Open (PeiServices, SmmAccessPpi, Index); + Index++; + } while (!EFI_ERROR (Status)); + + SmramCpuData = GetSmmCpuData (PeiServices, SmmAccessPpi); + DEBUG ((EFI_D_INFO, "CpuS3 SmramCpuData - 0x%x \n", SmramCpuData)); + DEBUG ((EFI_D_INFO, "SmramCpuData->GdtrProfileSize - %x\n", SmramCpuData->GdtrProfileSize)); + DEBUG ((EFI_D_INFO, "SmramCpuData->GdtSize - %x\n", SmramCpuData->GdtSize)); + DEBUG ((EFI_D_INFO, "SmramCpuData->IdtrProfileSize - %x\n", SmramCpuData->IdtrProfileSize)); + DEBUG ((EFI_D_INFO, "SmramCpuData->IdtSize - %x\n", SmramCpuData->IdtSize)); + DEBUG ((EFI_D_INFO, "SmramCpuData->CpuPrivateDataSize - %x\n", SmramCpuData->CpuPrivateDataSize)); + DEBUG ((EFI_D_INFO, "SmramCpuData->S3BootScriptTableSize - %x\n", SmramCpuData->S3BootScriptTableSize)); + DEBUG ((EFI_D_INFO, "SmramCpuData->S3BspMtrrTableSize - %x\n", SmramCpuData->S3BspMtrrTableSize)); + DEBUG ((EFI_D_INFO, "SmramCpuData->MicrocodePointerBufferSize - %x\n", SmramCpuData->MicrocodePointerBufferSize)); + DEBUG ((EFI_D_INFO, "SmramCpuData->MicrocodeDataBufferSize - %x\n", SmramCpuData->MicrocodeDataBufferSize)); + DEBUG ((EFI_D_INFO, "SmramCpuData->GdtrProfileOffset - %x\n", SmramCpuData->GdtrProfileOffset)); + DEBUG ((EFI_D_INFO, "SmramCpuData->GdtOffset - %x\n", SmramCpuData->GdtOffset)); + DEBUG ((EFI_D_INFO, "SmramCpuData->IdtrProfileOffset - %x\n", SmramCpuData->IdtrProfileOffset)); + DEBUG ((EFI_D_INFO, "SmramCpuData->IdtOffset - %x\n", SmramCpuData->IdtOffset)); + DEBUG ((EFI_D_INFO, "SmramCpuData->CpuPrivateDataOffset - %x\n", SmramCpuData->CpuPrivateDataOffset)); + DEBUG ((EFI_D_INFO, "SmramCpuData->S3BootScriptTableOffset - %x\n", SmramCpuData->S3BootScriptTableOffset)); + DEBUG ((EFI_D_INFO, "SmramCpuData->S3BspMtrrTableOffset - %x\n", SmramCpuData->S3BspMtrrTableOffset)); + DEBUG ((EFI_D_INFO, "SmramCpuData->MicrocodePointerBufferOffset - %x\n", SmramCpuData->MicrocodePointerBufferOffset)); + DEBUG ((EFI_D_INFO, "SmramCpuData->MicrocodeDataBufferOffset - %x\n", SmramCpuData->MicrocodeDataBufferOffset)); + + /// + /// Start restore data to NVS + /// + AcpiCpuData = (ACPI_CPU_DATA *) (UINTN) SmramCpuData->AcpiCpuPointer; + CopyMem (AcpiCpuData, &SmramCpuData->AcpiCpuData, sizeof (ACPI_CPU_DATA)); + + CopyMem ( + (VOID *) (UINTN) AcpiCpuData->GdtrProfile, + (UINT8 *) SmramCpuData + SmramCpuData->GdtrProfileOffset, + SmramCpuData->GdtrProfileSize + ); + Gdtr = (PSEUDO_DESCRIPTOR *) (UINTN) AcpiCpuData->GdtrProfile; + CopyMem ( + (VOID *) (UINTN) Gdtr->Base, + (UINT8 *) SmramCpuData + SmramCpuData->GdtOffset, + SmramCpuData->GdtSize + ); + CopyMem ( + (VOID *) (UINTN) AcpiCpuData->IdtrProfile, + (UINT8 *) SmramCpuData + SmramCpuData->IdtrProfileOffset, + SmramCpuData->IdtrProfileSize + ); + Idtr = (PSEUDO_DESCRIPTOR *) (UINTN) AcpiCpuData->IdtrProfile; + CopyMem ( + (VOID *) (UINTN) Idtr->Base, + (UINT8 *) SmramCpuData + SmramCpuData->IdtOffset, + SmramCpuData->IdtSize + ); + + CopyMem ( + (VOID *) (UINTN) AcpiCpuData->CpuPrivateData, + (UINT8 *) SmramCpuData + SmramCpuData->CpuPrivateDataOffset, + SmramCpuData->CpuPrivateDataSize + ); + CpuS3DataPtr = (MP_CPU_S3_DATA_POINTER *) (UINTN) AcpiCpuData->CpuPrivateData; + CopyMem ( + (VOID *) (UINTN) CpuS3DataPtr->S3BootScriptTable, + (UINT8 *) SmramCpuData + SmramCpuData->S3BootScriptTableOffset, + SmramCpuData->S3BootScriptTableSize + ); + CopyMem ( + (VOID *) (UINTN) CpuS3DataPtr->S3BspMtrrTable, + (UINT8 *) SmramCpuData + SmramCpuData->S3BspMtrrTableOffset, + SmramCpuData->S3BspMtrrTableSize + ); + + CopyMem ( + (VOID *) (UINTN) AcpiCpuData->MicrocodePointerBuffer, + (UINT8 *) SmramCpuData + SmramCpuData->MicrocodePointerBufferOffset, + SmramCpuData->MicrocodePointerBufferSize + ); + /// + /// Restore Microcode Data + /// + Microcode = (VOID *) (UINTN) AcpiCpuData->MicrocodePointerBuffer; + LockBoxMicrocode = (EFI_CPU_MICROCODE_HEADER *) ((UINT8 *) SmramCpuData + SmramCpuData->MicrocodeDataBufferOffset); + if (Microcode != NULL) { + Index = 0; + MicrocodeSize = 0; + while (Microcode[Index] != NULL) { + if (LockBoxMicrocode->DataSize == 0) { + MicrocodeSize = 2048; + } else { + MicrocodeSize = LockBoxMicrocode->TotalSize; + } + + CopyMem (Microcode[Index], LockBoxMicrocode, MicrocodeSize); + LockBoxMicrocode = (EFI_CPU_MICROCODE_HEADER *) ((UINT8 *) LockBoxMicrocode + MicrocodeSize); + Index++; + } + } + /// + /// Close all SMM regions + /// + Index = 0; + do { + Status = SmmAccessPpi->Close (PeiServices, SmmAccessPpi, Index); + Index++; + } while (!EFI_ERROR (Status)); + + return AcpiCpuData; +} + +/** + Initialize multiple processors. + + @param[in] FfsHeader - Pointer to an alleged FFS file. + @param[in] PeiServices - Indirect reference to the PEI Services Table + + @retval EFI_SUCCESS - Multiple processors are intialized successfully +**/ +EFI_STATUS +InitializeCpu ( + IN EFI_FFS_FILE_HEADER *FfsHeader, + IN EFI_PEI_SERVICES **PeiServices + ) +{ + EFI_STATUS Status; + EFI_PEI_STALL_PPI *PeiStall; + ACPI_CPU_DATA *AcpiCpuData; + EFI_BOOT_MODE BootMode; + UINT64 *MtrrValues; + MP_CPU_S3_DATA_POINTER *CpuS3DataPtr; + UINTN VariableMtrrNumber; + EFI_PHYSICAL_ADDRESS WakeUpBuffer; + MP_CPU_EXCHANGE_INFO *ExchangeInfo; + UINT32 FailedRevision; + VOID *Hob; + + DEBUG ((EFI_D_INFO, "Cpu S3 dispatch\n")); + + Status = PeiServicesGetBootMode (&BootMode); + if (EFI_ERROR (Status)) { + /// + /// If not in S3 boot path. do nothing + /// + return EFI_SUCCESS; + } + + if (BootMode != BOOT_ON_S3_RESUME) { + return EFI_SUCCESS; + } + + DEBUG ((EFI_D_INFO, "Cpu S3 Entrypoint\n")); + + /// + /// Restore ACPI Nvs data from SMRAM + /// + AcpiCpuData = RestoreSmramCpuData (PeiServices); + DEBUG ((EFI_D_INFO, "CpuS3 RestoreSmramCpuData - 0x%x \n", AcpiCpuData)); + + AcpiCpuData->S3BootPath = TRUE; + + Status = PeiServicesLocatePpi ( + &gEfiPeiStallPpiGuid, + 0, + NULL, + (VOID **) &PeiStall + ); + ASSERT_EFI_ERROR (Status); + + CpuS3DataPtr = (MP_CPU_S3_DATA_POINTER *) (UINTN) AcpiCpuData->CpuPrivateData; + + VariableMtrrNumber = (UINTN) ((UINT64) AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT) * 2; + Status = PeiServicesAllocatePool ( + (FixedMtrrNumber + MtrrDefTypeNumber + VariableMtrrNumber) * sizeof (UINT64), + (VOID **) &MtrrValues + ); + ASSERT_EFI_ERROR (Status); + ReadMtrrRegisters (PeiServices, MtrrValues); + + WakeUpBuffer = AcpiCpuData->WakeUpBuffer; + ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + (0x1000 - 0x200)); + ExchangeInfo->WakeupCount = (UINT32) 0; + ExchangeInfo->FinishedCount = (UINT32) 0; + + /// + /// Restore AP configuration + /// + WakeUpAPs (PeiServices, PeiStall, AcpiCpuData, MtrrValues, MPRendezvousProcedure); + + /// + /// Program XApic register + /// + ProgramXApic ( + TRUE + ); + + InitializeMicrocode ( + ExchangeInfo, + (EFI_CPU_MICROCODE_HEADER **) (UINTN) AcpiCpuData->MicrocodePointerBuffer, + &FailedRevision + ); + + /// + /// Restore features for BSP + /// + InitializeFeaturesLog ( + PeiServices, + (MP_CPU_S3_SCRIPT_DATA *) CpuS3DataPtr->S3BootScriptTable + ); + + /// + /// Save acpi cpu data into one hob, it will be used by a callback when End of Pei Signal installed. + /// + Hob = BuildGuidDataHob ( + &gPeiAcpiCpuDataGuid, + (VOID *)(UINTN)AcpiCpuData, + (UINTN) sizeof (ACPI_CPU_DATA) + ); + ASSERT (Hob != NULL); + + //(AMI_CHG)> + //DEBUG ((EFI_D_INFO, "Install CPU S3 Notify callback\n")); + //Status = PeiServicesNotifyPpi (&mCpuS3ResumeNotifyDesc); + //ASSERT_EFI_ERROR (Status); + //(AMI_CHG)< + + /// + /// Wait for all APs to complete + /// + while (ExchangeInfo->FinishedCount < AcpiCpuData->NumberOfCpus - 1) { + CpuPause (); + } + + return EFI_SUCCESS; +} + +/** + This function handles CPU S3 resume task + + @param[in] PeiServices - Pointer to PEI Services Table. + @param[in] NotifyDesc - Pointer to the descriptor for the Notification event that + caused this function to execute. + @param[in] Ppi - Pointer to the PPI data associated with this function. + + @retval EFI_STATUS - Always return EFI_SUCCESS +**/ +STATIC +EFI_STATUS +CpuS3ResumeAtEndOfPei ( + IN EFI_PEI_SERVICES **PeiServices, + IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc, + IN VOID *Ppi + ) +{ + + EFI_STATUS Status; + EFI_PEI_STALL_PPI *PeiStall; + ACPI_CPU_DATA *AcpiCpuData; + EFI_PHYSICAL_ADDRESS WakeUpBuffer; + MP_CPU_S3_DATA_POINTER *CpuS3DataPtr; + MP_CPU_EXCHANGE_INFO *ExchangeInfo; + VOID *Hob; + + DEBUG ((EFI_D_INFO, "Cpu S3 callback Entry\n")); + + /// + /// Find the saved acpi cpu data from HOB. + /// + AcpiCpuData = NULL; + Hob = GetFirstGuidHob (&gPeiAcpiCpuDataGuid); + if (Hob != NULL) { + AcpiCpuData = (ACPI_CPU_DATA *) ((UINTN) Hob + sizeof (EFI_HOB_GUID_TYPE)); + ASSERT (AcpiCpuData != NULL); + if (AcpiCpuData == NULL) { + return EFI_UNSUPPORTED; + } + } else { + return EFI_UNSUPPORTED; + } + + WakeUpBuffer = AcpiCpuData->WakeUpBuffer; + ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + (0x1000 - 0x200)); + /// + /// Have APs to continue the task - Restore S3BspMtrrTable + /// + ExchangeInfo->WakeupCount = (UINT32) 0; + ExchangeInfo->FinishedCount = (UINT32) 0; + + PeiStall = NULL; + Status = PeiServicesLocatePpi ( + &gEfiPeiStallPpiGuid, + 0, + NULL, + (VOID **) &PeiStall + ); + ASSERT_EFI_ERROR (Status); + + /// + /// Set MTRR to the final values + /// Do not do it too early so as to avoid performance penalty + /// + CpuS3DataPtr = (MP_CPU_S3_DATA_POINTER *) (UINTN) AcpiCpuData->CpuPrivateData; + +#ifdef EFI_DEBUG + ShowMtrrRegisters (PeiServices, (EFI_MTRR_VALUES *) CpuS3DataPtr->S3BspMtrrTable); +#endif + SetMtrrRegisters (PeiServices, (EFI_MTRR_VALUES *) CpuS3DataPtr->S3BspMtrrTable); + + PeiStall->Stall ( + PeiServices, + PeiStall, + 1 * STALL_ONE_MILLI_SECOND ///< 1ms + ); + + while (ExchangeInfo->FinishedCount < AcpiCpuData->NumberOfCpus - 1) { + CpuPause (); + } + + return EFI_SUCCESS; + +} |