2 Implementation of SMM CPU Services Protocol.
4 Copyright (c) 2011 - 2022, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "PiSmmCpuDxeSmm.h"
12 // SMM CPU Service Protocol instance
14 EFI_SMM_CPU_SERVICE_PROTOCOL mSmmCpuService
= {
20 SmmRegisterExceptionHandler
24 // EDKII SMM CPU Rendezvous Service Protocol instance
26 EDKII_SMM_CPU_RENDEZVOUS_PROTOCOL mSmmCpuRendezvousService
= {
31 Gets processor information on the requested processor at the instant this call is made.
33 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
34 @param[in] ProcessorNumber The handle number of processor.
35 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
36 the requested processor is deposited.
38 @retval EFI_SUCCESS Processor information was returned.
39 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
40 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
41 @retval EFI_NOT_FOUND The processor with the handle specified by
42 ProcessorNumber does not exist in the platform.
48 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL
*This
,
49 IN UINTN ProcessorNumber
,
50 OUT EFI_PROCESSOR_INFORMATION
*ProcessorInfoBuffer
56 if ((ProcessorNumber
>= mMaxNumberOfCpus
) || (ProcessorInfoBuffer
== NULL
)) {
57 return EFI_INVALID_PARAMETER
;
60 if (gSmmCpuPrivate
->ProcessorInfo
[ProcessorNumber
].ProcessorId
== INVALID_APIC_ID
) {
65 // Fill in processor information
67 CopyMem (ProcessorInfoBuffer
, &gSmmCpuPrivate
->ProcessorInfo
[ProcessorNumber
], sizeof (EFI_PROCESSOR_INFORMATION
));
72 This service switches the requested AP to be the BSP since the next SMI.
74 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
75 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
77 @retval EFI_SUCCESS BSP will be switched in next SMI.
78 @retval EFI_UNSUPPORTED Switching the BSP or a processor to be hot-removed is not supported.
79 @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.
80 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
85 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL
*This
,
86 IN UINTN ProcessorNumber
92 if (ProcessorNumber
>= mMaxNumberOfCpus
) {
93 return EFI_INVALID_PARAMETER
;
96 if (gSmmCpuPrivate
->ProcessorInfo
[ProcessorNumber
].ProcessorId
== INVALID_APIC_ID
) {
100 if ((gSmmCpuPrivate
->Operation
[ProcessorNumber
] != SmmCpuNone
) ||
101 (gSmst
->CurrentlyExecutingCpu
== ProcessorNumber
))
103 return EFI_UNSUPPORTED
;
107 // Setting of the BSP for next SMI is pending until all SMI handlers are finished
109 gSmmCpuPrivate
->Operation
[ProcessorNumber
] = SmmCpuSwitchBsp
;
114 Notify that a processor was hot-added.
116 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
117 @param[in] ProcessorId Local APIC ID of the hot-added processor.
118 @param[out] ProcessorNumber The handle number of the hot-added processor.
120 @retval EFI_SUCCESS The hot-addition of the specified processors was successfully notified.
121 @retval EFI_UNSUPPORTED Hot addition of processor is not supported.
122 @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.
123 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
124 @retval EFI_ALREADY_STARTED The processor is already online in the system.
129 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL
*This
,
130 IN UINT64 ProcessorId
,
131 OUT UINTN
*ProcessorNumber
136 if (!FeaturePcdGet (PcdCpuHotPlugSupport
)) {
137 return EFI_UNSUPPORTED
;
143 if ((ProcessorNumber
== NULL
) || (ProcessorId
== INVALID_APIC_ID
)) {
144 return EFI_INVALID_PARAMETER
;
148 // Check if the processor already exists
151 for (Index
= 0; Index
< mMaxNumberOfCpus
; Index
++) {
152 if (gSmmCpuPrivate
->ProcessorInfo
[Index
].ProcessorId
== ProcessorId
) {
153 return EFI_ALREADY_STARTED
;
158 // Check CPU hot plug data. The CPU RAS handler should have created the mapping
159 // of the APIC ID to SMBASE.
161 for (Index
= 0; Index
< mMaxNumberOfCpus
; Index
++) {
162 if ((mCpuHotPlugData
.ApicId
[Index
] == ProcessorId
) &&
163 (gSmmCpuPrivate
->ProcessorInfo
[Index
].ProcessorId
== INVALID_APIC_ID
))
165 gSmmCpuPrivate
->ProcessorInfo
[Index
].ProcessorId
= ProcessorId
;
166 gSmmCpuPrivate
->ProcessorInfo
[Index
].StatusFlag
= 0;
167 GetProcessorLocationByApicId (
169 &gSmmCpuPrivate
->ProcessorInfo
[Index
].Location
.Package
,
170 &gSmmCpuPrivate
->ProcessorInfo
[Index
].Location
.Core
,
171 &gSmmCpuPrivate
->ProcessorInfo
[Index
].Location
.Thread
174 *ProcessorNumber
= Index
;
175 gSmmCpuPrivate
->Operation
[Index
] = SmmCpuAdd
;
180 return EFI_INVALID_PARAMETER
;
184 Notify that a processor was hot-removed.
186 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
187 @param[in] ProcessorNumber The handle number of the hot-added processor.
189 @retval EFI_SUCCESS The hot-removal of the specified processors was successfully notified.
190 @retval EFI_UNSUPPORTED Hot removal of processor is not supported.
191 @retval EFI_UNSUPPORTED Hot removal of BSP is not supported.
192 @retval EFI_UNSUPPORTED Hot removal of a processor with pending hot-plug operation is not supported.
193 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.
198 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL
*This
,
199 IN UINTN ProcessorNumber
202 if (!FeaturePcdGet (PcdCpuHotPlugSupport
)) {
203 return EFI_UNSUPPORTED
;
209 if ((ProcessorNumber
>= mMaxNumberOfCpus
) ||
210 (gSmmCpuPrivate
->ProcessorInfo
[ProcessorNumber
].ProcessorId
== INVALID_APIC_ID
))
212 return EFI_INVALID_PARAMETER
;
218 if (ProcessorNumber
== gSmmCpuPrivate
->SmmCoreEntryContext
.CurrentlyExecutingCpu
) {
219 return EFI_UNSUPPORTED
;
222 if (gSmmCpuPrivate
->Operation
[ProcessorNumber
] != SmmCpuNone
) {
223 return EFI_UNSUPPORTED
;
226 gSmmCpuPrivate
->ProcessorInfo
[ProcessorNumber
].ProcessorId
= INVALID_APIC_ID
;
227 mCpuHotPlugData
.ApicId
[ProcessorNumber
] = INVALID_APIC_ID
;
230 // Removal of the processor from the CPU list is pending until all SMI handlers are finished
232 gSmmCpuPrivate
->Operation
[ProcessorNumber
] = SmmCpuRemove
;
237 This return the handle number for the calling processor.
239 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.
240 @param[out] ProcessorNumber The handle number of currently executing processor.
242 @retval EFI_SUCCESS The current processor handle number was returned
244 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
250 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL
*This
,
251 OUT UINTN
*ProcessorNumber
260 if (ProcessorNumber
== NULL
) {
261 return EFI_INVALID_PARAMETER
;
264 ApicId
= GetApicId ();
266 for (Index
= 0; Index
< mMaxNumberOfCpus
; Index
++) {
267 if (gSmmCpuPrivate
->ProcessorInfo
[Index
].ProcessorId
== ApicId
) {
268 *ProcessorNumber
= Index
;
274 // This should not happen
277 return EFI_NOT_FOUND
;
281 Update the SMM CPU list per the pending operation.
283 This function is called after return from SMI handlers.
293 // Handle pending BSP switch operations
295 for (Index
= 0; Index
< mMaxNumberOfCpus
; Index
++) {
296 if (gSmmCpuPrivate
->Operation
[Index
] == SmmCpuSwitchBsp
) {
297 gSmmCpuPrivate
->Operation
[Index
] = SmmCpuNone
;
298 mSmmMpSyncData
->SwitchBsp
= TRUE
;
299 mSmmMpSyncData
->CandidateBsp
[Index
] = TRUE
;
304 // Handle pending hot-add operations
306 for (Index
= 0; Index
< mMaxNumberOfCpus
; Index
++) {
307 if (gSmmCpuPrivate
->Operation
[Index
] == SmmCpuAdd
) {
308 gSmmCpuPrivate
->Operation
[Index
] = SmmCpuNone
;
314 // Handle pending hot-remove operations
316 for (Index
= 0; Index
< mMaxNumberOfCpus
; Index
++) {
317 if (gSmmCpuPrivate
->Operation
[Index
] == SmmCpuRemove
) {
318 gSmmCpuPrivate
->Operation
[Index
] = SmmCpuNone
;
325 Register exception handler.
327 @param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance.
328 @param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and
329 the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL
330 of the UEFI 2.0 specification.
331 @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER
332 that is called when a processor interrupt occurs.
333 If this parameter is NULL, then the handler will be uninstalled.
335 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
336 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed.
337 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed.
338 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
343 SmmRegisterExceptionHandler (
344 IN EFI_SMM_CPU_SERVICE_PROTOCOL
*This
,
345 IN EFI_EXCEPTION_TYPE ExceptionType
,
346 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
349 return RegisterCpuInterruptHandler (ExceptionType
, InterruptHandler
);
353 Initialize SMM CPU Services.
355 It installs EFI SMM CPU Services Protocol.
357 @param ImageHandle The firmware allocated handle for the EFI image.
359 @retval EFI_SUCCESS EFI SMM CPU Services Protocol was installed successfully.
360 @retval OTHER Fail to install Protocol.
363 InitializeSmmCpuServices (
369 Status
= gSmst
->SmmInstallProtocolInterface (
371 &gEfiSmmCpuServiceProtocolGuid
,
372 EFI_NATIVE_INTERFACE
,
375 ASSERT_EFI_ERROR (Status
);
376 if (EFI_ERROR (Status
)) {
380 Status
= gSmst
->SmmInstallProtocolInterface (
382 &gEdkiiSmmCpuRendezvousProtocolGuid
,
383 EFI_NATIVE_INTERFACE
,
384 &mSmmCpuRendezvousService
386 ASSERT_EFI_ERROR (Status
);
391 Wait for all processors enterring SMM until all CPUs are already synchronized or not.
393 If BlockingMode is False, timeout value is zero.
395 @param This A pointer to the EDKII_SMM_CPU_RENDEZVOUS_PROTOCOL instance.
396 @param BlockingMode Blocking mode or non-blocking mode.
398 @retval EFI_SUCCESS All avaiable APs arrived.
399 @retval EFI_TIMEOUT Wait for all APs until timeout.
405 IN EDKII_SMM_CPU_RENDEZVOUS_PROTOCOL
*This
,
406 IN BOOLEAN BlockingMode
412 // Return success immediately if all CPUs are already synchronized.
414 if (mSmmMpSyncData
->AllApArrivedWithException
) {
415 Status
= EFI_SUCCESS
;
420 Status
= EFI_TIMEOUT
;
425 // There are some APs outside SMM, Wait for all avaiable APs to arrive.
427 SmmWaitForApArrival ();
428 Status
= mSmmMpSyncData
->AllApArrivedWithException
? EFI_SUCCESS
: EFI_TIMEOUT
;
431 if (!mSmmMpSyncData
->AllApArrivedWithException
) {
432 DEBUG ((DEBUG_INFO
, "EdkiiSmmWaitForAllApArrival: Timeout to wait all APs arrival\n"));