diff --git a/UefiCpuPkg/Include/Library/SmmCpuSyncLib.h b/UefiCpuPkg/Include/Library/SmmCpuSyncLib.h new file mode 100644 index 0000000000..4d273095c9 --- /dev/null +++ b/UefiCpuPkg/Include/Library/SmmCpuSyncLib.h @@ -0,0 +1,290 @@ +/** @file + Library that provides SMM CPU Sync related operations. + + The lib provides 3 sets of APIs: + 1. ContextInit/ContextDeinit/ContextReset: + + ContextInit() is called in driver's entrypoint to allocate and initialize the SMM CPU Sync context. + ContextDeinit() is called in driver's unload function to deinitialize the SMM CPU Sync context. + ContextReset() is called by one of CPUs after all CPUs are ready to exit SMI, which allows CPU to + check into the next SMI from this point. + + 2. GetArrivedCpuCount/CheckInCpu/CheckOutCpu/LockDoor: + When SMI happens, all processors including BSP enter to SMM mode by calling CheckInCpu(). + CheckOutCpu() can be called in error handling flow for the CPU who calls CheckInCpu() earlier. + The elected BSP calls LockDoor() so that CheckInCpu() and CheckOutCpu() will return the error code after that. + GetArrivedCpuCount() returns the number of checked-in CPUs. + + 3. WaitForAPs/ReleaseOneAp/WaitForBsp/ReleaseBsp + WaitForAPs() & ReleaseOneAp() are called from BSP to wait the number of APs and release one specific AP. + WaitForBsp() & ReleaseBsp() are called from APs to wait and release BSP. + The 4 APIs are used to synchronize the running flow among BSP and APs. + BSP and AP Sync flow can be easy understand as below: + BSP: ReleaseOneAp --> AP: WaitForBsp + BSP: WaitForAPs <-- AP: ReleaseBsp + + Copyright (c) 2023, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef SMM_CPU_SYNC_LIB_H_ +#define SMM_CPU_SYNC_LIB_H_ + +#include + +// +// Opaque structure for SMM CPU Sync context. +// +typedef struct SMM_CPU_SYNC_CONTEXT SMM_CPU_SYNC_CONTEXT; + +/** + Create and initialize the SMM CPU Sync context. It is to allocate and initialize the + SMM CPU Sync context. + + If Context is NULL, then ASSERT(). + + @param[in] NumberOfCpus The number of Logical Processors in the system. + @param[out] Context Pointer to the new created and initialized SMM CPU Sync context object. + NULL will be returned if any error happen during init. + + @retval RETURN_SUCCESS The SMM CPU Sync context was successful created and initialized. + @retval RETURN_OUT_OF_RESOURCES There are not enough resources available to create and initialize SMM CPU Sync context. + @retval RETURN_BUFFER_TOO_SMALL Overflow happen + +**/ +RETURN_STATUS +EFIAPI +SmmCpuSyncContextInit ( + IN UINTN NumberOfCpus, + OUT SMM_CPU_SYNC_CONTEXT **Context + ); + +/** + Deinit an allocated SMM CPU Sync context. The resources allocated in SmmCpuSyncContextInit() will + be freed. + + If Context is NULL, then ASSERT(). + + @param[in,out] Context Pointer to the SMM CPU Sync context object to be deinitialized. + +**/ +VOID +EFIAPI +SmmCpuSyncContextDeinit ( + IN OUT SMM_CPU_SYNC_CONTEXT *Context + ); + +/** + Reset SMM CPU Sync context. SMM CPU Sync context will be reset to the initialized state. + + This function is called by one of CPUs after all CPUs are ready to exit SMI, which allows CPU to + check into the next SMI from this point. + + If Context is NULL, then ASSERT(). + + @param[in,out] Context Pointer to the SMM CPU Sync context object to be reset. + +**/ +VOID +EFIAPI +SmmCpuSyncContextReset ( + IN OUT SMM_CPU_SYNC_CONTEXT *Context + ); + +/** + Get current number of arrived CPU in SMI. + + BSP might need to know the current number of arrived CPU in SMI to make sure all APs + in SMI. This API can be for that purpose. + + If Context is NULL, then ASSERT(). + + @param[in] Context Pointer to the SMM CPU Sync context object. + + @retval Current number of arrived CPU in SMI. + +**/ +UINTN +EFIAPI +SmmCpuSyncGetArrivedCpuCount ( + IN SMM_CPU_SYNC_CONTEXT *Context + ); + +/** + Performs an atomic operation to check in CPU. + + When SMI happens, all processors including BSP enter to SMM mode by calling SmmCpuSyncCheckInCpu(). + + If Context is NULL, then ASSERT(). + If CpuIndex exceeds the range of all CPUs in the system, then ASSERT(). + + @param[in,out] Context Pointer to the SMM CPU Sync context object. + @param[in] CpuIndex Check in CPU index. + + @retval RETURN_SUCCESS Check in CPU (CpuIndex) successfully. + @retval RETURN_ABORTED Check in CPU failed due to SmmCpuSyncLockDoor() has been called by one elected CPU. + +**/ +RETURN_STATUS +EFIAPI +SmmCpuSyncCheckInCpu ( + IN OUT SMM_CPU_SYNC_CONTEXT *Context, + IN UINTN CpuIndex + ); + +/** + Performs an atomic operation to check out CPU. + + This function can be called in error handling flow for the CPU who calls CheckInCpu() earlier. + The caller shall make sure the CPU specified by CpuIndex has already checked-in. + + If Context is NULL, then ASSERT(). + If CpuIndex exceeds the range of all CPUs in the system, then ASSERT(). + + @param[in,out] Context Pointer to the SMM CPU Sync context object. + @param[in] CpuIndex Check out CPU index. + + @retval RETURN_SUCCESS Check out CPU (CpuIndex) successfully. + @retval RETURN_ABORTED Check out CPU failed due to SmmCpuSyncLockDoor() has been called by one elected CPU. + +**/ +RETURN_STATUS +EFIAPI +SmmCpuSyncCheckOutCpu ( + IN OUT SMM_CPU_SYNC_CONTEXT *Context, + IN UINTN CpuIndex + ); + +/** + Performs an atomic operation lock door for CPU checkin and checkout. After this function: + CPU can not check in via SmmCpuSyncCheckInCpu(). + CPU can not check out via SmmCpuSyncCheckOutCpu(). + + The CPU specified by CpuIndex is elected to lock door. The caller shall make sure the CpuIndex + is the actual CPU calling this function to avoid the undefined behavior. + + If Context is NULL, then ASSERT(). + If CpuCount is NULL, then ASSERT(). + If CpuIndex exceeds the range of all CPUs in the system, then ASSERT(). + + @param[in,out] Context Pointer to the SMM CPU Sync context object. + @param[in] CpuIndex Indicate which CPU to lock door. + @param[out] CpuCount Number of arrived CPU in SMI after look door. + +**/ +VOID +EFIAPI +SmmCpuSyncLockDoor ( + IN OUT SMM_CPU_SYNC_CONTEXT *Context, + IN UINTN CpuIndex, + OUT UINTN *CpuCount + ); + +/** + Used by the BSP to wait for APs. + + The number of APs need to be waited is specified by NumberOfAPs. The BSP is specified by BspIndex. + The caller shall make sure the BspIndex is the actual CPU calling this function to avoid the undefined behavior. + The caller shall make sure the NumberOfAPs have already checked-in to avoid the undefined behavior. + + If Context is NULL, then ASSERT(). + If NumberOfAPs >= All CPUs in system, then ASSERT(). + If BspIndex exceeds the range of all CPUs in the system, then ASSERT(). + + Note: + This function is blocking mode, and it will return only after the number of APs released by + calling SmmCpuSyncReleaseBsp(): + BSP: WaitForAPs <-- AP: ReleaseBsp + + @param[in,out] Context Pointer to the SMM CPU Sync context object. + @param[in] NumberOfAPs Number of APs need to be waited by BSP. + @param[in] BspIndex The BSP Index to wait for APs. + +**/ +VOID +EFIAPI +SmmCpuSyncWaitForAPs ( + IN OUT SMM_CPU_SYNC_CONTEXT *Context, + IN UINTN NumberOfAPs, + IN UINTN BspIndex + ); + +/** + Used by the BSP to release one AP. + + The AP is specified by CpuIndex. The BSP is specified by BspIndex. + The caller shall make sure the BspIndex is the actual CPU calling this function to avoid the undefined behavior. + The caller shall make sure the CpuIndex has already checked-in to avoid the undefined behavior. + + If Context is NULL, then ASSERT(). + If CpuIndex == BspIndex, then ASSERT(). + If BspIndex or CpuIndex exceed the range of all CPUs in the system, then ASSERT(). + + @param[in,out] Context Pointer to the SMM CPU Sync context object. + @param[in] CpuIndex Indicate which AP need to be released. + @param[in] BspIndex The BSP Index to release AP. + +**/ +VOID +EFIAPI +SmmCpuSyncReleaseOneAp ( + IN OUT SMM_CPU_SYNC_CONTEXT *Context, + IN UINTN CpuIndex, + IN UINTN BspIndex + ); + +/** + Used by the AP to wait BSP. + + The AP is specified by CpuIndex. + The caller shall make sure the CpuIndex is the actual CPU calling this function to avoid the undefined behavior. + The BSP is specified by BspIndex. + + If Context is NULL, then ASSERT(). + If CpuIndex == BspIndex, then ASSERT(). + If BspIndex or CpuIndex exceed the range of all CPUs in the system, then ASSERT(). + + Note: + This function is blocking mode, and it will return only after the AP released by + calling SmmCpuSyncReleaseOneAp(): + BSP: ReleaseOneAp --> AP: WaitForBsp + + @param[in,out] Context Pointer to the SMM CPU Sync context object. + @param[in] CpuIndex Indicate which AP wait BSP. + @param[in] BspIndex The BSP Index to be waited. + +**/ +VOID +EFIAPI +SmmCpuSyncWaitForBsp ( + IN OUT SMM_CPU_SYNC_CONTEXT *Context, + IN UINTN CpuIndex, + IN UINTN BspIndex + ); + +/** + Used by the AP to release BSP. + + The AP is specified by CpuIndex. + The caller shall make sure the CpuIndex is the actual CPU calling this function to avoid the undefined behavior. + The BSP is specified by BspIndex. + + If Context is NULL, then ASSERT(). + If CpuIndex == BspIndex, then ASSERT(). + If BspIndex or CpuIndex exceed the range of all CPUs in the system, then ASSERT(). + + @param[in,out] Context Pointer to the SMM CPU Sync context object. + @param[in] CpuIndex Indicate which AP release BSP. + @param[in] BspIndex The BSP Index to be released. + +**/ +VOID +EFIAPI +SmmCpuSyncReleaseBsp ( + IN OUT SMM_CPU_SYNC_CONTEXT *Context, + IN UINTN CpuIndex, + IN UINTN BspIndex + ); + +#endif diff --git a/UefiCpuPkg/UefiCpuPkg.dec b/UefiCpuPkg/UefiCpuPkg.dec index 61bd34ef17..cc785a3222 100644 --- a/UefiCpuPkg/UefiCpuPkg.dec +++ b/UefiCpuPkg/UefiCpuPkg.dec @@ -64,6 +64,9 @@ ## @libraryclass Provides functions for manipulating smram savestate registers. MmSaveStateLib|Include/Library/MmSaveStateLib.h + ## @libraryclass Provides functions for SMM CPU Sync Operation. + SmmCpuSyncLib|Include/Library/SmmCpuSyncLib.h + [LibraryClasses.RISCV64] ## @libraryclass Provides functions to manage MMU features on RISCV64 CPUs. ##