diff options
author | Jeff Fan <jeff.fan@intel.com> | 2015-08-06 06:57:47 +0000 |
---|---|---|
committer | vanjeff <vanjeff@Edk2> | 2015-08-06 06:57:47 +0000 |
commit | ea0f431cec51247658901a4f65ae76d6bbdd96e9 (patch) | |
tree | 176db392bafca088b2389d79f2883aa08de8be8a | |
parent | 3fd56a2672ede208e44d5bc495339bfb9ba6cd5d (diff) | |
download | edk2-platforms-ea0f431cec51247658901a4f65ae76d6bbdd96e9.tar.xz |
UefiCpuPkg/CpuMpPei: Update files format to DOS
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Jeff Fan <jeff.fan@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18168 6f19259b-4bc3-4df7-8a09-765794883524
-rw-r--r-- | UefiCpuPkg/CpuMpPei/CpuBist.c | 520 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/CpuMpPei.c | 1132 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/CpuMpPei.h | 604 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/CpuMpPei.inf | 180 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc | 80 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm | 552 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm | 510 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/Microcode.c | 400 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/Microcode.h | 136 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/PeiMpServices.c | 1884 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/PeiMpServices.h | 754 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/X64/MpEqu.inc | 90 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm | 668 | ||||
-rw-r--r-- | UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm | 654 |
14 files changed, 4082 insertions, 4082 deletions
diff --git a/UefiCpuPkg/CpuMpPei/CpuBist.c b/UefiCpuPkg/CpuMpPei/CpuBist.c index 579b6b0b24..2bee7a4a66 100644 --- a/UefiCpuPkg/CpuMpPei/CpuBist.c +++ b/UefiCpuPkg/CpuMpPei/CpuBist.c @@ -1,260 +1,260 @@ -/** @file - Update and publish processors' BIST information. - - Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "CpuMpPei.h" - -EFI_SEC_PLATFORM_INFORMATION2_PPI mSecPlatformInformation2Ppi = { - SecPlatformInformation2 -}; - -EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformation2Ppi = { - (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), - &gEfiSecPlatformInformation2PpiGuid, - &mSecPlatformInformation2Ppi -}; - -/** - Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI. - - @param PeiServices The pointer to the PEI Services Table. - @param StructureSize The pointer to the variable describing size of the input buffer. - @param PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2. - - @retval EFI_SUCCESS The data was successfully returned. - @retval EFI_BUFFER_TOO_SMALL The buffer was too small. The current buffer size needed to - hold the record is returned in StructureSize. - -**/ -EFI_STATUS -EFIAPI -SecPlatformInformation2 ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN OUT UINT64 *StructureSize, - OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2 - ) -{ - PEI_CPU_MP_DATA *PeiCpuMpData; - UINTN BistInformationSize; - UINTN CpuIndex; - EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstance; - - PeiCpuMpData = GetMpHobData (); - - BistInformationSize = sizeof (EFI_SEC_PLATFORM_INFORMATION_RECORD2) + - sizeof (EFI_SEC_PLATFORM_INFORMATION_CPU) * PeiCpuMpData->CpuCount; - // - // return the information size if input buffer size is too small - // - if ((*StructureSize) < (UINT64) BistInformationSize) { - *StructureSize = (UINT64) BistInformationSize; - return EFI_BUFFER_TOO_SMALL; - } - - PlatformInformationRecord2->NumberOfCpus = PeiCpuMpData->CpuCount; - CpuInstance = PlatformInformationRecord2->CpuInstance; - for (CpuIndex = 0; CpuIndex < PeiCpuMpData->CpuCount; CpuIndex ++) { - CpuInstance[CpuIndex].CpuLocation = PeiCpuMpData->CpuData[CpuIndex].ApicId; - CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags = PeiCpuMpData->CpuData[CpuIndex].Health; - } - - return EFI_SUCCESS; -} - -/** - Worker function to get CPUs' BIST by calling SecPlatformInformationPpi - or SecPlatformInformation2Ppi. - - @param PeiServices Pointer to PEI Services Table - @param Guid PPI Guid - @param PpiDescriptor Return a pointer to instance of the - EFI_PEI_PPI_DESCRIPTOR - @param BistInformationData Pointer to BIST information data - - @retval EFI_SUCCESS Retrieve of the BIST data successfully - @retval EFI_NOT_FOUND No sec platform information(2) ppi export - @retval EFI_DEVICE_ERROR Failed to get CPU Information - -**/ -EFI_STATUS -GetBistInfoFromPpi ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN CONST EFI_GUID *Guid, - OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor, - OUT VOID **BistInformationData - ) -{ - EFI_STATUS Status; - EFI_SEC_PLATFORM_INFORMATION2_PPI *SecPlatformInformation2Ppi; - EFI_SEC_PLATFORM_INFORMATION_RECORD2 *SecPlatformInformation2; - UINT64 InformationSize; - - Status = PeiServicesLocatePpi ( - Guid, // GUID - 0, // INSTANCE - PpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR - (VOID **)&SecPlatformInformation2Ppi // PPI - ); - if (Status == EFI_NOT_FOUND) { - return EFI_NOT_FOUND; - } - - if (Status == EFI_SUCCESS) { - // - // Get the size of the sec platform information2(BSP/APs' BIST data) - // - InformationSize = 0; - SecPlatformInformation2 = NULL; - Status = SecPlatformInformation2Ppi->PlatformInformation2 ( - PeiServices, - &InformationSize, - SecPlatformInformation2 - ); - if (Status == EFI_BUFFER_TOO_SMALL) { - Status = PeiServicesAllocatePool ( - (UINTN) InformationSize, - (VOID **) &SecPlatformInformation2 - ); - if (Status == EFI_SUCCESS) { - // - // Retrieve BIST data - // - Status = SecPlatformInformation2Ppi->PlatformInformation2 ( - PeiServices, - &InformationSize, - SecPlatformInformation2 - ); - if (Status == EFI_SUCCESS) { - *BistInformationData = SecPlatformInformation2; - return EFI_SUCCESS; - } - } - } - } - - return EFI_DEVICE_ERROR; -} - -/** - Collects BIST data from PPI. - - This function collects BIST data from Sec Platform Information2 PPI - or SEC Platform Information PPI. - - @param PeiServices Pointer to PEI Services Table - @param PeiCpuMpData Pointer to PEI CPU MP Data - -**/ -VOID -CollectBistDataFromPpi ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN PEI_CPU_MP_DATA *PeiCpuMpData - ) -{ - EFI_STATUS Status; - EFI_PEI_PPI_DESCRIPTOR *SecInformationDescriptor; - EFI_SEC_PLATFORM_INFORMATION_RECORD2 *SecPlatformInformation2; - EFI_SEC_PLATFORM_INFORMATION_RECORD *SecPlatformInformation; - UINTN NumberOfData; - EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstance; - EFI_SEC_PLATFORM_INFORMATION_CPU BspCpuInstance; - UINTN ProcessorNumber; - UINTN CpuIndex; - PEI_CPU_DATA *CpuData; - - SecPlatformInformation2 = NULL; - SecPlatformInformation = NULL; - NumberOfData = 0; - CpuInstance = NULL; - - // - // Get BIST information from Sec Platform Information2 Ppi firstly - // - Status = GetBistInfoFromPpi ( - PeiServices, - &gEfiSecPlatformInformation2PpiGuid, - &SecInformationDescriptor, - (VOID *) &SecPlatformInformation2 - ); - if (Status == EFI_SUCCESS) { - // - // Sec Platform Information2 PPI includes BSP/APs' BIST information - // - NumberOfData = SecPlatformInformation2->NumberOfCpus; - CpuInstance = SecPlatformInformation2->CpuInstance; - } else { - // - // Otherwise, get BIST information from Sec Platform Information Ppi - // - Status = GetBistInfoFromPpi ( - PeiServices, - &gEfiSecPlatformInformationPpiGuid, - &SecInformationDescriptor, - (VOID *) &SecPlatformInformation - ); - if (Status == EFI_SUCCESS) { - NumberOfData = 1; - // - // SEC Platform Information only includes BSP's BIST information - // and does not have BSP's APIC ID - // - BspCpuInstance.CpuLocation = GetInitialApicId (); - BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32 = SecPlatformInformation->IA32HealthFlags.Uint32; - CpuInstance = &BspCpuInstance; - } else { - DEBUG ((EFI_D_INFO, "Does not find any stored CPU BIST information from PPI!\n")); - } - } - for (ProcessorNumber = 0; ProcessorNumber < PeiCpuMpData->CpuCount; ProcessorNumber ++) { - CpuData = &PeiCpuMpData->CpuData[ProcessorNumber]; - for (CpuIndex = 0; CpuIndex < NumberOfData; CpuIndex ++) { - ASSERT (CpuInstance != NULL); - if (CpuData->ApicId == CpuInstance[CpuIndex].CpuLocation) { - // - // Update processor's BIST data if it is already stored before - // - CpuData->Health = CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags; - } - } - if (CpuData->Health.Uint32 != 0) { - // - // Report Status Code that self test is failed - // - REPORT_STATUS_CODE ( - EFI_ERROR_CODE | EFI_ERROR_MAJOR, - (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST) - ); - } - DEBUG ((EFI_D_INFO, " APICID - 0x%08x, BIST - 0x%08x\n", - PeiCpuMpData->CpuData[ProcessorNumber].ApicId, - PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 - )); - } - - if (SecPlatformInformation2 != NULL && NumberOfData < PeiCpuMpData->CpuCount) { - // - // Reinstall SecPlatformInformation2 PPI to include new BIST inforamtion - // - Status = PeiServicesReInstallPpi ( - SecInformationDescriptor, - &mPeiSecPlatformInformation2Ppi - ); - ASSERT_EFI_ERROR (Status); - } else { - // - // Install SecPlatformInformation2 PPI to include new BIST inforamtion - // - Status = PeiServicesInstallPpi (&mPeiSecPlatformInformation2Ppi); - ASSERT_EFI_ERROR(Status); - } -} +/** @file
+ Update and publish processors' BIST information.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "CpuMpPei.h"
+
+EFI_SEC_PLATFORM_INFORMATION2_PPI mSecPlatformInformation2Ppi = {
+ SecPlatformInformation2
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPeiSecPlatformInformation2Ppi = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiSecPlatformInformation2PpiGuid,
+ &mSecPlatformInformation2Ppi
+};
+
+/**
+ Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI.
+
+ @param PeiServices The pointer to the PEI Services Table.
+ @param StructureSize The pointer to the variable describing size of the input buffer.
+ @param PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2.
+
+ @retval EFI_SUCCESS The data was successfully returned.
+ @retval EFI_BUFFER_TOO_SMALL The buffer was too small. The current buffer size needed to
+ hold the record is returned in StructureSize.
+
+**/
+EFI_STATUS
+EFIAPI
+SecPlatformInformation2 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT UINT64 *StructureSize,
+ OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN BistInformationSize;
+ UINTN CpuIndex;
+ EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstance;
+
+ PeiCpuMpData = GetMpHobData ();
+
+ BistInformationSize = sizeof (EFI_SEC_PLATFORM_INFORMATION_RECORD2) +
+ sizeof (EFI_SEC_PLATFORM_INFORMATION_CPU) * PeiCpuMpData->CpuCount;
+ //
+ // return the information size if input buffer size is too small
+ //
+ if ((*StructureSize) < (UINT64) BistInformationSize) {
+ *StructureSize = (UINT64) BistInformationSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ PlatformInformationRecord2->NumberOfCpus = PeiCpuMpData->CpuCount;
+ CpuInstance = PlatformInformationRecord2->CpuInstance;
+ for (CpuIndex = 0; CpuIndex < PeiCpuMpData->CpuCount; CpuIndex ++) {
+ CpuInstance[CpuIndex].CpuLocation = PeiCpuMpData->CpuData[CpuIndex].ApicId;
+ CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags = PeiCpuMpData->CpuData[CpuIndex].Health;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Worker function to get CPUs' BIST by calling SecPlatformInformationPpi
+ or SecPlatformInformation2Ppi.
+
+ @param PeiServices Pointer to PEI Services Table
+ @param Guid PPI Guid
+ @param PpiDescriptor Return a pointer to instance of the
+ EFI_PEI_PPI_DESCRIPTOR
+ @param BistInformationData Pointer to BIST information data
+
+ @retval EFI_SUCCESS Retrieve of the BIST data successfully
+ @retval EFI_NOT_FOUND No sec platform information(2) ppi export
+ @retval EFI_DEVICE_ERROR Failed to get CPU Information
+
+**/
+EFI_STATUS
+GetBistInfoFromPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN CONST EFI_GUID *Guid,
+ OUT EFI_PEI_PPI_DESCRIPTOR **PpiDescriptor,
+ OUT VOID **BistInformationData
+ )
+{
+ EFI_STATUS Status;
+ EFI_SEC_PLATFORM_INFORMATION2_PPI *SecPlatformInformation2Ppi;
+ EFI_SEC_PLATFORM_INFORMATION_RECORD2 *SecPlatformInformation2;
+ UINT64 InformationSize;
+
+ Status = PeiServicesLocatePpi (
+ Guid, // GUID
+ 0, // INSTANCE
+ PpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR
+ (VOID **)&SecPlatformInformation2Ppi // PPI
+ );
+ if (Status == EFI_NOT_FOUND) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (Status == EFI_SUCCESS) {
+ //
+ // Get the size of the sec platform information2(BSP/APs' BIST data)
+ //
+ InformationSize = 0;
+ SecPlatformInformation2 = NULL;
+ Status = SecPlatformInformation2Ppi->PlatformInformation2 (
+ PeiServices,
+ &InformationSize,
+ SecPlatformInformation2
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Status = PeiServicesAllocatePool (
+ (UINTN) InformationSize,
+ (VOID **) &SecPlatformInformation2
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // Retrieve BIST data
+ //
+ Status = SecPlatformInformation2Ppi->PlatformInformation2 (
+ PeiServices,
+ &InformationSize,
+ SecPlatformInformation2
+ );
+ if (Status == EFI_SUCCESS) {
+ *BistInformationData = SecPlatformInformation2;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ Collects BIST data from PPI.
+
+ This function collects BIST data from Sec Platform Information2 PPI
+ or SEC Platform Information PPI.
+
+ @param PeiServices Pointer to PEI Services Table
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+
+**/
+VOID
+CollectBistDataFromPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_PPI_DESCRIPTOR *SecInformationDescriptor;
+ EFI_SEC_PLATFORM_INFORMATION_RECORD2 *SecPlatformInformation2;
+ EFI_SEC_PLATFORM_INFORMATION_RECORD *SecPlatformInformation;
+ UINTN NumberOfData;
+ EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstance;
+ EFI_SEC_PLATFORM_INFORMATION_CPU BspCpuInstance;
+ UINTN ProcessorNumber;
+ UINTN CpuIndex;
+ PEI_CPU_DATA *CpuData;
+
+ SecPlatformInformation2 = NULL;
+ SecPlatformInformation = NULL;
+ NumberOfData = 0;
+ CpuInstance = NULL;
+
+ //
+ // Get BIST information from Sec Platform Information2 Ppi firstly
+ //
+ Status = GetBistInfoFromPpi (
+ PeiServices,
+ &gEfiSecPlatformInformation2PpiGuid,
+ &SecInformationDescriptor,
+ (VOID *) &SecPlatformInformation2
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // Sec Platform Information2 PPI includes BSP/APs' BIST information
+ //
+ NumberOfData = SecPlatformInformation2->NumberOfCpus;
+ CpuInstance = SecPlatformInformation2->CpuInstance;
+ } else {
+ //
+ // Otherwise, get BIST information from Sec Platform Information Ppi
+ //
+ Status = GetBistInfoFromPpi (
+ PeiServices,
+ &gEfiSecPlatformInformationPpiGuid,
+ &SecInformationDescriptor,
+ (VOID *) &SecPlatformInformation
+ );
+ if (Status == EFI_SUCCESS) {
+ NumberOfData = 1;
+ //
+ // SEC Platform Information only includes BSP's BIST information
+ // and does not have BSP's APIC ID
+ //
+ BspCpuInstance.CpuLocation = GetInitialApicId ();
+ BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32 = SecPlatformInformation->IA32HealthFlags.Uint32;
+ CpuInstance = &BspCpuInstance;
+ } else {
+ DEBUG ((EFI_D_INFO, "Does not find any stored CPU BIST information from PPI!\n"));
+ }
+ }
+ for (ProcessorNumber = 0; ProcessorNumber < PeiCpuMpData->CpuCount; ProcessorNumber ++) {
+ CpuData = &PeiCpuMpData->CpuData[ProcessorNumber];
+ for (CpuIndex = 0; CpuIndex < NumberOfData; CpuIndex ++) {
+ ASSERT (CpuInstance != NULL);
+ if (CpuData->ApicId == CpuInstance[CpuIndex].CpuLocation) {
+ //
+ // Update processor's BIST data if it is already stored before
+ //
+ CpuData->Health = CpuInstance[CpuIndex].InfoRecord.IA32HealthFlags;
+ }
+ }
+ if (CpuData->Health.Uint32 != 0) {
+ //
+ // Report Status Code that self test is failed
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MAJOR,
+ (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST)
+ );
+ }
+ DEBUG ((EFI_D_INFO, " APICID - 0x%08x, BIST - 0x%08x\n",
+ PeiCpuMpData->CpuData[ProcessorNumber].ApicId,
+ PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32
+ ));
+ }
+
+ if (SecPlatformInformation2 != NULL && NumberOfData < PeiCpuMpData->CpuCount) {
+ //
+ // Reinstall SecPlatformInformation2 PPI to include new BIST inforamtion
+ //
+ Status = PeiServicesReInstallPpi (
+ SecInformationDescriptor,
+ &mPeiSecPlatformInformation2Ppi
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // Install SecPlatformInformation2 PPI to include new BIST inforamtion
+ //
+ Status = PeiServicesInstallPpi (&mPeiSecPlatformInformation2Ppi);
+ ASSERT_EFI_ERROR(Status);
+ }
+}
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.c b/UefiCpuPkg/CpuMpPei/CpuMpPei.c index 97b7e99c9a..d5aee86d11 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.c +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.c @@ -1,566 +1,566 @@ -/** @file - CPU PEI Module installs CPU Multiple Processor PPI. - - Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "CpuMpPei.h" - -// -// Global Descriptor Table (GDT) -// -GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = { -/* selector { Global Segment Descriptor } */ -/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor -/* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor -/* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor -/* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor -/* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor -/* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor -/* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor -/* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor -/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor -}; - -// -// IA32 Gdt register -// -GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = { - sizeof (mGdtEntries) - 1, - (UINTN) mGdtEntries - }; - -GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = { - (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), - &gEfiEndOfPeiSignalPpiGuid, - CpuMpEndOfPeiCallback -}; - -/** - Sort the APIC ID of all processors. - - This function sorts the APIC ID of all processors so that processor number is - assigned in the ascending order of APIC ID which eases MP debugging. - - @param PeiCpuMpData Pointer to PEI CPU MP Data -**/ -VOID -SortApicId ( - IN PEI_CPU_MP_DATA *PeiCpuMpData - ) -{ - UINTN Index1; - UINTN Index2; - UINTN Index3; - UINT32 ApicId; - EFI_HEALTH_FLAGS Health; - UINT32 ApCount; - - ApCount = PeiCpuMpData->CpuCount - 1; - - if (ApCount != 0) { - for (Index1 = 0; Index1 < ApCount; Index1++) { - Index3 = Index1; - // - // Sort key is the hardware default APIC ID - // - ApicId = PeiCpuMpData->CpuData[Index1].ApicId; - for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) { - if (ApicId > PeiCpuMpData->CpuData[Index2].ApicId) { - Index3 = Index2; - ApicId = PeiCpuMpData->CpuData[Index2].ApicId; - } - } - if (Index3 != Index1) { - PeiCpuMpData->CpuData[Index3].ApicId = PeiCpuMpData->CpuData[Index1].ApicId; - PeiCpuMpData->CpuData[Index1].ApicId = ApicId; - Health = PeiCpuMpData->CpuData[Index3].Health; - PeiCpuMpData->CpuData[Index3].Health = PeiCpuMpData->CpuData[Index1].Health; - PeiCpuMpData->CpuData[Index1].Health = Health; - } - } - - // - // Get the processor number for the BSP - // - ApicId = GetInitialApicId (); - for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) { - if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) { - PeiCpuMpData->BspNumber = (UINT32) Index1; - break; - } - } - } -} - -/** - Get CPU MP Data pointer from the Guided HOB. - - @return Pointer to Pointer to PEI CPU MP Data -**/ -PEI_CPU_MP_DATA * -GetMpHobData ( - VOID - ) -{ - EFI_HOB_GUID_TYPE *GuidHob; - VOID *DataInHob; - PEI_CPU_MP_DATA *CpuMpData; - - CpuMpData = NULL; - GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid); - if (GuidHob != NULL) { - DataInHob = GET_GUID_HOB_DATA (GuidHob); - CpuMpData = (PEI_CPU_MP_DATA *)(*(UINTN *)DataInHob); - } - ASSERT (CpuMpData != NULL); - return CpuMpData; -} - -/** - This function will be called from AP reset code if BSP uses WakeUpAP. - - @param ExchangeInfo Pointer to the MP exchange info buffer - @param NumApsExecuting Number of curret executing AP -**/ -VOID -EFIAPI -ApCFunction ( - IN MP_CPU_EXCHANGE_INFO *ExchangeInfo, - IN UINTN NumApsExecuting - ) -{ - PEI_CPU_MP_DATA *PeiCpuMpData; - UINTN ProcessorNumber; - EFI_AP_PROCEDURE Procedure; - UINTN BistData; - - PeiCpuMpData = ExchangeInfo->PeiCpuMpData; - if (PeiCpuMpData->InitFlag) { - // - // This is first time AP wakeup, get BIST inforamtion from AP stack - // - BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN)); - PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId (); - PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData; - // - // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs. - // - MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable); - MicrocodeDetect (); - } else { - // - // Execute AP function if AP is not disabled - // - GetProcessorNumber (PeiCpuMpData, &ProcessorNumber); - if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) && - (PeiCpuMpData->ApFunction != 0)) { - PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy; - Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction; - Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument); - PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; - } - } - - // - // AP finished executing C code - // - InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount); - - AsmCliHltLoop (); -} - -/** - This function will be called by BSP to wakeup AP. - - @param PeiCpuMpData Pointer to PEI CPU MP Data - @param Broadcast TRUE: Send broadcast IPI to all APs - FALSE: Send IPI to AP by ApicId - @param ApicId Apic ID for the processor to be waked - @param Procedure The function to be invoked by AP - @param ProcedureArgument The argument to be passed into AP function -**/ -VOID -WakeUpAP ( - IN PEI_CPU_MP_DATA *PeiCpuMpData, - IN BOOLEAN Broadcast, - IN UINT32 ApicId, - IN EFI_AP_PROCEDURE Procedure, OPTIONAL - IN VOID *ProcedureArgument OPTIONAL - ) -{ - volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo; - - PeiCpuMpData->ApFunction = (UINTN) Procedure; - PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument; - PeiCpuMpData->FinishedCount = 0; - - ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo; - ExchangeInfo->Lock = 0; - ExchangeInfo->StackStart = PeiCpuMpData->Buffer; - ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize; - ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer; - ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset; - ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset; - ExchangeInfo->Cr3 = AsmReadCr3 (); - ExchangeInfo->CFunction = (UINTN) ApCFunction; - ExchangeInfo->NumApsExecuting = 0; - ExchangeInfo->PeiCpuMpData = PeiCpuMpData; - - // - // Get the BSP's data of GDT and IDT - // - CopyMem ((VOID *)&ExchangeInfo->GdtrProfile, &mGdt, sizeof(mGdt)); - AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile); - - if (Broadcast) { - SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart); - } else { - SendInitSipiSipi (ApicId, (UINT32) ExchangeInfo->BufferStart); - } - - return ; -} - -/** - Get available system memory below 1MB by specified size. - - @param WakeupBufferSize Wakeup buffer size required - - @retval other Return wakeup buffer address below 1MB. - @retval -1 Cannot find free memory below 1MB. -**/ -UINTN -GetWakeupBuffer ( - IN UINTN WakeupBufferSize - ) -{ - EFI_PEI_HOB_POINTERS Hob; - UINTN WakeupBufferStart; - UINTN WakeupBufferEnd; - - // - // Get the HOB list for processing - // - Hob.Raw = GetHobList (); - - // - // Collect memory ranges - // - while (!END_OF_HOB_LIST (Hob)) { - if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) { - if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) && - (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) && - ((Hob.ResourceDescriptor->ResourceAttribute & - (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED | - EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED | - EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED - )) == 0) - ) { - // - // Need memory under 1MB to be collected here - // - WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength); - if (WakeupBufferEnd > BASE_1MB) { - // - // Wakeup buffer should be under 1MB - // - WakeupBufferEnd = BASE_1MB; - } - // - // Wakeup buffer should be aligned on 4KB - // - WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1); - if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) { - continue; - } - // - // Create a memory allocation HOB. - // - BuildMemoryAllocationHob ( - WakeupBufferStart, - WakeupBufferSize, - EfiBootServicesData - ); - return WakeupBufferStart; - } - } - // - // Find the next HOB - // - Hob.Raw = GET_NEXT_HOB (Hob); - } - - return (UINTN) -1; -} - -/** - Get available system memory below 1MB by specified size. - - @param PeiCpuMpData Pointer to PEI CPU MP Data -**/ -VOID -BackupAndPrepareWakeupBuffer( - IN PEI_CPU_MP_DATA *PeiCpuMpData - ) -{ - CopyMem ( - (VOID *) PeiCpuMpData->BackupBuffer, - (VOID *) PeiCpuMpData->WakeupBuffer, - PeiCpuMpData->BackupBufferSize - ); - CopyMem ( - (VOID *) PeiCpuMpData->WakeupBuffer, - (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress, - PeiCpuMpData->AddressMap.RendezvousFunnelSize - ); -} - -/** - Restore wakeup buffer data. - - @param PeiCpuMpData Pointer to PEI CPU MP Data -**/ -VOID -RestoreWakeupBuffer( - IN PEI_CPU_MP_DATA *PeiCpuMpData - ) -{ - CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize); -} - -/** - This function will get CPU count in the system. - - @param PeiCpuMpData Pointer to PEI CPU MP Data - - @return AP processor count -**/ -UINT32 -CountProcessorNumber ( - IN PEI_CPU_MP_DATA *PeiCpuMpData - ) -{ - // - // Load Microcode on BSP - // - MicrocodeDetect (); - // - // Store BSP's MTRR setting - // - MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable); - // - // Send broadcast IPI to APs to wakeup APs - // - PeiCpuMpData->InitFlag = 1; - WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL); - // - // Wait for AP task to complete and then exit. - // - MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)); - PeiCpuMpData->InitFlag = 0; - PeiCpuMpData->CpuCount += (UINT32) PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting; - // - // Sort BSP/Aps by CPU APIC ID in ascending order - // - SortApicId (PeiCpuMpData); - - DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount)); - return PeiCpuMpData->CpuCount; -} - -/** - Prepare for AP wakeup buffer and copy AP reset code into it. - - Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack. - - @return Pointer to PEI CPU MP Data -**/ -PEI_CPU_MP_DATA * -PrepareAPStartupVector ( - VOID - ) -{ - EFI_STATUS Status; - UINT32 MaxCpuCount; - PEI_CPU_MP_DATA *PeiCpuMpData; - EFI_PHYSICAL_ADDRESS Buffer; - UINTN BufferSize; - UINTN WakeupBuffer; - UINTN WakeupBufferSize; - MP_ASSEMBLY_ADDRESS_MAP AddressMap; - - AsmGetAddressMap (&AddressMap); - WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO); - WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1)); - ASSERT (WakeupBuffer != (UINTN) -1); - DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer)); - - // - // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer - // - MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber); - BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA) - + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount; - Status = PeiServicesAllocatePages ( - EfiBootServicesData, - EFI_SIZE_TO_PAGES (BufferSize), - &Buffer - ); - ASSERT_EFI_ERROR (Status); - - PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount); - PeiCpuMpData->Buffer = (UINTN) Buffer; - PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize); - PeiCpuMpData->WakeupBuffer = WakeupBuffer; - PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA); - PeiCpuMpData->BackupBufferSize = WakeupBufferSize; - PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize); - - PeiCpuMpData->CpuCount = 1; - PeiCpuMpData->BspNumber = 0; - PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->MpCpuExchangeInfo + 1); - PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId (); - PeiCpuMpData->CpuData[0].Health.Uint32 = 0; - PeiCpuMpData->EndOfPeiFlag = FALSE; - CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP)); - - // - // Backup original data and copy AP reset code in it - // - BackupAndPrepareWakeupBuffer(PeiCpuMpData); - - return PeiCpuMpData; -} - -/** - Notify function on End Of Pei PPI. - - On S3 boot, this function will restore wakeup buffer data. - On normal boot, this function will flag wakeup buffer to be un-used type. - - @param PeiServices The pointer to the PEI Services Table. - @param NotifyDescriptor Address of the notification descriptor data structure. - @param Ppi Address of the PPI that was installed. - - @retval EFI_SUCCESS When everything is OK. - -**/ -EFI_STATUS -EFIAPI -CpuMpEndOfPeiCallback ( - IN EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, - IN VOID *Ppi - ) -{ - EFI_STATUS Status; - EFI_BOOT_MODE BootMode; - PEI_CPU_MP_DATA *PeiCpuMpData; - EFI_PEI_HOB_POINTERS Hob; - EFI_HOB_MEMORY_ALLOCATION *MemoryHob; - - DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invokded\n")); - - Status = PeiServicesGetBootMode (&BootMode); - ASSERT_EFI_ERROR (Status); - - PeiCpuMpData = GetMpHobData (); - ASSERT (PeiCpuMpData != NULL); - - if (BootMode != BOOT_ON_S3_RESUME) { - // - // Get the HOB list for processing - // - Hob.Raw = GetHobList (); - // - // Collect memory ranges - // - while (!END_OF_HOB_LIST (Hob)) { - if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) { - MemoryHob = Hob.MemoryAllocation; - if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) { - // - // Flag this HOB type to un-used - // - GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED; - break; - } - } - Hob.Raw = GET_NEXT_HOB (Hob); - } - } else { - RestoreWakeupBuffer (PeiCpuMpData); - PeiCpuMpData->EndOfPeiFlag = TRUE; - } - return EFI_SUCCESS; -} - -/** - The Entry point of the MP CPU PEIM. - - This function will wakeup APs and collect CPU AP count and install the - Mp Service Ppi. - - @param FileHandle Handle of the file being invoked. - @param PeiServices Describes the list of possible PEI Services. - - @retval EFI_SUCCESS MpServicePpi is installed successfully. - -**/ -EFI_STATUS -EFIAPI -CpuMpPeimInit ( - IN EFI_PEI_FILE_HANDLE FileHandle, - IN CONST EFI_PEI_SERVICES **PeiServices - ) -{ - EFI_STATUS Status; - PEI_CPU_MP_DATA *PeiCpuMpData; - UINT32 ProcessorCount; - - // - // Load new GDT table on BSP - // - AsmInitializeGdt (&mGdt); - // - // Get wakeup buffer and copy AP reset code in it - // - PeiCpuMpData = PrepareAPStartupVector (); - // - // Count processor number and collect processor information - // - ProcessorCount = CountProcessorNumber (PeiCpuMpData); - // - // Build location of PEI CPU MP DATA buffer in HOB - // - BuildGuidDataHob ( - &gEfiCallerIdGuid, - (VOID *)&PeiCpuMpData, - sizeof(UINT64) - ); - // - // Update and publish CPU BIST information - // - CollectBistDataFromPpi (PeiServices, PeiCpuMpData); - // - // register an event for EndOfPei - // - Status = PeiServicesNotifyPpi (&mNotifyList); - ASSERT_EFI_ERROR (Status); - // - // Install CPU MP PPI - // - Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc); - ASSERT_EFI_ERROR (Status); - - return Status; -} +/** @file
+ CPU PEI Module installs CPU Multiple Processor PPI.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "CpuMpPei.h"
+
+//
+// Global Descriptor Table (GDT)
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
+/* selector { Global Segment Descriptor } */
+/* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //null descriptor
+/* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear data segment descriptor
+/* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //linear code segment descriptor
+/* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
+/* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system code segment descriptor
+/* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+/* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, //system data segment descriptor
+/* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, //system code segment descriptor
+/* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, //spare segment descriptor
+};
+
+//
+// IA32 Gdt register
+//
+GLOBAL_REMOVE_IF_UNREFERENCED IA32_DESCRIPTOR mGdt = {
+ sizeof (mGdtEntries) - 1,
+ (UINTN) mGdtEntries
+ };
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_PEI_NOTIFY_DESCRIPTOR mNotifyList = {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiEndOfPeiSignalPpiGuid,
+ CpuMpEndOfPeiCallback
+};
+
+/**
+ Sort the APIC ID of all processors.
+
+ This function sorts the APIC ID of all processors so that processor number is
+ assigned in the ascending order of APIC ID which eases MP debugging.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+SortApicId (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ )
+{
+ UINTN Index1;
+ UINTN Index2;
+ UINTN Index3;
+ UINT32 ApicId;
+ EFI_HEALTH_FLAGS Health;
+ UINT32 ApCount;
+
+ ApCount = PeiCpuMpData->CpuCount - 1;
+
+ if (ApCount != 0) {
+ for (Index1 = 0; Index1 < ApCount; Index1++) {
+ Index3 = Index1;
+ //
+ // Sort key is the hardware default APIC ID
+ //
+ ApicId = PeiCpuMpData->CpuData[Index1].ApicId;
+ for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
+ if (ApicId > PeiCpuMpData->CpuData[Index2].ApicId) {
+ Index3 = Index2;
+ ApicId = PeiCpuMpData->CpuData[Index2].ApicId;
+ }
+ }
+ if (Index3 != Index1) {
+ PeiCpuMpData->CpuData[Index3].ApicId = PeiCpuMpData->CpuData[Index1].ApicId;
+ PeiCpuMpData->CpuData[Index1].ApicId = ApicId;
+ Health = PeiCpuMpData->CpuData[Index3].Health;
+ PeiCpuMpData->CpuData[Index3].Health = PeiCpuMpData->CpuData[Index1].Health;
+ PeiCpuMpData->CpuData[Index1].Health = Health;
+ }
+ }
+
+ //
+ // Get the processor number for the BSP
+ //
+ ApicId = GetInitialApicId ();
+ for (Index1 = 0; Index1 < PeiCpuMpData->CpuCount; Index1++) {
+ if (PeiCpuMpData->CpuData[Index1].ApicId == ApicId) {
+ PeiCpuMpData->BspNumber = (UINT32) Index1;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ Get CPU MP Data pointer from the Guided HOB.
+
+ @return Pointer to Pointer to PEI CPU MP Data
+**/
+PEI_CPU_MP_DATA *
+GetMpHobData (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *DataInHob;
+ PEI_CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = NULL;
+ GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
+ if (GuidHob != NULL) {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ CpuMpData = (PEI_CPU_MP_DATA *)(*(UINTN *)DataInHob);
+ }
+ ASSERT (CpuMpData != NULL);
+ return CpuMpData;
+}
+
+/**
+ This function will be called from AP reset code if BSP uses WakeUpAP.
+
+ @param ExchangeInfo Pointer to the MP exchange info buffer
+ @param NumApsExecuting Number of curret executing AP
+**/
+VOID
+EFIAPI
+ApCFunction (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN UINTN NumApsExecuting
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN ProcessorNumber;
+ EFI_AP_PROCEDURE Procedure;
+ UINTN BistData;
+
+ PeiCpuMpData = ExchangeInfo->PeiCpuMpData;
+ if (PeiCpuMpData->InitFlag) {
+ //
+ // This is first time AP wakeup, get BIST inforamtion from AP stack
+ //
+ BistData = *(UINTN *) (PeiCpuMpData->Buffer + NumApsExecuting * PeiCpuMpData->CpuApStackSize - sizeof (UINTN));
+ PeiCpuMpData->CpuData[NumApsExecuting].ApicId = GetInitialApicId ();
+ PeiCpuMpData->CpuData[NumApsExecuting].Health.Uint32 = (UINT32) BistData;
+ //
+ // Sync BSP's Mtrr table to all wakeup APs and load microcode on APs.
+ //
+ MtrrSetAllMtrrs (&PeiCpuMpData->MtrrTable);
+ MicrocodeDetect ();
+ } else {
+ //
+ // Execute AP function if AP is not disabled
+ //
+ GetProcessorNumber (PeiCpuMpData, &ProcessorNumber);
+ if ((PeiCpuMpData->CpuData[ProcessorNumber].State != CpuStateDisabled) &&
+ (PeiCpuMpData->ApFunction != 0)) {
+ PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateBusy;
+ Procedure = (EFI_AP_PROCEDURE)(UINTN)PeiCpuMpData->ApFunction;
+ Procedure ((VOID *)(UINTN)PeiCpuMpData->ApFunctionArgument);
+ PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
+ }
+ }
+
+ //
+ // AP finished executing C code
+ //
+ InterlockedIncrement ((UINT32 *)&PeiCpuMpData->FinishedCount);
+
+ AsmCliHltLoop ();
+}
+
+/**
+ This function will be called by BSP to wakeup AP.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param ApicId Apic ID for the processor to be waked
+ @param Procedure The function to be invoked by AP
+ @param ProcedureArgument The argument to be passed into AP function
+**/
+VOID
+WakeUpAP (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINT32 ApicId,
+ IN EFI_AP_PROCEDURE Procedure, OPTIONAL
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+
+ PeiCpuMpData->ApFunction = (UINTN) Procedure;
+ PeiCpuMpData->ApFunctionArgument = (UINTN) ProcedureArgument;
+ PeiCpuMpData->FinishedCount = 0;
+
+ ExchangeInfo = PeiCpuMpData->MpCpuExchangeInfo;
+ ExchangeInfo->Lock = 0;
+ ExchangeInfo->StackStart = PeiCpuMpData->Buffer;
+ ExchangeInfo->StackSize = PeiCpuMpData->CpuApStackSize;
+ ExchangeInfo->BufferStart = PeiCpuMpData->WakeupBuffer;
+ ExchangeInfo->PmodeOffset = PeiCpuMpData->AddressMap.PModeEntryOffset;
+ ExchangeInfo->LmodeOffset = PeiCpuMpData->AddressMap.LModeEntryOffset;
+ ExchangeInfo->Cr3 = AsmReadCr3 ();
+ ExchangeInfo->CFunction = (UINTN) ApCFunction;
+ ExchangeInfo->NumApsExecuting = 0;
+ ExchangeInfo->PeiCpuMpData = PeiCpuMpData;
+
+ //
+ // Get the BSP's data of GDT and IDT
+ //
+ CopyMem ((VOID *)&ExchangeInfo->GdtrProfile, &mGdt, sizeof(mGdt));
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
+
+ if (Broadcast) {
+ SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
+ } else {
+ SendInitSipiSipi (ApicId, (UINT32) ExchangeInfo->BufferStart);
+ }
+
+ return ;
+}
+
+/**
+ Get available system memory below 1MB by specified size.
+
+ @param WakeupBufferSize Wakeup buffer size required
+
+ @retval other Return wakeup buffer address below 1MB.
+ @retval -1 Cannot find free memory below 1MB.
+**/
+UINTN
+GetWakeupBuffer (
+ IN UINTN WakeupBufferSize
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ UINTN WakeupBufferStart;
+ UINTN WakeupBufferEnd;
+
+ //
+ // Get the HOB list for processing
+ //
+ Hob.Raw = GetHobList ();
+
+ //
+ // Collect memory ranges
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
+ (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
+ ((Hob.ResourceDescriptor->ResourceAttribute &
+ (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
+ )) == 0)
+ ) {
+ //
+ // Need memory under 1MB to be collected here
+ //
+ WakeupBufferEnd = (UINTN) (Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength);
+ if (WakeupBufferEnd > BASE_1MB) {
+ //
+ // Wakeup buffer should be under 1MB
+ //
+ WakeupBufferEnd = BASE_1MB;
+ }
+ //
+ // Wakeup buffer should be aligned on 4KB
+ //
+ WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
+ if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
+ continue;
+ }
+ //
+ // Create a memory allocation HOB.
+ //
+ BuildMemoryAllocationHob (
+ WakeupBufferStart,
+ WakeupBufferSize,
+ EfiBootServicesData
+ );
+ return WakeupBufferStart;
+ }
+ }
+ //
+ // Find the next HOB
+ //
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ return (UINTN) -1;
+}
+
+/**
+ Get available system memory below 1MB by specified size.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+BackupAndPrepareWakeupBuffer(
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ )
+{
+ CopyMem (
+ (VOID *) PeiCpuMpData->BackupBuffer,
+ (VOID *) PeiCpuMpData->WakeupBuffer,
+ PeiCpuMpData->BackupBufferSize
+ );
+ CopyMem (
+ (VOID *) PeiCpuMpData->WakeupBuffer,
+ (VOID *) PeiCpuMpData->AddressMap.RendezvousFunnelAddress,
+ PeiCpuMpData->AddressMap.RendezvousFunnelSize
+ );
+}
+
+/**
+ Restore wakeup buffer data.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+RestoreWakeupBuffer(
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ )
+{
+ CopyMem ((VOID *) PeiCpuMpData->WakeupBuffer, (VOID *) PeiCpuMpData->BackupBuffer, PeiCpuMpData->BackupBufferSize);
+}
+
+/**
+ This function will get CPU count in the system.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+
+ @return AP processor count
+**/
+UINT32
+CountProcessorNumber (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ )
+{
+ //
+ // Load Microcode on BSP
+ //
+ MicrocodeDetect ();
+ //
+ // Store BSP's MTRR setting
+ //
+ MtrrGetAllMtrrs (&PeiCpuMpData->MtrrTable);
+ //
+ // Send broadcast IPI to APs to wakeup APs
+ //
+ PeiCpuMpData->InitFlag = 1;
+ WakeUpAP (PeiCpuMpData, TRUE, 0, NULL, NULL);
+ //
+ // Wait for AP task to complete and then exit.
+ //
+ MicroSecondDelay (PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
+ PeiCpuMpData->InitFlag = 0;
+ PeiCpuMpData->CpuCount += (UINT32) PeiCpuMpData->MpCpuExchangeInfo->NumApsExecuting;
+ //
+ // Sort BSP/Aps by CPU APIC ID in ascending order
+ //
+ SortApicId (PeiCpuMpData);
+
+ DEBUG ((EFI_D_INFO, "CpuMpPei: Find %d processors in system.\n", PeiCpuMpData->CpuCount));
+ return PeiCpuMpData->CpuCount;
+}
+
+/**
+ Prepare for AP wakeup buffer and copy AP reset code into it.
+
+ Get wakeup buffer below 1MB. Allocate memory for CPU MP Data and APs Stack.
+
+ @return Pointer to PEI CPU MP Data
+**/
+PEI_CPU_MP_DATA *
+PrepareAPStartupVector (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 MaxCpuCount;
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ EFI_PHYSICAL_ADDRESS Buffer;
+ UINTN BufferSize;
+ UINTN WakeupBuffer;
+ UINTN WakeupBufferSize;
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+
+ AsmGetAddressMap (&AddressMap);
+ WakeupBufferSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
+ WakeupBuffer = GetWakeupBuffer ((WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1));
+ ASSERT (WakeupBuffer != (UINTN) -1);
+ DEBUG ((EFI_D_INFO, "CpuMpPei: WakeupBuffer = 0x%x\n", WakeupBuffer));
+
+ //
+ // Allocate Pages for APs stack, CPU MP Data and backup buffer for wakeup buffer
+ //
+ MaxCpuCount = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
+ BufferSize = PcdGet32 (PcdCpuApStackSize) * MaxCpuCount + sizeof (PEI_CPU_MP_DATA)
+ + WakeupBufferSize + sizeof (PEI_CPU_DATA) * MaxCpuCount;
+ Status = PeiServicesAllocatePages (
+ EfiBootServicesData,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &Buffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ PeiCpuMpData = (PEI_CPU_MP_DATA *) (UINTN) (Buffer + PcdGet32 (PcdCpuApStackSize) * MaxCpuCount);
+ PeiCpuMpData->Buffer = (UINTN) Buffer;
+ PeiCpuMpData->CpuApStackSize = PcdGet32 (PcdCpuApStackSize);
+ PeiCpuMpData->WakeupBuffer = WakeupBuffer;
+ PeiCpuMpData->BackupBuffer = (UINTN)PeiCpuMpData + sizeof (PEI_CPU_MP_DATA);
+ PeiCpuMpData->BackupBufferSize = WakeupBufferSize;
+ PeiCpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN) (WakeupBuffer + AddressMap.RendezvousFunnelSize);
+
+ PeiCpuMpData->CpuCount = 1;
+ PeiCpuMpData->BspNumber = 0;
+ PeiCpuMpData->CpuData = (PEI_CPU_DATA *) (PeiCpuMpData->MpCpuExchangeInfo + 1);
+ PeiCpuMpData->CpuData[0].ApicId = GetInitialApicId ();
+ PeiCpuMpData->CpuData[0].Health.Uint32 = 0;
+ PeiCpuMpData->EndOfPeiFlag = FALSE;
+ CopyMem (&PeiCpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
+
+ //
+ // Backup original data and copy AP reset code in it
+ //
+ BackupAndPrepareWakeupBuffer(PeiCpuMpData);
+
+ return PeiCpuMpData;
+}
+
+/**
+ Notify function on End Of Pei PPI.
+
+ On S3 boot, this function will restore wakeup buffer data.
+ On normal boot, this function will flag wakeup buffer to be un-used type.
+
+ @param PeiServices The pointer to the PEI Services Table.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS When everything is OK.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMpEndOfPeiCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ )
+{
+ EFI_STATUS Status;
+ EFI_BOOT_MODE BootMode;
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+
+ DEBUG ((EFI_D_INFO, "CpuMpPei: CpuMpEndOfPeiCallback () invokded\n"));
+
+ Status = PeiServicesGetBootMode (&BootMode);
+ ASSERT_EFI_ERROR (Status);
+
+ PeiCpuMpData = GetMpHobData ();
+ ASSERT (PeiCpuMpData != NULL);
+
+ if (BootMode != BOOT_ON_S3_RESUME) {
+ //
+ // Get the HOB list for processing
+ //
+ Hob.Raw = GetHobList ();
+ //
+ // Collect memory ranges
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ if(MemoryHob->AllocDescriptor.MemoryBaseAddress == PeiCpuMpData->WakeupBuffer) {
+ //
+ // Flag this HOB type to un-used
+ //
+ GET_HOB_TYPE (Hob) = EFI_HOB_TYPE_UNUSED;
+ break;
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ } else {
+ RestoreWakeupBuffer (PeiCpuMpData);
+ PeiCpuMpData->EndOfPeiFlag = TRUE;
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ The Entry point of the MP CPU PEIM.
+
+ This function will wakeup APs and collect CPU AP count and install the
+ Mp Service Ppi.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS MpServicePpi is installed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMpPeimInit (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINT32 ProcessorCount;
+
+ //
+ // Load new GDT table on BSP
+ //
+ AsmInitializeGdt (&mGdt);
+ //
+ // Get wakeup buffer and copy AP reset code in it
+ //
+ PeiCpuMpData = PrepareAPStartupVector ();
+ //
+ // Count processor number and collect processor information
+ //
+ ProcessorCount = CountProcessorNumber (PeiCpuMpData);
+ //
+ // Build location of PEI CPU MP DATA buffer in HOB
+ //
+ BuildGuidDataHob (
+ &gEfiCallerIdGuid,
+ (VOID *)&PeiCpuMpData,
+ sizeof(UINT64)
+ );
+ //
+ // Update and publish CPU BIST information
+ //
+ CollectBistDataFromPpi (PeiServices, PeiCpuMpData);
+ //
+ // register an event for EndOfPei
+ //
+ Status = PeiServicesNotifyPpi (&mNotifyList);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Install CPU MP PPI
+ //
+ Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.h b/UefiCpuPkg/CpuMpPei/CpuMpPei.h index 8d01ac6433..19e649eb82 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.h +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.h @@ -1,302 +1,302 @@ -/** @file - Definitions to install Multiple Processor PPI. - - Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef _CPU_MP_PEI_H_ -#define _CPU_MP_PEI_H_ - -#include <PiPei.h> - -#include <Ppi/MpServices.h> -#include <Ppi/SecPlatformInformation.h> -#include <Ppi/SecPlatformInformation2.h> -#include <Ppi/EndOfPeiPhase.h> - -#include <Register/LocalApic.h> - -#include <Library/BaseLib.h> -#include <Library/BaseMemoryLib.h> -#include <Library/DebugLib.h> -#include <Library/HobLib.h> -#include <Library/LocalApicLib.h> -#include <Library/MtrrLib.h> -#include <Library/PcdLib.h> -#include <Library/PeimEntryPoint.h> -#include <Library/PeiServicesLib.h> -#include <Library/ReportStatusCodeLib.h> -#include <Library/SynchronizationLib.h> -#include <Library/TimerLib.h> -#include <Library/UefiCpuLib.h> - -#include "Microcode.h" - -// -// AP state -// -typedef enum { - CpuStateIdle, - CpuStateBusy, - CpuStateDisabled -} CPU_STATE; - -// -// AP reset code information -// -typedef struct { - UINT8 *RendezvousFunnelAddress; - UINTN PModeEntryOffset; - UINTN LModeEntryOffset; - UINTN RendezvousFunnelSize; -} MP_ASSEMBLY_ADDRESS_MAP; - -// -// CPU exchange information for switch BSP -// -typedef struct { - UINT8 State; // offset 0 - UINTN StackPointer; // offset 4 / 8 - IA32_DESCRIPTOR Gdtr; // offset 8 / 16 - IA32_DESCRIPTOR Idtr; // offset 14 / 26 -} CPU_EXCHANGE_ROLE_INFO; - -typedef struct _PEI_CPU_MP_DATA PEI_CPU_MP_DATA; - -#pragma pack() - -typedef union { - struct { - UINT32 LimitLow : 16; - UINT32 BaseLow : 16; - UINT32 BaseMid : 8; - UINT32 Type : 4; - UINT32 System : 1; - UINT32 Dpl : 2; - UINT32 Present : 1; - UINT32 LimitHigh : 4; - UINT32 Software : 1; - UINT32 Reserved : 1; - UINT32 DefaultSize : 1; - UINT32 Granularity : 1; - UINT32 BaseHigh : 8; - } Bits; - UINT64 Uint64; -} IA32_GDT; - -// -// MP CPU exchange information for AP reset code -// -typedef struct { - UINTN Lock; - UINTN StackStart; - UINTN StackSize; - UINTN CFunction; - IA32_DESCRIPTOR GdtrProfile; - IA32_DESCRIPTOR IdtrProfile; - UINTN BufferStart; - UINTN PmodeOffset; - UINTN NumApsExecuting; - UINTN LmodeOffset; - UINTN Cr3; - PEI_CPU_MP_DATA *PeiCpuMpData; -} MP_CPU_EXCHANGE_INFO; - -#pragma pack() - -typedef struct { - UINT32 ApicId; - EFI_HEALTH_FLAGS Health; - CPU_STATE State; - BOOLEAN CpuHealthy; -} PEI_CPU_DATA; - -// -// PEI CPU MP Data save in memory -// -struct _PEI_CPU_MP_DATA { - UINT32 CpuCount; - UINT32 BspNumber; - UINTN Buffer; - UINTN CpuApStackSize; - MP_ASSEMBLY_ADDRESS_MAP AddressMap; - UINTN WakeupBuffer; - UINTN BackupBuffer; - UINTN BackupBufferSize; - UINTN ApFunction; - UINTN ApFunctionArgument; - volatile UINT32 FinishedCount; - BOOLEAN EndOfPeiFlag; - BOOLEAN InitFlag; - CPU_EXCHANGE_ROLE_INFO BSPInfo; - CPU_EXCHANGE_ROLE_INFO APInfo; - MTRR_SETTINGS MtrrTable; - PEI_CPU_DATA *CpuData; - volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo; -}; -extern EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiDesc; - - -/** - Assembly code to get starting address and size of the rendezvous entry for APs. - Information for fixing a jump instruction in the code is also returned. - - @param AddressMap Output buffer for address map information. -**/ -VOID -EFIAPI -AsmGetAddressMap ( - OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap - ); - -/** - Assembly code to load GDT table and update segment accordingly. - - @param Gdtr Pointer to GDT descriptor -**/ -VOID -EFIAPI -AsmInitializeGdt ( - IN IA32_DESCRIPTOR *Gdtr - ); - -/** - Assembly code to do CLI-HALT loop. - -**/ -VOID -EFIAPI -AsmCliHltLoop ( - VOID - ); - -/** - Get available system memory below 1MB by specified size. - - @param PeiCpuMpData Pointer to PEI CPU MP Data -**/ -VOID -BackupAndPrepareWakeupBuffer( - IN PEI_CPU_MP_DATA *PeiCpuMpData - ); - -/** - Restore wakeup buffer data. - - @param PeiCpuMpData Pointer to PEI CPU MP Data -**/ -VOID -RestoreWakeupBuffer( - IN PEI_CPU_MP_DATA *PeiCpuMpData - ); - -/** - Notify function on End Of Pei PPI. - - On S3 boot, this function will restore wakeup buffer data. - On normal boot, this function will flag wakeup buffer to be un-used type. - - @param PeiServices The pointer to the PEI Services Table. - @param NotifyDescriptor Address of the notification descriptor data structure. - @param Ppi Address of the PPI that was installed. - - @retval EFI_SUCCESS When everything is OK. - -**/ -EFI_STATUS -EFIAPI -CpuMpEndOfPeiCallback ( - IN EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor, - IN VOID *Ppi - ); - -/** - This function will be called by BSP to wakeup AP. - - @param PeiCpuMpData Pointer to PEI CPU MP Data - @param Broadcast TRUE: Send broadcast IPI to all APs - FALSE: Send IPI to AP by ApicId - @param ApicId Apic ID for the processor to be waked - @param Procedure The function to be invoked by AP - @param ProcedureArgument The argument to be passed into AP function -**/ -VOID -WakeUpAP ( - IN PEI_CPU_MP_DATA *PeiCpuMpData, - IN BOOLEAN Broadcast, - IN UINT32 ApicId, - IN EFI_AP_PROCEDURE Procedure, OPTIONAL - IN VOID *ProcedureArgument OPTIONAL - ); - -/** - Get CPU MP Data pointer from the Guided HOB. - - @return Pointer to Pointer to PEI CPU MP Data -**/ -PEI_CPU_MP_DATA * -GetMpHobData ( - VOID - ); - -/** - Find the current Processor number by APIC ID. - - @param PeiCpuMpData Pointer to PEI CPU MP Data - @param ProcessorNumber Return the pocessor number found - - @retval EFI_SUCCESS ProcessorNumber is found and returned. - @retval EFI_NOT_FOUND ProcessorNumber is not found. -**/ -EFI_STATUS -GetProcessorNumber ( - IN PEI_CPU_MP_DATA *PeiCpuMpData, - OUT UINTN *ProcessorNumber - ); - -/** - Collects BIST data from PPI. - - This function collects BIST data from Sec Platform Information2 PPI - or SEC Platform Information PPI. - - @param PeiServices Pointer to PEI Services Table - @param PeiCpuMpData Pointer to PEI CPU MP Data - -**/ -VOID -CollectBistDataFromPpi ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN PEI_CPU_MP_DATA *PeiCpuMpData - ); - -/** - Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI. - - @param PeiServices The pointer to the PEI Services Table. - @param StructureSize The pointer to the variable describing size of the input buffer. - @param PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2. - - @retval EFI_SUCCESS The data was successfully returned. - @retval EFI_BUFFER_TOO_SMALL The buffer was too small. The current buffer size needed to - hold the record is returned in StructureSize. - -**/ -EFI_STATUS -EFIAPI -SecPlatformInformation2 ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN OUT UINT64 *StructureSize, - OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2 - ); - -#endif +/** @file
+ Definitions to install Multiple Processor PPI.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _CPU_MP_PEI_H_
+#define _CPU_MP_PEI_H_
+
+#include <PiPei.h>
+
+#include <Ppi/MpServices.h>
+#include <Ppi/SecPlatformInformation.h>
+#include <Ppi/SecPlatformInformation2.h>
+#include <Ppi/EndOfPeiPhase.h>
+
+#include <Register/LocalApic.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/TimerLib.h>
+#include <Library/UefiCpuLib.h>
+
+#include "Microcode.h"
+
+//
+// AP state
+//
+typedef enum {
+ CpuStateIdle,
+ CpuStateBusy,
+ CpuStateDisabled
+} CPU_STATE;
+
+//
+// AP reset code information
+//
+typedef struct {
+ UINT8 *RendezvousFunnelAddress;
+ UINTN PModeEntryOffset;
+ UINTN LModeEntryOffset;
+ UINTN RendezvousFunnelSize;
+} MP_ASSEMBLY_ADDRESS_MAP;
+
+//
+// CPU exchange information for switch BSP
+//
+typedef struct {
+ UINT8 State; // offset 0
+ UINTN StackPointer; // offset 4 / 8
+ IA32_DESCRIPTOR Gdtr; // offset 8 / 16
+ IA32_DESCRIPTOR Idtr; // offset 14 / 26
+} CPU_EXCHANGE_ROLE_INFO;
+
+typedef struct _PEI_CPU_MP_DATA PEI_CPU_MP_DATA;
+
+#pragma pack()
+
+typedef union {
+ struct {
+ UINT32 LimitLow : 16;
+ UINT32 BaseLow : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHigh : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHigh : 8;
+ } Bits;
+ UINT64 Uint64;
+} IA32_GDT;
+
+//
+// MP CPU exchange information for AP reset code
+//
+typedef struct {
+ UINTN Lock;
+ UINTN StackStart;
+ UINTN StackSize;
+ UINTN CFunction;
+ IA32_DESCRIPTOR GdtrProfile;
+ IA32_DESCRIPTOR IdtrProfile;
+ UINTN BufferStart;
+ UINTN PmodeOffset;
+ UINTN NumApsExecuting;
+ UINTN LmodeOffset;
+ UINTN Cr3;
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+} MP_CPU_EXCHANGE_INFO;
+
+#pragma pack()
+
+typedef struct {
+ UINT32 ApicId;
+ EFI_HEALTH_FLAGS Health;
+ CPU_STATE State;
+ BOOLEAN CpuHealthy;
+} PEI_CPU_DATA;
+
+//
+// PEI CPU MP Data save in memory
+//
+struct _PEI_CPU_MP_DATA {
+ UINT32 CpuCount;
+ UINT32 BspNumber;
+ UINTN Buffer;
+ UINTN CpuApStackSize;
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+ UINTN WakeupBuffer;
+ UINTN BackupBuffer;
+ UINTN BackupBufferSize;
+ UINTN ApFunction;
+ UINTN ApFunctionArgument;
+ volatile UINT32 FinishedCount;
+ BOOLEAN EndOfPeiFlag;
+ BOOLEAN InitFlag;
+ CPU_EXCHANGE_ROLE_INFO BSPInfo;
+ CPU_EXCHANGE_ROLE_INFO APInfo;
+ MTRR_SETTINGS MtrrTable;
+ PEI_CPU_DATA *CpuData;
+ volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
+};
+extern EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiDesc;
+
+
+/**
+ Assembly code to get starting address and size of the rendezvous entry for APs.
+ Information for fixing a jump instruction in the code is also returned.
+
+ @param AddressMap Output buffer for address map information.
+**/
+VOID
+EFIAPI
+AsmGetAddressMap (
+ OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap
+ );
+
+/**
+ Assembly code to load GDT table and update segment accordingly.
+
+ @param Gdtr Pointer to GDT descriptor
+**/
+VOID
+EFIAPI
+AsmInitializeGdt (
+ IN IA32_DESCRIPTOR *Gdtr
+ );
+
+/**
+ Assembly code to do CLI-HALT loop.
+
+**/
+VOID
+EFIAPI
+AsmCliHltLoop (
+ VOID
+ );
+
+/**
+ Get available system memory below 1MB by specified size.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+BackupAndPrepareWakeupBuffer(
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ );
+
+/**
+ Restore wakeup buffer data.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+RestoreWakeupBuffer(
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ );
+
+/**
+ Notify function on End Of Pei PPI.
+
+ On S3 boot, this function will restore wakeup buffer data.
+ On normal boot, this function will flag wakeup buffer to be un-used type.
+
+ @param PeiServices The pointer to the PEI Services Table.
+ @param NotifyDescriptor Address of the notification descriptor data structure.
+ @param Ppi Address of the PPI that was installed.
+
+ @retval EFI_SUCCESS When everything is OK.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMpEndOfPeiCallback (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Ppi
+ );
+
+/**
+ This function will be called by BSP to wakeup AP.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param ApicId Apic ID for the processor to be waked
+ @param Procedure The function to be invoked by AP
+ @param ProcedureArgument The argument to be passed into AP function
+**/
+VOID
+WakeUpAP (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINT32 ApicId,
+ IN EFI_AP_PROCEDURE Procedure, OPTIONAL
+ IN VOID *ProcedureArgument OPTIONAL
+ );
+
+/**
+ Get CPU MP Data pointer from the Guided HOB.
+
+ @return Pointer to Pointer to PEI CPU MP Data
+**/
+PEI_CPU_MP_DATA *
+GetMpHobData (
+ VOID
+ );
+
+/**
+ Find the current Processor number by APIC ID.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param ProcessorNumber Return the pocessor number found
+
+ @retval EFI_SUCCESS ProcessorNumber is found and returned.
+ @retval EFI_NOT_FOUND ProcessorNumber is not found.
+**/
+EFI_STATUS
+GetProcessorNumber (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData,
+ OUT UINTN *ProcessorNumber
+ );
+
+/**
+ Collects BIST data from PPI.
+
+ This function collects BIST data from Sec Platform Information2 PPI
+ or SEC Platform Information PPI.
+
+ @param PeiServices Pointer to PEI Services Table
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+
+**/
+VOID
+CollectBistDataFromPpi (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN PEI_CPU_MP_DATA *PeiCpuMpData
+ );
+
+/**
+ Implementation of the PlatformInformation2 service in EFI_SEC_PLATFORM_INFORMATION2_PPI.
+
+ @param PeiServices The pointer to the PEI Services Table.
+ @param StructureSize The pointer to the variable describing size of the input buffer.
+ @param PlatformInformationRecord2 The pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD2.
+
+ @retval EFI_SUCCESS The data was successfully returned.
+ @retval EFI_BUFFER_TOO_SMALL The buffer was too small. The current buffer size needed to
+ hold the record is returned in StructureSize.
+
+**/
+EFI_STATUS
+EFIAPI
+SecPlatformInformation2 (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT UINT64 *StructureSize,
+ OUT EFI_SEC_PLATFORM_INFORMATION_RECORD2 *PlatformInformationRecord2
+ );
+
+#endif
diff --git a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf index 64add554c4..423f7f10ed 100644 --- a/UefiCpuPkg/CpuMpPei/CpuMpPei.inf +++ b/UefiCpuPkg/CpuMpPei/CpuMpPei.inf @@ -1,90 +1,90 @@ -## @file -# CPU driver installs CPU PI Multi-processor PPI. -# -# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> -# This program and the accompanying materials -# are licensed and made available under the terms and conditions of the BSD License -# which accompanies this distribution. The full text of the license may be found at -# http://opensource.org/licenses/bsd-license.php -# -# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -# -## - -[Defines] - INF_VERSION = 0x00010005 - BASE_NAME = CpuMpPei - MODULE_UNI_FILE = CpuMpPei.uni - FILE_GUID = EDADEB9D-DDBA-48BD-9D22-C1C169C8C5C6 - MODULE_TYPE = PEIM - VERSION_STRING = 1.0 - ENTRY_POINT = CpuMpPeimInit - -# -# The following information is for reference only and not required by the build tools. -# -# VALID_ARCHITECTURES = IA32 X64 -# - -[Sources] - CpuMpPei.h - CpuMpPei.c - CpuBist.c - Microcode.h - Microcode.c - PeiMpServices.h - PeiMpServices.c - -[Sources.IA32] - Ia32/MpEqu.inc - Ia32/MpFuncs.asm | MSFT - Ia32/MpFuncs.asm | INTEL - Ia32/MpFuncs.nasm | GCC - -[Sources.X64] - X64/MpEqu.inc - X64/MpFuncs.asm | MSFT - X64/MpFuncs.asm | INTEL - X64/MpFuncs.nasm | GCC - -[Packages] - MdePkg/MdePkg.dec - UefiCpuPkg/UefiCpuPkg.dec - -[LibraryClasses] - BaseLib - BaseMemoryLib - DebugLib - HobLib - LocalApicLib - MtrrLib - PcdLib - PeimEntryPoint - PeiServicesLib - ReportStatusCodeLib - SynchronizationLib - TimerLib - UefiCpuLib - -[Ppis] - gEfiPeiMpServicesPpiGuid ## PRODUCES - gEfiEndOfPeiSignalPpiGuid ## NOTIFY - gEfiSecPlatformInformationPpiGuid ## SOMETIMES_CONSUMES - ## SOMETIMES_CONSUMES - ## SOMETIMES_PRODUCES - gEfiSecPlatformInformation2PpiGuid - -[Pcd] - gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES - gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds ## CONSUMES - gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES - gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress ## CONSUMES - gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES - -[Depex] - gEfiPeiMemoryDiscoveredPpiGuid - -[UserExtensions.TianoCore."ExtraFiles"] - CpuMpPeiExtra.uni - +## @file
+# CPU driver installs CPU PI Multi-processor PPI.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CpuMpPei
+ MODULE_UNI_FILE = CpuMpPei.uni
+ FILE_GUID = EDADEB9D-DDBA-48BD-9D22-C1C169C8C5C6
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = CpuMpPeimInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ CpuMpPei.h
+ CpuMpPei.c
+ CpuBist.c
+ Microcode.h
+ Microcode.c
+ PeiMpServices.h
+ PeiMpServices.c
+
+[Sources.IA32]
+ Ia32/MpEqu.inc
+ Ia32/MpFuncs.asm | MSFT
+ Ia32/MpFuncs.asm | INTEL
+ Ia32/MpFuncs.nasm | GCC
+
+[Sources.X64]
+ X64/MpEqu.inc
+ X64/MpFuncs.asm | MSFT
+ X64/MpFuncs.asm | INTEL
+ X64/MpFuncs.nasm | GCC
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ HobLib
+ LocalApicLib
+ MtrrLib
+ PcdLib
+ PeimEntryPoint
+ PeiServicesLib
+ ReportStatusCodeLib
+ SynchronizationLib
+ TimerLib
+ UefiCpuLib
+
+[Ppis]
+ gEfiPeiMpServicesPpiGuid ## PRODUCES
+ gEfiEndOfPeiSignalPpiGuid ## NOTIFY
+ gEfiSecPlatformInformationPpiGuid ## SOMETIMES_CONSUMES
+ ## SOMETIMES_CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiSecPlatformInformation2PpiGuid
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CpuMpPeiExtra.uni
+
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc b/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc index 50ec8c9cfc..fc637cc70f 100644 --- a/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc +++ b/UefiCpuPkg/CpuMpPei/Ia32/MpEqu.inc @@ -1,40 +1,40 @@ -;------------------------------------------------------------------------------ ; -; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> -; This program and the accompanying materials -; are licensed and made available under the terms and conditions of the BSD License -; which accompanies this distribution. The full text of the license may be found at -; http://opensource.org/licenses/bsd-license.php. -; -; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -; -; Module Name: -; -; MpEqu.inc -; -; Abstract: -; -; This is the equates file for Multiple Processor support -; -;------------------------------------------------------------------------------- - -PROTECT_MODE_CS equ 10h -PROTECT_MODE_DS equ 18h - -VacantFlag equ 00h -NotVacantFlag equ 0ffh - -CPU_SWITCH_STATE_IDLE equ 0 -CPU_SWITCH_STATE_STORED equ 1 -CPU_SWITCH_STATE_LOADED equ 2 - -LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart) -StackStartAddressLocation equ LockLocation + 04h -StackSizeLocation equ LockLocation + 08h -ApProcedureLocation equ LockLocation + 0Ch -GdtrLocation equ LockLocation + 10h -IdtrLocation equ LockLocation + 16h -BufferStartLocation equ LockLocation + 1Ch -PmodeOffsetLocation equ LockLocation + 20h -NumApsExecutingLoction equ LockLocation + 24h - +;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpEqu.inc
+;
+; Abstract:
+;
+; This is the equates file for Multiple Processor support
+;
+;-------------------------------------------------------------------------------
+
+PROTECT_MODE_CS equ 10h
+PROTECT_MODE_DS equ 18h
+
+VacantFlag equ 00h
+NotVacantFlag equ 0ffh
+
+CPU_SWITCH_STATE_IDLE equ 0
+CPU_SWITCH_STATE_STORED equ 1
+CPU_SWITCH_STATE_LOADED equ 2
+
+LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
+StackStartAddressLocation equ LockLocation + 04h
+StackSizeLocation equ LockLocation + 08h
+ApProcedureLocation equ LockLocation + 0Ch
+GdtrLocation equ LockLocation + 10h
+IdtrLocation equ LockLocation + 16h
+BufferStartLocation equ LockLocation + 1Ch
+PmodeOffsetLocation equ LockLocation + 20h
+NumApsExecutingLoction equ LockLocation + 24h
+
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm index 060f4670e0..eb23a16917 100644 --- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm +++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.asm @@ -1,276 +1,276 @@ -;------------------------------------------------------------------------------ ; -; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> -; This program and the accompanying materials -; are licensed and made available under the terms and conditions of the BSD License -; which accompanies this distribution. The full text of the license may be found at -; http://opensource.org/licenses/bsd-license.php. -; -; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -; -; Module Name: -; -; MpFuncs32.asm -; -; Abstract: -; -; This is the assembly code for MP support -; -;------------------------------------------------------------------------------- - -.686p -.model flat - -include MpEqu.inc -InitializeFloatingPointUnits PROTO C - -.code - -;------------------------------------------------------------------------------------- -;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 PROC PUBLIC -RendezvousFunnelProcStart:: -; At this point CS = 0x(vv00) and ip= 0x0. -; Save BIST information to ebp firstly - db 66h, 08bh, 0e8h ; mov ebp, eax ; save BIST information - - 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 - dw IdtrLocation ; mov si, IdtrLocation - 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 PROTECT_MODE_CS ; 16-bit selector - -Flat32Start:: ; protected mode entry point - mov ax, PROTECT_MODE_DS - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - mov esi, ebx - mov edi, esi - add edi, LockLocation - mov eax, NotVacantFlag - -TestLock: - xchg dword ptr [edi], eax - cmp eax, NotVacantFlag - jz TestLock - - mov edi, esi - add edi, NumApsExecutingLoction - inc dword ptr [edi] - mov ebx, dword ptr [edi] - -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: - push ebp ; push BIST data at top of AP stack - xor ebp, ebp ; clear ebp for call stack trace - push ebp - mov ebp, esp - - mov eax, InitializeFloatingPointUnits - call eax ; Call assembly function to initialize FPU per UEFI spec - - push ebx ; Push NumApsExecuting - mov eax, esi - add eax, LockLocation - push eax ; push address of exchange info data buffer - - mov edi, esi - add edi, ApProcedureLocation - mov eax, dword ptr [edi] - - call eax ; invoke C function - - jmp $ ; never reach here - -RendezvousFunnelProc ENDP -RendezvousFunnelProcEnd:: - -AsmCliHltLoop PROC near C PUBLIC - cli - hlt - jmp $-2 -AsmCliHltLoop ENDP - -;------------------------------------------------------------------------------------- -; AsmGetAddressMap (&AddressMap); -;------------------------------------------------------------------------------------- -AsmGetAddressMap PROC near C PUBLIC - pushad - mov ebp,esp - - mov ebx, dword ptr [ebp+24h] - mov dword ptr [ebx], RendezvousFunnelProcStart - mov dword ptr [ebx + 4h], Flat32Start - RendezvousFunnelProcStart - mov dword ptr [ebx + 8h], 0 - mov dword ptr [ebx + 0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart - - popad - ret -AsmGetAddressMap ENDP - -PAUSE32 MACRO - DB 0F3h - DB 090h - ENDM - -;------------------------------------------------------------------------------------- -;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); -;------------------------------------------------------------------------------------- -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 function, 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 register to stack - pushfd - mov eax, cr4 - push eax ; push cr4 firstly - mov eax, cr0 - push eax - - 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 - pop eax - mov cr0, eax - pop eax - mov cr4, eax - popfd - - popad - ret -AsmExchangeRole ENDP - -AsmInitializeGdt PROC near C PUBLIC - push ebp - mov ebp, esp - pushad - mov edi, [ebp + 8] ; Load GDT register - - mov ax,cs ; Get the selector data from our code image - mov es,ax - lgdt FWORD PTR es:[edi] ; and update the GDTR - - push PROTECT_MODE_CS - lea eax, SetCodeSelectorFarJump - push eax - retf -SetCodeSelectorFarJump: - mov ax, PROTECT_MODE_DS ; Update the Base for the new selectors, too - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - popad - pop ebp - ret -AsmInitializeGdt ENDP - -END +;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpFuncs32.asm
+;
+; Abstract:
+;
+; This is the assembly code for MP support
+;
+;-------------------------------------------------------------------------------
+
+.686p
+.model flat
+
+include MpEqu.inc
+InitializeFloatingPointUnits PROTO C
+
+.code
+
+;-------------------------------------------------------------------------------------
+;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 PROC PUBLIC
+RendezvousFunnelProcStart::
+; At this point CS = 0x(vv00) and ip= 0x0.
+; Save BIST information to ebp firstly
+ db 66h, 08bh, 0e8h ; mov ebp, eax ; save BIST information
+
+ 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
+ dw IdtrLocation ; mov si, IdtrLocation
+ 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 PROTECT_MODE_CS ; 16-bit selector
+
+Flat32Start:: ; protected mode entry point
+ mov ax, PROTECT_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ mov esi, ebx
+ mov edi, esi
+ add edi, LockLocation
+ mov eax, NotVacantFlag
+
+TestLock:
+ xchg dword ptr [edi], eax
+ cmp eax, NotVacantFlag
+ jz TestLock
+
+ mov edi, esi
+ add edi, NumApsExecutingLoction
+ inc dword ptr [edi]
+ mov ebx, dword ptr [edi]
+
+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:
+ push ebp ; push BIST data at top of AP stack
+ xor ebp, ebp ; clear ebp for call stack trace
+ push ebp
+ mov ebp, esp
+
+ mov eax, InitializeFloatingPointUnits
+ call eax ; Call assembly function to initialize FPU per UEFI spec
+
+ push ebx ; Push NumApsExecuting
+ mov eax, esi
+ add eax, LockLocation
+ push eax ; push address of exchange info data buffer
+
+ mov edi, esi
+ add edi, ApProcedureLocation
+ mov eax, dword ptr [edi]
+
+ call eax ; invoke C function
+
+ jmp $ ; never reach here
+
+RendezvousFunnelProc ENDP
+RendezvousFunnelProcEnd::
+
+AsmCliHltLoop PROC near C PUBLIC
+ cli
+ hlt
+ jmp $-2
+AsmCliHltLoop ENDP
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+AsmGetAddressMap PROC near C PUBLIC
+ pushad
+ mov ebp,esp
+
+ mov ebx, dword ptr [ebp+24h]
+ mov dword ptr [ebx], RendezvousFunnelProcStart
+ mov dword ptr [ebx + 4h], Flat32Start - RendezvousFunnelProcStart
+ mov dword ptr [ebx + 8h], 0
+ mov dword ptr [ebx + 0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+
+ popad
+ ret
+AsmGetAddressMap ENDP
+
+PAUSE32 MACRO
+ DB 0F3h
+ DB 090h
+ ENDM
+
+;-------------------------------------------------------------------------------------
+;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);
+;-------------------------------------------------------------------------------------
+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 function, 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 register to stack
+ pushfd
+ mov eax, cr4
+ push eax ; push cr4 firstly
+ mov eax, cr0
+ push eax
+
+ 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
+ pop eax
+ mov cr0, eax
+ pop eax
+ mov cr4, eax
+ popfd
+
+ popad
+ ret
+AsmExchangeRole ENDP
+
+AsmInitializeGdt PROC near C PUBLIC
+ push ebp
+ mov ebp, esp
+ pushad
+ mov edi, [ebp + 8] ; Load GDT register
+
+ mov ax,cs ; Get the selector data from our code image
+ mov es,ax
+ lgdt FWORD PTR es:[edi] ; and update the GDTR
+
+ push PROTECT_MODE_CS
+ lea eax, SetCodeSelectorFarJump
+ push eax
+ retf
+SetCodeSelectorFarJump:
+ mov ax, PROTECT_MODE_DS ; Update the Base for the new selectors, too
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ popad
+ pop ebp
+ ret
+AsmInitializeGdt ENDP
+
+END
diff --git a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm index 3a8e91fe74..5d2da82d14 100644 --- a/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm +++ b/UefiCpuPkg/CpuMpPei/Ia32/MpFuncs.nasm @@ -1,255 +1,255 @@ -;------------------------------------------------------------------------------ ; -; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> -; This program and the accompanying materials -; are licensed and made available under the terms and conditions of the BSD License -; which accompanies this distribution. The full text of the license may be found at -; http://opensource.org/licenses/bsd-license.php. -; -; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -; -; Module Name: -; -; MpFuncs.nasm -; -; Abstract: -; -; This is the assembly code for MP support -; -;------------------------------------------------------------------------------- - -%include "MpEqu.inc" -extern ASM_PFX(InitializeFloatingPointUnits) - -SECTION .text - -;------------------------------------------------------------------------------------- -;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. -;------------------------------------------------------------------------------------- -global ASM_PFX(RendezvousFunnelProc) -ASM_PFX(RendezvousFunnelProc): -RendezvousFunnelProcStart: -; At this point CS = 0x(vv00) and ip= 0x0. -BITS 16 - mov ebp, eax ; save BIST information - - mov ax, cs - mov ds, ax - mov es, ax - mov ss, ax - xor ax, ax - mov fs, ax - mov gs, ax - - mov si, BufferStartLocation - mov ebx, [si] - - mov di, PmodeOffsetLocation - mov eax, [di] - mov di, ax - sub di, 06h - add eax, ebx - mov [di],eax - - mov si, GdtrLocation -o32 lgdt [cs:si] - - mov si, IdtrLocation -o32 lidt [cs:si] - - xor ax, ax - mov ds, ax - - mov eax, cr0 ;Get control register 0 - or eax, 000000003h ;Set PE bit (bit #0) & MP - mov cr0, eax - - jmp PROTECT_MODE_CS:strict dword 0 ; far jump to protected mode -BITS 32 -Flat32Start: ; protected mode entry point - mov ax, PROTECT_MODE_DS - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - mov esi, ebx - mov edi, esi - add edi, LockLocation - mov eax, NotVacantFlag - -TestLock: - xchg [edi], eax - cmp eax, NotVacantFlag - jz TestLock - - mov edi, esi - add edi, NumApsExecutingLoction - inc dword [edi] - mov ebx, [edi] - -ProgramStack: - mov edi, esi - add edi, StackSizeLocation - mov eax, [edi] - mov edi, esi - add edi, StackStartAddressLocation - add eax, [edi] - mov esp, eax - mov [edi], eax - -Releaselock: - mov eax, VacantFlag - mov edi, esi - add edi, LockLocation - xchg [edi], eax - -CProcedureInvoke: - push ebp ; push BIST data at top of AP stack - xor ebp, ebp ; clear ebp for call stack trace - push ebp - mov ebp, esp - - mov eax, ASM_PFX(InitializeFloatingPointUnits) - call eax ; Call assembly function to initialize FPU per UEFI spec - - push ebx ; Push NumApsExecuting - mov eax, esi - add eax, LockLocation - push eax ; push address of exchange info data buffer - - mov edi, esi - add edi, ApProcedureLocation - mov eax, [edi] - - call eax ; invoke C function - - jmp $ ; never reach here -RendezvousFunnelProcEnd: - -global ASM_PFX(AsmCliHltLoop) -ASM_PFX(AsmCliHltLoop): - cli - hlt - jmp $-2 - -;------------------------------------------------------------------------------------- -; AsmGetAddressMap (&AddressMap); -;------------------------------------------------------------------------------------- -global ASM_PFX(AsmGetAddressMap) -ASM_PFX(AsmGetAddressMap): - pushad - mov ebp,esp - - mov ebx, [ebp + 24h] - mov dword [ebx], RendezvousFunnelProcStart - mov dword [ebx + 4h], Flat32Start - RendezvousFunnelProcStart - mov dword [ebx + 8h], 0 - mov dword [ebx + 0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart - - popad - 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); -;------------------------------------------------------------------------------------- -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 function, stack will be corrupted. - pushad - mov ebp,esp - - ; esi contains MyInfo pointer - mov esi, [ebp + 24h] - - ; edi contains OthersInfo pointer - mov edi, [ebp + 28h] - - ;Store EFLAGS, GDTR and IDTR register to stack - pushfd - mov eax, cr4 - push eax ; push cr4 firstly - mov eax, cr0 - push eax - - sgdt [esi + 8] - sidt [esi + 14] - - ; Store the its StackPointer - mov [esi + 4],esp - - ; update its switch state to STORED - mov byte [esi], CPU_SWITCH_STATE_STORED - -WaitForOtherStored: - ; wait until the other CPU finish storing its state - cmp byte [edi], CPU_SWITCH_STATE_STORED - jz OtherStored - pause - jmp WaitForOtherStored - -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, [edi + 4] - - ; update the other CPU's switch state to LOADED - mov byte [edi], CPU_SWITCH_STATE_LOADED - -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 OtherLoaded - pause - jmp WaitForOtherLoaded - -OtherLoaded: - ; since the other CPU already get the data it want, leave this procedure - pop eax - mov cr0, eax - pop eax - mov cr4, eax - popfd - - popad - ret - -global ASM_PFX(AsmInitializeGdt) -ASM_PFX(AsmInitializeGdt): - push ebp - mov ebp, esp - pushad - mov edi, [ebp + 8] ; Load GDT register - - lgdt [edi] ; and update the GDTR - - push PROTECT_MODE_CS - mov eax, ASM_PFX(SetCodeSelectorFarJump) - push eax - retf -ASM_PFX(SetCodeSelectorFarJump): - mov ax, PROTECT_MODE_DS ; Update the Base for the new selectors, too - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - popad - pop ebp - ret +;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpFuncs.nasm
+;
+; Abstract:
+;
+; This is the assembly code for MP support
+;
+;-------------------------------------------------------------------------------
+
+%include "MpEqu.inc"
+extern ASM_PFX(InitializeFloatingPointUnits)
+
+SECTION .text
+
+;-------------------------------------------------------------------------------------
+;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.
+;-------------------------------------------------------------------------------------
+global ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+RendezvousFunnelProcStart:
+; At this point CS = 0x(vv00) and ip= 0x0.
+BITS 16
+ mov ebp, eax ; save BIST information
+
+ mov ax, cs
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+ xor ax, ax
+ mov fs, ax
+ mov gs, ax
+
+ mov si, BufferStartLocation
+ mov ebx, [si]
+
+ mov di, PmodeOffsetLocation
+ mov eax, [di]
+ mov di, ax
+ sub di, 06h
+ add eax, ebx
+ mov [di],eax
+
+ mov si, GdtrLocation
+o32 lgdt [cs:si]
+
+ mov si, IdtrLocation
+o32 lidt [cs:si]
+
+ xor ax, ax
+ mov ds, ax
+
+ mov eax, cr0 ;Get control register 0
+ or eax, 000000003h ;Set PE bit (bit #0) & MP
+ mov cr0, eax
+
+ jmp PROTECT_MODE_CS:strict dword 0 ; far jump to protected mode
+BITS 32
+Flat32Start: ; protected mode entry point
+ mov ax, PROTECT_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ mov esi, ebx
+ mov edi, esi
+ add edi, LockLocation
+ mov eax, NotVacantFlag
+
+TestLock:
+ xchg [edi], eax
+ cmp eax, NotVacantFlag
+ jz TestLock
+
+ mov edi, esi
+ add edi, NumApsExecutingLoction
+ inc dword [edi]
+ mov ebx, [edi]
+
+ProgramStack:
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov eax, [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add eax, [edi]
+ mov esp, eax
+ mov [edi], eax
+
+Releaselock:
+ mov eax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg [edi], eax
+
+CProcedureInvoke:
+ push ebp ; push BIST data at top of AP stack
+ xor ebp, ebp ; clear ebp for call stack trace
+ push ebp
+ mov ebp, esp
+
+ mov eax, ASM_PFX(InitializeFloatingPointUnits)
+ call eax ; Call assembly function to initialize FPU per UEFI spec
+
+ push ebx ; Push NumApsExecuting
+ mov eax, esi
+ add eax, LockLocation
+ push eax ; push address of exchange info data buffer
+
+ mov edi, esi
+ add edi, ApProcedureLocation
+ mov eax, [edi]
+
+ call eax ; invoke C function
+
+ jmp $ ; never reach here
+RendezvousFunnelProcEnd:
+
+global ASM_PFX(AsmCliHltLoop)
+ASM_PFX(AsmCliHltLoop):
+ cli
+ hlt
+ jmp $-2
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+ pushad
+ mov ebp,esp
+
+ mov ebx, [ebp + 24h]
+ mov dword [ebx], RendezvousFunnelProcStart
+ mov dword [ebx + 4h], Flat32Start - RendezvousFunnelProcStart
+ mov dword [ebx + 8h], 0
+ mov dword [ebx + 0ch], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+
+ popad
+ 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);
+;-------------------------------------------------------------------------------------
+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 function, stack will be corrupted.
+ pushad
+ mov ebp,esp
+
+ ; esi contains MyInfo pointer
+ mov esi, [ebp + 24h]
+
+ ; edi contains OthersInfo pointer
+ mov edi, [ebp + 28h]
+
+ ;Store EFLAGS, GDTR and IDTR register to stack
+ pushfd
+ mov eax, cr4
+ push eax ; push cr4 firstly
+ mov eax, cr0
+ push eax
+
+ sgdt [esi + 8]
+ sidt [esi + 14]
+
+ ; Store the its StackPointer
+ mov [esi + 4],esp
+
+ ; update its switch state to STORED
+ mov byte [esi], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte [edi], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ pause
+ jmp WaitForOtherStored
+
+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, [edi + 4]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte [edi], CPU_SWITCH_STATE_LOADED
+
+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 OtherLoaded
+ pause
+ jmp WaitForOtherLoaded
+
+OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ pop eax
+ mov cr0, eax
+ pop eax
+ mov cr4, eax
+ popfd
+
+ popad
+ ret
+
+global ASM_PFX(AsmInitializeGdt)
+ASM_PFX(AsmInitializeGdt):
+ push ebp
+ mov ebp, esp
+ pushad
+ mov edi, [ebp + 8] ; Load GDT register
+
+ lgdt [edi] ; and update the GDTR
+
+ push PROTECT_MODE_CS
+ mov eax, ASM_PFX(SetCodeSelectorFarJump)
+ push eax
+ retf
+ASM_PFX(SetCodeSelectorFarJump):
+ mov ax, PROTECT_MODE_DS ; Update the Base for the new selectors, too
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ popad
+ pop ebp
+ ret
diff --git a/UefiCpuPkg/CpuMpPei/Microcode.c b/UefiCpuPkg/CpuMpPei/Microcode.c index eb2e76b6a7..70e149be87 100644 --- a/UefiCpuPkg/CpuMpPei/Microcode.c +++ b/UefiCpuPkg/CpuMpPei/Microcode.c @@ -1,200 +1,200 @@ -/** @file - Implementation of loading microcode on processors. - - Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "CpuMpPei.h" - -/** - Get microcode update signature of currently loaded microcode update. - - @return Microcode signature. - -**/ -UINT32 -GetCurrentMicrocodeSignature ( - VOID - ) -{ - UINT64 Signature; - - AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0); - AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL); - Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID); - return (UINT32) RShiftU64 (Signature, 32); -} - -/** - Detect whether specified processor can find matching microcode patch and load it. - -**/ -VOID -MicrocodeDetect ( - VOID - ) -{ - UINT64 MicrocodePatchAddress; - UINT64 MicrocodePatchRegionSize; - UINT32 ExtendedTableLength; - UINT32 ExtendedTableCount; - EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable; - EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader; - EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint; - UINTN MicrocodeEnd; - UINTN Index; - UINT8 PlatformId; - UINT32 RegEax; - UINT32 LatestRevision; - UINTN TotalSize; - UINT32 CheckSum32; - BOOLEAN CorrectMicrocode; - INT32 CurrentSignature; - MICROCODE_INFO MicrocodeInfo; - - ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO)); - MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress); - MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize); - if (MicrocodePatchRegionSize == 0) { - // - // There is no microcode patches - // - return; - } - - ExtendedTableLength = 0; - // - // Here data of CPUID leafs have not been collected into context buffer, so - // GetProcessorCpuid() cannot be used here to retrieve CPUID data. - // - AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL); - - // - // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID - // - PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52); - - LatestRevision = 0; - MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize); - MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress; - do { - // - // Check if the microcode is for the Cpu and the version is newer - // and the update can be processed on the platform - // - CorrectMicrocode = FALSE; - if (MicrocodeEntryPoint->HeaderVersion == 0x1) { - // - // It is the microcode header. It is not the padding data between microcode patches - // becasue the padding data should not include 0x00000001 and it should be the repeated - // byte format (like 0xXYXYXYXY....). - // - if (MicrocodeEntryPoint->ProcessorId == RegEax && - MicrocodeEntryPoint->UpdateRevision > LatestRevision && - (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId)) - ) { - if (MicrocodeEntryPoint->DataSize == 0) { - CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048); - } else { - CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER)); - } - if (CheckSum32 == 0) { - CorrectMicrocode = TRUE; - } - } else if ((MicrocodeEntryPoint->DataSize != 0) && - (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) { - ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER)); - if (ExtendedTableLength != 0) { - // - // Extended Table exist, check if the CPU in support list - // - ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER)); - // - // Calculate Extended Checksum - // - if ((ExtendedTableLength % 4) == 0) { - CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength); - if (CheckSum32 == 0) { - // - // Checksum correct - // - ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount; - ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1); - for (Index = 0; Index < ExtendedTableCount; Index ++) { - CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE)); - if (CheckSum32 == 0) { - // - // Verify Header - // - if ((ExtendedTable->ProcessorSignature == RegEax) && - (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) { - // - // Find one - // - CorrectMicrocode = TRUE; - break; - } - } - ExtendedTable ++; - } - } - } - } - } - } else { - // - // It is the padding data between the microcode patches for microcode patches alignment. - // Because the microcode patch is the multiple of 1-KByte, the padding data should not - // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode - // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to - // find the next possible microcode patch header. - // - MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB); - continue; - } - // - // Get the next patch. - // - if (MicrocodeEntryPoint->DataSize == 0) { - TotalSize = 2048; - } else { - TotalSize = MicrocodeEntryPoint->TotalSize; - } - - if (CorrectMicrocode) { - LatestRevision = MicrocodeEntryPoint->UpdateRevision; - MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER)); - MicrocodeInfo.MicrocodeSize = TotalSize; - MicrocodeInfo.ProcessorId = RegEax; - } - - MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize); - } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd)); - - if (LatestRevision > 0) { - // - // Get microcode update signature of currently loaded microcode update - // - CurrentSignature = GetCurrentMicrocodeSignature (); - // - // If no microcode update has been loaded, then trigger microcode load. - // - if (CurrentSignature == 0) { - AsmWriteMsr64 ( - EFI_MSR_IA32_BIOS_UPDT_TRIG, - (UINT64) (UINTN) MicrocodeInfo.MicrocodeData - ); - MicrocodeInfo.Load = TRUE; - } else { - MicrocodeInfo.Load = FALSE; - } - } -} +/** @file
+ Implementation of loading microcode on processors.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "CpuMpPei.h"
+
+/**
+ Get microcode update signature of currently loaded microcode update.
+
+ @return Microcode signature.
+
+**/
+UINT32
+GetCurrentMicrocodeSignature (
+ VOID
+ )
+{
+ UINT64 Signature;
+
+ AsmWriteMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID, 0);
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
+ Signature = AsmReadMsr64 (EFI_MSR_IA32_BIOS_SIGN_ID);
+ return (UINT32) RShiftU64 (Signature, 32);
+}
+
+/**
+ Detect whether specified processor can find matching microcode patch and load it.
+
+**/
+VOID
+MicrocodeDetect (
+ VOID
+ )
+{
+ UINT64 MicrocodePatchAddress;
+ UINT64 MicrocodePatchRegionSize;
+ UINT32 ExtendedTableLength;
+ UINT32 ExtendedTableCount;
+ EFI_CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
+ EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
+ EFI_CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
+ UINTN MicrocodeEnd;
+ UINTN Index;
+ UINT8 PlatformId;
+ UINT32 RegEax;
+ UINT32 LatestRevision;
+ UINTN TotalSize;
+ UINT32 CheckSum32;
+ BOOLEAN CorrectMicrocode;
+ INT32 CurrentSignature;
+ MICROCODE_INFO MicrocodeInfo;
+
+ ZeroMem (&MicrocodeInfo, sizeof (MICROCODE_INFO));
+ MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
+ MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
+ if (MicrocodePatchRegionSize == 0) {
+ //
+ // There is no microcode patches
+ //
+ return;
+ }
+
+ ExtendedTableLength = 0;
+ //
+ // Here data of CPUID leafs have not been collected into context buffer, so
+ // GetProcessorCpuid() cannot be used here to retrieve CPUID data.
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, NULL);
+
+ //
+ // The index of platform information resides in bits 50:52 of MSR IA32_PLATFORM_ID
+ //
+ PlatformId = (UINT8) AsmMsrBitFieldRead64 (EFI_MSR_IA32_PLATFORM_ID, 50, 52);
+
+ LatestRevision = 0;
+ MicrocodeEnd = (UINTN) (MicrocodePatchAddress + MicrocodePatchRegionSize);
+ MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (UINTN) MicrocodePatchAddress;
+ do {
+ //
+ // Check if the microcode is for the Cpu and the version is newer
+ // and the update can be processed on the platform
+ //
+ CorrectMicrocode = FALSE;
+ if (MicrocodeEntryPoint->HeaderVersion == 0x1) {
+ //
+ // It is the microcode header. It is not the padding data between microcode patches
+ // becasue the padding data should not include 0x00000001 and it should be the repeated
+ // byte format (like 0xXYXYXYXY....).
+ //
+ if (MicrocodeEntryPoint->ProcessorId == RegEax &&
+ MicrocodeEntryPoint->UpdateRevision > LatestRevision &&
+ (MicrocodeEntryPoint->ProcessorFlags & (1 << PlatformId))
+ ) {
+ if (MicrocodeEntryPoint->DataSize == 0) {
+ CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, 2048);
+ } else {
+ CheckSum32 = CalculateSum32 ((UINT32 *)MicrocodeEntryPoint, MicrocodeEntryPoint->DataSize + sizeof(EFI_CPU_MICROCODE_HEADER));
+ }
+ if (CheckSum32 == 0) {
+ CorrectMicrocode = TRUE;
+ }
+ } else if ((MicrocodeEntryPoint->DataSize != 0) &&
+ (MicrocodeEntryPoint->UpdateRevision > LatestRevision)) {
+ ExtendedTableLength = MicrocodeEntryPoint->TotalSize - (MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+ if (ExtendedTableLength != 0) {
+ //
+ // Extended Table exist, check if the CPU in support list
+ //
+ ExtendedTableHeader = (EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER *)((UINT8 *)(MicrocodeEntryPoint) + MicrocodeEntryPoint->DataSize + sizeof (EFI_CPU_MICROCODE_HEADER));
+ //
+ // Calculate Extended Checksum
+ //
+ if ((ExtendedTableLength % 4) == 0) {
+ CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTableHeader, ExtendedTableLength);
+ if (CheckSum32 == 0) {
+ //
+ // Checksum correct
+ //
+ ExtendedTableCount = ExtendedTableHeader->ExtendedSignatureCount;
+ ExtendedTable = (EFI_CPU_MICROCODE_EXTENDED_TABLE *)(ExtendedTableHeader + 1);
+ for (Index = 0; Index < ExtendedTableCount; Index ++) {
+ CheckSum32 = CalculateSum32 ((UINT32 *)ExtendedTable, sizeof(EFI_CPU_MICROCODE_EXTENDED_TABLE));
+ if (CheckSum32 == 0) {
+ //
+ // Verify Header
+ //
+ if ((ExtendedTable->ProcessorSignature == RegEax) &&
+ (ExtendedTable->ProcessorFlag & (1 << PlatformId)) ) {
+ //
+ // Find one
+ //
+ CorrectMicrocode = TRUE;
+ break;
+ }
+ }
+ ExtendedTable ++;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ //
+ // It is the padding data between the microcode patches for microcode patches alignment.
+ // Because the microcode patch is the multiple of 1-KByte, the padding data should not
+ // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
+ // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
+ // find the next possible microcode patch header.
+ //
+ MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
+ continue;
+ }
+ //
+ // Get the next patch.
+ //
+ if (MicrocodeEntryPoint->DataSize == 0) {
+ TotalSize = 2048;
+ } else {
+ TotalSize = MicrocodeEntryPoint->TotalSize;
+ }
+
+ if (CorrectMicrocode) {
+ LatestRevision = MicrocodeEntryPoint->UpdateRevision;
+ MicrocodeInfo.MicrocodeData = (VOID *)((UINTN)MicrocodeEntryPoint + sizeof (EFI_CPU_MICROCODE_HEADER));
+ MicrocodeInfo.MicrocodeSize = TotalSize;
+ MicrocodeInfo.ProcessorId = RegEax;
+ }
+
+ MicrocodeEntryPoint = (EFI_CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + TotalSize);
+ } while (((UINTN) MicrocodeEntryPoint < MicrocodeEnd));
+
+ if (LatestRevision > 0) {
+ //
+ // Get microcode update signature of currently loaded microcode update
+ //
+ CurrentSignature = GetCurrentMicrocodeSignature ();
+ //
+ // If no microcode update has been loaded, then trigger microcode load.
+ //
+ if (CurrentSignature == 0) {
+ AsmWriteMsr64 (
+ EFI_MSR_IA32_BIOS_UPDT_TRIG,
+ (UINT64) (UINTN) MicrocodeInfo.MicrocodeData
+ );
+ MicrocodeInfo.Load = TRUE;
+ } else {
+ MicrocodeInfo.Load = FALSE;
+ }
+ }
+}
diff --git a/UefiCpuPkg/CpuMpPei/Microcode.h b/UefiCpuPkg/CpuMpPei/Microcode.h index 6f93e2f044..ea686690ff 100644 --- a/UefiCpuPkg/CpuMpPei/Microcode.h +++ b/UefiCpuPkg/CpuMpPei/Microcode.h @@ -1,68 +1,68 @@ -/** @file - Definitions for loading microcode on processors. - - Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef _CPU_MICROCODE_H_ -#define _CPU_MICROCODE_H_ - -#define EFI_MSR_IA32_PLATFORM_ID 0x17 -#define EFI_MSR_IA32_BIOS_UPDT_TRIG 0x79 -#define EFI_MSR_IA32_BIOS_SIGN_ID 0x8b - -#define MAX_MICROCODE_DESCRIPTOR_LENGTH 100 - -typedef struct { - VOID *MicrocodeData; - UINTN MicrocodeSize; - UINT32 ProcessorId; - BOOLEAN Load; -} MICROCODE_INFO; - -// -// Definition for IA32 microcode format -// -typedef struct { - UINT32 HeaderVersion; - UINT32 UpdateRevision; - UINT32 Date; - UINT32 ProcessorId; - UINT32 Checksum; - UINT32 LoaderRevision; - UINT32 ProcessorFlags; - UINT32 DataSize; - UINT32 TotalSize; - UINT8 Reserved[12]; -} EFI_CPU_MICROCODE_HEADER; - -typedef struct { - UINT32 ExtendedSignatureCount; - UINT32 ExtendedTableChecksum; - UINT8 Reserved[12]; -} EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER; - -typedef struct { - UINT32 ProcessorSignature; - UINT32 ProcessorFlag; - UINT32 ProcessorChecksum; -} EFI_CPU_MICROCODE_EXTENDED_TABLE; - -/** - Detect whether specified processor can find matching microcode patch and load it. - -**/ -VOID -MicrocodeDetect ( - VOID - ); - -#endif +/** @file
+ Definitions for loading microcode on processors.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _CPU_MICROCODE_H_
+#define _CPU_MICROCODE_H_
+
+#define EFI_MSR_IA32_PLATFORM_ID 0x17
+#define EFI_MSR_IA32_BIOS_UPDT_TRIG 0x79
+#define EFI_MSR_IA32_BIOS_SIGN_ID 0x8b
+
+#define MAX_MICROCODE_DESCRIPTOR_LENGTH 100
+
+typedef struct {
+ VOID *MicrocodeData;
+ UINTN MicrocodeSize;
+ UINT32 ProcessorId;
+ BOOLEAN Load;
+} MICROCODE_INFO;
+
+//
+// Definition for IA32 microcode format
+//
+typedef struct {
+ UINT32 HeaderVersion;
+ UINT32 UpdateRevision;
+ UINT32 Date;
+ UINT32 ProcessorId;
+ UINT32 Checksum;
+ UINT32 LoaderRevision;
+ UINT32 ProcessorFlags;
+ UINT32 DataSize;
+ UINT32 TotalSize;
+ UINT8 Reserved[12];
+} EFI_CPU_MICROCODE_HEADER;
+
+typedef struct {
+ UINT32 ExtendedSignatureCount;
+ UINT32 ExtendedTableChecksum;
+ UINT8 Reserved[12];
+} EFI_CPU_MICROCODE_EXTENDED_TABLE_HEADER;
+
+typedef struct {
+ UINT32 ProcessorSignature;
+ UINT32 ProcessorFlag;
+ UINT32 ProcessorChecksum;
+} EFI_CPU_MICROCODE_EXTENDED_TABLE;
+
+/**
+ Detect whether specified processor can find matching microcode patch and load it.
+
+**/
+VOID
+MicrocodeDetect (
+ VOID
+ );
+
+#endif
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.c b/UefiCpuPkg/CpuMpPei/PeiMpServices.c index 4689d2fcc0..503778fd93 100644 --- a/UefiCpuPkg/CpuMpPei/PeiMpServices.c +++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.c @@ -1,942 +1,942 @@ -/** @file - Implementation of Multiple Processor PPI services. - - Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "PeiMpServices.h" - -// -// CPU MP PPI to be installed -// -EFI_PEI_MP_SERVICES_PPI mMpServicesPpi = { - PeiGetNumberOfProcessors, - PeiGetProcessorInfo, - PeiStartupAllAPs, - PeiStartupThisAP, - PeiSwitchBSP, - PeiEnableDisableAP, - PeiWhoAmI, -}; - -EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiDesc = { - (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST), - &gEfiPeiMpServicesPpiGuid, - &mMpServicesPpi -}; - -/** - Get CPU Package/Core/Thread location information. - - @param InitialApicId CPU APIC ID - @param Location Pointer to CPU location information -**/ -VOID -ExtractProcessorLocation ( - IN UINT32 InitialApicId, - OUT EFI_CPU_PHYSICAL_LOCATION *Location - ) -{ - BOOLEAN TopologyLeafSupported; - UINTN ThreadBits; - UINTN CoreBits; - UINT32 RegEax; - UINT32 RegEbx; - UINT32 RegEcx; - UINT32 RegEdx; - UINT32 MaxCpuIdIndex; - UINT32 SubIndex; - UINTN LevelType; - UINT32 MaxLogicProcessorsPerPackage; - UINT32 MaxCoresPerPackage; - - // - // Check if the processor is capable of supporting more than one logical processor. - // - AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx); - if ((RegEdx & BIT28) == 0) { - Location->Thread = 0; - Location->Core = 0; - Location->Package = 0; - return; - } - - ThreadBits = 0; - CoreBits = 0; - - // - // Assume three-level mapping of APIC ID: Package:Core:SMT. - // - - TopologyLeafSupported = FALSE; - // - // Get the max index of basic CPUID - // - AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL); - - // - // If the extended topology enumeration leaf is available, it - // is the preferred mechanism for enumerating topology. - // - if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) { - AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, &RegEax, &RegEbx, &RegEcx, NULL); - // - // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for - // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not - // supported on that processor. - // - if (RegEbx != 0) { - TopologyLeafSupported = TRUE; - - // - // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract - // the SMT sub-field of x2APIC ID. - // - LevelType = (RegEcx >> 8) & 0xff; - ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT); - ThreadBits = RegEax & 0x1f; - - // - // Software must not assume any "level type" encoding - // value to be related to any sub-leaf index, except sub-leaf 0. - // - SubIndex = 1; - do { - AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, SubIndex, &RegEax, NULL, &RegEcx, NULL); - LevelType = (RegEcx >> 8) & 0xff; - if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) { - CoreBits = (RegEax & 0x1f) - ThreadBits; - break; - } - SubIndex++; - } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID); - } - } - - if (!TopologyLeafSupported) { - AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL); - MaxLogicProcessorsPerPackage = (RegEbx >> 16) & 0xff; - if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) { - AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &RegEax, NULL, NULL, NULL); - MaxCoresPerPackage = (RegEax >> 26) + 1; - } else { - // - // Must be a single-core processor. - // - MaxCoresPerPackage = 1; - } - - ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1); - CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1); - } - - Location->Thread = InitialApicId & ~((-1) << ThreadBits); - Location->Core = (InitialApicId >> ThreadBits) & ~((-1) << CoreBits); - Location->Package = (InitialApicId >> (ThreadBits + CoreBits)); -} - -/** - Find the current Processor number by APIC ID. - - @param PeiCpuMpData Pointer to PEI CPU MP Data - @param ProcessorNumber Return the pocessor number found - - @retval EFI_SUCCESS ProcessorNumber is found and returned. - @retval EFI_NOT_FOUND ProcessorNumber is not found. -**/ -EFI_STATUS -GetProcessorNumber ( - IN PEI_CPU_MP_DATA *PeiCpuMpData, - OUT UINTN *ProcessorNumber - ) -{ - UINTN TotalProcessorNumber; - UINTN Index; - - TotalProcessorNumber = PeiCpuMpData->CpuCount; - for (Index = 0; Index < TotalProcessorNumber; Index ++) { - if (PeiCpuMpData->CpuData[Index].ApicId == GetInitialApicId ()) { - *ProcessorNumber = Index; - return EFI_SUCCESS; - } - } - return EFI_NOT_FOUND; -} - -/** - Worker function for SwitchBSP(). - - Worker function for SwitchBSP(), assigned to the AP which is intended to become BSP. - - @param Buffer Pointer to CPU MP Data -**/ -VOID -EFIAPI -FutureBSPProc ( - IN VOID *Buffer - ) -{ - PEI_CPU_MP_DATA *DataInHob; - - DataInHob = (PEI_CPU_MP_DATA *) Buffer; - AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo); -} - -/** - This service retrieves the number of logical processor in the platform - and the number of those logical processors that are enabled on this boot. - This service may only be called from the BSP. - - This function is used to retrieve the following information: - - The number of logical processors that are present in the system. - - The number of enabled logical processors in the system at the instant - this call is made. - - Because MP Service Ppi provides services to enable and disable processors - dynamically, the number of enabled logical processors may vary during the - course of a boot session. - - If this service is called from an AP, then EFI_DEVICE_ERROR is returned. - If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then - EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors - is returned in NumberOfProcessors, the number of currently enabled processor - is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This Pointer to this instance of the PPI. - @param[out] NumberOfProcessors Pointer to the total number of logical processors in - the system, including the BSP and disabled APs. - @param[out] NumberOfEnabledProcessors - Number of processors in the system that are enabled. - - @retval EFI_SUCCESS The number of logical processors and enabled - logical processors was retrieved. - @retval EFI_DEVICE_ERROR The calling processor is an AP. - @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL. - NumberOfEnabledProcessors is NULL. -**/ -EFI_STATUS -EFIAPI -PeiGetNumberOfProcessors ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - OUT UINTN *NumberOfProcessors, - OUT UINTN *NumberOfEnabledProcessors - ) -{ - PEI_CPU_MP_DATA *PeiCpuMpData; - UINTN CallerNumber; - UINTN ProcessorNumber; - UINTN EnabledProcessorNumber; - UINTN Index; - - PeiCpuMpData = GetMpHobData (); - if (PeiCpuMpData == NULL) { - return EFI_NOT_FOUND; - } - - if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) { - return EFI_INVALID_PARAMETER; - } - - // - // Check whether caller processor is BSP - // - PeiWhoAmI (PeiServices, This, &CallerNumber); - if (CallerNumber != PeiCpuMpData->BspNumber) { - return EFI_DEVICE_ERROR; - } - - ProcessorNumber = PeiCpuMpData->CpuCount; - EnabledProcessorNumber = 0; - for (Index = 0; Index < ProcessorNumber; Index++) { - if (PeiCpuMpData->CpuData[Index].State != CpuStateDisabled) { - EnabledProcessorNumber ++; - } - } - - *NumberOfProcessors = ProcessorNumber; - *NumberOfEnabledProcessors = EnabledProcessorNumber; - - return EFI_SUCCESS; -} - -/** - Gets detailed MP-related information on the requested processor at the - instant this call is made. This service may only be called from the BSP. - - This service retrieves detailed MP-related information about any processor - on the platform. Note the following: - - The processor information may change during the course of a boot session. - - The information presented here is entirely MP related. - - Information regarding the number of caches and their sizes, frequency of operation, - slot numbers is all considered platform-related information and is not provided - by this service. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This Pointer to this instance of the PPI. - @param[in] ProcessorNumber Pointer to the total number of logical processors in - the system, including the BSP and disabled APs. - @param[out] ProcessorInfoBuffer Number of processors in the system that are enabled. - - @retval EFI_SUCCESS Processor information was returned. - @retval EFI_DEVICE_ERROR The calling processor is an AP. - @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. - @retval EFI_NOT_FOUND The processor with the handle specified by - ProcessorNumber does not exist in the platform. -**/ -EFI_STATUS -EFIAPI -PeiGetProcessorInfo ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - IN UINTN ProcessorNumber, - OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer - ) -{ - PEI_CPU_MP_DATA *PeiCpuMpData; - UINTN CallerNumber; - - PeiCpuMpData = GetMpHobData (); - if (PeiCpuMpData == NULL) { - return EFI_NOT_FOUND; - } - - // - // Check whether caller processor is BSP - // - PeiWhoAmI (PeiServices, This, &CallerNumber); - if (CallerNumber != PeiCpuMpData->BspNumber) { - return EFI_DEVICE_ERROR; - } - - if (ProcessorInfoBuffer == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (ProcessorNumber >= PeiCpuMpData->CpuCount) { - return EFI_NOT_FOUND; - } - - ProcessorInfoBuffer->ProcessorId = (UINT64) PeiCpuMpData->CpuData[ProcessorNumber].ApicId; - ProcessorInfoBuffer->StatusFlag = 0; - if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId == GetInitialApicId()) { - ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT; - } - if (PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 == 0) { - ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT; - } - if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) { - ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT; - } else { - ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT; - } - - // - // Get processor location information - // - ExtractProcessorLocation (PeiCpuMpData->CpuData[ProcessorNumber].ApicId, &ProcessorInfoBuffer->Location); - - return EFI_SUCCESS; -} - -/** - This service executes a caller provided function on all enabled APs. APs can - run either simultaneously or one at a time in sequence. This service supports - both blocking requests only. This service may only - be called from the BSP. - - This function is used to dispatch all the enabled APs to the function specified - by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned - immediately and Procedure is not started on any AP. - - If SingleThread is TRUE, all the enabled APs execute the function specified by - Procedure one by one, in ascending order of processor handle number. Otherwise, - all the enabled APs execute the function specified by Procedure simultaneously. - - If the timeout specified by TimeoutInMicroSeconds expires before all APs return - from Procedure, then Procedure on the failed APs is terminated. All enabled APs - are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() - and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its - content points to the list of processor handle numbers in which Procedure was - terminated. - - Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() - to make sure that the nature of the code that is executed on the BSP and the - dispatched APs is well controlled. The MP Services Ppi does not guarantee - that the Procedure function is MP-safe. Hence, the tasks that can be run in - parallel are limited to certain independent tasks and well-controlled exclusive - code. PEI services and Ppis may not be called by APs unless otherwise - specified. - - In blocking execution mode, BSP waits until all APs finish or - TimeoutInMicroSeconds expires. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance. - @param[in] Procedure A pointer to the function to be run on enabled APs of - the system. - @param[in] SingleThread If TRUE, then all the enabled APs execute the function - specified by Procedure one by one, in ascending order - of processor handle number. If FALSE, then all the - enabled APs execute the function specified by Procedure - simultaneously. - @param[in] TimeoutInMicroSeconds - Indicates the time limit in microseconds for APs to - return from Procedure, for blocking mode only. Zero - means infinity. If the timeout expires before all APs - return from Procedure, then Procedure on the failed APs - is terminated. All enabled APs are available for next - function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() - or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the - timeout expires in blocking mode, BSP returns - EFI_TIMEOUT. - @param[in] ProcedureArgument The parameter passed into Procedure for all APs. - - @retval EFI_SUCCESS In blocking mode, all APs have finished before the - timeout expired. - @retval EFI_DEVICE_ERROR Caller processor is AP. - @retval EFI_NOT_STARTED No enabled APs exist in the system. - @retval EFI_NOT_READY Any enabled APs are busy. - @retval EFI_TIMEOUT In blocking mode, the timeout expired before all - enabled APs have finished. - @retval EFI_INVALID_PARAMETER Procedure is NULL. -**/ -EFI_STATUS -EFIAPI -PeiStartupAllAPs ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - IN EFI_AP_PROCEDURE Procedure, - IN BOOLEAN SingleThread, - IN UINTN TimeoutInMicroSeconds, - IN VOID *ProcedureArgument OPTIONAL - ) -{ - PEI_CPU_MP_DATA *PeiCpuMpData; - UINTN ProcessorNumber; - UINTN Index; - UINTN CallerNumber; - BOOLEAN HasEnabledAp; - BOOLEAN HasEnabledIdleAp; - volatile UINT32 *FinishedCount; - EFI_STATUS Status; - UINTN WaitCountIndex; - UINTN WaitCountNumber; - - PeiCpuMpData = GetMpHobData (); - if (PeiCpuMpData == NULL) { - return EFI_NOT_FOUND; - } - - // - // Check whether caller processor is BSP - // - PeiWhoAmI (PeiServices, This, &CallerNumber); - if (CallerNumber != PeiCpuMpData->BspNumber) { - return EFI_DEVICE_ERROR; - } - - ProcessorNumber = PeiCpuMpData->CpuCount; - - HasEnabledAp = FALSE; - HasEnabledIdleAp = FALSE; - for (Index = 0; Index < ProcessorNumber; Index ++) { - if (Index == CallerNumber) { - // - // Skip BSP - // - continue; - } - if (PeiCpuMpData->CpuData[Index].State != CpuStateDisabled) { - HasEnabledAp = TRUE; - if (PeiCpuMpData->CpuData[Index].State != CpuStateBusy) { - HasEnabledIdleAp = TRUE; - } - } - } - if (!HasEnabledAp) { - // - // If no enabled AP exists, return EFI_NOT_STARTED. - // - return EFI_NOT_STARTED; - } - if (!HasEnabledIdleAp) { - // - // If any enabled APs are busy, return EFI_NOT_READY. - // - return EFI_NOT_READY; - } - - if (PeiCpuMpData->EndOfPeiFlag) { - // - // Backup original data and copy AP reset vector in it - // - BackupAndPrepareWakeupBuffer(PeiCpuMpData); - } - - WaitCountNumber = TimeoutInMicroSeconds / CPU_CHECK_AP_INTERVAL + 1; - WaitCountIndex = 0; - FinishedCount = &PeiCpuMpData->FinishedCount; - if (!SingleThread) { - WakeUpAP (PeiCpuMpData, TRUE, 0, Procedure, ProcedureArgument); - // - // Wait to finish - // - if (TimeoutInMicroSeconds == 0) { - while (*FinishedCount < ProcessorNumber - 1) { - CpuPause (); - } - Status = EFI_SUCCESS; - } else { - Status = EFI_TIMEOUT; - for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) { - MicroSecondDelay (CPU_CHECK_AP_INTERVAL); - if (*FinishedCount >= ProcessorNumber - 1) { - Status = EFI_SUCCESS; - break; - } - } - } - } else { - Status = EFI_SUCCESS; - for (Index = 0; Index < ProcessorNumber; Index++) { - if (Index == CallerNumber) { - continue; - } - WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[Index].ApicId, Procedure, ProcedureArgument); - // - // Wait to finish - // - if (TimeoutInMicroSeconds == 0) { - while (*FinishedCount < 1) { - CpuPause (); - } - } else { - for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) { - MicroSecondDelay (CPU_CHECK_AP_INTERVAL); - if (*FinishedCount >= 1) { - break; - } - } - if (WaitCountIndex == WaitCountNumber) { - Status = EFI_TIMEOUT; - } - } - } - } - - if (PeiCpuMpData->EndOfPeiFlag) { - // - // Restore original data - // - RestoreWakeupBuffer(PeiCpuMpData); - } - - return Status; -} - -/** - This service lets the caller get one enabled AP to execute a caller-provided - function. The caller can request the BSP to wait for the completion - of the AP. This service may only be called from the BSP. - - This function is used to dispatch one enabled AP to the function specified by - Procedure passing in the argument specified by ProcedureArgument. - The execution is in blocking mode. The BSP waits until the AP finishes or - TimeoutInMicroSecondss expires. - - If the timeout specified by TimeoutInMicroseconds expires before the AP returns - from Procedure, then execution of Procedure by the AP is terminated. The AP is - available for subsequent calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() and - EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance. - @param[in] Procedure A pointer to the function to be run on enabled APs of - the system. - @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the - total number of logical processors minus 1. The total - number of logical processors can be retrieved by - EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). - @param[in] TimeoutInMicroseconds - Indicates the time limit in microseconds for APs to - return from Procedure, for blocking mode only. Zero - means infinity. If the timeout expires before all APs - return from Procedure, then Procedure on the failed APs - is terminated. All enabled APs are available for next - function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() - or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the - timeout expires in blocking mode, BSP returns - EFI_TIMEOUT. - @param[in] ProcedureArgument The parameter passed into Procedure for all APs. - - @retval EFI_SUCCESS In blocking mode, specified AP finished before the - timeout expires. - @retval EFI_DEVICE_ERROR The calling processor is an AP. - @retval EFI_TIMEOUT In blocking mode, the timeout expired before the - specified AP has finished. - @retval EFI_NOT_FOUND The processor with the handle specified by - ProcessorNumber does not exist. - @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP. - @retval EFI_INVALID_PARAMETER Procedure is NULL. -**/ -EFI_STATUS -EFIAPI -PeiStartupThisAP ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - IN EFI_AP_PROCEDURE Procedure, - IN UINTN ProcessorNumber, - IN UINTN TimeoutInMicroseconds, - IN VOID *ProcedureArgument OPTIONAL - ) -{ - PEI_CPU_MP_DATA *PeiCpuMpData; - UINTN CallerNumber; - volatile UINT32 *FinishedCount; - EFI_STATUS Status; - UINTN WaitCountIndex; - UINTN WaitCountNumber; - - PeiCpuMpData = GetMpHobData (); - if (PeiCpuMpData == NULL) { - return EFI_NOT_FOUND; - } - - // - // Check whether caller processor is BSP - // - PeiWhoAmI (PeiServices, This, &CallerNumber); - if (CallerNumber != PeiCpuMpData->BspNumber) { - return EFI_DEVICE_ERROR; - } - - if (ProcessorNumber >= PeiCpuMpData->CpuCount) { - return EFI_NOT_FOUND; - } - - if (ProcessorNumber == PeiCpuMpData->BspNumber || Procedure == NULL) { - return EFI_INVALID_PARAMETER; - } - - // - // Check whether specified AP is disabled - // - if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) { - return EFI_INVALID_PARAMETER; - } - - if (PeiCpuMpData->EndOfPeiFlag) { - // - // Backup original data and copy AP reset vector in it - // - BackupAndPrepareWakeupBuffer(PeiCpuMpData); - } - - WaitCountNumber = TimeoutInMicroseconds / CPU_CHECK_AP_INTERVAL + 1; - WaitCountIndex = 0; - FinishedCount = &PeiCpuMpData->FinishedCount; - - WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[ProcessorNumber].ApicId, Procedure, ProcedureArgument); - - // - // Wait to finish - // - if (TimeoutInMicroseconds == 0) { - while (*FinishedCount < 1) { - CpuPause() ; - } - Status = EFI_SUCCESS; - } else { - Status = EFI_TIMEOUT; - for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) { - MicroSecondDelay (CPU_CHECK_AP_INTERVAL); - if (*FinishedCount >= 1) { - Status = EFI_SUCCESS; - break; - } - } - } - - if (PeiCpuMpData->EndOfPeiFlag) { - // - // Backup original data and copy AP reset vector in it - // - RestoreWakeupBuffer(PeiCpuMpData); - } - - return Status; -} - -/** - This service switches the requested AP to be the BSP from that point onward. - This service changes the BSP for all purposes. This call can only be performed - by the current BSP. - - This service switches the requested AP to be the BSP from that point onward. - This service changes the BSP for all purposes. The new BSP can take over the - execution of the old BSP and continue seamlessly from where the old one left - off. - - If the BSP cannot be switched prior to the return from this service, then - EFI_UNSUPPORTED must be returned. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance. - @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the - total number of logical processors minus 1. The total - number of logical processors can be retrieved by - EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). - @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an enabled - AP. Otherwise, it will be disabled. - - @retval EFI_SUCCESS BSP successfully switched. - @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to this - service returning. - @retval EFI_UNSUPPORTED Switching the BSP is not supported. - @retval EFI_SUCCESS The calling processor is an AP. - @retval EFI_NOT_FOUND The processor with the handle specified by - ProcessorNumber does not exist. - @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or a disabled - AP. - @retval EFI_NOT_READY The specified AP is busy. -**/ -EFI_STATUS -EFIAPI -PeiSwitchBSP ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - IN UINTN ProcessorNumber, - IN BOOLEAN EnableOldBSP - ) -{ - PEI_CPU_MP_DATA *PeiCpuMpData; - UINTN CallerNumber; - MSR_IA32_APIC_BASE ApicBaseMsr; - - PeiCpuMpData = GetMpHobData (); - if (PeiCpuMpData == NULL) { - return EFI_NOT_FOUND; - } - - // - // Check whether caller processor is BSP - // - PeiWhoAmI (PeiServices, This, &CallerNumber); - if (CallerNumber != PeiCpuMpData->BspNumber) { - return EFI_SUCCESS; - } - - if (ProcessorNumber >= PeiCpuMpData->CpuCount) { - return EFI_NOT_FOUND; - } - - // - // Check whether specified AP is disabled - // - if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) { - return EFI_INVALID_PARAMETER; - } - - // - // Check whether ProcessorNumber specifies the current BSP - // - if (ProcessorNumber == PeiCpuMpData->BspNumber) { - return EFI_INVALID_PARAMETER; - } - - // - // Check whether specified AP is busy - // - if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateBusy) { - return EFI_NOT_READY; - } - - // - // Clear the BSP bit of MSR_IA32_APIC_BASE - // - ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS); - ApicBaseMsr.Bits.Bsp = 0; - AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64); - - PeiCpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE; - PeiCpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE; - - if (PeiCpuMpData->EndOfPeiFlag) { - // - // Backup original data and copy AP reset vector in it - // - BackupAndPrepareWakeupBuffer(PeiCpuMpData); - } - - // - // Need to wakeUp AP (future BSP). - // - WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[ProcessorNumber].ApicId, FutureBSPProc, PeiCpuMpData); - - AsmExchangeRole (&PeiCpuMpData->BSPInfo, &PeiCpuMpData->APInfo); - - if (PeiCpuMpData->EndOfPeiFlag) { - // - // Backup original data and copy AP reset vector in it - // - RestoreWakeupBuffer(PeiCpuMpData); - } - - // - // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP - // - ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS); - ApicBaseMsr.Bits.Bsp = 1; - AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64); - - return EFI_SUCCESS; -} - -/** - This service lets the caller enable or disable an AP from this point onward. - This service may only be called from the BSP. - - This service allows the caller enable or disable an AP from this point onward. - The caller can optionally specify the health status of the AP by Health. If - an AP is being disabled, then the state of the disabled AP is implementation - dependent. If an AP is enabled, then the implementation must guarantee that a - complete initialization sequence is performed on the AP, so the AP is in a state - that is compatible with an MP operating system. - - If the enable or disable AP operation cannot be completed prior to the return - from this service, then EFI_UNSUPPORTED must be returned. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance. - @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the - total number of logical processors minus 1. The total - number of logical processors can be retrieved by - EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). - @param[in] EnableAP Specifies the new state for the processor for enabled, - FALSE for disabled. - @param[in] HealthFlag If not NULL, a pointer to a value that specifies the - new health status of the AP. This flag corresponds to - StatusFlag defined in EFI_PEI_MP_SERVICES_PPI.GetProcessorInfo(). - Only the PROCESSOR_HEALTH_STATUS_BIT is used. All other - bits are ignored. If it is NULL, this parameter is - ignored. - - @retval EFI_SUCCESS The specified AP was enabled or disabled successfully. - @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed prior - to this service returning. - @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported. - @retval EFI_DEVICE_ERROR The calling processor is an AP. - @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber - does not exist. - @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. -**/ -EFI_STATUS -EFIAPI -PeiEnableDisableAP ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - IN UINTN ProcessorNumber, - IN BOOLEAN EnableAP, - IN UINT32 *HealthFlag OPTIONAL - ) -{ - PEI_CPU_MP_DATA *PeiCpuMpData; - UINTN CallerNumber; - - PeiCpuMpData = GetMpHobData (); - if (PeiCpuMpData == NULL) { - return EFI_NOT_FOUND; - } - - // - // Check whether caller processor is BSP - // - PeiWhoAmI (PeiServices, This, &CallerNumber); - if (CallerNumber != PeiCpuMpData->BspNumber) { - return EFI_DEVICE_ERROR; - } - - if (ProcessorNumber == PeiCpuMpData->BspNumber) { - return EFI_INVALID_PARAMETER; - } - - if (ProcessorNumber >= PeiCpuMpData->CpuCount) { - return EFI_NOT_FOUND; - } - - if (!EnableAP) { - PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateDisabled; - } else { - PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle; - } - - if (HealthFlag != NULL) { - PeiCpuMpData->CpuData[ProcessorNumber].CpuHealthy = - (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0); - } - return EFI_SUCCESS; -} - -/** - This return the handle number for the calling processor. This service may be - called from the BSP and APs. - - This service returns the processor handle number for the calling processor. - The returned value is in the range from 0 to the total number of logical - processors minus 1. The total number of logical processors can be retrieved - with EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). This service may be - called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER - is returned. Otherwise, the current processors handle number is returned in - ProcessorNumber, and EFI_SUCCESS is returned. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance. - @param[out] ProcessorNumber The handle number of the AP. The range is from 0 to the - total number of logical processors minus 1. The total - number of logical processors can be retrieved by - EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). - - @retval EFI_SUCCESS The current processor handle number was returned in - ProcessorNumber. - @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. -**/ -EFI_STATUS -EFIAPI -PeiWhoAmI ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - OUT UINTN *ProcessorNumber - ) -{ - PEI_CPU_MP_DATA *PeiCpuMpData; - - PeiCpuMpData = GetMpHobData (); - if (PeiCpuMpData == NULL) { - return EFI_NOT_FOUND; - } - - if (ProcessorNumber == NULL) { - return EFI_INVALID_PARAMETER; - } - - return GetProcessorNumber (PeiCpuMpData, ProcessorNumber); -} - +/** @file
+ Implementation of Multiple Processor PPI services.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PeiMpServices.h"
+
+//
+// CPU MP PPI to be installed
+//
+EFI_PEI_MP_SERVICES_PPI mMpServicesPpi = {
+ PeiGetNumberOfProcessors,
+ PeiGetProcessorInfo,
+ PeiStartupAllAPs,
+ PeiStartupThisAP,
+ PeiSwitchBSP,
+ PeiEnableDisableAP,
+ PeiWhoAmI,
+};
+
+EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiDesc = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiMpServicesPpiGuid,
+ &mMpServicesPpi
+};
+
+/**
+ Get CPU Package/Core/Thread location information.
+
+ @param InitialApicId CPU APIC ID
+ @param Location Pointer to CPU location information
+**/
+VOID
+ExtractProcessorLocation (
+ IN UINT32 InitialApicId,
+ OUT EFI_CPU_PHYSICAL_LOCATION *Location
+ )
+{
+ BOOLEAN TopologyLeafSupported;
+ UINTN ThreadBits;
+ UINTN CoreBits;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+ UINT32 RegEdx;
+ UINT32 MaxCpuIdIndex;
+ UINT32 SubIndex;
+ UINTN LevelType;
+ UINT32 MaxLogicProcessorsPerPackage;
+ UINT32 MaxCoresPerPackage;
+
+ //
+ // Check if the processor is capable of supporting more than one logical processor.
+ //
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT28) == 0) {
+ Location->Thread = 0;
+ Location->Core = 0;
+ Location->Package = 0;
+ return;
+ }
+
+ ThreadBits = 0;
+ CoreBits = 0;
+
+ //
+ // Assume three-level mapping of APIC ID: Package:Core:SMT.
+ //
+
+ TopologyLeafSupported = FALSE;
+ //
+ // Get the max index of basic CPUID
+ //
+ AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
+
+ //
+ // If the extended topology enumeration leaf is available, it
+ // is the preferred mechanism for enumerating topology.
+ //
+ if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
+ AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, &RegEax, &RegEbx, &RegEcx, NULL);
+ //
+ // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
+ // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
+ // supported on that processor.
+ //
+ if (RegEbx != 0) {
+ TopologyLeafSupported = TRUE;
+
+ //
+ // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
+ // the SMT sub-field of x2APIC ID.
+ //
+ LevelType = (RegEcx >> 8) & 0xff;
+ ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
+ ThreadBits = RegEax & 0x1f;
+
+ //
+ // Software must not assume any "level type" encoding
+ // value to be related to any sub-leaf index, except sub-leaf 0.
+ //
+ SubIndex = 1;
+ do {
+ AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, SubIndex, &RegEax, NULL, &RegEcx, NULL);
+ LevelType = (RegEcx >> 8) & 0xff;
+ if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
+ CoreBits = (RegEax & 0x1f) - ThreadBits;
+ break;
+ }
+ SubIndex++;
+ } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
+ }
+ }
+
+ if (!TopologyLeafSupported) {
+ AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
+ MaxLogicProcessorsPerPackage = (RegEbx >> 16) & 0xff;
+ if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
+ AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &RegEax, NULL, NULL, NULL);
+ MaxCoresPerPackage = (RegEax >> 26) + 1;
+ } else {
+ //
+ // Must be a single-core processor.
+ //
+ MaxCoresPerPackage = 1;
+ }
+
+ ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
+ CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1);
+ }
+
+ Location->Thread = InitialApicId & ~((-1) << ThreadBits);
+ Location->Core = (InitialApicId >> ThreadBits) & ~((-1) << CoreBits);
+ Location->Package = (InitialApicId >> (ThreadBits + CoreBits));
+}
+
+/**
+ Find the current Processor number by APIC ID.
+
+ @param PeiCpuMpData Pointer to PEI CPU MP Data
+ @param ProcessorNumber Return the pocessor number found
+
+ @retval EFI_SUCCESS ProcessorNumber is found and returned.
+ @retval EFI_NOT_FOUND ProcessorNumber is not found.
+**/
+EFI_STATUS
+GetProcessorNumber (
+ IN PEI_CPU_MP_DATA *PeiCpuMpData,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ UINTN TotalProcessorNumber;
+ UINTN Index;
+
+ TotalProcessorNumber = PeiCpuMpData->CpuCount;
+ for (Index = 0; Index < TotalProcessorNumber; Index ++) {
+ if (PeiCpuMpData->CpuData[Index].ApicId == GetInitialApicId ()) {
+ *ProcessorNumber = Index;
+ return EFI_SUCCESS;
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Worker function for SwitchBSP().
+
+ Worker function for SwitchBSP(), assigned to the AP which is intended to become BSP.
+
+ @param Buffer Pointer to CPU MP Data
+**/
+VOID
+EFIAPI
+FutureBSPProc (
+ IN VOID *Buffer
+ )
+{
+ PEI_CPU_MP_DATA *DataInHob;
+
+ DataInHob = (PEI_CPU_MP_DATA *) Buffer;
+ AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
+}
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ This function is used to retrieve the following information:
+ - The number of logical processors that are present in the system.
+ - The number of enabled logical processors in the system at the instant
+ this call is made.
+
+ Because MP Service Ppi provides services to enable and disable processors
+ dynamically, the number of enabled logical processors may vary during the
+ course of a boot session.
+
+ If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+ If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+ EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+ is returned in NumberOfProcessors, the number of currently enabled processor
+ is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This Pointer to this instance of the PPI.
+ @param[out] NumberOfProcessors Pointer to the total number of logical processors in
+ the system, including the BSP and disabled APs.
+ @param[out] NumberOfEnabledProcessors
+ Number of processors in the system that are enabled.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ NumberOfEnabledProcessors is NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNumberOfProcessors (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN CallerNumber;
+ UINTN ProcessorNumber;
+ UINTN EnabledProcessorNumber;
+ UINTN Index;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ProcessorNumber = PeiCpuMpData->CpuCount;
+ EnabledProcessorNumber = 0;
+ for (Index = 0; Index < ProcessorNumber; Index++) {
+ if (PeiCpuMpData->CpuData[Index].State != CpuStateDisabled) {
+ EnabledProcessorNumber ++;
+ }
+ }
+
+ *NumberOfProcessors = ProcessorNumber;
+ *NumberOfEnabledProcessors = EnabledProcessorNumber;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ This service retrieves detailed MP-related information about any processor
+ on the platform. Note the following:
+ - The processor information may change during the course of a boot session.
+ - The information presented here is entirely MP related.
+
+ Information regarding the number of caches and their sizes, frequency of operation,
+ slot numbers is all considered platform-related information and is not provided
+ by this service.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This Pointer to this instance of the PPI.
+ @param[in] ProcessorNumber Pointer to the total number of logical processors in
+ the system, including the BSP and disabled APs.
+ @param[out] ProcessorInfoBuffer Number of processors in the system that are enabled.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetProcessorInfo (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN CallerNumber;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ ProcessorInfoBuffer->ProcessorId = (UINT64) PeiCpuMpData->CpuData[ProcessorNumber].ApicId;
+ ProcessorInfoBuffer->StatusFlag = 0;
+ if (PeiCpuMpData->CpuData[ProcessorNumber].ApicId == GetInitialApicId()) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+ }
+ if (PeiCpuMpData->CpuData[ProcessorNumber].Health.Uint32 == 0) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
+ }
+ if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) {
+ ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
+ } else {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
+ }
+
+ //
+ // Get processor location information
+ //
+ ExtractProcessorLocation (PeiCpuMpData->CpuData[ProcessorNumber].ApicId, &ProcessorInfoBuffer->Location);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking requests only. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function specified
+ by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
+ immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number. Otherwise,
+ all the enabled APs execute the function specified by Procedure simultaneously.
+
+ If the timeout specified by TimeoutInMicroSeconds expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+ are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ to make sure that the nature of the code that is executed on the BSP and the
+ dispatched APs is well controlled. The MP Services Ppi does not guarantee
+ that the Procedure function is MP-safe. Hence, the tasks that can be run in
+ parallel are limited to certain independent tasks and well-controlled exclusive
+ code. PEI services and Ppis may not be called by APs unless otherwise
+ specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroSeconds expires.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] Procedure A pointer to the function to be run on enabled APs of
+ the system.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute the function
+ specified by Procedure one by one, in ascending order
+ of processor handle number. If FALSE, then all the
+ enabled APs execute the function specified by Procedure
+ simultaneously.
+ @param[in] TimeoutInMicroSeconds
+ Indicates the time limit in microseconds for APs to
+ return from Procedure, for blocking mode only. Zero
+ means infinity. If the timeout expires before all APs
+ return from Procedure, then Procedure on the failed APs
+ is terminated. All enabled APs are available for next
+ function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
+ timeout expires in blocking mode, BSP returns
+ EFI_TIMEOUT.
+ @param[in] ProcedureArgument The parameter passed into Procedure for all APs.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before the
+ timeout expired.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before all
+ enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiStartupAllAPs (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN UINTN TimeoutInMicroSeconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN ProcessorNumber;
+ UINTN Index;
+ UINTN CallerNumber;
+ BOOLEAN HasEnabledAp;
+ BOOLEAN HasEnabledIdleAp;
+ volatile UINT32 *FinishedCount;
+ EFI_STATUS Status;
+ UINTN WaitCountIndex;
+ UINTN WaitCountNumber;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ProcessorNumber = PeiCpuMpData->CpuCount;
+
+ HasEnabledAp = FALSE;
+ HasEnabledIdleAp = FALSE;
+ for (Index = 0; Index < ProcessorNumber; Index ++) {
+ if (Index == CallerNumber) {
+ //
+ // Skip BSP
+ //
+ continue;
+ }
+ if (PeiCpuMpData->CpuData[Index].State != CpuStateDisabled) {
+ HasEnabledAp = TRUE;
+ if (PeiCpuMpData->CpuData[Index].State != CpuStateBusy) {
+ HasEnabledIdleAp = TRUE;
+ }
+ }
+ }
+ if (!HasEnabledAp) {
+ //
+ // If no enabled AP exists, return EFI_NOT_STARTED.
+ //
+ return EFI_NOT_STARTED;
+ }
+ if (!HasEnabledIdleAp) {
+ //
+ // If any enabled APs are busy, return EFI_NOT_READY.
+ //
+ return EFI_NOT_READY;
+ }
+
+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Backup original data and copy AP reset vector in it
+ //
+ BackupAndPrepareWakeupBuffer(PeiCpuMpData);
+ }
+
+ WaitCountNumber = TimeoutInMicroSeconds / CPU_CHECK_AP_INTERVAL + 1;
+ WaitCountIndex = 0;
+ FinishedCount = &PeiCpuMpData->FinishedCount;
+ if (!SingleThread) {
+ WakeUpAP (PeiCpuMpData, TRUE, 0, Procedure, ProcedureArgument);
+ //
+ // Wait to finish
+ //
+ if (TimeoutInMicroSeconds == 0) {
+ while (*FinishedCount < ProcessorNumber - 1) {
+ CpuPause ();
+ }
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_TIMEOUT;
+ for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
+ MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
+ if (*FinishedCount >= ProcessorNumber - 1) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ }
+ } else {
+ Status = EFI_SUCCESS;
+ for (Index = 0; Index < ProcessorNumber; Index++) {
+ if (Index == CallerNumber) {
+ continue;
+ }
+ WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[Index].ApicId, Procedure, ProcedureArgument);
+ //
+ // Wait to finish
+ //
+ if (TimeoutInMicroSeconds == 0) {
+ while (*FinishedCount < 1) {
+ CpuPause ();
+ }
+ } else {
+ for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
+ MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
+ if (*FinishedCount >= 1) {
+ break;
+ }
+ }
+ if (WaitCountIndex == WaitCountNumber) {
+ Status = EFI_TIMEOUT;
+ }
+ }
+ }
+ }
+
+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Restore original data
+ //
+ RestoreWakeupBuffer(PeiCpuMpData);
+ }
+
+ return Status;
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to wait for the completion
+ of the AP. This service may only be called from the BSP.
+
+ This function is used to dispatch one enabled AP to the function specified by
+ Procedure passing in the argument specified by ProcedureArgument.
+ The execution is in blocking mode. The BSP waits until the AP finishes or
+ TimeoutInMicroSecondss expires.
+
+ If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+ from Procedure, then execution of Procedure by the AP is terminated. The AP is
+ available for subsequent calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() and
+ EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] Procedure A pointer to the function to be run on enabled APs of
+ the system.
+ @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the
+ total number of logical processors minus 1. The total
+ number of logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] TimeoutInMicroseconds
+ Indicates the time limit in microseconds for APs to
+ return from Procedure, for blocking mode only. Zero
+ means infinity. If the timeout expires before all APs
+ return from Procedure, then Procedure on the failed APs
+ is terminated. All enabled APs are available for next
+ function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
+ timeout expires in blocking mode, BSP returns
+ EFI_TIMEOUT.
+ @param[in] ProcedureArgument The parameter passed into Procedure for all APs.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before the
+ timeout expires.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before the
+ specified AP has finished.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiStartupThisAP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN CallerNumber;
+ volatile UINT32 *FinishedCount;
+ EFI_STATUS Status;
+ UINTN WaitCountIndex;
+ UINTN WaitCountNumber;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (ProcessorNumber == PeiCpuMpData->BspNumber || Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether specified AP is disabled
+ //
+ if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Backup original data and copy AP reset vector in it
+ //
+ BackupAndPrepareWakeupBuffer(PeiCpuMpData);
+ }
+
+ WaitCountNumber = TimeoutInMicroseconds / CPU_CHECK_AP_INTERVAL + 1;
+ WaitCountIndex = 0;
+ FinishedCount = &PeiCpuMpData->FinishedCount;
+
+ WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[ProcessorNumber].ApicId, Procedure, ProcedureArgument);
+
+ //
+ // Wait to finish
+ //
+ if (TimeoutInMicroseconds == 0) {
+ while (*FinishedCount < 1) {
+ CpuPause() ;
+ }
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_TIMEOUT;
+ for (WaitCountIndex = 0; WaitCountIndex < WaitCountNumber; WaitCountIndex++) {
+ MicroSecondDelay (CPU_CHECK_AP_INTERVAL);
+ if (*FinishedCount >= 1) {
+ Status = EFI_SUCCESS;
+ break;
+ }
+ }
+ }
+
+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Backup original data and copy AP reset vector in it
+ //
+ RestoreWakeupBuffer(PeiCpuMpData);
+ }
+
+ return Status;
+}
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be performed
+ by the current BSP.
+
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. The new BSP can take over the
+ execution of the old BSP and continue seamlessly from where the old one left
+ off.
+
+ If the BSP cannot be switched prior to the return from this service, then
+ EFI_UNSUPPORTED must be returned.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the
+ total number of logical processors minus 1. The total
+ number of logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an enabled
+ AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to this
+ service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or a disabled
+ AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+**/
+EFI_STATUS
+EFIAPI
+PeiSwitchBSP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN CallerNumber;
+ MSR_IA32_APIC_BASE ApicBaseMsr;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_SUCCESS;
+ }
+
+ if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether specified AP is disabled
+ //
+ if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateDisabled) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether ProcessorNumber specifies the current BSP
+ //
+ if (ProcessorNumber == PeiCpuMpData->BspNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether specified AP is busy
+ //
+ if (PeiCpuMpData->CpuData[ProcessorNumber].State == CpuStateBusy) {
+ return EFI_NOT_READY;
+ }
+
+ //
+ // Clear the BSP bit of MSR_IA32_APIC_BASE
+ //
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
+ ApicBaseMsr.Bits.Bsp = 0;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);
+
+ PeiCpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
+ PeiCpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;
+
+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Backup original data and copy AP reset vector in it
+ //
+ BackupAndPrepareWakeupBuffer(PeiCpuMpData);
+ }
+
+ //
+ // Need to wakeUp AP (future BSP).
+ //
+ WakeUpAP (PeiCpuMpData, FALSE, PeiCpuMpData->CpuData[ProcessorNumber].ApicId, FutureBSPProc, PeiCpuMpData);
+
+ AsmExchangeRole (&PeiCpuMpData->BSPInfo, &PeiCpuMpData->APInfo);
+
+ if (PeiCpuMpData->EndOfPeiFlag) {
+ //
+ // Backup original data and copy AP reset vector in it
+ //
+ RestoreWakeupBuffer(PeiCpuMpData);
+ }
+
+ //
+ // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
+ //
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
+ ApicBaseMsr.Bits.Bsp = 1;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ This service allows the caller enable or disable an AP from this point onward.
+ The caller can optionally specify the health status of the AP by Health. If
+ an AP is being disabled, then the state of the disabled AP is implementation
+ dependent. If an AP is enabled, then the implementation must guarantee that a
+ complete initialization sequence is performed on the AP, so the AP is in a state
+ that is compatible with an MP operating system.
+
+ If the enable or disable AP operation cannot be completed prior to the return
+ from this service, then EFI_UNSUPPORTED must be returned.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the
+ total number of logical processors minus 1. The total
+ number of logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for enabled,
+ FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies the
+ new health status of the AP. This flag corresponds to
+ StatusFlag defined in EFI_PEI_MP_SERVICES_PPI.GetProcessorInfo().
+ Only the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter is
+ ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed prior
+ to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+**/
+EFI_STATUS
+EFIAPI
+PeiEnableDisableAP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+ UINTN CallerNumber;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ PeiWhoAmI (PeiServices, This, &CallerNumber);
+ if (CallerNumber != PeiCpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber == PeiCpuMpData->BspNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= PeiCpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!EnableAP) {
+ PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateDisabled;
+ } else {
+ PeiCpuMpData->CpuData[ProcessorNumber].State = CpuStateIdle;
+ }
+
+ if (HealthFlag != NULL) {
+ PeiCpuMpData->CpuData[ProcessorNumber].CpuHealthy =
+ (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ This service returns the processor handle number for the calling processor.
+ The returned value is in the range from 0 to the total number of logical
+ processors minus 1. The total number of logical processors can be retrieved
+ with EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). This service may be
+ called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+ is returned. Otherwise, the current processors handle number is returned in
+ ProcessorNumber, and EFI_SUCCESS is returned.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[out] ProcessorNumber The handle number of the AP. The range is from 0 to the
+ total number of logical processors minus 1. The total
+ number of logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned in
+ ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiWhoAmI (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ PEI_CPU_MP_DATA *PeiCpuMpData;
+
+ PeiCpuMpData = GetMpHobData ();
+ if (PeiCpuMpData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (ProcessorNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return GetProcessorNumber (PeiCpuMpData, ProcessorNumber);
+}
+
diff --git a/UefiCpuPkg/CpuMpPei/PeiMpServices.h b/UefiCpuPkg/CpuMpPei/PeiMpServices.h index 1550574e5a..57f7691161 100644 --- a/UefiCpuPkg/CpuMpPei/PeiMpServices.h +++ b/UefiCpuPkg/CpuMpPei/PeiMpServices.h @@ -1,377 +1,377 @@ -/** @file - Functions prototype of Multiple Processor PPI services. - - Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> - This program and the accompanying materials - are licensed and made available under the terms and conditions of the BSD License - which accompanies this distribution. The full text of the license may be found at - http://opensource.org/licenses/bsd-license.php - - THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#ifndef _PEI_MP_SERVICES_H_ -#define _PEI_MP_SERVICES_H_ - -#include "CpuMpPei.h" - -// -// The MP data for switch BSP -// -#define CPU_SWITCH_STATE_IDLE 0 -#define CPU_SWITCH_STATE_STORED 1 -#define CPU_SWITCH_STATE_LOADED 2 - -#define CPU_CHECK_AP_INTERVAL 0x100 // 100 microseconds - -/** - This function is called by both the BSP and the AP which is to become the BSP to - Exchange execution context including stack between them. After return from this - function, the BSP becomes AP and the AP becomes the BSP. - - @param MyInfo Pointer to buffer holding the exchanging information for the executing processor. - @param OthersInfo Pointer to buffer holding the exchanging information for the peer. -**/ -VOID -EFIAPI -AsmExchangeRole ( - IN CPU_EXCHANGE_ROLE_INFO *MyInfo, - IN CPU_EXCHANGE_ROLE_INFO *OthersInfo - ); - -/** - This service retrieves the number of logical processor in the platform - and the number of those logical processors that are enabled on this boot. - This service may only be called from the BSP. - - This function is used to retrieve the following information: - - The number of logical processors that are present in the system. - - The number of enabled logical processors in the system at the instant - this call is made. - - Because MP Service Ppi provides services to enable and disable processors - dynamically, the number of enabled logical processors may vary during the - course of a boot session. - - If this service is called from an AP, then EFI_DEVICE_ERROR is returned. - If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then - EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors - is returned in NumberOfProcessors, the number of currently enabled processor - is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This Pointer to this instance of the PPI. - @param[out] NumberOfProcessors Pointer to the total number of logical processors in - the system, including the BSP and disabled APs. - @param[out] NumberOfEnabledProcessors - Number of processors in the system that are enabled. - - @retval EFI_SUCCESS The number of logical processors and enabled - logical processors was retrieved. - @retval EFI_DEVICE_ERROR The calling processor is an AP. - @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL. - NumberOfEnabledProcessors is NULL. -**/ -EFI_STATUS -EFIAPI -PeiGetNumberOfProcessors ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - OUT UINTN *NumberOfProcessors, - OUT UINTN *NumberOfEnabledProcessors - ); - -/** - Gets detailed MP-related information on the requested processor at the - instant this call is made. This service may only be called from the BSP. - - This service retrieves detailed MP-related information about any processor - on the platform. Note the following: - - The processor information may change during the course of a boot session. - - The information presented here is entirely MP related. - - Information regarding the number of caches and their sizes, frequency of operation, - slot numbers is all considered platform-related information and is not provided - by this service. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This Pointer to this instance of the PPI. - @param[in] ProcessorNumber Pointer to the total number of logical processors in - the system, including the BSP and disabled APs. - @param[out] ProcessorInfoBuffer Number of processors in the system that are enabled. - - @retval EFI_SUCCESS Processor information was returned. - @retval EFI_DEVICE_ERROR The calling processor is an AP. - @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL. - @retval EFI_NOT_FOUND The processor with the handle specified by - ProcessorNumber does not exist in the platform. -**/ -EFI_STATUS -EFIAPI -PeiGetProcessorInfo ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - IN UINTN ProcessorNumber, - OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer - ); - -/** - This service executes a caller provided function on all enabled APs. APs can - run either simultaneously or one at a time in sequence. This service supports - both blocking requests only. This service may only - be called from the BSP. - - This function is used to dispatch all the enabled APs to the function specified - by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned - immediately and Procedure is not started on any AP. - - If SingleThread is TRUE, all the enabled APs execute the function specified by - Procedure one by one, in ascending order of processor handle number. Otherwise, - all the enabled APs execute the function specified by Procedure simultaneously. - - If the timeout specified by TimeoutInMicroSeconds expires before all APs return - from Procedure, then Procedure on the failed APs is terminated. All enabled APs - are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() - and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its - content points to the list of processor handle numbers in which Procedure was - terminated. - - Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() - to make sure that the nature of the code that is executed on the BSP and the - dispatched APs is well controlled. The MP Services Ppi does not guarantee - that the Procedure function is MP-safe. Hence, the tasks that can be run in - parallel are limited to certain independent tasks and well-controlled exclusive - code. PEI services and Ppis may not be called by APs unless otherwise - specified. - - In blocking execution mode, BSP waits until all APs finish or - TimeoutInMicroSeconds expires. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance. - @param[in] Procedure A pointer to the function to be run on enabled APs of - the system. - @param[in] SingleThread If TRUE, then all the enabled APs execute the function - specified by Procedure one by one, in ascending order - of processor handle number. If FALSE, then all the - enabled APs execute the function specified by Procedure - simultaneously. - @param[in] TimeoutInMicroSeconds - Indicates the time limit in microseconds for APs to - return from Procedure, for blocking mode only. Zero - means infinity. If the timeout expires before all APs - return from Procedure, then Procedure on the failed APs - is terminated. All enabled APs are available for next - function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() - or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the - timeout expires in blocking mode, BSP returns - EFI_TIMEOUT. - @param[in] ProcedureArgument The parameter passed into Procedure for all APs. - - @retval EFI_SUCCESS In blocking mode, all APs have finished before the - timeout expired. - @retval EFI_DEVICE_ERROR Caller processor is AP. - @retval EFI_NOT_STARTED No enabled APs exist in the system. - @retval EFI_NOT_READY Any enabled APs are busy. - @retval EFI_TIMEOUT In blocking mode, the timeout expired before all - enabled APs have finished. - @retval EFI_INVALID_PARAMETER Procedure is NULL. -**/ -EFI_STATUS -EFIAPI -PeiStartupAllAPs ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - IN EFI_AP_PROCEDURE Procedure, - IN BOOLEAN SingleThread, - IN UINTN TimeoutInMicroSeconds, - IN VOID *ProcedureArgument OPTIONAL - ); - -/** - This service lets the caller get one enabled AP to execute a caller-provided - function. The caller can request the BSP to wait for the completion - of the AP. This service may only be called from the BSP. - - This function is used to dispatch one enabled AP to the function specified by - Procedure passing in the argument specified by ProcedureArgument. - The execution is in blocking mode. The BSP waits until the AP finishes or - TimeoutInMicroSecondss expires. - - If the timeout specified by TimeoutInMicroseconds expires before the AP returns - from Procedure, then execution of Procedure by the AP is terminated. The AP is - available for subsequent calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() and - EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance. - @param[in] Procedure A pointer to the function to be run on enabled APs of - the system. - @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the - total number of logical processors minus 1. The total - number of logical processors can be retrieved by - EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). - @param[in] TimeoutInMicroseconds - Indicates the time limit in microseconds for APs to - return from Procedure, for blocking mode only. Zero - means infinity. If the timeout expires before all APs - return from Procedure, then Procedure on the failed APs - is terminated. All enabled APs are available for next - function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() - or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the - timeout expires in blocking mode, BSP returns - EFI_TIMEOUT. - @param[in] ProcedureArgument The parameter passed into Procedure for all APs. - - @retval EFI_SUCCESS In blocking mode, specified AP finished before the - timeout expires. - @retval EFI_DEVICE_ERROR The calling processor is an AP. - @retval EFI_TIMEOUT In blocking mode, the timeout expired before the - specified AP has finished. - @retval EFI_NOT_FOUND The processor with the handle specified by - ProcessorNumber does not exist. - @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP. - @retval EFI_INVALID_PARAMETER Procedure is NULL. -**/ -EFI_STATUS -EFIAPI -PeiStartupThisAP ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - IN EFI_AP_PROCEDURE Procedure, - IN UINTN ProcessorNumber, - IN UINTN TimeoutInMicroseconds, - IN VOID *ProcedureArgument OPTIONAL - ); - -/** - This service switches the requested AP to be the BSP from that point onward. - This service changes the BSP for all purposes. This call can only be performed - by the current BSP. - - This service switches the requested AP to be the BSP from that point onward. - This service changes the BSP for all purposes. The new BSP can take over the - execution of the old BSP and continue seamlessly from where the old one left - off. - - If the BSP cannot be switched prior to the return from this service, then - EFI_UNSUPPORTED must be returned. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance. - @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the - total number of logical processors minus 1. The total - number of logical processors can be retrieved by - EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). - @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an enabled - AP. Otherwise, it will be disabled. - - @retval EFI_SUCCESS BSP successfully switched. - @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to this - service returning. - @retval EFI_UNSUPPORTED Switching the BSP is not supported. - @retval EFI_SUCCESS The calling processor is an AP. - @retval EFI_NOT_FOUND The processor with the handle specified by - ProcessorNumber does not exist. - @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or a disabled - AP. - @retval EFI_NOT_READY The specified AP is busy. -**/ -EFI_STATUS -EFIAPI -PeiSwitchBSP ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - IN UINTN ProcessorNumber, - IN BOOLEAN EnableOldBSP - ); - -/** - This service lets the caller enable or disable an AP from this point onward. - This service may only be called from the BSP. - - This service allows the caller enable or disable an AP from this point onward. - The caller can optionally specify the health status of the AP by Health. If - an AP is being disabled, then the state of the disabled AP is implementation - dependent. If an AP is enabled, then the implementation must guarantee that a - complete initialization sequence is performed on the AP, so the AP is in a state - that is compatible with an MP operating system. - - If the enable or disable AP operation cannot be completed prior to the return - from this service, then EFI_UNSUPPORTED must be returned. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance. - @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the - total number of logical processors minus 1. The total - number of logical processors can be retrieved by - EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). - @param[in] EnableAP Specifies the new state for the processor for enabled, - FALSE for disabled. - @param[in] HealthFlag If not NULL, a pointer to a value that specifies the - new health status of the AP. This flag corresponds to - StatusFlag defined in EFI_PEI_MP_SERVICES_PPI.GetProcessorInfo(). - Only the PROCESSOR_HEALTH_STATUS_BIT is used. All other - bits are ignored. If it is NULL, this parameter is - ignored. - - @retval EFI_SUCCESS The specified AP was enabled or disabled successfully. - @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed prior - to this service returning. - @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported. - @retval EFI_DEVICE_ERROR The calling processor is an AP. - @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber - does not exist. - @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP. -**/ -EFI_STATUS -EFIAPI -PeiEnableDisableAP ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - IN UINTN ProcessorNumber, - IN BOOLEAN EnableAP, - IN UINT32 *HealthFlag OPTIONAL - ); - -/** - This return the handle number for the calling processor. This service may be - called from the BSP and APs. - - This service returns the processor handle number for the calling processor. - The returned value is in the range from 0 to the total number of logical - processors minus 1. The total number of logical processors can be retrieved - with EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). This service may be - called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER - is returned. Otherwise, the current processors handle number is returned in - ProcessorNumber, and EFI_SUCCESS is returned. - - @param[in] PeiServices An indirect pointer to the PEI Services Table - published by the PEI Foundation. - @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance. - @param[out] ProcessorNumber The handle number of the AP. The range is from 0 to the - total number of logical processors minus 1. The total - number of logical processors can be retrieved by - EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). - - @retval EFI_SUCCESS The current processor handle number was returned in - ProcessorNumber. - @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL. -**/ -EFI_STATUS -EFIAPI -PeiWhoAmI ( - IN CONST EFI_PEI_SERVICES **PeiServices, - IN EFI_PEI_MP_SERVICES_PPI *This, - OUT UINTN *ProcessorNumber - ); - -#endif +/** @file
+ Functions prototype of Multiple Processor PPI services.
+
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_MP_SERVICES_H_
+#define _PEI_MP_SERVICES_H_
+
+#include "CpuMpPei.h"
+
+//
+// The MP data for switch BSP
+//
+#define CPU_SWITCH_STATE_IDLE 0
+#define CPU_SWITCH_STATE_STORED 1
+#define CPU_SWITCH_STATE_LOADED 2
+
+#define CPU_CHECK_AP_INTERVAL 0x100 // 100 microseconds
+
+/**
+ This function is called by both the BSP and the AP which is to become the BSP to
+ Exchange execution context including stack between them. After return from this
+ function, the BSP becomes AP and the AP becomes the BSP.
+
+ @param MyInfo Pointer to buffer holding the exchanging information for the executing processor.
+ @param OthersInfo Pointer to buffer holding the exchanging information for the peer.
+**/
+VOID
+EFIAPI
+AsmExchangeRole (
+ IN CPU_EXCHANGE_ROLE_INFO *MyInfo,
+ IN CPU_EXCHANGE_ROLE_INFO *OthersInfo
+ );
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ This function is used to retrieve the following information:
+ - The number of logical processors that are present in the system.
+ - The number of enabled logical processors in the system at the instant
+ this call is made.
+
+ Because MP Service Ppi provides services to enable and disable processors
+ dynamically, the number of enabled logical processors may vary during the
+ course of a boot session.
+
+ If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+ If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+ EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+ is returned in NumberOfProcessors, the number of currently enabled processor
+ is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This Pointer to this instance of the PPI.
+ @param[out] NumberOfProcessors Pointer to the total number of logical processors in
+ the system, including the BSP and disabled APs.
+ @param[out] NumberOfEnabledProcessors
+ Number of processors in the system that are enabled.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ NumberOfEnabledProcessors is NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetNumberOfProcessors (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ );
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ This service retrieves detailed MP-related information about any processor
+ on the platform. Note the following:
+ - The processor information may change during the course of a boot session.
+ - The information presented here is entirely MP related.
+
+ Information regarding the number of caches and their sizes, frequency of operation,
+ slot numbers is all considered platform-related information and is not provided
+ by this service.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This Pointer to this instance of the PPI.
+ @param[in] ProcessorNumber Pointer to the total number of logical processors in
+ the system, including the BSP and disabled APs.
+ @param[out] ProcessorInfoBuffer Number of processors in the system that are enabled.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+**/
+EFI_STATUS
+EFIAPI
+PeiGetProcessorInfo (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking requests only. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function specified
+ by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
+ immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number. Otherwise,
+ all the enabled APs execute the function specified by Procedure simultaneously.
+
+ If the timeout specified by TimeoutInMicroSeconds expires before all APs return
+ from Procedure, then Procedure on the failed APs is terminated. All enabled APs
+ are always available for further calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ and EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ to make sure that the nature of the code that is executed on the BSP and the
+ dispatched APs is well controlled. The MP Services Ppi does not guarantee
+ that the Procedure function is MP-safe. Hence, the tasks that can be run in
+ parallel are limited to certain independent tasks and well-controlled exclusive
+ code. PEI services and Ppis may not be called by APs unless otherwise
+ specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroSeconds expires.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] Procedure A pointer to the function to be run on enabled APs of
+ the system.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute the function
+ specified by Procedure one by one, in ascending order
+ of processor handle number. If FALSE, then all the
+ enabled APs execute the function specified by Procedure
+ simultaneously.
+ @param[in] TimeoutInMicroSeconds
+ Indicates the time limit in microseconds for APs to
+ return from Procedure, for blocking mode only. Zero
+ means infinity. If the timeout expires before all APs
+ return from Procedure, then Procedure on the failed APs
+ is terminated. All enabled APs are available for next
+ function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
+ timeout expires in blocking mode, BSP returns
+ EFI_TIMEOUT.
+ @param[in] ProcedureArgument The parameter passed into Procedure for all APs.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before the
+ timeout expired.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before all
+ enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiStartupAllAPs (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN UINTN TimeoutInMicroSeconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ );
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to wait for the completion
+ of the AP. This service may only be called from the BSP.
+
+ This function is used to dispatch one enabled AP to the function specified by
+ Procedure passing in the argument specified by ProcedureArgument.
+ The execution is in blocking mode. The BSP waits until the AP finishes or
+ TimeoutInMicroSecondss expires.
+
+ If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+ from Procedure, then execution of Procedure by the AP is terminated. The AP is
+ available for subsequent calls to EFI_PEI_MP_SERVICES_PPI.StartupAllAPs() and
+ EFI_PEI_MP_SERVICES_PPI.StartupThisAP().
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] Procedure A pointer to the function to be run on enabled APs of
+ the system.
+ @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the
+ total number of logical processors minus 1. The total
+ number of logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] TimeoutInMicroseconds
+ Indicates the time limit in microseconds for APs to
+ return from Procedure, for blocking mode only. Zero
+ means infinity. If the timeout expires before all APs
+ return from Procedure, then Procedure on the failed APs
+ is terminated. All enabled APs are available for next
+ function assigned by EFI_PEI_MP_SERVICES_PPI.StartupAllAPs()
+ or EFI_PEI_MP_SERVICES_PPI.StartupThisAP(). If the
+ timeout expires in blocking mode, BSP returns
+ EFI_TIMEOUT.
+ @param[in] ProcedureArgument The parameter passed into Procedure for all APs.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before the
+ timeout expires.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before the
+ specified AP has finished.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiStartupThisAP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ );
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be performed
+ by the current BSP.
+
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. The new BSP can take over the
+ execution of the old BSP and continue seamlessly from where the old one left
+ off.
+
+ If the BSP cannot be switched prior to the return from this service, then
+ EFI_UNSUPPORTED must be returned.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the
+ total number of logical processors minus 1. The total
+ number of logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an enabled
+ AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to this
+ service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or a disabled
+ AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+**/
+EFI_STATUS
+EFIAPI
+PeiSwitchBSP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ );
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ This service allows the caller enable or disable an AP from this point onward.
+ The caller can optionally specify the health status of the AP by Health. If
+ an AP is being disabled, then the state of the disabled AP is implementation
+ dependent. If an AP is enabled, then the implementation must guarantee that a
+ complete initialization sequence is performed on the AP, so the AP is in a state
+ that is compatible with an MP operating system.
+
+ If the enable or disable AP operation cannot be completed prior to the return
+ from this service, then EFI_UNSUPPORTED must be returned.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[in] ProcessorNumber The handle number of the AP. The range is from 0 to the
+ total number of logical processors minus 1. The total
+ number of logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for enabled,
+ FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies the
+ new health status of the AP. This flag corresponds to
+ StatusFlag defined in EFI_PEI_MP_SERVICES_PPI.GetProcessorInfo().
+ Only the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter is
+ ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed prior
+ to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+**/
+EFI_STATUS
+EFIAPI
+PeiEnableDisableAP (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ );
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ This service returns the processor handle number for the calling processor.
+ The returned value is in the range from 0 to the total number of logical
+ processors minus 1. The total number of logical processors can be retrieved
+ with EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors(). This service may be
+ called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+ is returned. Otherwise, the current processors handle number is returned in
+ ProcessorNumber, and EFI_SUCCESS is returned.
+
+ @param[in] PeiServices An indirect pointer to the PEI Services Table
+ published by the PEI Foundation.
+ @param[in] This A pointer to the EFI_PEI_MP_SERVICES_PPI instance.
+ @param[out] ProcessorNumber The handle number of the AP. The range is from 0 to the
+ total number of logical processors minus 1. The total
+ number of logical processors can be retrieved by
+ EFI_PEI_MP_SERVICES_PPI.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned in
+ ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+**/
+EFI_STATUS
+EFIAPI
+PeiWhoAmI (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_MP_SERVICES_PPI *This,
+ OUT UINTN *ProcessorNumber
+ );
+
+#endif
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc b/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc index 946fe506d0..ab851cf3e7 100644 --- a/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc +++ b/UefiCpuPkg/CpuMpPei/X64/MpEqu.inc @@ -1,45 +1,45 @@ -;------------------------------------------------------------------------------ ; -; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> -; This program and the accompanying materials -; are licensed and made available under the terms and conditions of the BSD License -; which accompanies this distribution. The full text of the license may be found at -; http://opensource.org/licenses/bsd-license.php. -; -; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -; -; Module Name: -; -; MpEqu.inc -; -; Abstract: -; -; This is the equates file for Multiple Processor support -; -;------------------------------------------------------------------------------- - -PROTECT_MODE_CS equ 10h -PROTECT_MODE_DS equ 18h -LONG_MODE_CS equ 38h -LONG_MODE_DS equ 30h - -VacantFlag equ 00h -NotVacantFlag equ 0ffh - -CPU_SWITCH_STATE_IDLE equ 0 -CPU_SWITCH_STATE_STORED equ 1 -CPU_SWITCH_STATE_LOADED equ 2 - -LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart) -StackStartAddressLocation equ LockLocation + 08h -StackSizeLocation equ LockLocation + 10h -ApProcedureLocation equ LockLocation + 18h -GdtrLocation equ LockLocation + 20h -IdtrLocation equ LockLocation + 2Ah -BufferStartLocation equ LockLocation + 34h -PmodeOffsetLocation equ LockLocation + 3Ch -NumApsExecutingLoction equ LockLocation + 44h -LmodeOffsetLocation equ LockLocation + 4Ch -Cr3Location equ LockLocation + 54h - -;------------------------------------------------------------------------------- +;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpEqu.inc
+;
+; Abstract:
+;
+; This is the equates file for Multiple Processor support
+;
+;-------------------------------------------------------------------------------
+
+PROTECT_MODE_CS equ 10h
+PROTECT_MODE_DS equ 18h
+LONG_MODE_CS equ 38h
+LONG_MODE_DS equ 30h
+
+VacantFlag equ 00h
+NotVacantFlag equ 0ffh
+
+CPU_SWITCH_STATE_IDLE equ 0
+CPU_SWITCH_STATE_STORED equ 1
+CPU_SWITCH_STATE_LOADED equ 2
+
+LockLocation equ (RendezvousFunnelProcEnd - RendezvousFunnelProcStart)
+StackStartAddressLocation equ LockLocation + 08h
+StackSizeLocation equ LockLocation + 10h
+ApProcedureLocation equ LockLocation + 18h
+GdtrLocation equ LockLocation + 20h
+IdtrLocation equ LockLocation + 2Ah
+BufferStartLocation equ LockLocation + 34h
+PmodeOffsetLocation equ LockLocation + 3Ch
+NumApsExecutingLoction equ LockLocation + 44h
+LmodeOffsetLocation equ LockLocation + 4Ch
+Cr3Location equ LockLocation + 54h
+
+;-------------------------------------------------------------------------------
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm index 18c8b72a34..fad5e8d443 100644 --- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm +++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.asm @@ -1,334 +1,334 @@ -;------------------------------------------------------------------------------ ; -; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> -; This program and the accompanying materials -; are licensed and made available under the terms and conditions of the BSD License -; which accompanies this distribution. The full text of the license may be found at -; http://opensource.org/licenses/bsd-license.php. -; -; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -; -; Module Name: -; -; MpFuncs32.asm -; -; Abstract: -; -; This is the assembly code for MP support -; -;------------------------------------------------------------------------------- - -include MpEqu.inc -extern InitializeFloatingPointUnits:PROC - -.code -;------------------------------------------------------------------------------------- -;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 PROC PUBLIC -RendezvousFunnelProcStart:: -; At this point CS = 0x(vv00) and ip= 0x0. -; Save BIST information to ebp firstly - db 66h, 08bh, 0e8h ; mov ebp, eax ; save BIST information - - 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 0BFh ; opcode of mov di, mem16 - dw LmodeOffsetLocation ; mov di, LmodeOffsetLocation - 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 - dw Cr3Location ; mov si, Cr3Location - db 66h, 8Bh, 0Ch ; mov ecx,dword ptr [si] ; ECX is keeping the value of CR3 - - 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 - dw IdtrLocation ; mov si, IdtrLocation - 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 PROTECT_MODE_CS ; 16-bit selector - -Flat32Start:: ; protected mode entry point - mov ax, PROTECT_MODE_DS - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - db 0Fh, 20h, 0E0h ; mov eax, cr4 - db 0Fh, 0BAh, 0E8h, 05h ; bts eax, 5 - db 0Fh, 22h, 0E0h ; mov cr4, eax - - db 0Fh, 22h, 0D9h ; mov cr3, ecx - - db 0B9h - dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number. - db 0Fh, 32h ; rdmsr ; Read EFER. - db 0Fh, 0BAh, 0E8h, 08h ; bts eax, 8 ; Set LME=1. - db 0Fh, 30h ; wrmsr ; Write EFER. - - db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0. - db 0Fh, 0BAh, 0E8h, 1Fh ; bts eax, 31 ; Set PG=1. - db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0. - -LONG_JUMP: - db 67h, 0EAh ; far jump - dd 0h ; 32-bit offset - dw LONG_MODE_CS ; 16-bit selector - -LongModeStart:: - mov ax, LONG_MODE_DS - mov ds, ax - mov es, ax - mov ss, ax - - mov esi, ebx - mov edi, esi - add edi, LockLocation - mov rax, NotVacantFlag - -TestLock: - xchg qword ptr [edi], rax - cmp rax, NotVacantFlag - jz TestLock - - mov edi, esi - add edi, NumApsExecutingLoction - inc dword ptr [edi] - mov ebx, dword ptr [edi] - -ProgramStack: - mov edi, esi - add edi, StackSizeLocation - mov rax, qword ptr [edi] - mov edi, esi - add edi, StackStartAddressLocation - add rax, qword ptr [edi] - mov rsp, rax - mov qword ptr [edi], rax - -Releaselock: - mov rax, VacantFlag - mov edi, esi - add edi, LockLocation - xchg qword ptr [edi], rax - -CProcedureInvoke: - push rbp ; push BIST data - xor rbp, rbp ; clear ebp for call stack trace - push rbp - mov rbp, rsp - - mov rax, InitializeFloatingPointUnits - sub rsp, 20h - call rax ; Call assembly function to initialize FPU per UEFI spec - add rsp, 20h - - mov edx, ebx ; edx is NumApsExecuting - mov ecx, esi - add ecx, LockLocation ; rcx is address of exchange info data buffer - - mov edi, esi - add edi, ApProcedureLocation - mov rax, qword ptr [edi] - - sub rsp, 20h - call rax ; invoke C function - add rsp, 20h - jmp $ - -RendezvousFunnelProc ENDP -RendezvousFunnelProcEnd:: - -AsmCliHltLoop PROC - cli - hlt - jmp $-2 -AsmCliHltLoop ENDP - -;------------------------------------------------------------------------------------- -; AsmGetAddressMap (&AddressMap); -;------------------------------------------------------------------------------------- -AsmGetAddressMap PROC - mov rax, offset RendezvousFunnelProcStart - mov qword ptr [rcx], rax - mov qword ptr [rcx + 8h], Flat32Start - RendezvousFunnelProcStart - mov qword ptr [rcx + 10h], LongModeStart - RendezvousFunnelProcStart - mov qword ptr [rcx + 18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart - ret -AsmGetAddressMap 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); -;------------------------------------------------------------------------------------- -AsmExchangeRole PROC - ; 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 function, stack will be corrupted. - - push rax - push rbx - push rcx - push rdx - push rsi - push rdi - push rbp - push r8 - push r9 - push r10 - push r11 - push r12 - push r13 - push r14 - push r15 - - mov rax, cr0 - push rax - - mov rax, cr4 - push rax - - ; rsi contains MyInfo pointer - mov rsi, rcx - - ; rdi contains OthersInfo pointer - mov rdi, rdx - - ;Store EFLAGS, GDTR and IDTR regiter to stack - pushfq - sgdt fword ptr [rsi + 16] - sidt fword ptr [rsi + 26] - - ; Store the its StackPointer - mov qword ptr [rsi + 8], rsp - - ; update its switch state to STORED - mov byte ptr [rsi], CPU_SWITCH_STATE_STORED - -WaitForOtherStored: - ; wait until the other CPU finish storing its state - cmp byte ptr [rdi], CPU_SWITCH_STATE_STORED - jz OtherStored - pause - jmp WaitForOtherStored - -OtherStored: - ; Since another CPU already stored its state, load them - ; load GDTR value - lgdt fword ptr [rdi + 16] - - ; load IDTR value - lidt fword ptr [rdi + 26] - - ; load its future StackPointer - mov rsp, qword ptr [rdi + 8] - - ; update the other CPU's switch state to LOADED - mov byte ptr [rdi], CPU_SWITCH_STATE_LOADED - -WaitForOtherLoaded: - ; wait until the other CPU finish loading new state, - ; otherwise the data in stack may corrupt - cmp byte ptr [rsi], CPU_SWITCH_STATE_LOADED - jz OtherLoaded - pause - jmp WaitForOtherLoaded - -OtherLoaded: - ; since the other CPU already get the data it want, leave this procedure - popfq - - pop rax - mov cr4, rax - - pop rax - mov cr0, rax - - pop r15 - pop r14 - pop r13 - pop r12 - pop r11 - pop r10 - pop r9 - pop r8 - pop rbp - pop rdi - pop rsi - pop rdx - pop rcx - pop rbx - pop rax - - ret -AsmExchangeRole ENDP - -AsmInitializeGdt PROC - push rbp - mov rbp, rsp - - lgdt fword PTR [rcx] ; update the GDTR - - sub rsp, 0x10 - lea rax, SetCodeSelectorFarJump - mov [rsp], rax - mov rdx, LONG_MODE_CS - mov [rsp + 4], dx ; get new CS - jmp fword ptr [rsp] -SetCodeSelectorFarJump: - add rsp, 0x10 - - mov rax, LONG_MODE_DS ; get new DS - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - pop rbp - ret -AsmInitializeGdt ENDP - -END +;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpFuncs32.asm
+;
+; Abstract:
+;
+; This is the assembly code for MP support
+;
+;-------------------------------------------------------------------------------
+
+include MpEqu.inc
+extern InitializeFloatingPointUnits:PROC
+
+.code
+;-------------------------------------------------------------------------------------
+;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 PROC PUBLIC
+RendezvousFunnelProcStart::
+; At this point CS = 0x(vv00) and ip= 0x0.
+; Save BIST information to ebp firstly
+ db 66h, 08bh, 0e8h ; mov ebp, eax ; save BIST information
+
+ 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 0BFh ; opcode of mov di, mem16
+ dw LmodeOffsetLocation ; mov di, LmodeOffsetLocation
+ 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
+ dw Cr3Location ; mov si, Cr3Location
+ db 66h, 8Bh, 0Ch ; mov ecx,dword ptr [si] ; ECX is keeping the value of CR3
+
+ 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
+ dw IdtrLocation ; mov si, IdtrLocation
+ 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 PROTECT_MODE_CS ; 16-bit selector
+
+Flat32Start:: ; protected mode entry point
+ mov ax, PROTECT_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ db 0Fh, 20h, 0E0h ; mov eax, cr4
+ db 0Fh, 0BAh, 0E8h, 05h ; bts eax, 5
+ db 0Fh, 22h, 0E0h ; mov cr4, eax
+
+ db 0Fh, 22h, 0D9h ; mov cr3, ecx
+
+ db 0B9h
+ dd 0C0000080h ; mov ecx, 0c0000080h ; EFER MSR number.
+ db 0Fh, 32h ; rdmsr ; Read EFER.
+ db 0Fh, 0BAh, 0E8h, 08h ; bts eax, 8 ; Set LME=1.
+ db 0Fh, 30h ; wrmsr ; Write EFER.
+
+ db 0Fh, 20h, 0C0h ; mov eax, cr0 ; Read CR0.
+ db 0Fh, 0BAh, 0E8h, 1Fh ; bts eax, 31 ; Set PG=1.
+ db 0Fh, 22h, 0C0h ; mov cr0, eax ; Write CR0.
+
+LONG_JUMP:
+ db 67h, 0EAh ; far jump
+ dd 0h ; 32-bit offset
+ dw LONG_MODE_CS ; 16-bit selector
+
+LongModeStart::
+ mov ax, LONG_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ mov esi, ebx
+ mov edi, esi
+ add edi, LockLocation
+ mov rax, NotVacantFlag
+
+TestLock:
+ xchg qword ptr [edi], rax
+ cmp rax, NotVacantFlag
+ jz TestLock
+
+ mov edi, esi
+ add edi, NumApsExecutingLoction
+ inc dword ptr [edi]
+ mov ebx, dword ptr [edi]
+
+ProgramStack:
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov rax, qword ptr [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add rax, qword ptr [edi]
+ mov rsp, rax
+ mov qword ptr [edi], rax
+
+Releaselock:
+ mov rax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg qword ptr [edi], rax
+
+CProcedureInvoke:
+ push rbp ; push BIST data
+ xor rbp, rbp ; clear ebp for call stack trace
+ push rbp
+ mov rbp, rsp
+
+ mov rax, InitializeFloatingPointUnits
+ sub rsp, 20h
+ call rax ; Call assembly function to initialize FPU per UEFI spec
+ add rsp, 20h
+
+ mov edx, ebx ; edx is NumApsExecuting
+ mov ecx, esi
+ add ecx, LockLocation ; rcx is address of exchange info data buffer
+
+ mov edi, esi
+ add edi, ApProcedureLocation
+ mov rax, qword ptr [edi]
+
+ sub rsp, 20h
+ call rax ; invoke C function
+ add rsp, 20h
+ jmp $
+
+RendezvousFunnelProc ENDP
+RendezvousFunnelProcEnd::
+
+AsmCliHltLoop PROC
+ cli
+ hlt
+ jmp $-2
+AsmCliHltLoop ENDP
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+AsmGetAddressMap PROC
+ mov rax, offset RendezvousFunnelProcStart
+ mov qword ptr [rcx], rax
+ mov qword ptr [rcx + 8h], Flat32Start - RendezvousFunnelProcStart
+ mov qword ptr [rcx + 10h], LongModeStart - RendezvousFunnelProcStart
+ mov qword ptr [rcx + 18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+ ret
+AsmGetAddressMap 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);
+;-------------------------------------------------------------------------------------
+AsmExchangeRole PROC
+ ; 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 function, stack will be corrupted.
+
+ push rax
+ push rbx
+ push rcx
+ push rdx
+ push rsi
+ push rdi
+ push rbp
+ push r8
+ push r9
+ push r10
+ push r11
+ push r12
+ push r13
+ push r14
+ push r15
+
+ mov rax, cr0
+ push rax
+
+ mov rax, cr4
+ push rax
+
+ ; rsi contains MyInfo pointer
+ mov rsi, rcx
+
+ ; rdi contains OthersInfo pointer
+ mov rdi, rdx
+
+ ;Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfq
+ sgdt fword ptr [rsi + 16]
+ sidt fword ptr [rsi + 26]
+
+ ; Store the its StackPointer
+ mov qword ptr [rsi + 8], rsp
+
+ ; update its switch state to STORED
+ mov byte ptr [rsi], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte ptr [rdi], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ pause
+ jmp WaitForOtherStored
+
+OtherStored:
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt fword ptr [rdi + 16]
+
+ ; load IDTR value
+ lidt fword ptr [rdi + 26]
+
+ ; load its future StackPointer
+ mov rsp, qword ptr [rdi + 8]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte ptr [rdi], CPU_SWITCH_STATE_LOADED
+
+WaitForOtherLoaded:
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte ptr [rsi], CPU_SWITCH_STATE_LOADED
+ jz OtherLoaded
+ pause
+ jmp WaitForOtherLoaded
+
+OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ popfq
+
+ pop rax
+ mov cr4, rax
+
+ pop rax
+ mov cr0, rax
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rbp
+ pop rdi
+ pop rsi
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ ret
+AsmExchangeRole ENDP
+
+AsmInitializeGdt PROC
+ push rbp
+ mov rbp, rsp
+
+ lgdt fword PTR [rcx] ; update the GDTR
+
+ sub rsp, 0x10
+ lea rax, SetCodeSelectorFarJump
+ mov [rsp], rax
+ mov rdx, LONG_MODE_CS
+ mov [rsp + 4], dx ; get new CS
+ jmp fword ptr [rsp]
+SetCodeSelectorFarJump:
+ add rsp, 0x10
+
+ mov rax, LONG_MODE_DS ; get new DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ pop rbp
+ ret
+AsmInitializeGdt ENDP
+
+END
diff --git a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm index 4683543e3c..0b2e879905 100644 --- a/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm +++ b/UefiCpuPkg/CpuMpPei/X64/MpFuncs.nasm @@ -1,327 +1,327 @@ -;------------------------------------------------------------------------------ ; -; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> -; This program and the accompanying materials -; are licensed and made available under the terms and conditions of the BSD License -; which accompanies this distribution. The full text of the license may be found at -; http://opensource.org/licenses/bsd-license.php. -; -; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -; -; Module Name: -; -; MpFuncs.nasm -; -; Abstract: -; -; This is the assembly code for MP support -; -;------------------------------------------------------------------------------- - -%include "MpEqu.inc" -extern ASM_PFX(InitializeFloatingPointUnits) - -DEFAULT REL - -SECTION .text - -;------------------------------------------------------------------------------------- -;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. -;------------------------------------------------------------------------------------- -global ASM_PFX(RendezvousFunnelProc) -ASM_PFX(RendezvousFunnelProc): -RendezvousFunnelProcStart: -; At this point CS = 0x(vv00) and ip= 0x0. -; Save BIST information to ebp firstly -BITS 16 - - mov eax, 1234h - mov ebp, eax ; save BIST information - - mov ax, cs - mov ds, ax - mov es, ax - mov ss, ax - xor ax, ax - mov fs, ax - mov gs, ax - - mov si, BufferStartLocation - mov ebx, [si] - - mov di, PmodeOffsetLocation - mov eax, [di] - mov di, ax - sub di, 06h - add eax, ebx - mov [di],eax - - mov di, LmodeOffsetLocation - mov eax, [di] - mov di, ax - sub di, 06h - add eax, ebx - mov [di],eax - - - mov si, Cr3Location - mov ecx,[si] ; ECX is keeping the value of CR3 - - mov si, GdtrLocation -o32 lgdt [cs:si] - - mov si, IdtrLocation -o32 lidt [cs:si] - - - xor ax, ax - mov ds, ax - - mov eax, cr0 ;Get control register 0 - or eax, 000000003h ;Set PE bit (bit #0) & MP - mov cr0, eax - - jmp PROTECT_MODE_CS:strict dword 0 ; far jump to protected mode -BITS 32 -Flat32Start: ; protected mode entry point - mov ax, PROTECT_MODE_DS - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - mov eax, cr4 - bts eax, 5 - mov cr4, eax - - mov cr3, ecx - - - mov ecx, 0c0000080h ; EFER MSR number. - rdmsr ; Read EFER. - bts eax, 8 ; Set LME=1. - wrmsr ; Write EFER. - - mov eax, cr0 ; Read CR0. - bts eax, 31 ; Set PG=1. - mov cr0, eax ; Write CR0. - - jmp LONG_MODE_CS:strict dword 0 ; far jump to long mode -BITS 64 -LongModeStart: - mov ax, LONG_MODE_DS - mov ds, ax - mov es, ax - mov ss, ax - - mov esi, ebx - mov edi, esi - add edi, LockLocation - mov rax, NotVacantFlag - -TestLock: - xchg qword [edi], rax - cmp rax, NotVacantFlag - jz TestLock - - mov edi, esi - add edi, NumApsExecutingLoction - inc dword [edi] - mov ebx, [edi] - -ProgramStack: - mov edi, esi - add edi, StackSizeLocation - mov rax, qword [edi] - mov edi, esi - add edi, StackStartAddressLocation - add rax, qword [edi] - mov rsp, rax - mov qword [edi], rax - -Releaselock: - mov rax, VacantFlag - mov edi, esi - add edi, LockLocation - xchg qword [edi], rax - -CProcedureInvoke: - push rbp ; push BIST data at top of AP stack - xor rbp, rbp ; clear ebp for call stack trace - push rbp - mov rbp, rsp - - mov rax, ASM_PFX(InitializeFloatingPointUnits) - sub rsp, 20h - call rax ; Call assembly function to initialize FPU per UEFI spec - add rsp, 20h - - mov edx, ebx ; edx is NumApsExecuting - mov ecx, esi - add ecx, LockLocation ; rcx is address of exchange info data buffer - - mov edi, esi - add edi, ApProcedureLocation - mov rax, qword [edi] - - sub rsp, 20h - call rax ; invoke C function - add rsp, 20h - -RendezvousFunnelProcEnd: - -global ASM_PFX(AsmCliHltLoop) -ASM_PFX(AsmCliHltLoop): - cli - hlt - jmp $-2 - -;------------------------------------------------------------------------------------- -; AsmGetAddressMap (&AddressMap); -;------------------------------------------------------------------------------------- -global ASM_PFX(AsmGetAddressMap) -ASM_PFX(AsmGetAddressMap): - mov rax, ASM_PFX(RendezvousFunnelProc) - mov qword [rcx], rax - mov qword [rcx + 8h], Flat32Start - RendezvousFunnelProcStart - mov qword [rcx + 10h], LongModeStart - RendezvousFunnelProcStart - mov qword [rcx + 18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart - 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); -;------------------------------------------------------------------------------------- -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 function, stack will be corrupted. - - push rax - push rbx - push rcx - push rdx - push rsi - push rdi - push rbp - push r8 - push r9 - push r10 - push r11 - push r12 - push r13 - push r14 - push r15 - - mov rax, cr0 - push rax - - mov rax, cr4 - push rax - - ; rsi contains MyInfo pointer - mov rsi, rcx - - ; rdi contains OthersInfo pointer - mov rdi, rdx - - ;Store EFLAGS, GDTR and IDTR regiter to stack - pushfq - sgdt [rsi + 16] - sidt [rsi + 26] - - ; Store the its StackPointer - mov [rsi + 8], rsp - - ; update its switch state to STORED - mov byte [rsi], CPU_SWITCH_STATE_STORED - -WaitForOtherStored: - ; wait until the other CPU finish storing its state - cmp byte [rdi], CPU_SWITCH_STATE_STORED - jz OtherStored - pause - jmp WaitForOtherStored - -OtherStored: - ; Since another CPU already stored its state, load them - ; load GDTR value - lgdt [rdi + 16] - - ; load IDTR value - lidt [rdi + 26] - - ; load its future StackPointer - mov rsp, [rdi + 8] - - ; update the other CPU's switch state to LOADED - mov byte [rdi], CPU_SWITCH_STATE_LOADED - -WaitForOtherLoaded: - ; wait until the other CPU finish loading new state, - ; otherwise the data in stack may corrupt - cmp byte [rsi], CPU_SWITCH_STATE_LOADED - jz OtherLoaded - pause - jmp WaitForOtherLoaded - -OtherLoaded: - ; since the other CPU already get the data it want, leave this procedure - popfq - - pop rax - mov cr4, rax - - pop rax - mov cr0, rax - - pop r15 - pop r14 - pop r13 - pop r12 - pop r11 - pop r10 - pop r9 - pop r8 - pop rbp - pop rdi - pop rsi - pop rdx - pop rcx - pop rbx - pop rax - - ret - -global ASM_PFX(AsmInitializeGdt) -ASM_PFX(AsmInitializeGdt): - push rbp - mov rbp, rsp - - lgdt [rcx] ; update the GDTR - - sub rsp, 0x10 - mov rax, ASM_PFX(SetCodeSelectorFarJump) - mov [rsp], rax - mov rdx, LONG_MODE_CS - mov [rsp + 4], dx ; get new CS - jmp far dword [rsp] ; far jump with new CS -ASM_PFX(SetCodeSelectorFarJump): - add rsp, 0x10 - - mov rax, LONG_MODE_DS ; get new DS - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - mov ss, ax - - pop rbp - - ret +;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions of the BSD License
+; which accompanies this distribution. The full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php.
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+; Module Name:
+;
+; MpFuncs.nasm
+;
+; Abstract:
+;
+; This is the assembly code for MP support
+;
+;-------------------------------------------------------------------------------
+
+%include "MpEqu.inc"
+extern ASM_PFX(InitializeFloatingPointUnits)
+
+DEFAULT REL
+
+SECTION .text
+
+;-------------------------------------------------------------------------------------
+;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.
+;-------------------------------------------------------------------------------------
+global ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+RendezvousFunnelProcStart:
+; At this point CS = 0x(vv00) and ip= 0x0.
+; Save BIST information to ebp firstly
+BITS 16
+
+ mov eax, 1234h
+ mov ebp, eax ; save BIST information
+
+ mov ax, cs
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+ xor ax, ax
+ mov fs, ax
+ mov gs, ax
+
+ mov si, BufferStartLocation
+ mov ebx, [si]
+
+ mov di, PmodeOffsetLocation
+ mov eax, [di]
+ mov di, ax
+ sub di, 06h
+ add eax, ebx
+ mov [di],eax
+
+ mov di, LmodeOffsetLocation
+ mov eax, [di]
+ mov di, ax
+ sub di, 06h
+ add eax, ebx
+ mov [di],eax
+
+
+ mov si, Cr3Location
+ mov ecx,[si] ; ECX is keeping the value of CR3
+
+ mov si, GdtrLocation
+o32 lgdt [cs:si]
+
+ mov si, IdtrLocation
+o32 lidt [cs:si]
+
+
+ xor ax, ax
+ mov ds, ax
+
+ mov eax, cr0 ;Get control register 0
+ or eax, 000000003h ;Set PE bit (bit #0) & MP
+ mov cr0, eax
+
+ jmp PROTECT_MODE_CS:strict dword 0 ; far jump to protected mode
+BITS 32
+Flat32Start: ; protected mode entry point
+ mov ax, PROTECT_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ mov eax, cr4
+ bts eax, 5
+ mov cr4, eax
+
+ mov cr3, ecx
+
+
+ mov ecx, 0c0000080h ; EFER MSR number.
+ rdmsr ; Read EFER.
+ bts eax, 8 ; Set LME=1.
+ wrmsr ; Write EFER.
+
+ mov eax, cr0 ; Read CR0.
+ bts eax, 31 ; Set PG=1.
+ mov cr0, eax ; Write CR0.
+
+ jmp LONG_MODE_CS:strict dword 0 ; far jump to long mode
+BITS 64
+LongModeStart:
+ mov ax, LONG_MODE_DS
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+
+ mov esi, ebx
+ mov edi, esi
+ add edi, LockLocation
+ mov rax, NotVacantFlag
+
+TestLock:
+ xchg qword [edi], rax
+ cmp rax, NotVacantFlag
+ jz TestLock
+
+ mov edi, esi
+ add edi, NumApsExecutingLoction
+ inc dword [edi]
+ mov ebx, [edi]
+
+ProgramStack:
+ mov edi, esi
+ add edi, StackSizeLocation
+ mov rax, qword [edi]
+ mov edi, esi
+ add edi, StackStartAddressLocation
+ add rax, qword [edi]
+ mov rsp, rax
+ mov qword [edi], rax
+
+Releaselock:
+ mov rax, VacantFlag
+ mov edi, esi
+ add edi, LockLocation
+ xchg qword [edi], rax
+
+CProcedureInvoke:
+ push rbp ; push BIST data at top of AP stack
+ xor rbp, rbp ; clear ebp for call stack trace
+ push rbp
+ mov rbp, rsp
+
+ mov rax, ASM_PFX(InitializeFloatingPointUnits)
+ sub rsp, 20h
+ call rax ; Call assembly function to initialize FPU per UEFI spec
+ add rsp, 20h
+
+ mov edx, ebx ; edx is NumApsExecuting
+ mov ecx, esi
+ add ecx, LockLocation ; rcx is address of exchange info data buffer
+
+ mov edi, esi
+ add edi, ApProcedureLocation
+ mov rax, qword [edi]
+
+ sub rsp, 20h
+ call rax ; invoke C function
+ add rsp, 20h
+
+RendezvousFunnelProcEnd:
+
+global ASM_PFX(AsmCliHltLoop)
+ASM_PFX(AsmCliHltLoop):
+ cli
+ hlt
+ jmp $-2
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+ mov rax, ASM_PFX(RendezvousFunnelProc)
+ mov qword [rcx], rax
+ mov qword [rcx + 8h], Flat32Start - RendezvousFunnelProcStart
+ mov qword [rcx + 10h], LongModeStart - RendezvousFunnelProcStart
+ mov qword [rcx + 18h], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+ 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);
+;-------------------------------------------------------------------------------------
+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 function, stack will be corrupted.
+
+ push rax
+ push rbx
+ push rcx
+ push rdx
+ push rsi
+ push rdi
+ push rbp
+ push r8
+ push r9
+ push r10
+ push r11
+ push r12
+ push r13
+ push r14
+ push r15
+
+ mov rax, cr0
+ push rax
+
+ mov rax, cr4
+ push rax
+
+ ; rsi contains MyInfo pointer
+ mov rsi, rcx
+
+ ; rdi contains OthersInfo pointer
+ mov rdi, rdx
+
+ ;Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfq
+ sgdt [rsi + 16]
+ sidt [rsi + 26]
+
+ ; Store the its StackPointer
+ mov [rsi + 8], rsp
+
+ ; update its switch state to STORED
+ mov byte [rsi], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte [rdi], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ pause
+ jmp WaitForOtherStored
+
+OtherStored:
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt [rdi + 16]
+
+ ; load IDTR value
+ lidt [rdi + 26]
+
+ ; load its future StackPointer
+ mov rsp, [rdi + 8]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte [rdi], CPU_SWITCH_STATE_LOADED
+
+WaitForOtherLoaded:
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte [rsi], CPU_SWITCH_STATE_LOADED
+ jz OtherLoaded
+ pause
+ jmp WaitForOtherLoaded
+
+OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ popfq
+
+ pop rax
+ mov cr4, rax
+
+ pop rax
+ mov cr0, rax
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rbp
+ pop rdi
+ pop rsi
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ ret
+
+global ASM_PFX(AsmInitializeGdt)
+ASM_PFX(AsmInitializeGdt):
+ push rbp
+ mov rbp, rsp
+
+ lgdt [rcx] ; update the GDTR
+
+ sub rsp, 0x10
+ mov rax, ASM_PFX(SetCodeSelectorFarJump)
+ mov [rsp], rax
+ mov rdx, LONG_MODE_CS
+ mov [rsp + 4], dx ; get new CS
+ jmp far dword [rsp] ; far jump with new CS
+ASM_PFX(SetCodeSelectorFarJump):
+ add rsp, 0x10
+
+ mov rax, LONG_MODE_DS ; get new DS
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+
+ pop rbp
+
+ ret
|