/** @file\r
CPU PEI Module installs CPU Multiple Processor PPI.\r
\r
- Copyright (c) 2015 - 2016, 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
+ Copyright (c) 2015 - 2022, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "CpuMpPei.h"\r
\r
+extern EDKII_PEI_MP_SERVICES2_PPI mMpServices2Ppi;\r
+\r
//\r
// CPU MP PPI to be installed\r
//\r
-EFI_PEI_MP_SERVICES_PPI mMpServicesPpi = {\r
+EFI_PEI_MP_SERVICES_PPI mMpServicesPpi = {\r
PeiGetNumberOfProcessors,\r
PeiGetProcessorInfo,\r
PeiStartupAllAPs,\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
+EFI_PEI_PPI_DESCRIPTOR mPeiCpuMpPpiList[] = {\r
+ {\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+ &gEdkiiPeiMpServices2PpiGuid,\r
+ &mMpServices2Ppi\r
+ },\r
+ {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiPeiMpServicesPpiGuid,\r
+ &mMpServicesPpi\r
+ }\r
};\r
\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
+ 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
if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {\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
+ 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
return MpInitLibStartupAllAPs (\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
+ 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
return MpInitLibStartupThisAP (\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_DEVICE_ERROR 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
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
+ 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
return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);\r
return MpInitLibWhoAmI (ProcessorNumber);\r
}\r
\r
+//\r
+// Structure for InitializeSeparateExceptionStacks\r
+//\r
+typedef struct {\r
+ VOID *Buffer;\r
+ UINTN BufferSize;\r
+ EFI_STATUS Status;\r
+} EXCEPTION_STACK_SWITCH_CONTEXT;\r
+\r
/**\r
- The Entry point of the MP CPU PEIM.\r
+ Initializes CPU exceptions handlers for the sake of stack switch requirement.\r
\r
- This function will wakeup APs and collect CPU AP count and install the\r
- Mp Service Ppi.\r
+ This function is a wrapper of InitializeSeparateExceptionStacks. It's mainly\r
+ for the sake of AP's init because of EFI_AP_PROCEDURE API requirement.\r
\r
- @param FileHandle Handle of the file being invoked.\r
- @param PeiServices Describes the list of possible PEI Services.\r
+ @param[in,out] Buffer The pointer to private data buffer.\r
\r
- @retval EFI_SUCCESS MpServicePpi is installed successfully.\r
+**/\r
+VOID\r
+EFIAPI\r
+InitializeExceptionStackSwitchHandlers (\r
+ IN OUT VOID *Buffer\r
+ )\r
+{\r
+ EXCEPTION_STACK_SWITCH_CONTEXT *SwitchStackData;\r
+ UINTN Index;\r
+\r
+ MpInitLibWhoAmI (&Index);\r
+ SwitchStackData = (EXCEPTION_STACK_SWITCH_CONTEXT *)Buffer;\r
+\r
+ //\r
+ // This function may be called twice for each Cpu. Only run InitializeSeparateExceptionStacks\r
+ // if this is the first call or the first call failed because of size too small.\r
+ //\r
+ if ((SwitchStackData[Index].Status == EFI_NOT_STARTED) || (SwitchStackData[Index].Status == EFI_BUFFER_TOO_SMALL)) {\r
+ SwitchStackData[Index].Status = InitializeSeparateExceptionStacks (SwitchStackData[Index].Buffer, &SwitchStackData[Index].BufferSize);\r
+ }\r
+}\r
+\r
+/**\r
+ Initializes MP exceptions handlers for the sake of stack switch requirement.\r
+\r
+ This function will allocate required resources required to setup stack switch\r
+ and pass them through SwitchStackData to each logic processor.\r
+\r
+**/\r
+VOID\r
+InitializeMpExceptionStackSwitchHandlers (\r
+ VOID\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN NumberOfProcessors;\r
+ EXCEPTION_STACK_SWITCH_CONTEXT *SwitchStackData;\r
+ UINTN BufferSize;\r
+ EFI_STATUS Status;\r
+ UINT8 *Buffer;\r
+\r
+ if (!PcdGetBool (PcdCpuStackGuard)) {\r
+ return;\r
+ }\r
+\r
+ MpInitLibGetNumberOfProcessors (&NumberOfProcessors, NULL);\r
+ SwitchStackData = AllocatePages (EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (EXCEPTION_STACK_SWITCH_CONTEXT)));\r
+ ASSERT (SwitchStackData != NULL);\r
+ ZeroMem (SwitchStackData, NumberOfProcessors * sizeof (EXCEPTION_STACK_SWITCH_CONTEXT));\r
+ for (Index = 0; Index < NumberOfProcessors; ++Index) {\r
+ //\r
+ // Because the procedure may runs multiple times, use the status EFI_NOT_STARTED\r
+ // to indicate the procedure haven't been run yet.\r
+ //\r
+ SwitchStackData[Index].Status = EFI_NOT_STARTED;\r
+ }\r
+\r
+ Status = MpInitLibStartupAllCPUs (\r
+ InitializeExceptionStackSwitchHandlers,\r
+ 0,\r
+ SwitchStackData\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ BufferSize = 0;\r
+ for (Index = 0; Index < NumberOfProcessors; ++Index) {\r
+ if (SwitchStackData[Index].Status == EFI_BUFFER_TOO_SMALL) {\r
+ ASSERT (SwitchStackData[Index].BufferSize != 0);\r
+ BufferSize += SwitchStackData[Index].BufferSize;\r
+ } else {\r
+ ASSERT (SwitchStackData[Index].Status == EFI_SUCCESS);\r
+ ASSERT (SwitchStackData[Index].BufferSize == 0);\r
+ }\r
+ }\r
+\r
+ if (BufferSize != 0) {\r
+ Buffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));\r
+ ASSERT (Buffer != NULL);\r
+ BufferSize = 0;\r
+ for (Index = 0; Index < NumberOfProcessors; ++Index) {\r
+ if (SwitchStackData[Index].Status == EFI_BUFFER_TOO_SMALL) {\r
+ SwitchStackData[Index].Buffer = (VOID *)(&Buffer[BufferSize]);\r
+ BufferSize += SwitchStackData[Index].BufferSize;\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "Buffer[cpu%lu] for InitializeExceptionStackSwitchHandlers: 0x%lX with size 0x%lX\n",\r
+ (UINT64)(UINTN)Index,\r
+ (UINT64)(UINTN)SwitchStackData[Index].Buffer,\r
+ (UINT64)(UINTN)SwitchStackData[Index].BufferSize\r
+ ));\r
+ }\r
+ }\r
+\r
+ Status = MpInitLibStartupAllCPUs (\r
+ InitializeExceptionStackSwitchHandlers,\r
+ 0,\r
+ SwitchStackData\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+ for (Index = 0; Index < NumberOfProcessors; ++Index) {\r
+ ASSERT (SwitchStackData[Index].Status == EFI_SUCCESS);\r
+ }\r
+ }\r
+\r
+ FreePages (SwitchStackData, EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (EXCEPTION_STACK_SWITCH_CONTEXT)));\r
+}\r
+\r
+/**\r
+ Initializes MP and exceptions handlers.\r
+\r
+ @param PeiServices The pointer to the PEI Services Table.\r
+\r
+ @retval EFI_SUCCESS MP was successfully initialized.\r
+ @retval others Error occurred in MP initialization.\r
\r
**/\r
EFI_STATUS\r
-EFIAPI\r
-CpuMpPeimInit (\r
- IN EFI_PEI_FILE_HANDLE FileHandle,\r
- IN CONST EFI_PEI_SERVICES **PeiServices\r
+InitializeCpuMpWorker (\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
)\r
{\r
- EFI_STATUS Status;\r
- EFI_VECTOR_HANDOFF_INFO *VectorInfo;\r
- EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
+ EFI_STATUS Status;\r
+ EFI_VECTOR_HANDOFF_INFO *VectorInfo;\r
+ EFI_PEI_VECTOR_HANDOFF_INFO_PPI *VectorHandoffInfoPpi;\r
\r
//\r
// Get Vector Hand-off Info PPI\r
//\r
VectorInfo = NULL;\r
- Status = PeiServicesLocatePpi (\r
- &gEfiVectorHandoffInfoPpiGuid,\r
- 0,\r
- NULL,\r
- (VOID **)&VectorHandoffInfoPpi\r
- );\r
+ Status = PeiServicesLocatePpi (\r
+ &gEfiVectorHandoffInfoPpiGuid,\r
+ 0,\r
+ NULL,\r
+ (VOID **)&VectorHandoffInfoPpi\r
+ );\r
if (Status == EFI_SUCCESS) {\r
VectorInfo = VectorHandoffInfoPpi->Info;\r
}\r
- Status = InitializeCpuExceptionHandlers (VectorInfo);\r
- ASSERT_EFI_ERROR (Status);\r
- \r
+\r
//\r
- // Wakeup APs to do initialization\r
+ // Initialize default handlers\r
//\r
+ Status = InitializeCpuExceptionHandlers (VectorInfo);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
Status = MpInitLibInitialize ();\r
- ASSERT_EFI_ERROR (Status);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Special initialization for the sake of Stack Guard\r
+ //\r
+ InitializeMpExceptionStackSwitchHandlers ();\r
\r
//\r
// Update and publish CPU BIST information\r
//\r
// Install CPU MP PPI\r
//\r
- Status = PeiServicesInstallPpi(&mPeiCpuMpPpiDesc);\r
+ Status = PeiServicesInstallPpi (mPeiCpuMpPpiList);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return Status;\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
+\r
+ //\r
+ // For the sake of special initialization needing to be done right after\r
+ // memory discovery.\r
+ //\r
+ Status = PeiServicesNotifyPpi (&mPostMemNotifyList[0]);\r
ASSERT_EFI_ERROR (Status);\r
\r
return Status;\r