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