diff options
author | Guo Mang <mang.guo@intel.com> | 2016-12-22 19:41:14 +0800 |
---|---|---|
committer | Guo Mang <mang.guo@intel.com> | 2016-12-26 19:15:02 +0800 |
commit | a674eea1c47a6aa0170b2beb07d4f2bbefc798e0 (patch) | |
tree | 3db2b004775c74c311c7c5b7b3998f0c6dc91c32 /Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private | |
parent | f0a77159beb39438f311993bf6cd4136aa7e02fc (diff) | |
download | edk2-platforms-a674eea1c47a6aa0170b2beb07d4f2bbefc798e0.tar.xz |
BroxtonSiPkg: Add Cpu Include file and Library
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private')
21 files changed, 6109 insertions, 0 deletions
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/CpuS3.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/CpuS3.h new file mode 100644 index 0000000000..3ab1813b75 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/CpuS3.h @@ -0,0 +1,229 @@ +/** @file
+ Definitions for S3 Resume.
+
+ Copyright (c) 2014 - 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.
+
+**/
+
+#ifndef _CPU_S3_
+#define _CPU_S3_
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/TimerLib.h>
+#include <Library/HobLib.h>
+#include <Library/CpuPlatformLib.h>
+#include <Private/Library/CpuCommonLib.h>
+#include <Ppi/SmmAccess.h>
+#include <Ppi/MasterBootMode.h>
+#include <Ppi/EndOfPeiPhase.h>
+#include <Ppi/CpuPolicy.h>
+#include "CpuAccess.h"
+
+#define VacantFlag 0x00
+#define NotVacantFlag 0xff
+
+#define MICROSECOND 10
+
+#define MAXIMUM_CPU_NUMBER 0x40
+#define STACK_SIZE_PER_PROC 0x8000
+
+#define MAXIMUM_CPU_S3_TABLE_SIZE 0x1000
+
+#define IO_APIC_INDEX_REGISTER 0xFEC00000
+#define IO_APIC_DATA_REGISTER 0xFEC00010
+
+extern UINTN FixedMtrrNumber;
+extern UINTN MtrrDefTypeNumber;
+
+typedef struct {
+ UINT16 Index;
+ UINT64 Value;
+} EFI_MTRR_VALUES;
+
+typedef struct {
+ UINT32 ApicId;
+ UINT32 MsrIndex;
+ UINT64 MsrValue;
+} MP_CPU_S3_SCRIPT_DATA;
+
+typedef struct {
+ UINT32 S3BootScriptTable;
+ UINT32 S3BspMtrrTable;
+ UINT32 VirtualWireMode;
+} MP_CPU_S3_DATA_POINTER;
+
+typedef struct {
+ UINT32 Lock;
+ UINT32 StackStart;
+ UINT32 StackSize;
+ UINT32 ApFunction;
+ IA32_DESCRIPTOR GdtrProfile;
+ IA32_DESCRIPTOR IdtrProfile;
+ UINT32 BufferStart;
+ UINT32 PmodeOffset;
+ UINT32 AcpiCpuDataAddress;
+ UINT32 MtrrValuesAddress;
+ UINT32 FinishedCount;
+ UINT32 WakeupCount;
+ UINT32 SerializeLock;
+ MP_CPU_S3_SCRIPT_DATA *S3BootScriptTable;
+ UINT32 StartState;
+ UINT32 VirtualWireMode;
+ VOID (*SemaphoreCheck)(UINT32 *SemaphoreAddress);
+ UINT32 McuLoadCount;
+ IN CONST EFI_PEI_SERVICES **PeiServices;
+ UINT64 CpuPerfCtrlValue;
+ SI_CPU_POLICY_PPI *SiCpuPolicyPpi;
+} MP_CPU_EXCHANGE_INFO;
+
+/**
+ Get protected mode code offset
+
+ @retval Offset of protected mode code
+
+**/
+VOID *
+S3AsmGetPmodeOffset (
+ VOID
+ );
+
+/**
+ Get code offset of SemaphoreCheck
+
+ @retval Offset of SemaphoreCheck
+
+**/
+UINT32
+S3AsmGetSemaphoreCheckOffset (
+ VOID
+ );
+
+/**
+ Read MTRR settings
+
+ @param[in] MtrrValues Buffer to store MTRR settings
+
+**/
+VOID
+ReadMtrrRegisters (
+ UINT64 *MtrrValues
+ );
+
+/**
+ Syncup MTRR settings between all processors
+
+ @param[in] MtrrValues Buffer to store MTRR settings
+
+**/
+VOID
+MpMtrrSynchUp (
+ UINT64 *MtrrValues
+ );
+
+/**
+ Set MTRR registers
+
+ @param[in] MtrrArray Buffer with MTRR settings
+
+**/
+VOID
+SetMtrrRegisters (
+ IN EFI_MTRR_VALUES *MtrrArray
+ );
+
+#ifdef EFI_DEBUG
+/**
+ Print MTRR settings in debug build BIOS
+
+ @param[in] MtrrArray Buffer with MTRR settings
+
+**/
+VOID
+ShowMtrrRegisters (
+ IN EFI_MTRR_VALUES *MtrrArray
+ );
+#endif
+
+/**
+ This will check if the microcode address is valid for this processor, and if so, it will
+ load it to the processor.
+
+ @param[in] ExchangeInfo Pointer to the exchange info buffer for output.
+ @param[in] MicrocodeAddress The address of the microcode update binary (in memory).
+ @param[out] FailedRevision The microcode revision that fails to be loaded.
+
+ @retval EFI_SUCCESS A new microcode update is loaded.
+ @retval Other Due to some reason, no new microcode update is loaded.
+
+**/
+EFI_STATUS
+InitializeMicrocode (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN CPU_MICROCODE_HEADER *MicrocodeAddress,
+ OUT UINT32 *FailedRevision
+ );
+
+///
+/// Functions shared in MP/HT drivers
+///
+/**
+ 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
+ );
+
+/**
+ Programs Local APIC registers for virtual wire mode.
+
+ @param[in] BSP Is this BSP?
+
+**/
+VOID
+ProgramXApic (
+ BOOLEAN BSP
+ );
+
+/**
+ Get address map of S3RendezvousFunnelProc.
+
+ @retval AddressMap Output buffer for address map information
+
+**/
+VOID *
+S3AsmGetAddressMap (
+ VOID
+ );
+
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/CpuS3Lib.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/CpuS3Lib.c new file mode 100644 index 0000000000..8c4c8f34ee --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/CpuS3Lib.c @@ -0,0 +1,753 @@ +/** @file
+ Cpu S3 library running on S3 resume paths.
+
+ Copyright (c) 2014 - 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 <Private/Library/CpuS3Lib.h>
+#include "CpuS3.h"
+#include <Library/CpuPolicyLib.h>
+#include <Library/PostCodeLib.h>
+
+extern EFI_GUID gSmramCpuDataHeaderGuid;
+extern EFI_GUID gPeiAcpiCpuDataGuid;
+
+typedef VOID (*S3_AP_PROCEDURE) (
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ UINT64 *MtrrValues
+ );
+
+/**
+ This function handles CPU S3 resume task at the end of PEI
+
+ @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
+ );
+
+
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mCpuS3ResumeNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ CpuS3ResumeAtEndOfPei
+};
+
+
+/**
+ 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 ((ScriptTable->MsrIndex == MSR_IA32_FEATURE_CONTROL) && (AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL) & B_MSR_IA32_FEATURE_CONTROL_LOCK)) {
+ SkipMsr = 1;
+ }
+ if (SkipMsr == 0) {
+ AsmWriteMsr64 (ScriptTable->MsrIndex, ScriptTable->MsrValue);
+ }
+ }
+ ScriptTable++;
+ }
+}
+
+
+/**
+ Restore all MSR settings with debug message output
+
+ @param[in] ScriptTable Script table contain all MSR settings that will be restored
+
+**/
+VOID
+InitializeFeaturesLog (
+ IN MP_CPU_S3_SCRIPT_DATA *ScriptTable
+ )
+{
+ EFI_CPUID_REGISTER CpuidRegisters;
+ UINT32 ApicId;
+ BOOLEAN SkipMsr;
+
+ PostCode (0xC41);
+
+ //
+ // 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 ((DEBUG_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_FEATURE_CONTROL) && (AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL) & B_MSR_IA32_FEATURE_CONTROL_LOCK)) {
+ SkipMsr = TRUE;
+ }
+ if (ScriptTable->MsrIndex == MSR_IA32_DEBUG_INTERFACE) {
+ //
+ // Debug interface is supported if CPUID (EAX=1): ECX[11] = 1
+ //
+ if ((CpuidRegisters.RegEcx & BIT11) && (AsmReadMsr64 (MSR_IA32_DEBUG_INTERFACE) & B_DEBUG_INTERFACE_LOCK)) {
+ SkipMsr = TRUE;
+ }
+ }
+ if (!SkipMsr) {
+ AsmWriteMsr64 (ScriptTable->MsrIndex, ScriptTable->MsrValue);
+ }
+ }
+ ScriptTable++;
+ }
+ PostCode (0xC44);
+}
+
+
+/**
+ 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
+ )
+{
+ EFI_STATUS Status;
+ UINT32 FailedRevision;
+ ACPI_CPU_DATA *AcpiCpuData;
+ MP_CPU_S3_DATA_POINTER *CpuS3DataPtr;
+ EFI_CPUID_REGISTER CpuidRegisters;
+ CPU_CONFIG *CpuConfig;
+
+ Status = GetConfigBlock ((CONFIG_BLOCK_TABLE_HEADER *) ExchangeInfo->SiCpuPolicyPpi, &gCpuConfigGuid , (VOID *) &CpuConfig);
+ ASSERT_EFI_ERROR (Status);
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+
+ //
+ // Init XMM support on all APs
+ //
+ XmmInit ();
+
+ //
+ // Switch AP speed to BSP speed
+ //
+ if ((CpuidRegisters.RegEcx & B_CPUID_VERSION_INFO_ECX_EIST) != 0) {
+ AsmWriteMsr64 (MSR_IA32_PERF_CTRL, ExchangeInfo->CpuPerfCtrlValue);
+ }
+
+ AcpiCpuData = (ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress);
+
+ ProgramXApic (FALSE);
+
+ InitializeFeatures (ExchangeInfo->S3BootScriptTable);
+
+ InterlockedIncrement (&(ExchangeInfo->SerializeLock));
+ while (ExchangeInfo->SerializeLock < AcpiCpuData->NumberOfCpus) {
+ CpuPause ();
+ }
+
+ InitializeMicrocode (
+ ExchangeInfo,
+ (CPU_MICROCODE_HEADER *) (UINTN) CpuConfig->MicrocodePatchAddress,
+ &FailedRevision
+ );
+
+ ProcessorsPrefetcherInitialization (
+ CpuConfig->MlcStreamerPrefetcher,
+ CpuConfig->MlcSpatialPrefetcher
+ );
+
+ //
+ // wait till all CPUs done the Microcode Load
+ //
+ while (ExchangeInfo->McuLoadCount < AcpiCpuData->NumberOfCpus) {
+ CpuPause ();
+ }
+
+ MpMtrrSynchUp (MtrrValues);
+
+ InterlockedIncrement (&(ExchangeInfo->FinishedCount));
+
+ //
+ // Sempahore check loop executed in memory
+ //
+ (*ExchangeInfo->SemaphoreCheck) (&ExchangeInfo->FinishedCount);
+
+ InterlockedIncrement (&(ExchangeInfo->WakeupCount));
+
+ //
+ // Restore the MTRR programmed before OS boot
+ //
+ CpuS3DataPtr = (MP_CPU_S3_DATA_POINTER *) (UINTN) AcpiCpuData->CpuPrivateData;
+ SetMtrrRegisters ((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] 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
+S3WakeUpAps (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ 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;
+
+ PostCode (0xC45);
+ WakeUpBuffer = AcpiCpuData->WakeUpBuffer;
+ CopyMem ((VOID *) (UINTN) WakeUpBuffer, S3AsmGetAddressMap (), 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) (S3AsmGetPmodeOffset ());
+ ExchangeInfo->SemaphoreCheck = (VOID (*)(UINT32 *)) (S3AsmGetSemaphoreCheckOffset () + (UINT32) WakeUpBuffer);
+ ExchangeInfo->AcpiCpuDataAddress = (UINT32) AcpiCpuData;
+ ExchangeInfo->MtrrValuesAddress = (UINT32) MtrrValues;
+ ExchangeInfo->FinishedCount = (UINT32) 0;
+ ExchangeInfo->SerializeLock = (UINT32) 0;
+ 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->CpuPerfCtrlValue = AsmReadMsr64 (MSR_IA32_PERF_CTRL);
+
+ ExchangeInfo->SiCpuPolicyPpi = NULL;
+ PeiServicesLocatePpi (
+ &gSiCpuPolicyPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &(ExchangeInfo->SiCpuPolicyPpi)
+ );
+
+ CopyMem (
+ (VOID *) (UINTN) &ExchangeInfo->GdtrProfile,
+ (VOID *) (UINTN) AcpiCpuData->GdtrProfile,
+ sizeof (IA32_DESCRIPTOR)
+ );
+ CopyMem (
+ (VOID *) (UINTN) &ExchangeInfo->IdtrProfile,
+ (VOID *) (UINTN) AcpiCpuData->IdtrProfile,
+ sizeof (IA32_DESCRIPTOR)
+ );
+
+ DEBUG ((DEBUG_INFO, "Cpu S3 Bootscript at %08X\n", (UINT32) ExchangeInfo->S3BootScriptTable));
+
+ //
+ // 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
+ );
+
+ MicroSecondDelay (10 * STALL_ONE_MILLI_SECOND); //< 10ms
+
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ MicroSecondDelay (200 * STALL_ONE_MICRO_SECOND); //< 200us
+
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ MicroSecondDelay (200 * STALL_ONE_MICRO_SECOND); //< 200us
+ PostCode (0xC48);
+
+ 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 CONST 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 ((EFI_PEI_SERVICES **) PeiServices, SmmAccessPpi, &Size, NULL);
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ Status = PeiServicesAllocatePool (
+ Size,
+ (VOID **) &SmramRanges
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SmmAccessPpi->GetCapabilities ((EFI_PEI_SERVICES **) PeiServices, SmmAccessPpi, &Size, SmramRanges);
+ ASSERT_EFI_ERROR (Status);
+
+ Size /= sizeof (*SmramRanges);
+ SmramRangeCount = Size;
+
+ //
+ // We assume TSEG is the last range of SMRAM in SmramRanges
+ //
+ SmramRanges += SmramRangeCount - 1;
+
+ DEBUG ((DEBUG_INFO, "TsegBase - %x\n", SmramRanges->CpuStart));
+ DEBUG ((DEBUG_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)) {
+ 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 CONST 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;
+ IA32_DESCRIPTOR *Idtr;
+ IA32_DESCRIPTOR *Gdtr;
+ UINTN Index;
+
+ Status = PeiServicesLocatePpi (
+ &gPeiSmmAccessPpiGuid,
+ 0,
+ NULL,
+ (VOID **) &SmmAccessPpi
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Open all SMM regions
+ //
+ Index = 0;
+ do {
+ Status = SmmAccessPpi->Open ((EFI_PEI_SERVICES **) PeiServices, SmmAccessPpi, Index);
+ Index++;
+ } while (!EFI_ERROR (Status));
+
+ SmramCpuData = GetSmmCpuData ((CONST EFI_PEI_SERVICES **) PeiServices, SmmAccessPpi);
+ if (SmramCpuData == NULL) {
+ ASSERT (FALSE);
+ return NULL;
+ }
+ DEBUG ((DEBUG_INFO, "CpuS3 SmramCpuData - 0x%x \n", SmramCpuData));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->GdtrProfileSize - %x\n", SmramCpuData->GdtrProfileSize));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->GdtSize - %x\n", SmramCpuData->GdtSize));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->IdtrProfileSize - %x\n", SmramCpuData->IdtrProfileSize));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->IdtSize - %x\n", SmramCpuData->IdtSize));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->CpuPrivateDataSize - %x\n", SmramCpuData->CpuPrivateDataSize));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->S3BootScriptTableSize - %x\n", SmramCpuData->S3BootScriptTableSize));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->S3BspMtrrTableSize - %x\n", SmramCpuData->S3BspMtrrTableSize));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->GdtrProfileOffset - %x\n", SmramCpuData->GdtrProfileOffset));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->GdtOffset - %x\n", SmramCpuData->GdtOffset));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->IdtrProfileOffset - %x\n", SmramCpuData->IdtrProfileOffset));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->IdtOffset - %x\n", SmramCpuData->IdtOffset));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->CpuPrivateDataOffset - %x\n", SmramCpuData->CpuPrivateDataOffset));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->S3BootScriptTableOffset - %x\n", SmramCpuData->S3BootScriptTableOffset));
+ DEBUG ((DEBUG_INFO, "SmramCpuData->S3BspMtrrTableOffset - %x\n", SmramCpuData->S3BspMtrrTableOffset));
+
+ //
+ // 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 = (IA32_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 = (IA32_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
+ );
+ //
+ // Close all SMM regions
+ //
+ Index = 0;
+ do {
+ Status = SmmAccessPpi->Close ((EFI_PEI_SERVICES **) PeiServices, SmmAccessPpi, Index);
+ Index++;
+ } while (!EFI_ERROR (Status));
+
+ return AcpiCpuData;
+}
+
+
+/**
+ Cpu initialization called during S3 resume to take care
+ of CPU related activities in PEI phase
+
+ @param[in] PeiServices Indirect reference to the PEI Services Table
+
+ @retval EFI_SUCCESS Multiple processors are intialized successfully.
+
+**/
+EFI_STATUS
+S3InitializeCpu (
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ ACPI_CPU_DATA *AcpiCpuData;
+ UINT64 *MtrrValues;
+ MP_CPU_S3_DATA_POINTER *CpuS3DataPtr;
+ UINTN VariableMtrrNumber;
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINT32 FailedRevision;
+ VOID *Hob;
+ EFI_BOOT_MODE BootMode;
+ CPU_CONFIG *CpuConfig;
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ DEBUG ((DEBUG_INFO, "CPU: BootMode = %X\n", BootMode));
+ if ((Status == EFI_SUCCESS) && (BootMode != BOOT_ON_S3_RESUME)) {
+ DEBUG ((DEBUG_INFO,"CPU: Normal Boot\n"));
+ return EFI_SUCCESS;
+ }
+
+ DEBUG((DEBUG_INFO, "S3InitializeCpu Start \n"));
+ PostCode (0xC40);
+
+ //
+ // Restore ACPI Nvs data from SMRAM
+ //
+ AcpiCpuData = RestoreSmramCpuData ((CONST EFI_PEI_SERVICES **) PeiServices);
+ if (AcpiCpuData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((DEBUG_INFO, "CpuS3 RestoreSmramCpuData - 0x%x \n", AcpiCpuData));
+
+ AcpiCpuData->S3BootPath = TRUE;
+
+ 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 (MtrrValues);
+
+ WakeUpBuffer = AcpiCpuData->WakeUpBuffer;
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + (0x1000 - 0x200));
+ ExchangeInfo->WakeupCount = (UINT32) 0;
+ ExchangeInfo->FinishedCount = (UINT32) 0;
+ ExchangeInfo->SerializeLock = (UINT32) 0;
+
+ //
+ // Restore features for BSP
+ //
+ InitializeFeaturesLog ((MP_CPU_S3_SCRIPT_DATA *) CpuS3DataPtr->S3BootScriptTable);
+
+ //
+ // Restore AP configuration
+ //
+ S3WakeUpAps ((CONST EFI_PEI_SERVICES **)PeiServices, AcpiCpuData, MtrrValues, MPRendezvousProcedure);
+
+ //
+ // Program XApic register
+ //
+ ProgramXApic (
+ TRUE
+ );
+
+ InterlockedIncrement (&(ExchangeInfo->SerializeLock));
+ while (ExchangeInfo->SerializeLock < AcpiCpuData->NumberOfCpus) {
+ CpuPause ();
+ }
+
+ Status = GetConfigBlock ((CONFIG_BLOCK_TABLE_HEADER *) ExchangeInfo->SiCpuPolicyPpi, &gCpuConfigGuid , (VOID *) &CpuConfig);
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "Initialize Microcode Start \n"));
+ PostCode (0xC49);
+ InitializeMicrocode (
+ ExchangeInfo,
+ (CPU_MICROCODE_HEADER *) (UINTN) CpuConfig->MicrocodePatchAddress,
+ &FailedRevision
+ );
+
+ DEBUG ((DEBUG_INFO, "BuildGuid Data Hob Start \n"));
+ PostCode (0xC4D);
+ //
+ // 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);
+ DEBUG ((DEBUG_INFO, "CPU S3: Register notification to be trigerred at End of Pei event\n"));
+ Status = PeiServicesNotifyPpi (&mCpuS3ResumeNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Wait for all APs to complete
+ //
+ while (ExchangeInfo->FinishedCount < AcpiCpuData->NumberOfCpus - 1) {
+ CpuPause ();
+ }
+
+ DEBUG ((DEBUG_INFO, "S3InitializeCpu Done \n"));
+ PostCode (0xC5F);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function handles CPU S3 resume task at the end of PEI
+
+ @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
+ )
+{
+ ACPI_CPU_DATA *AcpiCpuData;
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_S3_DATA_POINTER *CpuS3DataPtr;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ VOID *Hob;
+
+ DEBUG ((DEBUG_INFO, "Cpu S3 callback Entry\n"));
+
+ PostCode (0xC51);
+
+ //
+ // 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;
+
+ //
+ // 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 ((EFI_MTRR_VALUES *) CpuS3DataPtr->S3BspMtrrTable);
+#endif
+
+ SetMtrrRegisters ((EFI_MTRR_VALUES *) CpuS3DataPtr->S3BspMtrrTable);
+
+ MicroSecondDelay (1 * STALL_ONE_MILLI_SECOND); //< 1ms
+
+ while (ExchangeInfo->FinishedCount < AcpiCpuData->NumberOfCpus - 1) {
+ CpuPause ();
+ }
+ PostCode (0xC54);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpEqu.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpEqu.h new file mode 100644 index 0000000000..d8ec879d1e --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpEqu.h @@ -0,0 +1,45 @@ +/** @file
+ This is the equates file for HT (Hyper-threading) support.
+
+ Copyright (c) 1999 - 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.
+
+**/
+
+#define VacantFlag 0x00
+#define NotVacantFlag 0xff
+
+#define LockLocation (0x1000 - 0x0200)
+#define StackStartAddressLocation (LockLocation + 0x04)
+#define StackSizeLocation (LockLocation + 0x08)
+#define CProcedureLocation (LockLocation + 0x0C)
+#define GdtrLocation (LockLocation + 0x10)
+#define IdtrLocation (LockLocation + 0x16)
+#define BufferStartLocation (LockLocation + 0x1C)
+#define PmodeOffsetLocation (LockLocation + 0x20)
+#define AcpiCpuDataAddressLocation (LockLocation + 0x24)
+#define MtrrValuesAddressLocation (LockLocation + 0x28)
+#define FinishedCountAddressLocation (LockLocation + 0x2C)
+#define WakeupCountAddressLocation (LockLocation + 0x30)
+#define SerializeLockAddressLocation (LockLocation + 0x34)
+#define MicrocodeAddressLocation (LockLocation + 0x38)
+#define BootScriptAddressLocation (LockLocation + 0x3C)
+#define StartStateLocation (LockLocation + 0x40)
+#define VirtualWireMode (LockLocation + 0x44)
+#define SemaphoreCheck (LockLocation + 0x48)
+#define PeiServices (LockLocation + 0x4C)
+#define PeiStall (LockLocation + 0x50)
+#define CpuPerfCtrlValue (LockLocation + 0x54)
+#define SiCpuPolicyPpi (LockLocation + 0x5C)
+#define MpSystemDataAddressLocation (LockLocation + 0x64)
+#define MpServicePpiAddressLocation (LockLocation + 0x68)
+#define CArgumentLocation (LockLocation + 0x6C)
+#define BistBufferLocation (LockLocation + 0x70)
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpEqu.inc b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpEqu.inc new file mode 100644 index 0000000000..8fa3dc30a9 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpEqu.inc @@ -0,0 +1,49 @@ +;; @file
+; This is the equates file used in MpFuncs.asm, for MP support.
+;
+; Copyright (c) 1999 - 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
+;
+;;
+
+VacantFlag Equ 00h
+NotVacantFlag Equ 0ffh
+
+LockLocation equ 1000h - 0200h
+StackStartAddressLocation equ LockLocation + 04h
+StackSizeLocation equ LockLocation + 08h
+CProcedureLocation equ LockLocation + 0Ch
+GdtrLocation equ LockLocation + 10h
+IdtrLocation equ LockLocation + 16h
+BufferStartLocation equ LockLocation + 1Ch
+PmodeOffsetLocation equ LockLocation + 20h
+AcpiCpuDataAddressLocation equ LockLocation + 24h
+MtrrValuesAddressLocation equ LockLocation + 28h
+FinishedCountAddressLocation equ LockLocation + 2Ch
+WakeupCountAddressLocation equ LockLocation + 30h
+SerializeLockAddressLocation equ LockLocation + 34h
+MicrocodeAddressLocation equ LockLocation + 38h
+BootScriptAddressLocation equ LockLocation + 3Ch
+StartStateLocation equ LockLocation + 40h
+VirtualWireMode equ LockLocation + 44h
+SemaphoreCheck equ LockLocation + 48h
+PeiServices equ LockLocation + 4Ch
+PeiStall equ LockLocation + 50h
+CpuPerfCtrlValue equ LockLocation + 54h
+SiCpuPolicyPpi equ LockLocation + 5Ch
+MpSystemDataAddressLocation equ LockLocation + 64h
+MpServicePpiAddressLocation equ LockLocation + 68h
+CArgumentLocation equ LockLocation + 6Ch
+BistBufferLocation equ LockLocation + 70h
+
+PAUSE32 MACRO
+ DB 0F3h
+ DB 090h
+ ENDM
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpFuncs.S b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpFuncs.S new file mode 100644 index 0000000000..8127ec30f8 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpFuncs.S @@ -0,0 +1,210 @@ +## @file
+# This is the assembly code for MP support.
+#
+# Copyright (c) 1999 - 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 "MpEqu.h"
+
+ .text
+ ASM_FUNCTION_REMOVE_IF_UNREFERENCED
+
+//-------------------------------------------------------------------------------------
+//S3RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+//procedure serializes all the AP processors through an Init sequence. It must be
+//noted that APs arrive here very raw...ie: real mode, no stack.
+//ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+//IS IN MACHINE CODE.
+//-------------------------------------------------------------------------------------
+//S3RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
+
+.globl ASM_PFX(S3RendezvousFunnelProc)
+ASM_PFX(S3RendezvousFunnelProc):
+L_S3RendezvousFunnelProcStart:
+
+ .code16
+
+// At this point CS = 0x(vv00) and ip= 0x0.
+ mov %eax, %ebp
+ mov %cs, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %ss
+ xor %ax, %ax
+ mov %ax, %fs
+ mov %ax, %gs
+
+// Get APIC ID
+ mov $1, %eax
+ cpuid
+ shr $24, %ebx
+ and $0xff, %ebx // EBX is APIC ID
+
+// If it is the first time AP wakes up, just record AP's BIST
+// Otherwise, switch to protected mode.
+
+ mov $StartStateLocation, %si
+ cmpl $0, (%si)
+ jnz L_SkipRecordBist
+
+// Record BIST information
+//
+ mov $8, %al
+ mul %bl
+ mov $BistBufferLocation, %si
+ add %ax, %si
+
+ movl $1, (%si) // Set Valid Flag
+ mov %ebp, 4(%si) // Store BIST value
+
+L_SkipRecordBist:
+// Switch to flat mode.
+
+ mov $BufferStartLocation, %si
+ mov (%si), %ebx
+
+ mov $PmodeOffsetLocation, %di
+ mov (%di), %eax
+ mov %ax, %di
+ sub $6, %di
+ add %ebx, %eax
+ mov %eax, (%di)
+
+ mov $0, %esi
+ mov $GdtrLocation, %si
+ lgdtl %cs:(%esi)
+
+ xor %ax, %ax
+ mov %ax, %ds
+
+ mov %cr0, %eax
+ or $0x00000003, %eax
+ mov %eax, %cr0
+
+ .byte 0x66, 0x67, 0xea // far jump
+ .long 0x00 // 32-bit offset
+ .short 0x20 // 16-bit selector
+
+ .code32
+L_NemInit: // protected mode entry point
+ mov $0x18, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+
+ mov %ebx, %esi
+
+ mov %esi, %edi
+ add $StartStateLocation, %edi
+ mov $1, %eax
+ movl %eax, (%edi)
+
+ mov %esi, %edi
+ add $LockLocation, %edi
+ mov $NotVacantFlag, %eax
+L_TestLock:
+ xchg %eax, (%edi)
+ cmp $NotVacantFlag, %eax
+ jz L_TestLock
+
+L_ProgramStack:
+
+ mov %esi, %edi
+ add $StackSizeLocation, %edi
+ mov (%edi), %eax
+ mov %esi, %edi
+ add $StackStartAddressLocation, %edi
+ add (%edi), %eax
+ mov %eax, %esp
+ movl %eax, (%edi)
+
+L_Releaselock:
+
+ mov $VacantFlag, %eax
+ mov %esi, %edi
+ add $LockLocation, %edi
+ xchg %eax, (%edi)
+
+L_CProcedureInvoke:
+
+ mov %esi, %edi
+ add $CArgumentLocation, %edi
+ mov (%edi), %eax
+ push %eax
+
+ mov %esi, %edi
+ add $CProcedureLocation, %edi
+ mov (%edi), %eax
+
+ call *%eax
+ add $4, %esp
+
+L_InterlockedIncrementFinishedCount:
+ mov %esi, %edi
+ add $FinishedCountAddressLocation, %edi
+ lock incl (%edi)
+
+1:
+ cli
+
+ hlt
+ jmp 1b
+
+
+//-------------------------------------------------------------------------------------
+// S3SemaphoreStartAddress
+//-------------------------------------------------------------------------------------
+
+L_S3SemaphoreStartAddress:
+ push %ebp
+ mov %esp, %ebp
+ mov 0x8(%ebp), %eax
+1:
+ cmpl $0, (%eax)
+ jz 1f
+
+ pause
+ jmp 1b
+
+1:
+ pop %ebp
+ ret
+
+//-------------------------------------------------------------------------------
+// S3AsmGetAddressMap
+//-------------------------------------------------------------------------------------
+.set L_NemInitOffset, L_NemInit - L_S3RendezvousFunnelProcStart
+.set L_SemaphoreOffset, L_S3SemaphoreStartAddress - L_S3RendezvousFunnelProcStart
+
+.globl ASM_PFX(S3AsmGetAddressMap)
+ASM_PFX(S3AsmGetAddressMap):
+ mov $L_S3RendezvousFunnelProcStart, %eax
+ ret
+
+
+//-------------------------------------------------------------------------------
+// S3AsmGetPmodeOffset
+//-------------------------------------------------------------------------------------
+.globl ASM_PFX(S3AsmGetPmodeOffset)
+ASM_PFX(S3AsmGetPmodeOffset):
+ mov $L_NemInitOffset, %eax
+ ret
+
+//-------------------------------------------------------------------------------
+// S3AsmGetSemaphoreCheckOffset
+//-------------------------------------------------------------------------------------
+.globl ASM_PFX(S3AsmGetSemaphoreCheckOffset)
+ASM_PFX(S3AsmGetSemaphoreCheckOffset):
+ mov $L_SemaphoreOffset, %eax
+ ret
\ No newline at end of file diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpFuncs.asm b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpFuncs.asm new file mode 100644 index 0000000000..9e3450d0d3 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/Ia32/MpFuncs.asm @@ -0,0 +1,206 @@ +;; @file
+; This is the assembly code for MP support.
+;
+; Copyright (c) 2005 - 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 MpEqu.inc
+
+;-------------------------------------------------------------------------------------
+;S3RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+;S3RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
+
+.686p
+.model flat
+.code
+
+PAUSE32 MACRO
+ DB 0F3h
+ DB 090h
+ ENDM
+
+S3RendezvousFunnelProc PROC PUBLIC
+S3RendezvousFunnelProcStart::
+
+;Step-1: Grab a lock. At this point CS = 0x(vv00) and ip= 0x0.
+
+ db 8ch,0c8h ; mov ax,cs
+ db 8eh,0d8h ; mov ds,ax
+ db 8eh,0c0h ; mov es,ax
+ db 8eh,0d0h ; mov ss,ax
+ db 33h,0c0h ; xor ax,ax
+ db 8eh,0e0h ; mov fs,ax
+ db 8eh,0e8h ; mov gs,ax
+
+ db 0BEh ; opcode of mov si, mem16
+ dw BufferStartLocation ; mov si, BufferStartLocation
+ db 66h, 8Bh, 1Ch ; mov ebx,dword ptr [si]
+
+ db 0BFh ; opcode of mov di, mem16
+ dw PmodeOffsetLocation ; mov di, PmodeOffsetLocation
+ db 66h, 8Bh, 05h ; mov eax,dword ptr [di]
+ db 8Bh, 0F8h ; mov di, ax
+ db 83h, 0EFh,06h ; sub di, 06h
+ db 66h, 03h, 0C3h ; add eax, ebx
+ db 66h, 89h, 05h ; mov dword ptr [di],eax
+
+ db 0BEh ; opcode of mov si, mem16
+ dw GdtrLocation ; mov si, GdtrLocation
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
+
+ db 0BEh ; opcode of mov si, mem16
+ dw IdtrLocation ; mov si, IdtrProfile
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 1Ch ; lidt fword ptr cs:[si]
+
+ db 33h, 0C0h ; xor ax, ax
+ db 8Eh, 0D8h ; mov ds, ax
+
+ db 0Fh, 20h, 0C0h ; mov eax, cr0 ;Get control register 0
+ db 66h, 83h, 0C8h, 03h ; or eax, 000000003h ;Set PE bit (bit #0) & MP
+ db 0Fh, 22h, 0C0h ; mov cr0, eax
+
+ db 66h, 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+ dw 20h ; 16-bit selector
+
+NemInit:: ; protected mode entry point
+
+ db 66h, 0B8h, 18h, 00h ; mov ax, 18h
+ db 66h, 8Eh, 0D8h ; mov ds, ax
+ db 66h, 8Eh, 0C0h ; mov es, ax
+ db 66h, 8Eh, 0E0h ; mov fs, ax
+ db 66h, 8Eh, 0E8h ; mov gs, ax
+ db 66h, 8Eh, 0D0h ; mov ss, ax ; Flat mode setup.
+
+ mov esi, ebx
+
+ mov edi, esi
+ add edi, StartStateLocation
+ mov eax, 1
+ mov dword ptr [edi], eax
+
+ mov edi, esi
+ add edi, LockLocation
+ mov eax, NotVacantFlag
+TestLock::
+ xchg dword ptr [edi], eax
+ cmp eax, NotVacantFlag
+ jz TestLock
+
+ProgramStack::
+
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov eax, dword ptr [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add eax, dword ptr [edi]
+ mov esp, eax
+ mov dword ptr [edi], eax
+
+Releaselock::
+
+ mov eax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg dword ptr [edi], eax
+
+CProcedureInvoke::
+
+ mov edi, esi
+ add edi, MtrrValuesAddressLocation
+ mov eax, dword ptr [edi]
+ push eax
+
+ mov eax, esi
+ add eax, LockLocation
+ push eax
+
+ mov edi, esi
+ add edi, CProcedureLocation
+ mov eax, dword ptr [edi]
+
+;
+; itp.threads[n].msr(0x121, 0x2FBA2E2500010408)
+; WA for ACPI PM1 timer BXT 0 and 1
+;
+ push ecx
+ push eax
+ push edx
+
+ mov ecx, 0121h
+ rdmsr
+ test eax, eax
+ jnz SkipAcpiTimerWA
+ mov eax, 00010408h ; Bit 16 is enable and 15:0 address
+ mov edx, 2FBA2E25h
+ wrmsr
+SkipAcpiTimerWA:
+ pop edx
+ pop eax
+ pop ecx
+
+ call eax
+ add esp, 8
+
+ cli
+ hlt
+ jmp $-2
+
+S3RendezvousFunnelProc ENDP
+
+S3SemaphoreStartAddress PROC C, SemaphoreAddress:PTR DWORD
+ mov eax, SemaphoreAddress
+@@:
+ cmp dword ptr [eax], 0
+ jz @F
+
+ PAUSE32
+ jmp @B
+@@:
+ ret
+S3SemaphoreStartAddress ENDP
+
+S3RendezvousFunnelProcEnd::
+
+
+;-------------------------------------------------------------------------------------
+; S3AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+S3AsmGetAddressMap PROC near C PUBLIC
+
+ mov eax, S3RendezvousFunnelProcStart
+ ret
+
+S3AsmGetAddressMap ENDP
+
+S3AsmGetPmodeOffset PROC near C PUBLIC
+
+ mov eax, NemInit - S3RendezvousFunnelProcStart
+ ret
+
+S3AsmGetPmodeOffset ENDP
+
+S3AsmGetSemaphoreCheckOffset PROC near C PUBLIC
+ mov eax, S3SemaphoreStartAddress - S3RendezvousFunnelProcStart
+ ret
+S3AsmGetSemaphoreCheckOffset ENDP
+
+END
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/PeiCpuS3Lib.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/PeiCpuS3Lib.inf new file mode 100644 index 0000000000..749dd98ad7 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiCpuS3Lib/PeiCpuS3Lib.inf @@ -0,0 +1,59 @@ +## @file
+# Component information file for CPU S3 module.
+#
+# Copyright (c) 2014 - 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = PeiCpuS3Lib
+ FILE_GUID = 6351F303-B76A-44F9-9171-026BDDCA8654
+ VERSION_STRING = 1.0
+ MODULE_TYPE = PEIM
+ LIBRARY_CLASS = CpuS3Lib
+
+[LibraryClasses]
+ CpuPlatformLib
+ DebugLib
+ BaseLib
+ PeiServicesLib
+ BaseMemoryLib
+ SynchronizationLib
+ HobLib
+ ReportStatusCodeLib
+ MemoryAllocationLib
+ IoLib
+ TimerLib
+ CpuCommonLib
+ PostCodeLib
+ MpServiceLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+ BroxtonSiPkg/BroxtonSiPrivate.dec
+
+[Sources]
+ CpuS3Lib.c
+
+[Sources.IA32]
+ Ia32/MpFuncs.S | GCC
+ Ia32/MpFuncs.asm | MSFT
+
+[Ppis]
+ gSiCpuPolicyPpiGuid ## CONSUMES
+ gPeiSmmAccessPpiGuid ## CONSUMES
+ gEfiEndOfPeiSignalPpiGuid ## NOTIFY
+
+[Guids]
+ gSmramCpuDataHeaderGuid ## UNDEFINED
+ gPeiAcpiCpuDataGuid ## UNDEFINED
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiDxeSmmCpuCommonLib/CpuCommonLib.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiDxeSmmCpuCommonLib/CpuCommonLib.c new file mode 100644 index 0000000000..556fa49a6a --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiDxeSmmCpuCommonLib/CpuCommonLib.c @@ -0,0 +1,683 @@ +/** @file
+ CPU Common Lib implementation.
+
+ Copyright (c) 2014 - 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 <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/CpuLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PciLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PostCodeLib.h>
+#include <CpuAccess.h>
+#include <Private/Library/CpuCommonLib.h>
+
+#define INTERRUPT_VECTOR_NUMBER 256
+#define END_OF_TABLE 0xFF
+
+///
+/// Table to convert PL1 / Pl2 / RATL Seconds into equivalent MSR values
+/// This table is used for TDP Time Window programming
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mSecondsToMsrValueMapTable[][2] = {
+ ///
+ /// Seconds, MSR Value
+ ///
+ { 1, 0x0A },
+ { 2, 0x0B },
+ { 3, 0x4B },
+ { 4, 0x0C },
+ { 5, 0x2C },
+ { 6, 0x4C },
+ { 7, 0x6C },
+ { 8, 0x0D },
+ { 10, 0x2D },
+ { 12, 0x4D },
+ { 14, 0x6D },
+ { 16, 0x0E },
+ { 20, 0x2E },
+ { 24, 0x4E },
+ { 28, 0x6E },
+ { 32, 0x0F },
+ { 40, 0x2F },
+ { 48, 0x4F },
+ { 56, 0x6F },
+ { 64, 0x10 },
+ { 80, 0x30 },
+ { 96, 0x50 },
+ { 112, 0x70 },
+ { 128, 0x11 },
+ { END_OF_TABLE, END_OF_TABLE }
+};
+
+///
+/// Table to convert PL3 Milli Seconds into equivalent MSR values
+/// This table is used for TDP Time Window programming
+///
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 mMilliSecondsToMsrValueMapTable[][2] = {
+ ///
+ /// MilliSeconds, MSR Value
+ ///
+ { 3, 0x41 },
+ { 4, 0x02 },
+ { 5, 0x22 },
+ { 6, 0x42 },
+ { 7, 0x62 },
+ { 8, 0x03 },
+ { 10, 0x23 },
+ { 12, 0x43 },
+ { 14, 0x63 },
+ { 16, 0x04 },
+ { 20, 0x24 },
+ { 24, 0x44 },
+ { 28, 0x64 },
+ { 32, 0x05 },
+ { 40, 0x25 },
+ { 48, 0x45 },
+ { 56, 0x65 },
+ { 64, 0x06 },
+ { END_OF_TABLE, END_OF_TABLE }
+};
+
+/**
+ 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 == 0) {
+ MsrValue |= B_MISC_FEATURE_CONTROL_MLC_STRP;
+ }
+
+ if (MlcSpatialPrefetcherEnabled == 0) {
+ 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;
+}
+
+
+/**
+ Set up flags in CR4 for XMM instruction enabling.
+
+**/
+VOID
+EFIAPI
+XmmInit (
+ VOID
+ )
+{
+ EFI_CPUID_REGISTER Cpuid;
+ UINTN Cr0;
+ UINTN Cr4;
+
+ //
+ // Read the CPUID information
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &Cpuid.RegEax, &Cpuid.RegEbx, &Cpuid.RegEcx, &Cpuid.RegEdx);
+
+ //
+ // Check whether SSE2 is supported
+ //
+ if (Cpuid.RegEdx & BIT26) {
+
+ //
+ // Enable XMM
+ //
+ Cr0 = AsmReadCr0 ();
+ Cr0 |= BIT1;
+ AsmWriteCr0 (Cr0);
+
+ Cr4 = AsmReadCr4 ();
+ Cr4 |= (BIT9 | BIT10);
+ AsmWriteCr4 (Cr4);
+ }
+}
+
+
+/**
+ Enable "Machine Check Enable" bit in Cr4.
+
+**/
+VOID
+EFIAPI
+EnableMce (
+ VOID
+ )
+{
+ UINTN Cr4;
+
+ //
+ // Enable MCE
+ //
+ Cr4 = AsmReadCr4 ();
+ Cr4 |= BIT6;
+ AsmWriteCr4 (Cr4);
+}
+
+
+/**
+ Mtrr Synch Up Entry.
+
+**/
+UINTN
+EFIAPI
+MpMtrrSynchUpEntry (
+ VOID
+ )
+{
+ EFI_CPUID_REGISTER Cpuid;
+ UINT64 MsrData;
+ UINTN Cr0;
+ UINTN Cr4;
+
+ //
+ // Read the CPUID and MSR 1Bh information
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &Cpuid.RegEax, &Cpuid.RegEbx, &Cpuid.RegEcx, &Cpuid.RegEdx);
+ MsrData = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+
+ //
+ // Set CD(Bit30) bit and clear NW(Bit29) bit of CR0 followed by a WBINVD.
+ //
+ if (!(Cpuid.RegEdx & BIT24) || (MsrData & BIT8)) {
+ AsmDisableCache ();
+ } else {
+ //
+ // We could bypass the wbinvd by
+ // checking MSR 1Bh(MSR_IA32_APIC_BASE) Bit8 (1 = BSP, 0 = AP) to see if we're the BSP?
+ // and checking CPUID if the processor support self-snooping.
+ //
+ Cr0 = AsmReadCr0 ();
+ Cr0 &= ~BIT29;
+ Cr0 |= BIT30;
+ AsmWriteCr0 (Cr0);
+ }
+
+ //
+ // Clear PGE flag Bit 7
+ //
+ Cr4 = AsmReadCr4 ();
+ Cr4 &= ~BIT7;
+ AsmWriteCr4 (Cr4);
+
+ //
+ // Flush all TLBs
+ //
+ CpuFlushTlb ();
+
+ return Cr4;
+}
+
+
+/**
+ Mtrr Synch Up Exit
+
+**/
+VOID
+EFIAPI
+MpMtrrSynchUpExit (
+ UINTN Cr4
+ )
+{
+ UINTN Cr0;
+
+ //
+ // Flush all TLBs the second time
+ //
+ CpuFlushTlb ();
+
+ //
+ // Clear both the CD and NW bits of CR0.
+ //
+ Cr0 = AsmReadCr0 ();
+ Cr0 &= ~(BIT29 | BIT30);
+ AsmWriteCr0 (Cr0);
+
+ //
+ // Set PGE Flag in CR4 if set
+ //
+ AsmWriteCr4 (Cr4);
+}
+
+
+/**
+ This procedure sends an IPI to the designated processor in
+ the requested delivery mode with the requested vector.
+
+ @param[in] ApicID APIC ID of processor.
+ @param[in] VectorNumber Vector number.
+ @param[in] DeliveryMode I/O APIC Interrupt Deliver Modes
+
+ @retval EFI_INVALID_PARAMETER Input paramters were not correct.
+ @retval EFI_NOT_READY There was a pending interrupt
+ @retval EFI_SUCCESS Interrupt sent successfully
+
+**/
+EFI_STATUS
+EFIAPI
+CpuSendIpi (
+ IN UINT32 ApicID,
+ IN UINTN VectorNumber,
+ IN UINTN DeliveryMode
+ )
+{
+ UINT64 ApicBaseReg;
+ UINT64 MsrValue;
+ EFI_PHYSICAL_ADDRESS ApicBase;
+ UINT32 IcrLow;
+ UINT32 IcrHigh;
+ BOOLEAN XapicEnabled;
+ UINT32 TriggerMode;
+
+ //
+ // Check for valid input parameters.
+ //
+ if (VectorNumber >= INTERRUPT_VECTOR_NUMBER) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DeliveryMode >= DELIVERY_MODE_MAX) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Fix the vector number for special interrupts like SMI and INIT.
+ //
+ if (DeliveryMode == DELIVERY_MODE_SMI || DeliveryMode == DELIVERY_MODE_INIT) {
+ VectorNumber = 0x0;
+ }
+
+ //
+ // Initialze ICR high dword, since P6 family processor needs
+ // the destination field to be 0x0F when it is a broadcast
+ //
+ IcrHigh = 0x0f000000;
+ IcrLow = (UINT32) (VectorNumber | (LShiftU64 (DeliveryMode, 8)));
+
+ TriggerMode = TRIGGER_MODE_EDGE;
+
+ //
+ // Interrupt trigger mode
+ //
+ if (TriggerMode == TRIGGER_MODE_LEVEL) {
+ IcrLow |= 0x8000;
+ }
+
+ //
+ // Interrupt pin polarity
+ //
+ IcrLow |= 0x4000;
+
+ //
+ // xAPIC Enabled
+ //
+ MsrValue = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ if (MsrValue & B_MSR_IA32_APIC_BASE_G_XAPIC) {
+ if (MsrValue & B_MSR_IA32_APIC_BASE_M_XAPIC) {
+ XapicEnabled = TRUE;
+ } else {
+ XapicEnabled = FALSE;
+ }
+ } else {
+ XapicEnabled = FALSE;
+ }
+
+ if (XapicEnabled) {
+ IcrHigh = (UINT32) ApicID;
+ } else {
+ IcrHigh = (UINT32) LShiftU64 (ApicID, 24);
+ }
+
+ ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBase = ApicBaseReg & 0xffffff000;
+
+ /* 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]
+ ----------------------------------------------------------------
+ */
+ //
+ // To write APIC register by MSR or MMIO
+ //
+ if (XapicEnabled) {
+ AsmWriteMsr64 (EXT_XAPIC_ICR, (((UINT64) LShiftU64 (IcrHigh, 32)) | (UINT64) IcrLow));
+ } else {
+ *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_HIGH_OFFSET) = (UINT32) IcrHigh;
+ *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET) = (UINT32) IcrLow;
+ }
+
+ MicroSecondDelay (10);
+
+ //
+ // To get APIC register from MSR or MMIO
+ //
+ if (XapicEnabled) {
+ IcrLow = (UINT32) AsmReadMsr64 (EXT_XAPIC_ICR);
+ } else {
+ IcrLow = (UINT32) *(volatile UINT32 *) (UINTN) (ApicBase + APIC_REGISTER_ICR_LOW_OFFSET);
+ }
+
+ if (IcrLow & BIT12) {
+ return EFI_NOT_READY;
+ }
+
+ MicroSecondDelay (100);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Private helper function to convert various Turbo Power Limit Time from Seconds to CPU units
+
+ @param[in] TimeInSeconds Time in seconds
+ @param[in] TimeWindowConvType Time Window Convert Type
+
+ @retval UINT8 Converted time in CPU units
+
+**/
+UINT8
+GetConvertedTime (
+ IN UINT32 TimeInSeconds,
+ IN TIME_WINDOW_CONV TimeWindowConvType
+ )
+{
+ UINT8 ConvertedPowerLimitTime;
+ UINT8 Index;
+
+ //
+ // Convert seconds to MSR value. Since not all values are programmable, we'll select
+ // the entry from mapping table which is either equal to the user selected value. OR to a value in the mapping table
+ // which is closest (but less than) to the user-selected value.
+ //
+ ConvertedPowerLimitTime = 0;
+ switch (TimeWindowConvType) {
+ case PL1TimeWindowConvert:
+ case TccOffsetTimeWindowConvert:
+ ConvertedPowerLimitTime = mSecondsToMsrValueMapTable[0][1];
+ for (Index = 0; mSecondsToMsrValueMapTable[Index][0] != END_OF_TABLE; Index++) {
+ if (TimeInSeconds == mSecondsToMsrValueMapTable[Index][0]) {
+ ConvertedPowerLimitTime = mSecondsToMsrValueMapTable[Index][1];
+ break;
+ }
+ if (TimeInSeconds > mSecondsToMsrValueMapTable[Index][0]) {
+ ConvertedPowerLimitTime = mSecondsToMsrValueMapTable[Index][1];
+ } else {
+ break;
+ }
+ }
+ break;
+ case PL3TimeWindowConvert:
+ ConvertedPowerLimitTime = mMilliSecondsToMsrValueMapTable[0][1];
+ for (Index = 0; mMilliSecondsToMsrValueMapTable[Index][0] != END_OF_TABLE; Index++) {
+ if (TimeInSeconds == mMilliSecondsToMsrValueMapTable[Index][0]) {
+ ConvertedPowerLimitTime = mMilliSecondsToMsrValueMapTable[Index][1];
+ break;
+ }
+ if (TimeInSeconds > mMilliSecondsToMsrValueMapTable[Index][0]) {
+ ConvertedPowerLimitTime = mMilliSecondsToMsrValueMapTable[Index][1];
+ } else {
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ConvertedPowerLimitTime;
+}
+
+
+/**
+ Get APIC ID of processor.
+
+ @retval APIC ID of processor.
+
+**/
+UINT32
+GetCpuApicId (
+ VOID
+ )
+{
+ EFI_CPUID_REGISTER CpuidRegisters;
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ return (UINT32) (CpuidRegisters.RegEbx >> 24);
+}
+
+
+/**
+ 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 vector 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;
+}
+
+
+/**
+ This function returns the maximum number of core supported in this physical processor package.
+
+ @retval Maximum number of cores in the package.
+
+**/
+UINT8
+GetMaxSupportedCoreCount (
+ VOID
+ )
+{
+ EFI_CPUID_REGISTER Cpuid;
+
+ AsmCpuidEx (
+ 4,
+ 0,
+ &Cpuid.RegEax,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ return (UINT8) (RShiftU64 (Cpuid.RegEax, 26) & 0x3f) + 1;
+}
+
+
+/**
+ This function returns the actual factory-configured number of threads per core,
+ and actual factory-configured number of cores in this physical processor package.
+
+ @param[out] NumberOfEnabledThreadsPerCore Variable that will store Maximum enabled threads per core.
+ @param[out] NumberOfEnabledCoresPerDie Variable that will store Maximum enabled cores per die.
+
+**/
+VOID
+GetSupportedCount (
+ OUT UINT16 *ThreadsPerCore, OPTIONAL
+ OUT UINT16 *NumberOfCores OPTIONAL
+ )
+{
+ EFI_CPUID_REGISTER CpuidRegs;
+ UINT16 Threads;
+
+ AsmCpuidEx (CPUID_CORE_TOPOLOGY, 0, NULL, &CpuidRegs.RegEbx, NULL, NULL);
+ Threads = (UINT16) CpuidRegs.RegEbx;
+
+ if (ThreadsPerCore != NULL) {
+ *ThreadsPerCore = Threads;
+ }
+
+ if (NumberOfCores != NULL) {
+ AsmCpuidEx (CPUID_CORE_TOPOLOGY, 1, NULL, &CpuidRegs.RegEbx, NULL, NULL);
+ *NumberOfCores = (UINT16) (CpuidRegs.RegEbx / Threads);
+ }
+}
+
+
+/**
+ This function returns the maximum enabled Core per die, maximum enabled threads per core,
+ maximum number of dies and packages.
+
+ @param[out] NumberOfEnabledThreadsPerCore Variable that will store Maximum enabled threads per core.
+ @param[out] NumberOfEnabledCoresPerDie Variable that will store Maximum enabled cores per die.
+ @param[out] NumberOfDiesPerPackage Variable that will store Maximum dies per package.
+ @param[out] NumberOfPackages Variable that will store Maximum Packages.
+
+**/
+VOID
+GetEnabledCount (
+ OUT UINT16 *NumberOfEnabledThreadsPerCore, OPTIONAL
+ OUT UINT16 *NumberOfEnabledCoresPerDie, OPTIONAL
+ OUT UINT16 *NumberOfDiesPerPackage, OPTIONAL
+ OUT UINT16 *NumberOfPackages OPTIONAL
+ )
+{
+ UINT64 MsrValue;
+ UINT16 NumCores;
+
+ PostCode (0xC81);
+
+ //
+ // Read MSR_CORE_THREAD_COUNT (0x35)
+ //
+ MsrValue = AsmReadMsr64 (MSR_CORE_THREAD_COUNT);
+
+ NumCores = (UINT16) RShiftU64 (MsrValue, N_CORE_COUNT_OFFSET);
+
+ //
+ // Get enabled core count in the package (BITS[31:16])
+ //
+ if (NumberOfEnabledCoresPerDie != NULL) {
+ *NumberOfEnabledCoresPerDie = NumCores;
+ }
+
+ //
+ // Get enabled thread count in the package (BITS[15:0])
+ //
+ if (NumberOfEnabledThreadsPerCore != NULL) {
+ *NumberOfEnabledThreadsPerCore = (UINT16)DivU64x32((UINT64)(MsrValue & B_THREAD_COUNT_MASK), (UINT32) NumCores);
+ }
+
+ //
+ // For client, the number of dies and packages will be one
+ //
+ if (NumberOfDiesPerPackage != NULL) {
+ *NumberOfDiesPerPackage = 1;
+ }
+
+ if (NumberOfPackages != NULL) {
+ *NumberOfPackages = 1;
+ }
+ PostCode (0xC84);
+}
+
+
+/**
+ Check to see if the executing thread is BSP.
+
+ @retval TRUE Executing thread is BSP
+ @retval FALSE Executing thread is AP
+
+**/
+BOOLEAN
+IsBsp (
+ VOID
+)
+{
+ BOOLEAN BspIndicator;
+
+ BspIndicator = (AsmReadMsr64 (MSR_IA32_APIC_BASE) & B_MSR_IA32_APIC_BASE_BSP) ? TRUE : FALSE;
+
+ return BspIndicator;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiDxeSmmCpuCommonLib/PeiDxeSmmCpuCommonLib.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiDxeSmmCpuCommonLib/PeiDxeSmmCpuCommonLib.inf new file mode 100644 index 0000000000..5b97d26b9d --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiDxeSmmCpuCommonLib/PeiDxeSmmCpuCommonLib.inf @@ -0,0 +1,44 @@ +## @file
+# CPU Common Lib.
+#
+# Copyright (c) 2014 - 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = PeiDxeSmmCpuCommonLib
+ FILE_GUID = B4E0E3E8-DCE9-46FE-9670-03FDD2F08D6C
+ VERSION_STRING = 1.0
+ MODULE_TYPE = BASE
+ LIBRARY_CLASS = CpuCommonLib
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ IoLib
+ PcdLib
+ PciLib
+ CpuLib
+ TimerLib
+ SynchronizationLib
+ TimerLib
+ CpuPlatformLib
+ PostCodeLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+ BroxtonSiPkg/BroxtonSiPrivate.dec
+
+[Sources]
+ CpuCommonLib.c
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Features.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Features.h new file mode 100644 index 0000000000..52209a5df4 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Features.h @@ -0,0 +1,120 @@ +/** @file
+ Header file of CPU feature control module.
+
+ Copyright (c) 1999 - 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.
+
+**/
+
+#ifndef _FEATURES_H_
+#define _FEATURES_H_
+
+#include <Private/Library/MpServiceLib.h>
+
+///
+/// Processor feature definitions.
+///
+#define TXT_SUPPORT 1
+#define VMX_SUPPORT (1 << 1)
+#define XD_SUPPORT (1 << 2)
+#define DCA_SUPPORT (1 << 3)
+#define X2APIC_SUPPORT (1 << 4)
+#define AES_SUPPORT (1 << 5)
+#define HT_SUPPORT (1 << 6)
+#define DEBUG_SUPPORT (1 << 7)
+#define DEBUG_LOCK_SUPPORT (1 << 8)
+#define PROC_TRACE_SUPPORT (1 << 9)
+
+#define OPTION_FEATURE_RESERVED_MASK 0xFFFB00F8 ///< bits 30:16, 18, 7:3
+#define OPTION_FEATURE_CONFIG_RESERVED_MASK 0xFFFFFFFC ///< bits 2:31
+
+#define MAX_TOPA_ENTRY_COUNT 2
+
+typedef struct {
+ UINT64 TopaEntry[MAX_TOPA_ENTRY_COUNT];
+} PROC_TRACE_TOPA_TABLE;
+
+/**
+ Create feature control structure which will be used to program each feature on each core.
+
+**/
+VOID
+InitializeFeaturePerSetup (
+ VOID
+ );
+
+/**
+ Program all processor features basing on desired settings
+
+**/
+VOID
+EFIAPI
+ProgramProcessorFeature (
+ VOID
+ );
+
+/**
+ Program CPUID Limit before booting to OS
+
+**/
+VOID
+EFIAPI
+ProgramCpuidLimit (
+ VOID
+ );
+
+/**
+ Initialize prefetcher settings
+
+ @param[in] MlcStreamerprefecterEnabled Enable/Disable MLC streamer prefetcher
+ @param[in] MlcSpatialPrefetcherEnabled Enable/Disable MLC spatial prefetcher
+
+**/
+VOID
+InitializeProcessorsPrefetcher (
+ IN UINTN MlcStreamerprefecterEnabled,
+ IN UINTN MlcSpatialPrefetcherEnabled
+ );
+
+/**
+ Detect each processor feature and log all supported features
+
+**/
+VOID
+EFIAPI
+CollectProcessorFeature (
+ VOID
+ );
+
+/**
+ Lock VMX/TXT feature bits on the processor.
+ Set "CFG Lock" (MSR 0E2h Bit[15]
+
+**/
+VOID
+LockFeatureBit (
+ VOID
+ );
+
+
+/**
+ Provide access to the CPU misc enables MSR
+
+ @param[in] Enable Enable or Disable Misc Features
+ @param[in] BitMask The register bit offset of MSR MSR_IA32_MISC_ENABLE
+
+**/
+VOID
+CpuMiscEnable (
+ BOOLEAN Enable,
+ UINT64 BitMask
+ );
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.h new file mode 100644 index 0000000000..df13a04a58 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.h @@ -0,0 +1,45 @@ +/** @file
+ This is the equates file for HT (Hyper-threading) support.
+
+ Copyright (c) 1999 - 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.
+
+**/
+
+#define VacantFlag 0x00
+#define NotVacantFlag 0xff
+
+#define LockLocation (0x1000 - 0x0400)
+#define StackStartAddressLocation (LockLocation + 0x04)
+#define StackSizeLocation (LockLocation + 0x08)
+#define CProcedureLocation (LockLocation + 0x0C)
+#define GdtrLocation (LockLocation + 0x10)
+#define IdtrLocation (LockLocation + 0x16)
+#define BufferStartLocation (LockLocation + 0x1C)
+#define PmodeOffsetLocation (LockLocation + 0x20)
+#define AcpiCpuDataAddressLocation (LockLocation + 0x24)
+#define MtrrValuesAddressLocation (LockLocation + 0x28)
+#define FinishedCountAddressLocation (LockLocation + 0x2C)
+#define WakeupCountAddressLocation (LockLocation + 0x30)
+#define SerializeLockAddressLocation (LockLocation + 0x34)
+#define MicrocodeAddressLocation (LockLocation + 0x38)
+#define BootScriptAddressLocation (LockLocation + 0x3C)
+#define StartStateLocation (LockLocation + 0x40)
+#define VirtualWireMode (LockLocation + 0x44)
+#define SemaphoreCheck (LockLocation + 0x48)
+#define PeiServices (LockLocation + 0x4C)
+#define PeiStall (LockLocation + 0x50)
+#define CpuPerfCtrlValue (LockLocation + 0x54)
+#define SiCpuPolicyPpi (LockLocation + 0x5C)
+#define MpSystemDataAddressLocation (LockLocation + 0x64)
+#define MpServicePpiAddressLocation (LockLocation + 0x68)
+#define CArgumentLocation (LockLocation + 0x6C)
+#define BistBufferLocation (LockLocation + 0x70)
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.inc b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.inc new file mode 100644 index 0000000000..196019fefb --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEqu.inc @@ -0,0 +1,49 @@ +;; @file
+; This is the equates file used in MpFuncs.asm, for MP support.
+;
+; Copyright (c) 1999 - 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
+;
+;;
+
+VacantFlag Equ 00h
+NotVacantFlag Equ 0ffh
+
+LockLocation equ 1000h - 0400h
+StackStartAddressLocation equ LockLocation + 04h
+StackSizeLocation equ LockLocation + 08h
+CProcedureLocation equ LockLocation + 0Ch
+GdtrLocation equ LockLocation + 10h
+IdtrLocation equ LockLocation + 16h
+BufferStartLocation equ LockLocation + 1Ch
+PmodeOffsetLocation equ LockLocation + 20h
+AcpiCpuDataAddressLocation equ LockLocation + 24h
+MtrrValuesAddressLocation equ LockLocation + 28h
+FinishedCountAddressLocation equ LockLocation + 2Ch
+WakeupCountAddressLocation equ LockLocation + 30h
+SerializeLockAddressLocation equ LockLocation + 34h
+MicrocodeAddressLocation equ LockLocation + 38h
+BootScriptAddressLocation equ LockLocation + 3Ch
+StartStateLocation equ LockLocation + 40h
+VirtualWireMode equ LockLocation + 44h
+SemaphoreCheck equ LockLocation + 48h
+PeiServices equ LockLocation + 4Ch
+PeiStall equ LockLocation + 50h
+CpuPerfCtrlValue equ LockLocation + 54h
+SiCpuPolicyPpi equ LockLocation + 5Ch
+MpSystemDataAddressLocation equ LockLocation + 64h
+MpServicePpiAddressLocation equ LockLocation + 68h
+CArgumentLocation equ LockLocation + 6Ch
+BistBufferLocation equ LockLocation + 70h
+
+PAUSE32 MACRO
+ DB 0F3h
+ DB 090h
+ ENDM
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEquNasm.inc b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEquNasm.inc new file mode 100644 index 0000000000..0590cd88de --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpEquNasm.inc @@ -0,0 +1,49 @@ +;; @file
+; This is the equates file used in MpFuncs.asm, for MP support.
+;
+; Copyright (c) 1999 - 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
+;
+;;
+
+%define VacantFlag 0x0
+%define NotVacantFlag 0xff
+
+%define LockLocation 0x1000 - 0x400
+%define StackStartAddressLocation LockLocation + 0x4
+%define StackSizeLocation LockLocation + 0x8
+%define CProcedureLocation LockLocation + 0xC
+%define GdtrLocation LockLocation + 0x10
+%define IdtrLocation LockLocation + 0x16
+%define BufferStartLocation LockLocation + 0x1C
+%define PmodeOffsetLocation LockLocation + 0x20
+%define AcpiCpuDataAddressLocation LockLocation + 0x24
+%define MtrrValuesAddressLocation LockLocation + 0x28
+%define FinishedCountAddressLocation LockLocation + 0x2C
+%define WakeupCountAddressLocation LockLocation + 0x30
+%define SerializeLockAddressLocation LockLocation + 0x34
+%define MicrocodeAddressLocation LockLocation + 0x38
+%define BootScriptAddressLocation LockLocation + 0x3C
+%define StartStateLocation LockLocation + 0x40
+%define VirtualWireMode LockLocation + 0x44
+%define SemaphoreCheck LockLocation + 0x48
+%define PeiServices LockLocation + 0x4C
+%define PeiStall LockLocation + 0x50
+%define CpuPerfCtrlValue LockLocation + 0x54
+%define SiCpuPolicyPpi LockLocation + 0x5C
+%define MpSystemDataAddressLocation LockLocation + 0x64
+%define MpServicePpiAddressLocation LockLocation + 0x68
+%define CArgumentLocation LockLocation + 0x6C
+%define BistBufferLocation LockLocation + 0x70
+
+%macro PAUSE32 0
+ DB 0xF3
+ DB 0x90
+ %endmacro
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.S b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.S new file mode 100644 index 0000000000..91ca56e85a --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.S @@ -0,0 +1,316 @@ +## @file
+# This is the assembly code for MP support.
+#
+# Copyright (c) 1999 - 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 "MpEqu.h"
+
+ .text
+ ASM_FUNCTION_REMOVE_IF_UNREFERENCED
+
+//-------------------------------------------------------------------------------
+// AsmAcquireMPLock (&Lock);
+//-------------------------------------------------------------------------------
+.globl ASM_PFX(AsmAcquireMPLock)
+ASM_PFX(AsmAcquireMPLock):
+
+ pusha
+ mov %esp, %ebp
+
+ mov $NotVacantFlag, %al
+ mov 0x24(%ebp), %ebx
+L_TryGetLock:
+ xchg (%ebx), %al
+ cmp $VacantFlag, %al
+ jz L_LockObtained
+
+ pause
+ jmp L_TryGetLock
+
+L_LockObtained:
+ popa
+ ret
+
+//-------------------------------------------------------------------------------
+// AsmReleaseMPLock (&Lock);
+//-------------------------------------------------------------------------------------
+.globl ASM_PFX(AsmReleaseMPLock)
+ASM_PFX(AsmReleaseMPLock):
+
+ pusha
+ mov %esp, %ebp
+
+ mov $VacantFlag, %al
+ movl 0x24(%ebp), %ebx
+ xchg (%ebx), %al
+
+ popa
+ ret
+
+//-------------------------------------------------------------------------------------
+//RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+//procedure serializes all the AP processors through an Init sequence. It must be
+//noted that APs arrive here very raw...ie: real mode, no stack.
+//ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+//IS IN MACHINE CODE.
+//-------------------------------------------------------------------------------------
+//RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
+
+.globl ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+L_RendezvousFunnelProcStart:
+
+ .code16
+
+// At this point CS = 0x(vv00) and ip= 0x0.
+ mov %eax, %ebp
+ mov %cs, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %ss
+ xor %ax, %ax
+ mov %ax, %fs
+ mov %ax, %gs
+
+// Get APIC ID
+ mov $1, %eax
+ cpuid
+ shr $24, %ebx
+ and $0xff, %ebx // EBX is APIC ID
+
+// If it is the first time AP wakes up, just record AP's BIST
+// Otherwise, switch to protected mode.
+
+ mov $StartStateLocation, %si
+ cmpl $0, (%si)
+ jnz L_SkipRecordBist
+
+// Record BIST information
+//
+ mov $8, %al
+ mul %bl
+ mov $BistBufferLocation, %si
+ add %ax, %si
+
+ movl $1, (%si) // Set Valid Flag
+ mov %ebp, 4(%si) // Store BIST value
+
+L_SkipRecordBist:
+// Switch to flat mode.
+
+ mov $BufferStartLocation, %si
+ mov (%si), %ebx
+
+ mov $PmodeOffsetLocation, %di
+ mov (%di), %eax
+ mov %ax, %di
+ sub $6, %di
+ add %ebx, %eax
+ mov %eax, (%di)
+
+ mov $0, %esi
+ mov $GdtrLocation, %si
+ lgdtl %cs:(%esi)
+
+ xor %ax, %ax
+ mov %ax, %ds
+
+ mov %cr0, %eax
+ or $0x00000003, %eax
+ mov %eax, %cr0
+
+ .byte 0x66, 0x67, 0xea // far jump
+ .long 0x00 // 32-bit offset
+ .short 0x20 // 16-bit selector
+
+ .code32
+L_NemInit: // protected mode entry point
+ mov $0x18, %ax
+ mov %ax, %ds
+ mov %ax, %es
+ mov %ax, %fs
+ mov %ax, %gs
+ mov %ax, %ss
+
+ mov %ebx, %esi
+
+ mov %esi, %edi
+ add $StartStateLocation, %edi
+ mov $1, %eax
+ movl %eax, (%edi)
+
+ mov %esi, %edi
+ add $LockLocation, %edi
+ mov $NotVacantFlag, %eax
+L_TestLock:
+ xchg %eax, (%edi)
+ cmp $NotVacantFlag, %eax
+ jz L_TestLock
+
+L_ProgramStack:
+
+ mov %esi, %edi
+ add $StackSizeLocation, %edi
+ mov (%edi), %eax
+ mov %esi, %edi
+ add $StackStartAddressLocation, %edi
+ add (%edi), %eax
+ mov %eax, %esp
+ movl %eax, (%edi)
+
+L_Releaselock:
+
+ mov $VacantFlag, %eax
+ mov %esi, %edi
+ add $LockLocation, %edi
+ xchg %eax, (%edi)
+
+L_CProcedureInvoke:
+
+ mov %esi, %edi
+ add $CArgumentLocation, %edi
+ mov (%edi), %eax
+ push %eax
+
+ mov %esi, %edi
+ add $CProcedureLocation, %edi
+ mov (%edi), %eax
+
+ call *%eax
+ add $4, %esp
+
+L_InterlockedIncrementFinishedCount:
+ mov %esi, %edi
+ add $FinishedCountAddressLocation, %edi
+ lock incl (%edi)
+
+1:
+ cli
+
+ hlt
+ jmp 1b
+
+
+//-------------------------------------------------------------------------------------
+// SemaphoreStartAddress
+//-------------------------------------------------------------------------------------
+
+L_SemaphoreStartAddress:
+ push %ebp
+ mov %esp, %ebp
+ mov 0x8(%ebp), %eax
+1:
+ cmpl $0, (%eax)
+ jz 1f
+
+ pause
+ jmp 1b
+
+1:
+ pop %ebp
+ ret
+
+//-------------------------------------------------------------------------------
+// AsmGetAddressMap
+//-------------------------------------------------------------------------------------
+.set L_NemInitOffset, L_NemInit - L_RendezvousFunnelProcStart
+.set L_SemaphoreOffset, L_SemaphoreStartAddress - L_RendezvousFunnelProcStart
+
+.globl ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+ mov $L_RendezvousFunnelProcStart, %eax
+ ret
+
+
+//-------------------------------------------------------------------------------
+// AsmGetPmodeOffset
+//-------------------------------------------------------------------------------------
+.globl ASM_PFX(AsmGetPmodeOffset)
+ASM_PFX(AsmGetPmodeOffset):
+ mov $L_NemInitOffset, %eax
+ ret
+
+//-------------------------------------------------------------------------------
+// AsmGetSemaphoreCheckOffset
+//-------------------------------------------------------------------------------------
+.globl ASM_PFX(AsmGetSemaphoreCheckOffset)
+ASM_PFX(AsmGetSemaphoreCheckOffset):
+ mov $L_SemaphoreOffset, %eax
+ ret
+
+//-------------------------------------------------------------------------------------
+//AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+//about to become an AP. It switches it'stack with the current AP.
+//AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+//-------------------------------------------------------------------------------------
+#define CPU_SWITCH_STATE_IDLE 0
+#define CPU_SWITCH_STATE_STORED 1
+#define CPU_SWITCH_STATE_LOADED 2
+
+.globl ASM_PFX(AsmExchangeRole)
+ASM_PFX(AsmExchangeRole):
+ // DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ // at the same time. If 1 CPU try to call a functiosn, stack will be corrupted.
+
+ pusha
+ mov %ebp, %esp
+
+
+ // esi contains MyInfo pointer
+ mov %ecx, %esi
+
+ // edi contains OthersInfo pointer
+ mov %edx, %edi
+
+ //Store EFLAGS, GDTR and IDTR regiter to stack
+ pushf
+ sgdt 8(%esi)
+ sidt 14(%esi)
+
+ // Store the its StackPointer
+ mov %esp, 4(%esi)
+
+ // update its switch state to STORED
+ movb $CPU_SWITCH_STATE_STORED, 1(%esi)
+ xchg %al, (%esi)
+
+L_WaitForOtherStored:
+ // wait until the other CPU finish storing its state
+ cmp $CPU_SWITCH_STATE_STORED, %edi
+ jb L_WaitForOtherStored
+
+ // Since another CPU already stored its state, load them
+ // load GDTR value
+ lgdt 8(%edi)
+
+ // load IDTR value
+ lidt 14(%edi)
+
+ // load its future StackPointer
+ mov 4(%edi), %esp
+
+ // update its switch state to LOADED
+ movb $CPU_SWITCH_STATE_LOADED, 1(%edi)
+ xchg %al, (%edi)
+
+L_WaitForOtherLoaded:
+ // wait until the other CPU finish loading new state,
+ // otherwise the data in stack may corrupt
+ cmp $CPU_SWITCH_STATE_LOADED, %esi
+ jb L_WaitForOtherLoaded
+
+ // since the other CPU already get the data it want, leave this procedure
+ popf
+
+ popa
+ ret
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.asm b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.asm new file mode 100644 index 0000000000..58a481d091 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.asm @@ -0,0 +1,365 @@ +;; @file
+; This is the assembly code for MP support.
+;
+; Copyright (c) 1999 - 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 MpEqu.inc
+
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
+
+.686p
+.model flat
+.code
+
+PAUSE32 MACRO
+ DB 0F3h
+ DB 090h
+ ENDM
+
+;-------------------------------------------------------------------------------
+; AsmAcquireMPLock (&Lock);
+;-------------------------------------------------------------------------------
+AsmAcquireMPLock PROC near C PUBLIC
+
+ pushad
+ mov ebp,esp
+
+ mov al, NotVacantFlag
+ mov ebx, dword ptr [ebp+24h]
+TryGetLock:
+ xchg al, byte ptr [ebx]
+ cmp al, VacantFlag
+ jz LockObtained
+
+ PAUSE32
+ jmp TryGetLock
+
+LockObtained:
+ popad
+ ret
+AsmAcquireMPLock ENDP
+
+;-------------------------------------------------------------------------------
+; AsmReleaseMPLock (&Lock);
+;-------------------------------------------------------------------------------------
+AsmReleaseMPLock PROC near C PUBLIC
+
+ pushad
+ mov ebp,esp
+
+ mov al, VacantFlag
+ mov ebx, dword ptr [ebp+24h]
+ xchg al, byte ptr [ebx]
+
+ popad
+ ret
+AsmReleaseMPLock ENDP
+
+RendezvousFunnelProc PROC PUBLIC
+RendezvousFunnelProcStart::
+
+;Step-1: Grab a lock. At this point CS = 0x(vv00) and ip= 0x0.
+ db 66h, 08bh, 0e8h ; mov ebp, eax
+ db 8ch,0c8h ; mov ax,cs
+ db 8eh,0d8h ; mov ds,ax
+ db 8eh,0c0h ; mov es,ax
+ db 8eh,0d0h ; mov ss,ax
+ db 33h,0c0h ; xor ax,ax
+ db 8eh,0e0h ; mov fs,ax
+ db 8eh,0e8h ; mov gs,ax
+; Get APIC ID
+;
+ db 66h, 0B8h
+ dd 00000001h ; mov eax, 1
+ db 0Fh, 0A2h ; cpuid
+ db 66h, 0C1h, 0EBh, 18h ; shr ebx, 24
+ db 66h, 81h, 0E3h
+ dd 000000FFh ; and ebx, 0ffh ; EBX is APIC ID
+
+; If it is the first time AP wakes up, just record AP's BIST
+; Otherwise, switch to protected mode.
+
+ db 0BEh ; opcode of mov si, imm16
+ dw StartStateLocation ; mov si, StartState
+ db 66h, 83h, 3Ch, 00h ; cmp dword ptr [si], 0
+ db 75h ; opcode of jnz
+ db SkipRecordBist - ($ + 1) ; jnz SkipRecordBist
+
+; Record BIST information
+;
+ db 0B0h, 08h ; mov al, 8
+ db 0F6h, 0E3h ; mul bl
+
+ db 0BEh ; opcode of mov si, imm16
+ dw BistBufferLocation ; mov si, BistBufferLocation
+ db 03h, 0F0h ; add si, ax
+
+ db 66h, 0C7h, 04h
+ dd 00000001h ; mov dword ptr [si], 1 ; Set Valid Flag
+ db 66h, 89h, 6Ch, 04h ; mov dword ptr [si + 4], ebp ; Store BIST value
+
+SkipRecordBist::
+ db 0BEh ; opcode of mov si, mem16
+ dw BufferStartLocation ; mov si, BufferStartLocation
+ db 66h, 8Bh, 1Ch ; mov ebx,dword ptr [si]
+
+ db 0BFh ; opcode of mov di, mem16
+ dw PmodeOffsetLocation ; mov di, PmodeOffsetLocation
+ db 66h, 8Bh, 05h ; mov eax,dword ptr [di]
+ db 8Bh, 0F8h ; mov di, ax
+ db 83h, 0EFh,06h ; sub di, 06h
+ db 66h, 03h, 0C3h ; add eax, ebx
+ db 66h, 89h, 05h ; mov dword ptr [di],eax
+
+ db 0BEh ; opcode of mov si, mem16
+ dw GdtrLocation ; mov si, GdtrLocation
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 14h ; lgdt fword ptr cs:[si]
+
+ db 0BEh ; opcode of mov si, mem16
+ dw IdtrLocation ; mov si, IdtrProfile
+ db 66h ; db 66h
+ db 2Eh, 0Fh, 01h, 1Ch ; lidt fword ptr cs:[si]
+
+ db 33h, 0C0h ; xor ax, ax
+ db 8Eh, 0D8h ; mov ds, ax
+
+ db 0Fh, 20h, 0C0h ; mov eax, cr0 ;Get control register 0
+ db 66h, 83h, 0C8h, 03h ; or eax, 000000003h ;Set PE bit (bit #0) & MP
+ db 0Fh, 22h, 0C0h ; mov cr0, eax
+
+ db 66h, 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+BspCS::
+ dw 00h ; 16-bit selector
+
+NemInit:: ; protected mode entry point
+
+ db 66h, 0B8h ; mov ax, 18h
+BspDS::
+ dw 00h
+ db 66h, 8Eh, 0D8h ; mov ds, ax
+ db 66h, 8Eh, 0C0h ; mov es, ax
+ db 66h, 8Eh, 0E0h ; mov fs, ax
+ db 66h, 8Eh, 0E8h ; mov gs, ax
+ db 66h, 8Eh, 0D0h ; mov ss, ax ; Flat mode setup.
+
+ mov esi, ebx
+
+ mov edi, esi
+ add edi, StartStateLocation
+ mov eax, 1
+ mov dword ptr [edi], eax
+
+ mov edi, esi
+ add edi, LockLocation
+ mov eax, NotVacantFlag
+TestLock::
+ xchg dword ptr [edi], eax
+ cmp eax, NotVacantFlag
+ jz TestLock
+
+ProgramStack::
+
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov eax, dword ptr [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add eax, dword ptr [edi]
+ mov esp, eax
+ mov dword ptr [edi], eax
+
+Releaselock::
+
+ mov eax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg dword ptr [edi], eax
+
+CProcedureInvoke::
+
+ mov edi, esi
+ add edi, CArgumentLocation
+ mov eax, dword ptr [edi]
+ push eax
+
+ mov edi, esi
+ add edi, CProcedureLocation
+ mov eax, dword ptr [edi]
+
+
+ push ecx
+ push eax
+ push edx
+
+ mov ecx, 0121h
+ rdmsr
+ test eax, eax
+ jnz SkipAcpiTimerWA
+ mov eax, 00010408h ; Bit 16 is enable and 15:0 address
+ mov edx, 2FBA2E25h
+ wrmsr
+SkipAcpiTimerWA:
+ pop edx
+ pop eax
+ pop ecx
+
+
+ call eax
+ add esp, 4
+
+InterlockedIncrementFinishedCount::
+ mov edi, esi
+ add edi, FinishedCountAddressLocation
+ lock inc dword ptr [edi]
+ cli
+ hlt
+ jmp $-2
+
+RendezvousFunnelProc ENDP
+
+SemaphoreStartAddress PROC C, SemaphoreAddress:PTR DWORD
+ mov eax, SemaphoreAddress
+@@:
+ cmp dword ptr [eax], 0
+ jz @F
+
+ PAUSE32
+ jmp @B
+@@:
+ ret
+SemaphoreStartAddress ENDP
+
+RendezvousFunnelProcEnd::
+
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+AsmGetAddressMap PROC near C PUBLIC
+
+ mov eax, RendezvousFunnelProcStart
+ ret
+
+AsmGetAddressMap ENDP
+
+AsmGetPmodeOffset PROC near C PUBLIC
+
+ mov eax, NemInit - RendezvousFunnelProcStart
+ ret
+
+AsmGetPmodeOffset ENDP
+
+AsmGetSemaphoreCheckOffset PROC near C PUBLIC
+ mov eax, SemaphoreStartAddress - RendezvousFunnelProcStart
+ ret
+AsmGetSemaphoreCheckOffset ENDP
+
+AsmPatchRendezvousCode PROC near C PUBLIC
+ mov eax, dword ptr [esp + 4]
+ push esi
+ push edi
+ mov edi, eax
+ mov ax, cs
+ mov esi, edi
+ add esi, BspCS - RendezvousFunnelProcStart
+ mov word ptr [esi], ax
+ mov ax, ds
+ mov esi, edi
+ add esi, BspDS - RendezvousFunnelProcStart
+ mov word ptr [esi], ax
+ pop edi
+ pop esi
+ xor eax, eax
+ ret
+AsmPatchRendezvousCode ENDP
+
+;-------------------------------------------------------------------------------------
+;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+;about to become an AP. It switches it'stack with the current AP.
+;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+;-------------------------------------------------------------------------------------
+CPU_SWITCH_STATE_IDLE equ 0
+CPU_SWITCH_STATE_STORED equ 1
+CPU_SWITCH_STATE_LOADED equ 2
+
+AsmExchangeRole PROC near C PUBLIC
+ ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ ; at the same time. If 1 CPU try to call a functiosn, stack will be corrupted.
+ pushad
+ mov ebp,esp
+
+ ; esi contains MyInfo pointer
+ mov esi, dword ptr [ebp+24h]
+
+ ; edi contains OthersInfo pointer
+ mov edi, dword ptr [ebp+28h]
+
+ ;Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfd
+ sgdt fword ptr [esi+8]
+ sidt fword ptr [esi+14]
+
+ ; Store the its StackPointer
+ mov dword ptr [esi+4],esp
+
+ ; update its switch state to STORED
+ mov byte ptr [esi], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored::
+ ; wait until the other CPU finish storing its state
+ cmp byte ptr [edi], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ PAUSE32
+ jmp WaitForOtherStored
+
+OtherStored::
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt fword ptr [edi+8]
+
+ ; load IDTR value
+ lidt fword ptr [edi+14]
+
+ ; load its future StackPointer
+ mov esp, dword ptr [edi+4]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte ptr [edi], CPU_SWITCH_STATE_LOADED
+
+WaitForOtherLoaded::
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte ptr [esi], CPU_SWITCH_STATE_LOADED
+ jz OtherLoaded
+ PAUSE32
+ jmp WaitForOtherLoaded
+
+OtherLoaded::
+ ; since the other CPU already get the data it want, leave this procedure
+ popfd
+
+ popad
+ ret
+AsmExchangeRole ENDP
+
+END
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.nasm b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.nasm new file mode 100644 index 0000000000..deb580b6bb --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Ia32/MpFuncs.nasm @@ -0,0 +1,361 @@ +;; @file
+; This is the assembly code for MP support.
+;
+; Copyright (c) 2005 - 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 "MpEquNasm.inc"
+
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc (&WakeUpBuffer,MemAddress);
+
+SECTION .text
+
+%macro PAUSE32 0
+ DB 0xF3
+ DB 0x90
+ %endmacro
+
+;-------------------------------------------------------------------------------
+; AsmAcquireMPLock (&Lock);
+;-------------------------------------------------------------------------------
+global ASM_PFX(AsmAcquireMPLock)
+ASM_PFX(AsmAcquireMPLock):
+
+ pushad
+ mov ebp,esp
+
+ mov al, NotVacantFlag
+ mov ebx, dword [ebp+0x24]
+L_TryGetLock:
+ xchg al, byte [ebx]
+ cmp al, VacantFlag
+ jz L_LockObtained
+
+ PAUSE32
+ jmp L_TryGetLock
+
+L_LockObtained:
+ popad
+ ret
+
+;-------------------------------------------------------------------------------
+; AsmReleaseMPLock (&Lock);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmReleaseMPLock)
+ASM_PFX(AsmReleaseMPLock):
+
+ pushad
+ mov ebp,esp
+
+ mov al, VacantFlag
+ mov ebx, dword [ebp+0x24]
+ xchg al, byte [ebx]
+
+ popad
+ ret
+
+global ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+L_RendezvousFunnelProcStart:
+
+;Step-1: Grab a lock. At this point CS = 0x(vv00) and ip= 0x0.
+ db 0x66, 0x8b, 0xe8 ; mov ebp, eax
+ db 0x8c,0xc8 ; mov ax,cs
+ db 0x8e,0xd8 ; mov ds,ax
+ db 0x8e,0xc0 ; mov es,ax
+ db 0x8e,0xd0 ; mov ss,ax
+ db 0x33,0xc0 ; xor ax,ax
+ db 0x8e,0xe0 ; mov fs,ax
+ db 0x8e,0xe8 ; mov gs,ax
+; Get APIC ID
+;
+ db 0x66, 0xB8
+ dd 0x1 ; mov eax, 1
+ db 0xF, 0xA2 ; cpuid
+ db 0x66, 0xC1, 0xEB, 0x18 ; shr ebx, 24
+ db 0x66, 0x81, 0xE3
+ dd 0xFF ; and ebx, 0ffh ; EBX is APIC ID
+
+; If it is the first time AP wakes up, just record AP's BIST
+; Otherwise, switch to protected mode.
+
+ db 0xBE ; opcode of mov si, imm16
+ dw StartStateLocation ; mov si, StartState
+ db 0x66, 0x83, 0x3C, 0x0 ; cmp dword ptr [si], 0
+ db 0x75 ; opcode of jnz
+ db L_SkipRecordBist - ($ + 1) ; jnz SkipRecordBist
+
+; Record BIST information
+;
+ db 0xB0, 0x8 ; mov al, 8
+ db 0xF6, 0xE3 ; mul bl
+
+ db 0xBE ; opcode of mov si, imm16
+ dw BistBufferLocation ; mov si, BistBufferLocation
+ db 0x3, 0xF0 ; add si, ax
+
+ db 0x66, 0xC7, 0x4
+ dd 0x1 ; mov dword ptr [si], 1 ; Set Valid Flag
+ db 0x66, 0x89, 0x6C, 0x4 ; mov dword ptr [si + 4], ebp ; Store BIST value
+
+L_SkipRecordBist:
+ db 0xBE ; opcode of mov si, mem16
+ dw BufferStartLocation ; mov si, BufferStartLocation
+ db 0x66, 0x8B, 0x1C ; mov ebx,dword ptr [si]
+
+ db 0xBF ; opcode of mov di, mem16
+ dw PmodeOffsetLocation ; mov di, PmodeOffsetLocation
+ db 0x66, 0x8B, 0x5 ; mov eax,dword ptr [di]
+ db 0x8B, 0xF8 ; mov di, ax
+ db 0x83, 0xEF,0x6 ; sub di, 06h
+ db 0x66, 0x3, 0xC3 ; add eax, ebx
+ db 0x66, 0x89, 0x5 ; mov dword ptr [di],eax
+
+ db 0xBE ; opcode of mov si, mem16
+ dw GdtrLocation ; mov si, GdtrLocation
+ db 0x66 ; db 66h
+ db 0x2E, 0xF, 0x1, 0x14 ; lgdt fword ptr cs:[si]
+
+ db 0xBE ; opcode of mov si, mem16
+ dw IdtrLocation ; mov si, IdtrProfile
+ db 0x66 ; db 66h
+ db 0x2E, 0xF, 0x1, 0x1C ; lidt fword ptr cs:[si]
+
+ db 0x33, 0xC0 ; xor ax, ax
+ db 0x8E, 0xD8 ; mov ds, ax
+
+ db 0xF, 0x20, 0xC0 ; mov eax, cr0 ;Get control register 0
+ db 0x66, 0x83, 0xC8, 0x3 ; or eax, 000000003h ;Set PE bit (bit #0) & MP
+ db 0xF, 0x22, 0xC0 ; mov cr0, eax
+
+ db 0x66, 0x67, 0xEA ; far jump
+ dd 0x0 ; 32-bit offset
+BspCS:
+ dw 0x0 ; 16-bit selector
+
+L_NemInit: ; protected mode entry point
+
+ db 0x66, 0xB8 ; mov ax, 18h
+BspDS:
+ dw 0x0
+ db 0x66, 0x8E, 0xD8 ; mov ds, ax
+ db 0x66, 0x8E, 0xC0 ; mov es, ax
+ db 0x66, 0x8E, 0xE0 ; mov fs, ax
+ db 0x66, 0x8E, 0xE8 ; mov gs, ax
+ db 0x66, 0x8E, 0xD0 ; mov ss, ax ; Flat mode setup.
+
+ mov esi, ebx
+
+ mov edi, esi
+ add edi, StartStateLocation
+ mov eax, 1
+ mov dword [edi], eax
+
+ mov edi, esi
+ add edi, LockLocation
+ mov eax, NotVacantFlag
+L_TestLock:
+ xchg dword [edi], eax
+ cmp eax, NotVacantFlag
+ jz L_TestLock
+
+ProgramStack:
+
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov eax, dword [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add eax, dword [edi]
+ mov esp, eax
+ mov dword [edi], eax
+
+L_Releaselock:
+
+ mov eax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg dword [edi], eax
+
+L_CProcedureInvoke:
+
+ mov edi, esi
+ add edi, CArgumentLocation
+ mov eax, dword [edi]
+ push eax
+
+ mov edi, esi
+ add edi, CProcedureLocation
+ mov eax, dword [edi]
+
+;
+; reserved for SV_HOOKS START
+; itp.threads[n].msr(0x121, 0x2FBA2E2500010408)
+; WA for ACPI PM1 timer BXT 0 and 1
+ push ecx
+ push eax
+ push edx
+
+ mov ecx, 0x121
+ rdmsr
+ test eax, eax
+ jnz SkipAcpiTimerWA
+ mov eax, 0x10408 ; Bit 16 is enable and 15:0 address
+ mov edx, 0x2FBA2E25
+ wrmsr
+SkipAcpiTimerWA:
+ pop edx
+ pop eax
+ pop ecx
+;
+; Reserved for SV_HOOKS END
+
+ call eax
+ add esp, 4
+
+L_InterlockedIncrementFinishedCount:
+ mov edi, esi
+ add edi, FinishedCountAddressLocation
+ lock inc dword [edi]
+ cli
+ hlt
+ jmp $-2
+
+global ASM_PFX(SemaphoreStartAddress)
+ASM_PFX(SemaphoreStartAddress):
+ push ebp
+ mov ebp, esp
+ mov eax, dword [ebp + 0x8]
+.0:
+ cmp dword [eax], 0
+ jz .1
+
+ PAUSE32
+ jmp .0
+.1:
+ ret
+
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+
+ mov eax, L_RendezvousFunnelProcStart
+ ret
+
+global ASM_PFX(AsmGetPmodeOffset)
+ASM_PFX(AsmGetPmodeOffset):
+
+ mov eax, L_NemInit - L_RendezvousFunnelProcStart
+ ret
+
+global ASM_PFX(AsmGetSemaphoreCheckOffset)
+ASM_PFX(AsmGetSemaphoreCheckOffset):
+ mov eax, SemaphoreStartAddress - L_RendezvousFunnelProcStart
+ ret
+
+global ASM_PFX(AsmPatchRendezvousCode)
+ASM_PFX(AsmPatchRendezvousCode):
+ mov eax, dword [esp + 4]
+ push esi
+ push edi
+ mov edi, eax
+ mov ax, cs
+ mov esi, edi
+ add esi, BspCS - L_RendezvousFunnelProcStart
+ mov word [esi], ax
+ mov ax, ds
+ mov esi, edi
+ add esi, BspDS - L_RendezvousFunnelProcStart
+ mov word [esi], ax
+ pop edi
+ pop esi
+ xor eax, eax
+ ret
+
+;-------------------------------------------------------------------------------------
+;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+;about to become an AP. It switches it'stack with the current AP.
+;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+;-------------------------------------------------------------------------------------
+%define CPU_SWITCH_STATE_IDLE 0
+%define CPU_SWITCH_STATE_STORED 1
+%define CPU_SWITCH_STATE_LOADED 2
+
+global ASM_PFX(AsmExchangeRole)
+ASM_PFX(AsmExchangeRole):
+ ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ ; at the same time. If 1 CPU try to call a functiosn, stack will be corrupted.
+ pushad
+ mov ebp,esp
+
+ ; esi contains MyInfo pointer
+ mov esi, dword [ebp+0x24]
+
+ ; edi contains OthersInfo pointer
+ mov edi, dword [ebp+0x28]
+
+ ;Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfd
+ sgdt [esi+8]
+ sidt [esi+14]
+
+ ; Store the its StackPointer
+ mov dword [esi+4],esp
+
+ ; update its switch state to STORED
+ mov byte [esi], CPU_SWITCH_STATE_STORED
+
+L_WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte [edi], CPU_SWITCH_STATE_STORED
+ jz L_OtherStored
+ PAUSE32
+ jmp L_WaitForOtherStored
+
+L_OtherStored:
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt [edi+8]
+
+ ; load IDTR value
+ lidt [edi+14]
+
+ ; load its future StackPointer
+ mov esp, dword [edi+4]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte [edi], CPU_SWITCH_STATE_LOADED
+
+L_WaitForOtherLoaded:
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte [esi], CPU_SWITCH_STATE_LOADED
+ jz L_OtherLoaded
+ PAUSE32
+ jmp L_WaitForOtherLoaded
+
+L_OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ popfd
+
+ popad
+ ret
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Microcode.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Microcode.c new file mode 100644 index 0000000000..1b4a0b581e --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/Microcode.c @@ -0,0 +1,221 @@ +/** @file
+ CPU microcode update library.
+
+ Copyright (c) 1999 - 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 <Private/Library/MpServiceLib.h>
+#include <CpuRegs.h>
+
+/**
+ Check if this is non-core processor - HT AP thread
+
+ @retval TRUE If this is HT AP thread
+ @retval FALSE If this is core thread
+
+**/
+BOOLEAN
+IsSecondaryThread (
+ VOID
+ )
+{
+ UINT32 ApicID;
+ EFI_CPUID_REGISTER CpuidRegisters;
+ UINT8 CpuCount;
+ UINT8 CoreCount;
+ UINT8 CpuPerCore;
+ UINT32 Mask;
+
+ ApicID = GetCpuApicId ();
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ if ((CpuidRegisters.RegEdx & 0x10000000) == 0) {
+ return FALSE;
+ }
+
+ CpuCount = (UINT8) ((CpuidRegisters.RegEbx >> 16) & 0xff);
+ if (CpuCount == 1) {
+ return FALSE;
+ }
+
+ AsmCpuid (
+ CPUID_SIGNATURE,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ if (CpuidRegisters.RegEax > 3) {
+
+ CoreCount = GetMaxSupportedCoreCount ();
+ } else {
+ CoreCount = 1;
+ }
+ //
+ // Assumes there is symmetry across core boundary, i.e. each core within a package has the same number of logical processors
+ //
+ if (CpuCount == CoreCount) {
+ return FALSE;
+ }
+
+ CpuPerCore = CpuCount / CoreCount;
+
+ //
+ // Assume 1 Core has no more than 8 threads
+ //
+ if (CpuPerCore == 2) {
+ Mask = 0x1;
+ } else if (CpuPerCore <= 4) {
+ Mask = 0x3;
+ } else {
+ Mask = 0x7;
+ }
+
+ if ((ApicID & Mask) == 0) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+
+/**
+ Wait until all primary threads are done with the microcode load.
+
+ @param[in] ExchangeInfo Pointer to the exchange info buffer for output.
+
+**/
+VOID
+WaitForPrimaryThreadMcuUpdate (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo
+ )
+{
+ UINTN CoreNumber;
+
+ CoreNumber = (UINTN) ((RShiftU64 (AsmReadMsr64 (MSR_CORE_THREAD_COUNT), 16)) & 0xffff);
+ if (IsSecondaryThread ()) {
+ while (ExchangeInfo->McuLoadCount < CoreNumber) {
+ CpuPause ();
+ }
+ }
+}
+
+
+/**
+ This will load the microcode to the processors.
+
+ @param[in] MicrocodeEntryPoint The microcode update pointer
+ @param[in, out] Revision The current (before load this microcode update) microcode revision
+ as output parameter, the microcode revision after microcode update is loaded
+
+ @retval EFI_SUCCESS Microcode loaded
+ @retval EFI_LOAD_ERROR Microcode not loaded
+
+**/
+EFI_STATUS
+LoadMicrocode (
+ IN CPU_MICROCODE_HEADER *MicrocodeEntryPoint,
+ IN OUT UINT32 *Revision
+ )
+{
+ EFI_STATUS Status;
+ UINT32 NewRevision;
+
+ Status = EFI_SUCCESS;
+
+#ifdef EFI_DEBUG
+ if (IsBsp()) {
+ DEBUG ((DEBUG_INFO, "LoadMicrocode: Before load, revision = 0x%x\n", *Revision));
+ }
+#endif
+
+ //
+ // Load the Processor Microcode
+ //
+ AsmWriteMsr64 (
+ MSR_IA32_BIOS_UPDT_TRIG,
+ (UINT64) ((UINTN) MicrocodeEntryPoint + sizeof (CPU_MICROCODE_HEADER))
+ );
+
+ NewRevision = GetCpuUcodeRevision ();
+
+#ifdef EFI_DEBUG
+ if (IsBsp ()) {
+ DEBUG ((DEBUG_INFO, "LoadMicrocode: After load, revision = 0x%x\n", NewRevision));
+ }
+#endif
+
+ //
+ // Verify that the microcode has been loaded
+ //
+ if (NewRevision == *Revision) {
+ return EFI_LOAD_ERROR;
+ }
+ *Revision = MicrocodeEntryPoint->UpdateRevision;
+
+ return Status;
+}
+
+
+/**
+ This will check if the microcode address is valid for this processor, and if so, it will
+ load it to the processor.
+
+ @param[in] ExchangeInfo Pointer to the exchange info buffer for output.
+ @param[in] MicrocodeAddress The address of the microcode update binary (in memory).
+ @param[out] FailedRevision The microcode revision that fails to be loaded.
+
+ @retval EFI_SUCCESS A new microcode update is loaded.
+ @retval Other Due to some reason, no new microcode update is loaded.
+
+**/
+EFI_STATUS
+InitializeMicrocode (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN CPU_MICROCODE_HEADER *MicrocodeAddress,
+ OUT UINT32 *FailedRevision
+ )
+{
+ EFI_STATUS Status;
+ EFI_CPUID_REGISTER Cpuid;
+ UINT32 UcodeRevision;
+ ACPI_CPU_DATA *mAcpiCpuData;
+
+ Status = EFI_NOT_FOUND;
+
+ mAcpiCpuData = (ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress);
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &Cpuid.RegEax,
+ &Cpuid.RegEbx,
+ &Cpuid.RegEcx,
+ &Cpuid.RegEdx
+ );
+
+ WaitForPrimaryThreadMcuUpdate (ExchangeInfo);
+ UcodeRevision = GetCpuUcodeRevision ();
+
+ if (CheckMicrocode (Cpuid.RegEax, MicrocodeAddress, &UcodeRevision)) {
+ Status = LoadMicrocode (MicrocodeAddress, &UcodeRevision);
+ *FailedRevision = UcodeRevision;
+ }
+ InterlockedIncrement (&(ExchangeInfo->McuLoadCount));
+
+ return Status;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.c new file mode 100644 index 0000000000..55e38c632b --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.c @@ -0,0 +1,1756 @@ +/** @file
+ PEIM to initialize multi-processor.
+
+ Copyright (c) 2013 - 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 <Private/Library/CpuCommonLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Ppi/MasterBootMode.h>
+#include <Library/HobLib.h>
+#include <Library/TimerLib.h>
+#include "MpService.h"
+#include <Ppi/CpuPolicy.h>
+#include <Private/CpuInitDataHob.h>
+#include <Features.h>
+#include <Library/CpuPolicyLib.h>
+#include <Library/PostCodeLib.h>
+#include <Library/MtrrLib.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED MP_CPU_RUNTIME_DATA *mMpCpuRuntimeData = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED MP_SYSTEM_DATA *mMpSystemData = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED SI_CPU_POLICY_PPI *mSiCpuPolicyPpi = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED CPU_CONFIG *mCpuConfig = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED CPU_CONFIG_PREMEM *mCpuConfigPreMem = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED POWER_MGMT_CONFIG *mPowerMgmtConfig = NULL;
+
+
+/**
+ This function handles CPU MP service task at the end of PEI
+
+ @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
+CpuMpServiceAtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ );
+
+STATIC EFI_PEI_NOTIFY_DESCRIPTOR mCpuMpServiceNotifyDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ CpuMpServiceAtEndOfPei
+};
+
+
+/**
+ Allocate a temporary memory under 1MB for MP Init to perform INIT-SIPI.
+ This buffer also provides memory for stack/data to run MP routine.
+
+ @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;
+ *WakeUpBuffer = 0x58000;
+
+ return Status;
+}
+
+
+/**
+ Prepare Wakeup Buffer and stack for APs.
+
+ @param[in] WakeUpBuffer Pointer to the address of wakeup buffer for output.
+ @param[in] StackAddressStart Pointer to the stack address of APs for output.
+ @param[in] MaximumCPUsForThisSystem Maximum CPUs in this system.
+
+ @retval EFI_SUCCESS Memory successfully prepared for APs.
+ @retval Other Error occurred while allocating memory.
+
+**/
+EFI_STATUS
+PrepareMemoryForAPs (
+ OUT EFI_PHYSICAL_ADDRESS *WakeUpBuffer,
+ OUT VOID **StackAddressStart,
+ IN UINTN MaximumCPUsForThisSystem
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Release All APs with a lock and wait for them to retire to rendezvous procedure.
+ // We need a page (4KB) of memory for IA-32 to use broadcast APIs, on a temporary basis.
+ //
+ Status = AllocateWakeUpBuffer (WakeUpBuffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Claim memory for AP stack
+ //
+ *StackAddressStart = AllocateRuntimePool (MaximumCPUsForThisSystem * STACK_SIZE_PER_PROC);
+
+ if (*StackAddressStart == NULL) {
+ FreePool (WakeUpBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Prepare GDTR and IDTR for AP
+
+ @param[in] Gdtr The GDTR profile
+ @param[in] Idtr The IDTR profile
+
+ @retval EFI_STATUS Status returned by each sub-routine
+ @retval EFI_SUCCESS GDTR and IDTR has been prepared for AP
+
+**/
+EFI_STATUS
+PrepareGdtIdtForAP (
+ OUT IA32_DESCRIPTOR *Gdtr,
+ OUT IA32_DESCRIPTOR *Idtr
+ )
+{
+ INTERRUPT_GATE_DESCRIPTOR *IdtForAP;
+ SEGMENT_DESCRIPTOR *GdtForAP;
+ IA32_DESCRIPTOR IdtrForBSP;
+ IA32_DESCRIPTOR GdtrForBSP;
+ UINT16 *MceHandler;
+
+ //
+ // Get Global Descriptor Table Register(GDTR) descriptor
+ //
+ AsmReadGdtr (&GdtrForBSP);
+
+ //
+ // Get Interrupt Descriptor Table Register(IDTR) descriptor
+ //
+ AsmReadIdtr (&IdtrForBSP);
+
+ //
+ // Allocate reserved memory for IDT
+ //
+ IdtForAP = (INTERRUPT_GATE_DESCRIPTOR *) AllocateAlignedRuntimePages (EFI_SIZE_TO_PAGES (IdtrForBSP.Limit + 1), sizeof (INTERRUPT_GATE_DESCRIPTOR));
+ if (IdtForAP == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Allocate reserved memory for GDT
+ //
+ GdtForAP = (SEGMENT_DESCRIPTOR *) AllocateAlignedRuntimePages (EFI_SIZE_TO_PAGES (GdtrForBSP.Limit + 1), sizeof (SEGMENT_DESCRIPTOR));
+ if (GdtForAP == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ MceHandler = AllocateRuntimePool (SIZE_OF_MCE_HANDLER);
+ if (MceHandler == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // MceHandler content: iret (opcode = 0xcf)
+ //
+ *MceHandler = 0xCF48;
+
+ CopyMem (GdtForAP, (VOID *) GdtrForBSP.Base, GdtrForBSP.Limit + 1);
+ CopyMem (IdtForAP, (VOID *) IdtrForBSP.Base, IdtrForBSP.Limit + 1);
+
+ IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset15To0 = (UINT16) (UINTN) MceHandler;
+ IdtForAP[INTERRUPT_HANDLER_MACHINE_CHECK].Offset31To16 = (UINT16) ((UINTN) MceHandler >> 16);
+
+ //
+ // Create Gdtr, IDTR profile
+ //
+ Gdtr->Base = (UINTN) GdtForAP;
+ Gdtr->Limit = GdtrForBSP.Limit;
+
+ Idtr->Base = (UINTN) IdtForAP;
+ Idtr->Limit = IdtrForBSP.Limit;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialize CPU Data Hob
+
+ @retval EFI_SUCCESS The driver installes/initialized correctly.
+ @retval EFI_OUT_OF_RESOURCES Allocation of the hob failed.
+
+**/
+EFI_STATUS
+InitializeCpuDataHob (
+ VOID
+ )
+{
+ CPU_INIT_DATA_HOB *CpuInitDataHob;
+ CPU_CONFIG *CpuConfig;
+ POWER_MGMT_CONFIG *PowerMgmtConfig;
+ VOID *Hob;
+
+ PostCode (0xC3B);
+
+ //
+ // Initial cpu data into one hob, it will be used by MP CPU DXE.
+ //
+ CpuInitDataHob = AllocateRuntimeZeroPool (sizeof (CPU_INIT_DATA_HOB));
+ if (CpuInitDataHob == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CpuConfig = &mMpCpuRuntimeData->CpuConfig;
+ PowerMgmtConfig = &mMpCpuRuntimeData->PowerMgmtConfig;
+
+ CopyMem (
+ (VOID *) (UINTN) PowerMgmtConfig,
+ (VOID *) (UINTN) mPowerMgmtConfig,
+ sizeof (POWER_MGMT_CONFIG)
+ );
+ CopyMem (
+ (VOID *) (UINTN) CpuConfig,
+ (VOID *) (UINTN) mCpuConfig,
+ sizeof (CPU_CONFIG)
+ );
+
+ CpuInitDataHob->CpuConfig = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->CpuConfig;
+ CpuInitDataHob->PowerMgmtConfig = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->PowerMgmtConfig;
+
+ CpuInitDataHob->MpData = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->AcpiCpuData;
+ CpuInitDataHob->FvidTable = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->FvidTable;
+
+ Hob = BuildGuidDataHob (
+ &gCpuInitDataHobGuid,
+ (VOID *) CpuInitDataHob,
+ (UINTN) sizeof (CPU_INIT_DATA_HOB)
+ );
+ ASSERT (Hob != NULL);
+
+ PostCode (0xC3E);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Initialize multi-processor service.
+
+**/
+EFI_STATUS
+InitializeMpServices (
+ IN SI_CPU_POLICY_PPI *SiCpuPolicyPpi
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_BOOT_MODE BootMode;
+ UINT64 *MtrrValues;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ VOID *StackAddressStart;
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MTRR_SETTINGS MtrrSetting;
+ UINT16 MaxEnabledThreadsPerCore;
+ UINT16 MaxEnabledCoresPerDie;
+ UINT16 MaxDiesPerPackage;
+ UINT16 MaxPackages;
+ UINTN MaximumCPUsForThisSystem;
+ UINT32 ResponseProcessorCount;
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ DEBUG ((DEBUG_INFO, "InitializeMpServices: BootMode = %X\n", BootMode));
+ if ((Status == EFI_SUCCESS) && (BootMode == BOOT_ON_S3_RESUME)) {
+ return EFI_SUCCESS;
+ }
+
+ DEBUG ((DEBUG_INFO, "Set Cpu MP Service Environment entry point\n"));
+ PostCode (0xC20);
+
+ //
+ // Allocate MP data structure memory.
+ //
+ mMpCpuRuntimeData = (MP_CPU_RUNTIME_DATA *) AllocateRuntimeZeroPool (sizeof (MP_CPU_RUNTIME_DATA));
+ if (mMpCpuRuntimeData == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize ACPI_CPU_DATA data
+ //
+ mMpCpuRuntimeData->AcpiCpuData.GdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->GdtrProfile;
+ mMpCpuRuntimeData->AcpiCpuData.IdtrProfile = (EFI_PHYSICAL_ADDRESS) (UINTN) &mMpCpuRuntimeData->IdtrProfile;
+ mMpCpuRuntimeData->AcpiCpuData.S3BootPath = FALSE;
+
+ mSiCpuPolicyPpi = SiCpuPolicyPpi;
+
+ Status = GetConfigBlock ((CONFIG_BLOCK_TABLE_HEADER *) SiCpuPolicyPpi, &gCpuConfigGuid , (VOID *)&mCpuConfig);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = GetConfigBlock ((CONFIG_BLOCK_TABLE_HEADER *) SiCpuPolicyPpi, &gPowerMgmtConfigGuid , (VOID *)&mPowerMgmtConfig);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Save the MTRR registers to global variables
+ //
+ MtrrValues = mMpCpuRuntimeData->MtrrValues;
+ ReadMtrrRegisters (MtrrValues);
+
+ //
+ // Get information on enabled threads, cores, dies and package for the CPU(s) on this platform
+ //
+ GetEnabledCount (
+ &MaxEnabledThreadsPerCore,
+ &MaxEnabledCoresPerDie,
+ &MaxDiesPerPackage,
+ &MaxPackages
+ );
+
+ //
+ // Get the total CPU count
+ //
+ MaximumCPUsForThisSystem = MaxEnabledThreadsPerCore * MaxEnabledCoresPerDie * MaxDiesPerPackage * MaxPackages;
+
+ //
+ // Prepare Wakeup Buffer and Stack for APs
+ //
+ Status = PrepareMemoryForAPs (
+ &WakeUpBuffer,
+ &StackAddressStart,
+ MaximumCPUsForThisSystem
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "Specify memory cacheable type as Write Back Start\n"));
+
+ //
+ // Set specify memory cacheable type as Write Back
+ //
+ Status = MtrrSetMemoryAttributeInMtrrSettings (
+ &MtrrSetting,
+ 0x50000,
+ 0x10000,
+ CacheWriteBack
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Fill MP Data
+ //
+ Status = FillMpData (
+ (UINTN) WakeUpBuffer,
+ StackAddressStart,
+ MaximumCPUsForThisSystem
+ );
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ //
+ // Wake up all APs at the first time
+ //
+ WakeUpAPs (MtrrValues, (EFI_AP_PROCEDURE) InitialMpProcedure);
+
+ //
+ // Program XApic register
+ //
+ ProgramXApic (TRUE);
+
+ //
+ // Wait for all APs to complete
+ //
+ while (ExchangeInfo->FinishedCount < mMpCpuRuntimeData->AcpiCpuData.NumberOfCpus - 1) {
+ CpuPause ();
+ }
+
+ //
+ // Collect all APs BIST status
+ //
+ for (Index = 1, ResponseProcessorCount = 1; Index < MAXIMUM_CPU_NUMBER; Index++) {
+ if (ExchangeInfo->BistBuffer[Index].Number == 1) {
+ ExchangeInfo->BistBuffer[Index].Number = ResponseProcessorCount++;
+ }
+ }
+
+ //
+ // Switch BSP to Lowest Feature Processor (LFP)
+ //
+ Status = SwitchToLowestFeatureProcess ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Register notification for CPU MP service task at the End of PEI
+ //
+ Status = PeiServicesNotifyPpi (&mCpuMpServiceNotifyDesc);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_INFO, "Cpu MP Service End\n"));
+ PostCode (0xC9F);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get general MP information
+
+ @param[in] NumberOfCpus Number of processors
+ @param[in] MaximumNumberOfCpus Max supported number of processors
+ @param[in] NumberOfEnabledCpus Number of processors enabled
+ @param[in] RendezvousIntNumber Number of Rendezvous procedure
+ @param[in] RendezvousProcLength Length of Rendezvous procedure
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+EFIAPI
+GetGeneralMpInfo (
+ OUT UINTN *NumberOfCpus,
+ OUT UINTN *MaximumNumberOfCpus,
+ OUT UINTN *NumberOfEnabledCpus,
+ OUT UINTN *RendezvousIntNumber,
+ OUT UINTN *RendezvousProcLength
+ )
+{
+ UINTN Index;
+ CPU_DATA_BLOCK *CpuData;
+
+ if (NumberOfCpus) {
+ *NumberOfCpus = mMpSystemData->NumberOfCpus;
+ }
+
+ if (MaximumNumberOfCpus) {
+ *MaximumNumberOfCpus = mMpSystemData->MaximumCpusForThisSystem;
+ }
+
+ if (RendezvousProcLength) {
+ *RendezvousProcLength = RENDEZVOUS_PROC_LENGTH;
+ }
+
+ if (RendezvousIntNumber) {
+ *RendezvousIntNumber = 0;
+ }
+
+ if (NumberOfEnabledCpus) {
+ *NumberOfEnabledCpus = mMpSystemData->NumberOfCpus;
+ for (Index = 0; Index < mMpSystemData->NumberOfCpus; Index++) {
+ CpuData = &mMpSystemData->CpuData[Index];
+ if (mMpSystemData->EnableSecondaryCpu) {
+ if (CpuData->State != CPU_STATE_DISABLED) {
+ (*NumberOfEnabledCpus)++;
+ }
+ } else {
+ if (CpuData->State != CPU_STATE_DISABLED && !mMpSystemData->CpuData[Index].SecondaryCpu) {
+ (*NumberOfEnabledCpus)++;
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get processor context
+
+ @param[in] CpuNumber Cpu number
+ @param[in] BufferLength Buffer length
+ @param[in] ProcessorContextBuffer Pointer to the buffer that will be updated
+
+ @retval EFI_INVALID_PARAMETER Buffer is NULL or CpuNumber our of range
+ @retval EFI_BUFFER_TOO_SMALL Buffer too small
+ @retval EFI_SUCCESS Got processor context successfully
+
+**/
+EFI_STATUS
+EFIAPI
+GetProcessorContext (
+ IN UINTN CpuNumber,
+ IN OUT UINTN *BufferLength,
+ IN OUT EFI_MP_PROC_CONTEXT *ProcessorContextBuffer
+ )
+{
+ EFI_MP_PROC_CONTEXT *ProcessorBuffer;
+ CPU_DATA_BLOCK *CpuData;
+
+ if (BufferLength == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*BufferLength < sizeof (EFI_MP_PROC_CONTEXT)) {
+ *BufferLength = sizeof (EFI_MP_PROC_CONTEXT);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if ((mMpSystemData->NumberOfCpus <= CpuNumber) || (ProcessorContextBuffer == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMpSystemData->CpuData[CpuNumber];
+
+ *BufferLength = sizeof (EFI_MP_PROC_CONTEXT);
+ ProcessorBuffer = ProcessorContextBuffer;
+
+ ProcessorBuffer->ApicID = CpuData->ApicID;
+
+ ProcessorBuffer->Enabled = TRUE;
+ if (!mMpSystemData->EnableSecondaryCpu) {
+ if (CpuData->SecondaryCpu) {
+ ProcessorBuffer->Enabled = FALSE;
+ }
+ }
+
+ if (CpuData->State == CPU_STATE_DISABLED) {
+ ProcessorBuffer->Enabled = FALSE;
+ }
+
+ if (CpuNumber == mMpSystemData->BSP) {
+ ProcessorBuffer->Designation = EfiCpuBSP;
+ } else {
+ ProcessorBuffer->Designation = EfiCpuAP;
+ }
+
+ ProcessorBuffer->Health.Flags = CpuData->Health;
+ ProcessorBuffer->Health.TestStatus = 0;
+
+ ProcessorBuffer->PackageNumber = CpuData->PhysicalLocation.Package;
+ ProcessorBuffer->NumberOfCores = CpuData->PhysicalLocation.Core;
+ ProcessorBuffer->NumberOfThreads = CpuData->PhysicalLocation.Thread;
+
+ ProcessorBuffer->ProcessorTestMask = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ MP Service to get specified application processor (AP)
+ to execute a caller-provided code stream.
+
+ @param[in] Function The procedure to be assigned to AP.
+ @param[in] CpuNumber Number of the specified processor.
+ @param[in] ProcArguments Argument for Procedure.
+
+ @retval EFI_INVALID_PARAMETER Procudure is NULL.
+ @retval EFI_INVALID_PARAMETER Number of CPU out of range, or it belongs to BSP.
+ @retval EFI_INVALID_PARAMETER Specified CPU is not idle.
+ @retval EFI_SUCCESS The AP has finished.
+ @retval EFI_TIMEOUT Time goes out before the AP has finished.
+
+**/
+EFI_STATUS
+EFIAPI
+StartupThisAP (
+ IN EFI_AP_PROCEDURE Function,
+ IN UINTN CpuNumber,
+ IN OUT VOID *ProcArguments OPTIONAL
+ )
+{
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINT64 *MtrrValues;
+
+ WakeUpBuffer = mMpCpuRuntimeData->AcpiCpuData.WakeUpBuffer;
+ MtrrValues = mMpCpuRuntimeData->MtrrValues;
+ ReadMtrrRegisters (MtrrValues);
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ ExchangeInfo->Lock = 0;
+ ExchangeInfo->ApFunction = (UINT32) Function;
+ ExchangeInfo->ApArgument = (UINT32) ProcArguments;
+ ExchangeInfo->MtrrValuesAddress = (UINT32) MtrrValues;
+ ExchangeInfo->FinishedCount = (UINT32) 0;
+ ExchangeInfo->SerializeLock = (UINT32) 0;
+ ExchangeInfo->StartState = (UINT32) 0;
+ ExchangeInfo->StackStart = (UINTN) ((ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress))->StackAddress;
+
+ //
+ // Send INIT IPI - SIPI to the AP
+ //
+ SendInterrupt (
+ BROADCAST_MODE_SPECIFY_CPU,
+ CpuNumber,
+ 0,
+ DELIVERY_MODE_INIT,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ SendInterrupt (
+ BROADCAST_MODE_SPECIFY_CPU,
+ CpuNumber,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ //
+ // Wait for the AP to complete
+ //
+ while (ExchangeInfo->FinishedCount != 1) {
+ CpuPause ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Wake up all the application processors
+
+ @param[in] Function The procedure to be assigned to AP.
+ @param[in] ProcArguments Argument for Procedure.
+
+ @retval EFI_SUCCESS APs are successfully waked up
+
+**/
+EFI_STATUS
+StartupAllAps (
+ IN EFI_AP_PROCEDURE Function,
+ IN OUT VOID *ProcArguments OPTIONAL
+ )
+{
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINT64 *MtrrValues;
+ UINTN NumberOfCpus;
+
+ WakeUpBuffer = mMpCpuRuntimeData->AcpiCpuData.WakeUpBuffer;
+ MtrrValues = mMpCpuRuntimeData->MtrrValues;
+ ReadMtrrRegisters (MtrrValues);
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ ExchangeInfo->Lock = 0;
+ ExchangeInfo->ApFunction = (UINT32) Function;
+ ExchangeInfo->ApArgument = (UINT32) ProcArguments;
+ ExchangeInfo->MtrrValuesAddress = (UINT32) MtrrValues;
+ ExchangeInfo->FinishedCount = (UINT32) 0;
+ ExchangeInfo->SerializeLock = (UINT32) 0;
+ ExchangeInfo->StackStart = (UINTN) ((ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress))->StackAddress;
+ NumberOfCpus = ((ACPI_CPU_DATA *) (ExchangeInfo->AcpiCpuDataAddress))->NumberOfCpus;
+
+ //
+ // Send INIT IPI - SIPI to all APs
+ //
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ 0,
+ DELIVERY_MODE_INIT,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ MicroSecondDelay (10 * STALL_ONE_MILLI_SECOND); ///< 10ms
+
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+ MicroSecondDelay (200 * STALL_ONE_MICRO_SECOND); ///< 200us
+
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ //
+ // Wait for all APs to complete
+ //
+ DEBUG ((DEBUG_INFO, "FinishedCount = %x, NumberOfCpus = %x\n", ExchangeInfo->FinishedCount, NumberOfCpus));
+ while (ExchangeInfo->FinishedCount < NumberOfCpus - 1) {
+ CpuPause ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ MP Service to makes the current BSP into an AP and then switches the
+ designated AP into the AP. This procedure is usually called after a CPU
+ test that has found that BSP is not healthy to continue it's responsbilities.
+
+ @param[in] CpuNumber The number of the specified AP.
+ @param[in] EnableOldBsp Whether to enable or disable the original BSP.
+
+ @retval EFI_INVALID_PARAMETER Number for Specified AP out of range.
+ @retval EFI_INVALID_PARAMETER Number of specified CPU belongs to BSP.
+ @retval EFI_NOT_READY Specified AP is not idle.
+ @retval EFI_SUCCESS BSP successfully switched.
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchBsp (
+ IN UINTN CpuNumber,
+ IN BOOLEAN EnableOldBsp
+ )
+{
+ EFI_STATUS Status;
+ CPU_DATA_BLOCK *CpuData;
+ CPU_STATE CpuState;
+ UINT64 *MtrrValues;
+
+ MtrrValues = mMpCpuRuntimeData->MtrrValues;
+ ReadMtrrRegisters (MtrrValues);
+
+ //
+ // Check if the specified CPU number is valid
+ //
+ if (CpuNumber >= mMpSystemData->NumberOfCpus) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check if the specified CPU is already BSP
+ //
+ if (CpuNumber == mMpSystemData->BSP) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMpSystemData->CpuData[CpuNumber];
+ if (CpuData->State != CPU_STATE_IDLE) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Before send both BSP and AP to a procedure to exchange their roles,
+ // interrupt must be disabled. This is because during the exchange role
+ // process, 2 CPU may use 1 stack. If interrupt happens, the stack will
+ // be corrputed, since interrupt return address will be pushed to stack
+ // by hardware.
+ //
+ DisableInterrupts ();
+
+ //
+ // Unprogram virtual wire mode for the old BSP
+ //
+ ProgramXApic (FALSE);
+ SetApicBspBit (FALSE);
+
+ mMpSystemData->BspInfo.State = CPU_SWITCH_STATE_IDLE;
+ mMpSystemData->BspInfo.Lock = VacantFlag;
+ mMpSystemData->ApInfo.State = CPU_SWITCH_STATE_IDLE;
+ mMpSystemData->ApInfo.Lock = VacantFlag;
+
+ //
+ // Need to wakeUp AP (future BSP)
+ //
+ WakeUpAPs (MtrrValues, (EFI_AP_PROCEDURE) FutureBspProc);
+
+ AsmExchangeRole (&mMpSystemData->BspInfo, &mMpSystemData->ApInfo);
+
+ //
+ // The new BSP has come out. Since it carries the register value of the AP, need
+ // to pay attention to variable which are stored in registers (due to optimization)
+ //
+ SetApicBspBit (TRUE);
+ ProgramXApic (TRUE);
+
+ EnableInterrupts ();
+
+ CpuData = &mMpSystemData->CpuData[mMpSystemData->BSP];
+ while (TRUE) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuState = CpuData->State;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ if (CpuState == CPU_STATE_FINISHED) {
+ break;
+ }
+ }
+
+ Status = ChangeCpuState (mMpSystemData->BSP, EnableOldBsp, CPU_CAUSE_NOT_DISABLED);
+ mMpSystemData->BSP = CpuNumber;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This procedure enables Or disables APs.
+
+ @param[in] CpuNumber The number of the specified AP.
+ @param[in] NewApState Indicate new desired AP state
+ @param[in] HealthState If not NULL, it points to the value that specifies
+ the new health status of the AP. If it is NULL,
+ this parameter is ignored.
+
+ @retval EFI_INVALID_PARAMETER Input paramters were not correct.
+ @retval EFI_SUCCESS Function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableDisableAp (
+ IN UINTN CpuNumber,
+ IN BOOLEAN NewApState,
+ IN EFI_MP_HEALTH *HealthState OPTIONAL
+ )
+{
+ CPU_DATA_BLOCK *CpuData;
+
+ //
+ // Check for valid input parameters.
+ //
+ if (CpuNumber >= mMpSystemData->NumberOfCpus || CpuNumber == mMpSystemData->BSP) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuData = &mMpSystemData->CpuData[CpuNumber];
+
+ if (HealthState != NULL) {
+ CopyMem (&CpuData->Health, HealthState, sizeof (EFI_MP_HEALTH));
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This procedure returns the calling CPU handle.
+
+ @dot
+ digraph G {
+ subgraph cluster_c0 {
+ node [shape = box];
+ b1[label="GetApicID ()" fontsize=12 style=filled color=lightblue];
+ b2[label="Index + 1" fontsize=12 style=filled color=lightblue];
+ b3[label="*CpuNumber = Index" fontsize=12 style=filled color=lightblue];
+
+ node [shape = ellipse];
+ e1[label="Start" fontsize=12 style=filled color=lightblue];
+ e2[label="End" fontsize=12 style=filled color=lightblue];
+
+ node [shape = diamond,style=filled,color=lightblue];
+ d1[label="Index < NumOfCpus" fontsize=12];
+ d2[label="Is ApicID equal to\n mMpSystemData->CpuData[Index].ApicID" fontsize=12];
+
+ label = "WhoAmI Flow"; fontsize=15; fontcolor=black; color=lightblue;
+ e1 -> b1
+ b1 -> d1
+ d1 -> d2 [label="Yes" fontsize=9]
+ d1 -> b3 [label="No" fontsize=9]
+ d2 -> b3 [label="Yes" fontsize=9]
+ d2 -> b2 [label="No" fontsize=9]
+ b2 -> d1
+ b3 -> e2
+
+ }
+ }
+ @enddot
+
+ @param[out] CpuNumber The number of the specified AP.
+
+ @retval EFI_SUCCESS Function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+WhoAmI (
+ OUT UINTN *CpuNumber
+ )
+{
+ UINTN ApicID;
+ UINTN NumOfCpus;
+ UINTN Index;
+
+ ApicID = GetCpuApicId ();
+ NumOfCpus = mMpSystemData->NumberOfCpus;
+
+ for (Index = 0; Index < NumOfCpus; Index++) {
+ if (ApicID == mMpSystemData->CpuData[Index].ApicID) {
+ break;
+ }
+ }
+ *CpuNumber = Index;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ This function handles CPU MP service task at the end of PEI
+
+ @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
+CpuMpServiceAtEndOfPei (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Send INIT IPI - to all APs
+ //
+ Status = SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ 0,
+ DELIVERY_MODE_INIT,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ return Status;
+}
+
+
+/**
+ AP initialization
+
+**/
+VOID
+InitialMpProcedure (
+ VOID
+ )
+{
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINT64 *MtrrValues;
+ EFI_CPUID_REGISTER CpuidRegisters;
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (mMpCpuRuntimeData->AcpiCpuData.WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ //
+ // Init XMM
+ //
+ XmmInit ();
+
+ MtrrValues = (UINT64 *)ExchangeInfo->MtrrValuesAddress;
+ ProgramXApic (FALSE);
+
+ MpMtrrSynchUp (MtrrValues);
+}
+
+
+/**
+ Get CPU platform features settings to fill MP data.
+
+ @param[in] WakeUpBuffer The address of wakeup buffer.
+ @param[in] StackAddressStart The start address of APs's stacks.
+ @param[in] MaximumCPUsForThisSystem Maximum CPUs in this system.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval Other Error occurred while allocating memory.
+
+**/
+EFI_STATUS
+EFIAPI
+FillMpData (
+ IN UINTN WakeUpBuffer,
+ IN VOID *StackAddressStart,
+ IN UINTN MaximumCPUsForThisSystem
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN HyperThreadingEnabled;
+
+ mMpSystemData = &mMpCpuRuntimeData->MpSystemData;
+
+ //
+ // First check if the MP data structures and AP rendezvous routine have been
+ // supplied by the PEIMs that executed in early boot stage.
+ //
+ //
+ // Clear the data structure area first.
+ //
+ ZeroMem (mMpSystemData, sizeof (MP_SYSTEM_DATA));
+ HyperThreadingEnabled = FALSE;
+
+ mMpCpuRuntimeData->AcpiCpuData.CpuPrivateData = (EFI_PHYSICAL_ADDRESS) (UINTN) (&mMpSystemData->S3DataPointer);
+ mMpCpuRuntimeData->AcpiCpuData.WakeUpBuffer = WakeUpBuffer;
+ mMpCpuRuntimeData->AcpiCpuData.NumberOfCpus = MaximumCPUsForThisSystem;
+ mMpCpuRuntimeData->AcpiCpuData.APState = HyperThreadingEnabled;
+ mMpCpuRuntimeData->AcpiCpuData.StackAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) StackAddressStart;
+
+ Status = PrepareGdtIdtForAP (
+ (IA32_DESCRIPTOR *) (UINTN) mMpCpuRuntimeData->AcpiCpuData.GdtrProfile,
+ (IA32_DESCRIPTOR *) (UINTN) mMpCpuRuntimeData->AcpiCpuData.IdtrProfile
+ );
+
+ //
+ // First BSP fills and inits all known values, including it's own records.
+ //
+ mMpSystemData->ApSerializeLock = VacantFlag;
+ mMpSystemData->NumberOfCpus = MaximumCPUsForThisSystem;
+ mMpSystemData->EnableSecondaryCpu = HyperThreadingEnabled;
+
+ mMpSystemData->VmxEnable = (BOOLEAN) mCpuConfig->VmxEnable;
+ mMpSystemData->TxtEnable = (BOOLEAN) mCpuConfig->SmxEnable;
+ mMpSystemData->MonitorMwaitEnable = (BOOLEAN) mCpuConfig->MonitorMwaitEnable;
+ mMpSystemData->MachineCheckEnable = (BOOLEAN) mCpuConfig->MachineCheckEnable;
+ mMpSystemData->AesEnable = (BOOLEAN) mCpuConfig->AesEnable;
+ mMpSystemData->DebugInterfaceEnable = (BOOLEAN) mCpuConfig->DebugInterfaceEnable;
+ mMpSystemData->DebugInterfaceLockEnable = (BOOLEAN) mCpuConfig->DebugInterfaceLockEnable;
+
+ mMpSystemData->ProcTraceMemSize = mCpuConfig->ProcTraceMemSize;
+ mMpSystemData->ProcTraceEnable = (BOOLEAN) mCpuConfig->ProcTraceEnable;
+ mMpSystemData->ProcTraceOutputScheme = (UINT8) mCpuConfig->ProcTraceOutputScheme;
+ mMpSystemData->HyperThreadingEnable = (BOOLEAN) mCpuConfig->HyperThreading;
+
+ mMpSystemData->S3DataPointer.S3BootScriptTable = (UINT32) (UINTN) mMpSystemData->S3BootScriptTable;
+ mMpSystemData->S3DataPointer.S3BspMtrrTable = (UINT32) (UINTN) mMpSystemData->S3BspMtrrTable;
+
+ mMpSystemData->MaximumCpusForThisSystem = MaximumCPUsForThisSystem;
+
+ mMpSystemData->BSP = 0;
+
+ //
+ // Collect CPU_DATA_BLOCK for BSP. All APs call ones, too.
+ //
+ FillInProcessorInformation (TRUE, 0);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get CPU platform features settings to fill MP data.
+
+ @retval MP_SYSTEM_DATA* Return MpSystemData pointer.
+
+**/
+MP_SYSTEM_DATA *
+EFIAPI
+GetMpSystemData (
+ VOID
+ )
+{
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ WakeUpBuffer = 0x58000;
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ return (MP_SYSTEM_DATA *) (VOID *) ExchangeInfo->MpSystemDataAddress;
+}
+
+
+/**
+ This function is called by all processors (both BSP and AP) once and collects MP related data.
+
+ @param[in] BSP TRUE if the CPU is BSP
+ @param[in] BistParam BIST (build-in self test) data for the processor. This data
+ is only valid for processors that are waked up for the 1ast
+ time in this CPU DXE driver.
+
+ @retval EFI_SUCCESS Data for the processor collected and filled in.
+
+**/
+EFI_STATUS
+FillInProcessorInformation (
+ IN BOOLEAN BSP,
+ IN UINT32 BistParam
+ )
+{
+ UINT32 Health;
+ UINT32 ApicID;
+ CPU_DATA_BLOCK *CpuData;
+ UINT32 BIST;
+ UINTN CpuNumber;
+ ACPI_CPU_DATA *AcpiCpuData;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ AcpiCpuData = &mMpCpuRuntimeData->AcpiCpuData;
+ ApicID = GetCpuApicId ();
+ BIST = 0;
+
+ if (BSP) {
+ CpuNumber = 0;
+ BIST = BistParam;
+ } else {
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (AcpiCpuData->WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+ CpuNumber = ExchangeInfo->BistBuffer[ApicID].Number;
+ BIST = ExchangeInfo->BistBuffer[ApicID].BIST;
+ }
+
+ CpuData = &mMpSystemData->CpuData[CpuNumber];
+ CpuData->SecondaryCpu = IsSecondaryThread ();
+ CpuData->ApicID = ApicID;
+ CpuData->Procedure = NULL;
+ CpuData->Parameter = NULL;
+ CpuData->StateLock = VacantFlag;
+ CpuData->ProcedureLock = VacantFlag;
+ CpuData->State = CPU_STATE_IDLE;
+
+ Health = BIST;
+ if (Health > 0) {
+ CpuData->State = CPU_STATE_DISABLED;
+ mMpSystemData->DisableCause[CpuNumber] = CPU_CAUSE_SELFTEST_FAILURE;
+ } else {
+ mMpSystemData->DisableCause[CpuNumber] = CPU_CAUSE_NOT_DISABLED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Wake up all the application processors
+
+ @param[in] MtrrValues Pointer to a buffer which stored MTRR settings
+ @param[in] Function Pointer to AP Procedure Function
+
+ @retval EFI_SUCCESS APs are successfully waked up
+
+**/
+EFI_STATUS
+WakeUpAPs (
+ UINT64 *MtrrValues,
+ EFI_AP_PROCEDURE Function
+ )
+{
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ MP_CPU_S3_DATA_POINTER *CpuS3DataPtr;
+ ACPI_CPU_DATA *AcpiCpuData;
+
+ AcpiCpuData = &mMpCpuRuntimeData->AcpiCpuData;
+ WakeUpBuffer = AcpiCpuData->WakeUpBuffer;
+ CopyMem (
+ (VOID *) (UINTN) WakeUpBuffer,
+ AsmGetAddressMap (),
+ MP_CPU_EXCHANGE_INFO_OFFSET
+ );
+ AsmPatchRendezvousCode ((VOID *) (UINTN) WakeUpBuffer);
+
+ ExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeUpBuffer + MP_CPU_EXCHANGE_INFO_OFFSET);
+
+ ExchangeInfo->Lock = 0;
+ ExchangeInfo->StackStart = (UINTN) AcpiCpuData->StackAddress;
+ ExchangeInfo->StackSize = STACK_SIZE_PER_PROC;
+ ExchangeInfo->ApFunction = (UINT32) Function;
+ ExchangeInfo->ApArgument = 0;
+ 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->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->CpuPerfCtrlValue = AsmReadMsr64 (MSR_IA32_PERF_CTRL);
+ ExchangeInfo->McuLoadCount = 0;
+ ExchangeInfo->MpSystemDataAddress = (UINT32) &mMpCpuRuntimeData->MpSystemData;
+ ExchangeInfo->MpServicePpiAddress = 0;
+ ExchangeInfo->SiCpuPolicyPpi = mSiCpuPolicyPpi;
+
+ CopyMem (
+ (VOID *) (UINTN) &ExchangeInfo->GdtrProfile,
+ (VOID *) (UINTN) AcpiCpuData->GdtrProfile,
+ sizeof (IA32_DESCRIPTOR)
+ );
+ CopyMem (
+ (VOID *) (UINTN) &ExchangeInfo->IdtrProfile,
+ (VOID *) (UINTN) AcpiCpuData->IdtrProfile,
+ sizeof (IA32_DESCRIPTOR)
+ );
+
+ //
+ // 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
+ );
+
+ MicroSecondDelay (10 * STALL_ONE_MILLI_SECOND); //< 10ms
+
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ MicroSecondDelay (200 * STALL_ONE_MICRO_SECOND); //< 200us
+
+ SendInterrupt (
+ BROADCAST_MODE_ALL_EXCLUDING_SELF,
+ 0,
+ (UINT32) RShiftU64 (WakeUpBuffer, 12),
+ DELIVERY_MODE_SIPI,
+ TRIGGER_MODE_EDGE,
+ TRUE
+ );
+
+ MicroSecondDelay (200 * STALL_ONE_MICRO_SECOND); //< 200us
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ 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;
+
+ //
+ // 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;
+
+ MicroSecondDelay (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;
+}
+
+
+/**
+ Switch BSP to the processor which has least features
+
+ @retval EFI_STATUS Status code returned from each sub-routines
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchToLowestFeatureProcess (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN CurrentProcessor;
+
+ Status = WhoAmI (&CurrentProcessor);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ReportStatusCode (
+ EFI_PROGRESS_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_PC_BSP_SELECT
+ );
+
+ //
+ // Take current BSP as the least feature
+ //
+ UpdateProcessorInfo (CurrentProcessor, &mMpSystemData->LeastFeatureProcessor);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Get processor feature
+
+ @param[in] Features Pointer to a buffer which stores feature information
+
+**/
+VOID
+EFIAPI
+GetProcessorFeatures (
+ IN UINT32 *Features
+ )
+{
+ EFI_CPUID_REGISTER CpuidRegisters;
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ Features[0] = CpuidRegisters.RegEcx;
+ Features[1] = CpuidRegisters.RegEdx;
+ AsmCpuid (
+ CPUID_EXTENDED_CPU_SIG,
+ &CpuidRegisters.RegEax,
+ &CpuidRegisters.RegEbx,
+ &CpuidRegisters.RegEcx,
+ &CpuidRegisters.RegEdx
+ );
+ Features[2] = CpuidRegisters.RegEax;
+ Features[3] = CpuidRegisters.RegEbx;
+ Features[4] = CpuidRegisters.RegEcx;
+ Features[5] = CpuidRegisters.RegEdx;
+
+ return;
+}
+
+
+/**
+ Find out the common features supported by all core/threads
+
+**/
+VOID
+EFIAPI
+GetProcessorCommonFeature (
+ VOID
+ )
+{
+ UINTN Index;
+ UINT32 Features[MAX_FEATURE_NUM];
+
+ GetProcessorFeatures (Features);
+ AsmAcquireMPLock (&mMpSystemData->Lock);
+
+ for (Index = 0; Index < MAX_FEATURE_NUM; Index++) {
+ mMpSystemData->LeastFeatureProcessor.Features[Index] &= Features[Index];
+ }
+ AsmReleaseMPLock (&mMpSystemData->Lock);
+}
+
+
+/**
+ Get the processor data with least features
+
+**/
+VOID
+EFIAPI
+GetProcessorWithLeastFeature (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN CurrentProcessor;
+ LEAST_FEATURE_PROC LeastFeatureProcessor;
+
+ Status = WhoAmI (&CurrentProcessor);
+ ASSERT_EFI_ERROR (Status);
+
+ GetProcessorFeatures (mMpSystemData->LeastFeatureProcessor.Features);
+ LeastFeatureProcessor.FeatureDelta = GetProcessorFeatureDelta (
+ LeastFeatureProcessor.Features,
+ mMpSystemData->LeastFeatureProcessor.Features
+ );
+
+ AsmAcquireMPLock (&mMpSystemData->Lock);
+ if (LeastFeatureProcessor.FeatureDelta < mMpSystemData->LeastFeatureProcessor.FeatureDelta) {
+ mMpSystemData->LeastFeatureProcessor.FeatureDelta = LeastFeatureProcessor.FeatureDelta;
+ UpdateProcessorInfo (CurrentProcessor, &mMpSystemData->LeastFeatureProcessor);
+ } else if (LeastFeatureProcessor.FeatureDelta == mMpSystemData->LeastFeatureProcessor.FeatureDelta) {
+ UpdateProcessorInfo (CurrentProcessor, &LeastFeatureProcessor);
+ if (LeastFeatureProcessor.Version < mMpSystemData->LeastFeatureProcessor.Version) {
+ UpdateProcessorInfo (CurrentProcessor, &mMpSystemData->LeastFeatureProcessor);
+ } else if (LeastFeatureProcessor.Version == mMpSystemData->LeastFeatureProcessor.Version) {
+ if (LeastFeatureProcessor.ApicId < mMpSystemData->LeastFeatureProcessor.ApicId) {
+ UpdateProcessorInfo (CurrentProcessor, &mMpSystemData->LeastFeatureProcessor);
+ }
+ }
+ }
+
+ AsmReleaseMPLock (&mMpSystemData->Lock);
+}
+
+
+/**
+ Extract CPU detail version infomation
+
+ @param[in] FamilyId FamilyId, including ExtendedFamilyId
+ @param[in] Model Model, including ExtendedModel
+ @param[in] SteppingId SteppingId
+ @param[in] Processor Processor
+
+**/
+VOID
+EFIAPI
+EfiCpuVersion (
+ IN OUT UINT16 *FamilyId, OPTIONAL
+ IN OUT UINT8 *Model, OPTIONAL
+ IN OUT UINT8 *SteppingId, OPTIONAL
+ IN OUT UINT8 *Processor OPTIONAL
+ )
+{
+ EFI_CPUID_REGISTER Register;
+ UINT8 TempFamilyId;
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &Register.RegEax,
+ &Register.RegEbx,
+ &Register.RegEcx,
+ &Register.RegEdx
+ );
+
+ if (SteppingId != NULL) {
+ *SteppingId = (UINT8) (Register.RegEax & 0xF);
+ }
+
+ if (Processor != NULL) {
+ *Processor = (UINT8) ((Register.RegEax >> 12) & 0x3);
+ }
+
+ if (Model != NULL || FamilyId != NULL) {
+ TempFamilyId = (UINT8) ((Register.RegEax >> 8) & 0xF);
+
+ if (Model != NULL) {
+ *Model = (UINT8) ((Register.RegEax >> 4) & 0xF);
+ if (TempFamilyId == 0x6 || TempFamilyId == 0xF) {
+ *Model |= (Register.RegEax >> 12) & 0xF0;
+ }
+ }
+
+ if (FamilyId != NULL) {
+ *FamilyId = TempFamilyId;
+ if (TempFamilyId == 0xF) {
+ *FamilyId = *FamilyId + (UINT16) ((Register.RegEax >> 20) & 0xFF);
+ }
+ }
+ }
+}
+
+
+/**
+ Update some processor info into LEAST_FEATURE_PROC data structure.
+
+ @param[in] Index Indicate which processor calling this routine
+ @param[in] LeastFeatureProcessor The data structure that will be updated
+
+**/
+VOID
+EFIAPI
+UpdateProcessorInfo (
+ IN UINTN Index,
+ IN LEAST_FEATURE_PROC *LeastFeatureProcessor
+ )
+{
+ UINT16 FamilyId;
+ UINT8 Model;
+ UINT8 SteppingId;
+
+ EfiCpuVersion (&FamilyId, &Model, &SteppingId, NULL);
+ LeastFeatureProcessor->Index = Index;
+ LeastFeatureProcessor->ApicId = GetCpuApicId ();
+ LeastFeatureProcessor->Version = EfiMakeCpuVersion (FamilyId, Model, SteppingId);
+}
+
+
+/**
+ Get processor feature delta
+
+ @param[in] FeaturesInput Supported features for input processor
+ @param[in] CommonFeatures Supported features for processor (subset of FeaturesInput)
+
+ @retval The least of processor features
+
+**/
+UINT32
+EFIAPI
+GetProcessorFeatureDelta (
+ IN UINT32 *FeaturesInput,
+ IN UINT32 *CommonFeatures
+ )
+{
+ UINT32 Delta;
+ UINTN Index;
+
+ //
+ // CommonFeatures is the subset of FeaturesInput
+ //
+ Delta = 0;
+ for (Index = 0; Index < MAX_FEATURE_NUM; Index++) {
+ Delta += GetBitsNumberOfOne (FeaturesInput[Index] - CommonFeatures[Index]);
+ }
+
+ return 0;
+}
+
+
+/**
+ Calculate how many bits are one from given number
+
+ @param[in] Value Number that will be calculated bits
+
+ @retval Number of bits
+
+**/
+UINT32
+EFIAPI
+GetBitsNumberOfOne (
+ IN UINT32 Value
+ )
+{
+ UINT32 Result;
+
+ Result = 0;
+ while (Value) {
+ if (Value & 1) {
+ Result++;
+ }
+ Value >>= 1;
+ }
+
+ return Result;
+}
+
+
+/**
+ Write 64bits MSR with script
+
+ @param[in] Index MSR index that will be written
+ @param[in] Value Value written to MSR
+
+**/
+VOID
+AsmWriteMsr64WithScript (
+ IN UINT32 Index,
+ IN UINT64 Value
+ )
+{
+ AsmWriteMsr64 (Index, Value);
+ WriteMsr64ToScript (Index, Value);
+}
+
+/**
+ Write 64bits MSR to script
+
+ @param[in] Index MSR index that will be written
+ @param[in] Value Value written to MSR
+
+**/
+VOID
+WriteMsr64ToScript (
+ IN UINT32 Index,
+ IN UINT64 Value
+ )
+{
+ UINTN TableIndex;
+ MP_SYSTEM_DATA *MpSystemData;
+
+ MpSystemData = GetMpSystemData ();
+ if (MpSystemData == NULL) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // Save it into script
+ //
+ AsmAcquireMPLock (&MpSystemData->S3BootScriptLock);
+ TableIndex = MpSystemData->S3BootScriptCount++;
+ AsmReleaseMPLock (&MpSystemData->S3BootScriptLock);
+
+ ASSERT (TableIndex < MAX_CPU_S3_TABLE_SIZE - 1);
+ MpSystemData->S3BootScriptTable[TableIndex].ApicId = GetCpuApicId ();
+ MpSystemData->S3BootScriptTable[TableIndex].MsrIndex = Index;
+ MpSystemData->S3BootScriptTable[TableIndex].MsrValue = Value;
+}
+
+
+/**
+ Set APIC BSP bit
+
+ @param[in] Enable Enable as BSP or not
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+SetApicBspBit (
+ IN BOOLEAN Enable
+ )
+{
+ UINT64 ApicBaseReg;
+
+ ApicBaseReg = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+
+ if (Enable) {
+ ApicBaseReg |= 0x100;
+ } else {
+ ApicBaseReg &= 0xfffffffffffffe00;
+ }
+
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseReg);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Switch current BSP processor to AP
+
+ @param[in] MPSystemData Pointer to the data structure containing MP related data
+
+**/
+VOID
+EFIAPI
+FutureBspProc (
+ VOID
+ )
+{
+ AsmExchangeRole (&mMpSystemData->ApInfo, &mMpSystemData->BspInfo);
+ return;
+}
+
+
+/**
+ Change CPU state
+
+ @param[in] CpuNumber CPU number
+ @param[in] NewState The new state that will be changed to
+ @param[in] Cause Cause
+
+ @retval EFI_SUCCESS Always return success
+
+**/
+EFI_STATUS
+ChangeCpuState (
+ IN UINTN CpuNumber,
+ IN BOOLEAN NewState,
+ IN CPU_STATE_CHANGE_CAUSE Cause
+ )
+{
+ CPU_DATA_BLOCK *CpuData;
+
+ CpuData = &mMpSystemData->CpuData[CpuNumber];
+
+ mMpSystemData->DisableCause[CpuNumber] = Cause;
+
+ if (!NewState) {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_DISABLED;
+ AsmReleaseMPLock (&CpuData->StateLock);
+
+ ReportStatusCode (
+ EFI_ERROR_MINOR | EFI_ERROR_CODE,
+ EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_EC_DISABLED
+ );
+ } else {
+ AsmAcquireMPLock (&CpuData->StateLock);
+ CpuData->State = CPU_STATE_IDLE;
+ AsmReleaseMPLock (&CpuData->StateLock);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.h b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.h new file mode 100644 index 0000000000..16cd80e538 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MpService.h @@ -0,0 +1,211 @@ +/** @file
+ Some definitions for MP services Ppi.
+
+ Copyright (c) 2013 - 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.
+
+**/
+
+#ifndef _MP_SERVICE_H_
+#define _MP_SERVICE_H_
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Private/Library/MpServiceLib.h>
+
+///
+/// Combine f(FamilyId), m(Model), s(SteppingId) to a single 32 bit number
+///
+#define EfiMakeCpuVersion(f, m, s) (((UINT32) (f) << 16) | ((UINT32) (m) << 8) | ((UINT32) (s)))
+
+/**
+ Get CPU platform features settings to fill MP data.
+
+ @param[in] WakeUpBuffer The address of wakeup buffer.
+ @param[in] StackAddressStart The start address of APs's stacks.
+ @param[in] MaximumCPUsForThisSystem Maximum CPUs in this system.
+
+ @retval EFI_SUCCESS Function successfully executed.
+ @retval Other Error occurred while allocating memory.
+
+**/
+EFI_STATUS
+EFIAPI
+FillMpData (
+ IN UINTN WakeUpBuffer,
+ IN VOID *StackAddressStart,
+ IN UINTN MaximumCPUsForThisSystem
+ );
+
+/**
+ This function is called by all processors (both BSP and AP) once and collects MP related data
+
+ @param[in] BSP TRUE if the CPU is BSP
+ @param[in] BistParam BIST (build-in self test) data for the processor. This data
+ is only valid for processors that are waked up for the 1st
+ time in this CPU DXE driver.
+
+ @retval EFI_SUCCESS Data for the processor collected and filled in
+
+**/
+EFI_STATUS
+FillInProcessorInformation (
+ IN BOOLEAN BSP,
+ IN UINT32 BistParam
+ );
+
+/**
+ Notification function that gets called once permanent memory installed to take care
+ of MP CPU related activities in PEI phase
+
+ @param[in] PeiServices Indirect reference to the 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_SUCCESS Multiple processors are intialized successfully
+
+**/
+EFI_STATUS
+InitializeMpSupport (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ );
+
+/**
+ Re-load microcode patch.
+
+ @retval EFI_SUCCESS Multiple processors re-load microcode patch
+
+**/
+EFI_STATUS
+ReloadMicrocode (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo
+ );
+
+/**
+ Get processor feature
+
+ @param[in] Features Pointer to a buffer which stores feature information
+
+**/
+VOID
+EFIAPI
+GetProcessorFeatures (
+ IN UINT32 *Features
+ );
+
+/**
+ Switch BSP to the processor which has least features
+
+ @retval EFI_STATUS Status code returned from each sub-routines
+
+**/
+EFI_STATUS
+EFIAPI
+SwitchToLowestFeatureProcess (
+ VOID
+ );
+
+/**
+ Find out the common features supported by all core/threads
+
+**/
+VOID
+EFIAPI
+GetProcessorCommonFeature (
+ VOID
+ );
+
+/**
+ Get the processor data with least features
+
+**/
+VOID
+EFIAPI
+GetProcessorWithLeastFeature (
+ VOID
+ );
+
+/**
+ Extract CPU detail version infomation
+
+ @param[in] FamilyId FamilyId, including ExtendedFamilyId
+ @param[in] Model Model, including ExtendedModel
+ @param[in] SteppingId SteppingId
+ @param[in] Processor Processor
+
+**/
+VOID
+EFIAPI
+EfiCpuVersion (
+ IN OUT UINT16 *FamilyId, OPTIONAL
+ IN OUT UINT8 *Model, OPTIONAL
+ IN OUT UINT8 *SteppingId, OPTIONAL
+ IN OUT UINT8 *Processor OPTIONAL
+ );
+
+/**
+ Update some processor info into LEAST_FEATURE_PROC data structure.
+
+ @param[in] Index Indicate which processor calling this routine
+ @param[in] LeastFeatureProcessor The data structure that will be updated
+
+**/
+VOID
+EFIAPI
+UpdateProcessorInfo (
+ IN UINTN Index,
+ IN LEAST_FEATURE_PROC *LeastFeatureProcessor
+ );
+
+/**
+ Get processor feature delta
+
+ @param[in] FeaturesInput Supported features for input processor
+ @param[in] CommonFeatures Supported features for processor (subset of FeaturesInput)
+
+ @retval The least of processor features
+
+**/
+UINT32
+EFIAPI
+GetProcessorFeatureDelta (
+ IN UINT32 *FeaturesInput,
+ IN UINT32 *CommonFeatures
+ );
+
+/**
+ Calculate how many bits are one from given number
+
+ @param[in] Value Number that will be calculated bits
+
+ @retval Number of bits
+
+**/
+UINT32
+EFIAPI
+GetBitsNumberOfOne (
+ IN UINT32 Value
+ );
+
+/**
+ Exchange 2 processors (BSP to AP or AP to BSP)
+
+ @param[in] MyInfo CPU info for current processor
+ @param[in] OthersInfo CPU info that will be exchanged with
+
+**/
+VOID
+AsmExchangeRole (
+ IN CPU_EXCHANGE_ROLE_INFO *MyInfo,
+ IN CPU_EXCHANGE_ROLE_INFO *OthersInfo
+ );
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MtrrSync.c b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MtrrSync.c new file mode 100644 index 0000000000..5c33674367 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/MtrrSync.c @@ -0,0 +1,273 @@ +/** @file
+ Synchronization of MTRRs on S3 boot path.
+
+ Copyright (c) 2005 - 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.
+
+**/
+
+///
+/// External include files do NOT need to be explicitly specified in real EDKII
+/// environment
+///
+#include "CpuAccess.h"
+#include <Private/Library/MpServiceLib.h>
+
+UINTN
+MpMtrrSynchUpEntry (
+ VOID
+ );
+
+VOID
+MpMtrrSynchUpExit (
+ UINTN Cr4
+ );
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mFixedMtrrIndex[] = {
+ IA32_MTRR_FIX64K_00000,
+ IA32_MTRR_FIX16K_80000,
+ IA32_MTRR_FIX16K_A0000,
+ IA32_MTRR_FIX4K_C0000,
+ IA32_MTRR_FIX4K_C8000,
+ IA32_MTRR_FIX4K_D0000,
+ IA32_MTRR_FIX4K_D8000,
+ IA32_MTRR_FIX4K_E0000,
+ IA32_MTRR_FIX4K_E8000,
+ IA32_MTRR_FIX4K_F0000,
+ IA32_MTRR_FIX4K_F8000,
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mMtrrDefType[] = { CACHE_IA32_MTRR_DEF_TYPE };
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mVariableMtrrIndex[] = {
+ CACHE_VARIABLE_MTRR_BASE,
+ CACHE_VARIABLE_MTRR_BASE + 1,
+ CACHE_VARIABLE_MTRR_BASE + 2,
+ CACHE_VARIABLE_MTRR_BASE + 3,
+ CACHE_VARIABLE_MTRR_BASE + 4,
+ CACHE_VARIABLE_MTRR_BASE + 5,
+ CACHE_VARIABLE_MTRR_BASE + 6,
+ CACHE_VARIABLE_MTRR_BASE + 7,
+ CACHE_VARIABLE_MTRR_BASE + 8,
+ CACHE_VARIABLE_MTRR_BASE + 9,
+ CACHE_VARIABLE_MTRR_BASE + 10,
+ CACHE_VARIABLE_MTRR_BASE + 11,
+ CACHE_VARIABLE_MTRR_BASE + 12,
+ CACHE_VARIABLE_MTRR_BASE + 13,
+ CACHE_VARIABLE_MTRR_BASE + 14,
+ CACHE_VARIABLE_MTRR_BASE + 15,
+ CACHE_VARIABLE_MTRR_BASE + 16,
+ CACHE_VARIABLE_MTRR_BASE + 17,
+ CACHE_VARIABLE_MTRR_BASE + 18,
+ CACHE_VARIABLE_MTRR_BASE + 19,
+ ///
+ /// CACHE_VARIABLE_MTRR_END,
+ ///
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN FixedMtrrNumber = sizeof (mFixedMtrrIndex) / sizeof (UINT16);
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN MtrrDefTypeNumber = sizeof (mMtrrDefType) / sizeof (UINT16);
+
+/**
+ Save the MTRR registers to global variables
+
+ @param[in] MtrrValues Pointer to the buffer which stores MTRR settings
+
+**/
+VOID
+ReadMtrrRegisters (
+ IN UINT64 *MtrrValues
+ )
+{
+ UINT32 Index;
+ UINT32 VariableMtrrNumber;
+
+ //
+ // Read all Mtrrs
+ //
+ for (Index = 0; Index < FixedMtrrNumber; Index++) {
+ *MtrrValues = AsmReadMsr64 (mFixedMtrrIndex[Index]);
+ MtrrValues++;
+ }
+
+ for (Index = 0; Index < MtrrDefTypeNumber; Index++) {
+ *MtrrValues = AsmReadMsr64 (mMtrrDefType[Index]);
+ MtrrValues++;
+ }
+
+ VariableMtrrNumber = ((UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT));
+ if (VariableMtrrNumber > V_MAXIMUM_VARIABLE_MTRR_NUMBER) {
+ VariableMtrrNumber = V_MAXIMUM_VARIABLE_MTRR_NUMBER;
+ }
+ for (Index = 0; Index < VariableMtrrNumber * 2; Index++) {
+ *MtrrValues = AsmReadMsr64 (mVariableMtrrIndex[Index]);
+ MtrrValues++;
+ }
+
+ return;
+}
+
+
+/**
+ Synch up the MTRR values for all processors
+
+ @param[in] MtrrValues Pointer to the buffer which stores MTRR settings
+
+**/
+VOID
+MpMtrrSynchUp (
+ UINT64 *MtrrValues
+ )
+{
+ UINT32 Index;
+ UINT32 VariableMtrrNumber;
+ UINTN Cr4;
+ UINT64 *FixedMtrr;
+ UINT64 *MtrrDefType;
+ UINT64 *VariableMtrr;
+ UINT64 ValidMtrrAddressMask;
+ EFI_CPUID_REGISTER FeatureInfo;
+ EFI_CPUID_REGISTER FunctionInfo;
+ UINT8 PhysicalAddressBits;
+
+ //
+ // Get physical CPU MTRR width in case of difference from BSP
+ //
+ AsmCpuid (
+ CPUID_EXTENDED_FUNCTION,
+ &FunctionInfo.RegEax,
+ &FunctionInfo.RegEbx,
+ &FunctionInfo.RegEcx,
+ &FunctionInfo.RegEdx
+ );
+ PhysicalAddressBits = 36;
+ if (FunctionInfo.RegEax >= CPUID_VIR_PHY_ADDRESS_SIZE) {
+ AsmCpuid (
+ CPUID_VIR_PHY_ADDRESS_SIZE,
+ &FeatureInfo.RegEax,
+ &FeatureInfo.RegEbx,
+ &FeatureInfo.RegEcx,
+ &FeatureInfo.RegEdx
+ );
+ PhysicalAddressBits = (UINT8) FeatureInfo.RegEax;
+ }
+
+ ValidMtrrAddressMask = (LShiftU64 (1, PhysicalAddressBits) - 1) & 0xfffffffffffff000ULL;
+
+ FixedMtrr = MtrrValues;
+ MtrrDefType = MtrrValues + FixedMtrrNumber;
+ VariableMtrr = MtrrValues + FixedMtrrNumber + MtrrDefTypeNumber;
+
+ //
+ // ASM code to setup processor register before synching up the MTRRs
+ //
+ Cr4 = MpMtrrSynchUpEntry ();
+
+ //
+ // Disable Fixed Mtrrs
+ //
+ AsmWriteMsr64 (CACHE_IA32_MTRR_DEF_TYPE, MtrrDefType[0] & 0xFFFFF7FF);
+
+ //
+ // Update Fixed Mtrrs
+ //
+ for (Index = 0; Index < FixedMtrrNumber; Index++) {
+ AsmWriteMsr64 (mFixedMtrrIndex[Index], FixedMtrr[Index]);
+ }
+ //
+ // Synchup Base Variable Mtrr
+ //
+ VariableMtrrNumber = (UINT32) (AsmReadMsr64 (IA32_MTRR_CAP) & B_IA32_MTRR_VARIABLE_SUPPORT);
+ if (VariableMtrrNumber > V_MAXIMUM_VARIABLE_MTRR_NUMBER) {
+ VariableMtrrNumber = V_MAXIMUM_VARIABLE_MTRR_NUMBER;
+ }
+
+ for (Index = 0; Index < VariableMtrrNumber * 2; Index++) {
+ AsmWriteMsr64 (
+ mVariableMtrrIndex[Index],
+ (VariableMtrr[Index] & 0x0FFF) | (VariableMtrr[Index] & ValidMtrrAddressMask)
+ );
+ }
+ //
+ // Synchup def type Fixed Mtrrs
+ //
+ AsmWriteMsr64 (CACHE_IA32_MTRR_DEF_TYPE, MtrrDefType[0]);
+
+ //
+ // ASM code to setup processor register after synching up the MTRRs
+ //
+ MpMtrrSynchUpExit (Cr4);
+
+ return;
+}
+
+
+/**
+ Set MTRR registers
+
+ @param[in] MtrrArray Buffer with MTRR settings
+
+**/
+VOID
+SetMtrrRegisters (
+ IN EFI_MTRR_VALUES *MtrrArray
+ )
+{
+ UINT32 Index;
+ UINTN Cr4;
+
+ //
+ // ASM code to setup processor register before synching up the MTRRs
+ //
+ Cr4 = MpMtrrSynchUpEntry ();
+
+ Index = 0;
+ while ((MtrrArray[Index].Index != 0) && (MtrrArray[Index].Index >= CACHE_VARIABLE_MTRR_BASE)) {
+ AsmWriteMsr64 (MtrrArray[Index].Index, MtrrArray[Index].Value);
+ Index++;
+ }
+ //
+ // ASM code to setup processor register after synching up the MTRRs
+ //
+ MpMtrrSynchUpExit (Cr4);
+}
+
+
+#ifdef EFI_DEBUG
+/**
+ Print MTRR settings in debug build BIOS
+
+ @param[in] MtrrArray Buffer with MTRR settings
+**/
+VOID
+ShowMtrrRegisters (
+ IN EFI_MTRR_VALUES *MtrrArray
+ )
+{
+ UINT32 Index;
+
+ Index = 0;
+ while ((MtrrArray[Index].Index != 0) && (MtrrArray[Index].Index >= CACHE_VARIABLE_MTRR_BASE)) {
+ DEBUG ((DEBUG_INFO, "MTRR: MtrrArray Index = %x\n", Index));
+ DEBUG (
+ (DEBUG_INFO,
+ "MTRR: MtrrArray[%x].Index = %x MtrrArray[%x].Value = %x\n",
+ Index,
+ MtrrArray[Index].Index,
+ Index,
+ MtrrArray[Index].Value)
+ );
+ Index++;
+ }
+
+ DEBUG ((DEBUG_INFO, "MTRR: Total Index = %x\n", Index));
+}
+#endif
+
diff --git a/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/PeiMpServiceLib.inf b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/PeiMpServiceLib.inf new file mode 100644 index 0000000000..ef76dd49b5 --- /dev/null +++ b/Silicon/BroxtonSoC/BroxtonSiPkg/Cpu/Library/Private/PeiMpServiceLib/PeiMpServiceLib.inf @@ -0,0 +1,65 @@ +## @file
+# Component information file for CPU module.
+#
+# Copyright (c) 2014 - 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.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = PeiMpServiceLib
+ FILE_GUID = 59E4C67A-59A8-4DEA-9072-F9CDB6CA3E2C
+ VERSION_STRING = 1.0
+ MODULE_TYPE = PEIM
+ LIBRARY_CLASS = MpServiceLib
+
+[BuildOptions]
+################################################################################
+#
+# Package Dependency Section - list of Package files that are required for
+# this module.
+#
+################################################################################
+
+
+[LibraryClasses]
+ HobLib
+ CpuPlatformLib
+ DebugLib
+ BaseLib
+ PeiServicesLib
+ BaseMemoryLib
+ SynchronizationLib
+ ReportStatusCodeLib
+ MemoryAllocationLib
+ TimerLib
+ PostCodeLib
+ MtrrLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ BroxtonSiPkg/BroxtonSiPkg.dec
+ BroxtonSiPkg/BroxtonSiPrivate.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[Sources]
+ MtrrSync.c
+ Microcode.c
+ MpService.c
+ Ia32/MpFuncs.asm|MSFT
+ Ia32/MpFuncs.nasm|GCC
+
+[Ppis]
+ gEfiEndOfPeiSignalPpiGuid ## NOTIFY
+
+[Guids]
+ gCpuInitDataHobGuid ## UNDEFINED
+ gMicroCodepointerGuid ## UNDEFINED
|