]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/PiSmmCpuDxeSmm/CpuService.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / UefiCpuPkg / PiSmmCpuDxeSmm / CpuService.c
CommitLineData
529a5a86
MK
1/** @file\r
2Implementation of SMM CPU Services Protocol.\r
3\r
4a68176c 4Copyright (c) 2011 - 2022, Intel Corporation. All rights reserved.<BR>\r
0acd8697 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
529a5a86
MK
6\r
7**/\r
8\r
9#include "PiSmmCpuDxeSmm.h"\r
10\r
11//\r
12// SMM CPU Service Protocol instance\r
13//\r
14EFI_SMM_CPU_SERVICE_PROTOCOL mSmmCpuService = {\r
15 SmmGetProcessorInfo,\r
16 SmmSwitchBsp,\r
17 SmmAddProcessor,\r
18 SmmRemoveProcessor,\r
19 SmmWhoAmI,\r
20 SmmRegisterExceptionHandler\r
21};\r
22\r
4a68176c
LZ
23//\r
24// EDKII SMM CPU Rendezvous Service Protocol instance\r
25//\r
26EDKII_SMM_CPU_RENDEZVOUS_PROTOCOL mSmmCpuRendezvousService = {\r
27 SmmCpuRendezvous\r
28};\r
29\r
529a5a86
MK
30/**\r
31 Gets processor information on the requested processor at the instant this call is made.\r
32\r
33 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.\r
34 @param[in] ProcessorNumber The handle number of processor.\r
35 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for\r
36 the requested processor is deposited.\r
37\r
38 @retval EFI_SUCCESS Processor information was returned.\r
39 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.\r
40 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.\r
41 @retval EFI_NOT_FOUND The processor with the handle specified by\r
42 ProcessorNumber does not exist in the platform.\r
43\r
44**/\r
45EFI_STATUS\r
46EFIAPI\r
47SmmGetProcessorInfo (\r
053e878b
MK
48 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,\r
49 IN UINTN ProcessorNumber,\r
50 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer\r
529a5a86
MK
51 )\r
52{\r
53 //\r
54 // Check parameter\r
55 //\r
053e878b 56 if ((ProcessorNumber >= mMaxNumberOfCpus) || (ProcessorInfoBuffer == NULL)) {\r
529a5a86
MK
57 return EFI_INVALID_PARAMETER;\r
58 }\r
59\r
60 if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {\r
61 return EFI_NOT_FOUND;\r
62 }\r
63\r
64 //\r
65 // Fill in processor information\r
66 //\r
67 CopyMem (ProcessorInfoBuffer, &gSmmCpuPrivate->ProcessorInfo[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION));\r
68 return EFI_SUCCESS;\r
69}\r
70\r
71/**\r
72 This service switches the requested AP to be the BSP since the next SMI.\r
73\r
74 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.\r
75 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.\r
76\r
77 @retval EFI_SUCCESS BSP will be switched in next SMI.\r
78 @retval EFI_UNSUPPORTED Switching the BSP or a processor to be hot-removed is not supported.\r
79 @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.\r
80 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.\r
81**/\r
82EFI_STATUS\r
83EFIAPI\r
84SmmSwitchBsp (\r
053e878b
MK
85 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,\r
86 IN UINTN ProcessorNumber\r
529a5a86
MK
87 )\r
88{\r
89 //\r
90 // Check parameter\r
91 //\r
92 if (ProcessorNumber >= mMaxNumberOfCpus) {\r
93 return EFI_INVALID_PARAMETER;\r
94 }\r
95\r
96 if (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID) {\r
97 return EFI_NOT_FOUND;\r
98 }\r
99\r
053e878b
MK
100 if ((gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone) ||\r
101 (gSmst->CurrentlyExecutingCpu == ProcessorNumber))\r
102 {\r
529a5a86
MK
103 return EFI_UNSUPPORTED;\r
104 }\r
105\r
106 //\r
107 // Setting of the BSP for next SMI is pending until all SMI handlers are finished\r
108 //\r
109 gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuSwitchBsp;\r
110 return EFI_SUCCESS;\r
111}\r
112\r
113/**\r
114 Notify that a processor was hot-added.\r
115\r
116 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.\r
117 @param[in] ProcessorId Local APIC ID of the hot-added processor.\r
118 @param[out] ProcessorNumber The handle number of the hot-added processor.\r
119\r
120 @retval EFI_SUCCESS The hot-addition of the specified processors was successfully notified.\r
121 @retval EFI_UNSUPPORTED Hot addition of processor is not supported.\r
122 @retval EFI_NOT_FOUND The processor with the handle specified by ProcessorNumber does not exist.\r
123 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.\r
124 @retval EFI_ALREADY_STARTED The processor is already online in the system.\r
125**/\r
126EFI_STATUS\r
127EFIAPI\r
128SmmAddProcessor (\r
129 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,\r
130 IN UINT64 ProcessorId,\r
131 OUT UINTN *ProcessorNumber\r
132 )\r
133{\r
134 UINTN Index;\r
135\r
136 if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {\r
137 return EFI_UNSUPPORTED;\r
138 }\r
139\r
140 //\r
141 // Check parameter\r
142 //\r
053e878b 143 if ((ProcessorNumber == NULL) || (ProcessorId == INVALID_APIC_ID)) {\r
529a5a86
MK
144 return EFI_INVALID_PARAMETER;\r
145 }\r
146\r
147 //\r
148 // Check if the processor already exists\r
149 //\r
150\r
151 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
152 if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ProcessorId) {\r
153 return EFI_ALREADY_STARTED;\r
154 }\r
155 }\r
156\r
157 //\r
158 // Check CPU hot plug data. The CPU RAS handler should have created the mapping\r
159 // of the APIC ID to SMBASE.\r
160 //\r
161 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
053e878b
MK
162 if ((mCpuHotPlugData.ApicId[Index] == ProcessorId) &&\r
163 (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == INVALID_APIC_ID))\r
164 {\r
529a5a86 165 gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId = ProcessorId;\r
053e878b 166 gSmmCpuPrivate->ProcessorInfo[Index].StatusFlag = 0;\r
262128e5 167 GetProcessorLocationByApicId (\r
73152f19
LD
168 (UINT32)ProcessorId,\r
169 &gSmmCpuPrivate->ProcessorInfo[Index].Location.Package,\r
170 &gSmmCpuPrivate->ProcessorInfo[Index].Location.Core,\r
171 &gSmmCpuPrivate->ProcessorInfo[Index].Location.Thread\r
172 );\r
529a5a86 173\r
053e878b 174 *ProcessorNumber = Index;\r
529a5a86
MK
175 gSmmCpuPrivate->Operation[Index] = SmmCpuAdd;\r
176 return EFI_SUCCESS;\r
177 }\r
178 }\r
179\r
180 return EFI_INVALID_PARAMETER;\r
181}\r
182\r
183/**\r
184 Notify that a processor was hot-removed.\r
185\r
186 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.\r
187 @param[in] ProcessorNumber The handle number of the hot-added processor.\r
188\r
189 @retval EFI_SUCCESS The hot-removal of the specified processors was successfully notified.\r
190 @retval EFI_UNSUPPORTED Hot removal of processor is not supported.\r
191 @retval EFI_UNSUPPORTED Hot removal of BSP is not supported.\r
192 @retval EFI_UNSUPPORTED Hot removal of a processor with pending hot-plug operation is not supported.\r
193 @retval EFI_INVALID_PARAMETER ProcessorNumber is invalid.\r
194**/\r
195EFI_STATUS\r
196EFIAPI\r
197SmmRemoveProcessor (\r
198 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,\r
199 IN UINTN ProcessorNumber\r
200 )\r
201{\r
202 if (!FeaturePcdGet (PcdCpuHotPlugSupport)) {\r
203 return EFI_UNSUPPORTED;\r
204 }\r
205\r
206 //\r
207 // Check parameter\r
208 //\r
053e878b
MK
209 if ((ProcessorNumber >= mMaxNumberOfCpus) ||\r
210 (gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId == INVALID_APIC_ID))\r
211 {\r
529a5a86
MK
212 return EFI_INVALID_PARAMETER;\r
213 }\r
214\r
215 //\r
216 // Can't remove BSP\r
217 //\r
218 if (ProcessorNumber == gSmmCpuPrivate->SmmCoreEntryContext.CurrentlyExecutingCpu) {\r
219 return EFI_UNSUPPORTED;\r
220 }\r
221\r
222 if (gSmmCpuPrivate->Operation[ProcessorNumber] != SmmCpuNone) {\r
223 return EFI_UNSUPPORTED;\r
224 }\r
225\r
226 gSmmCpuPrivate->ProcessorInfo[ProcessorNumber].ProcessorId = INVALID_APIC_ID;\r
053e878b 227 mCpuHotPlugData.ApicId[ProcessorNumber] = INVALID_APIC_ID;\r
529a5a86
MK
228\r
229 //\r
230 // Removal of the processor from the CPU list is pending until all SMI handlers are finished\r
231 //\r
232 gSmmCpuPrivate->Operation[ProcessorNumber] = SmmCpuRemove;\r
233 return EFI_SUCCESS;\r
234}\r
235\r
236/**\r
237 This return the handle number for the calling processor.\r
238\r
239 @param[in] This A pointer to the EFI_SMM_CPU_SERVICE_PROTOCOL instance.\r
240 @param[out] ProcessorNumber The handle number of currently executing processor.\r
241\r
242 @retval EFI_SUCCESS The current processor handle number was returned\r
243 in ProcessorNumber.\r
244 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.\r
245\r
246**/\r
247EFI_STATUS\r
248EFIAPI\r
249SmmWhoAmI (\r
053e878b
MK
250 IN CONST EFI_SMM_CPU_SERVICE_PROTOCOL *This,\r
251 OUT UINTN *ProcessorNumber\r
529a5a86
MK
252 )\r
253{\r
053e878b
MK
254 UINTN Index;\r
255 UINT64 ApicId;\r
529a5a86
MK
256\r
257 //\r
258 // Check parameter\r
259 //\r
260 if (ProcessorNumber == NULL) {\r
261 return EFI_INVALID_PARAMETER;\r
262 }\r
263\r
264 ApicId = GetApicId ();\r
265\r
266 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
267 if (gSmmCpuPrivate->ProcessorInfo[Index].ProcessorId == ApicId) {\r
268 *ProcessorNumber = Index;\r
269 return EFI_SUCCESS;\r
270 }\r
271 }\r
053e878b 272\r
529a5a86
MK
273 //\r
274 // This should not happen\r
275 //\r
276 ASSERT (FALSE);\r
277 return EFI_NOT_FOUND;\r
278}\r
279\r
280/**\r
281 Update the SMM CPU list per the pending operation.\r
282\r
283 This function is called after return from SMI handlers.\r
284**/\r
285VOID\r
286SmmCpuUpdate (\r
287 VOID\r
288 )\r
289{\r
053e878b 290 UINTN Index;\r
529a5a86
MK
291\r
292 //\r
293 // Handle pending BSP switch operations\r
294 //\r
295 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
296 if (gSmmCpuPrivate->Operation[Index] == SmmCpuSwitchBsp) {\r
053e878b
MK
297 gSmmCpuPrivate->Operation[Index] = SmmCpuNone;\r
298 mSmmMpSyncData->SwitchBsp = TRUE;\r
529a5a86
MK
299 mSmmMpSyncData->CandidateBsp[Index] = TRUE;\r
300 }\r
301 }\r
302\r
303 //\r
304 // Handle pending hot-add operations\r
305 //\r
306 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
307 if (gSmmCpuPrivate->Operation[Index] == SmmCpuAdd) {\r
308 gSmmCpuPrivate->Operation[Index] = SmmCpuNone;\r
309 mNumberOfCpus++;\r
310 }\r
311 }\r
312\r
313 //\r
314 // Handle pending hot-remove operations\r
315 //\r
316 for (Index = 0; Index < mMaxNumberOfCpus; Index++) {\r
317 if (gSmmCpuPrivate->Operation[Index] == SmmCpuRemove) {\r
318 gSmmCpuPrivate->Operation[Index] = SmmCpuNone;\r
319 mNumberOfCpus--;\r
320 }\r
321 }\r
322}\r
323\r
324/**\r
325 Register exception handler.\r
326\r
327 @param This A pointer to the SMM_CPU_SERVICE_PROTOCOL instance.\r
328 @param ExceptionType Defines which interrupt or exception to hook. Type EFI_EXCEPTION_TYPE and\r
329 the valid values for this parameter are defined in EFI_DEBUG_SUPPORT_PROTOCOL\r
330 of the UEFI 2.0 specification.\r
331 @param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER\r
332 that is called when a processor interrupt occurs.\r
333 If this parameter is NULL, then the handler will be uninstalled.\r
334\r
335 @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.\r
336 @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was previously installed.\r
337 @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not previously installed.\r
338 @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.\r
339\r
340**/\r
341EFI_STATUS\r
342EFIAPI\r
343SmmRegisterExceptionHandler (\r
053e878b
MK
344 IN EFI_SMM_CPU_SERVICE_PROTOCOL *This,\r
345 IN EFI_EXCEPTION_TYPE ExceptionType,\r
346 IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler\r
347 )\r
529a5a86
MK
348{\r
349 return RegisterCpuInterruptHandler (ExceptionType, InterruptHandler);\r
350}\r
351\r
352/**\r
353 Initialize SMM CPU Services.\r
354\r
355 It installs EFI SMM CPU Services Protocol.\r
356\r
357 @param ImageHandle The firmware allocated handle for the EFI image.\r
358\r
359 @retval EFI_SUCCESS EFI SMM CPU Services Protocol was installed successfully.\r
4a68176c 360 @retval OTHER Fail to install Protocol.\r
529a5a86
MK
361**/\r
362EFI_STATUS\r
363InitializeSmmCpuServices (\r
364 IN EFI_HANDLE Handle\r
365 )\r
366{\r
053e878b 367 EFI_STATUS Status;\r
529a5a86
MK
368\r
369 Status = gSmst->SmmInstallProtocolInterface (\r
370 &Handle,\r
371 &gEfiSmmCpuServiceProtocolGuid,\r
372 EFI_NATIVE_INTERFACE,\r
373 &mSmmCpuService\r
374 );\r
375 ASSERT_EFI_ERROR (Status);\r
4a68176c
LZ
376 if (EFI_ERROR (Status)) {\r
377 return Status;\r
378 }\r
379\r
380 Status = gSmst->SmmInstallProtocolInterface (\r
381 &Handle,\r
382 &gEdkiiSmmCpuRendezvousProtocolGuid,\r
383 EFI_NATIVE_INTERFACE,\r
384 &mSmmCpuRendezvousService\r
385 );\r
386 ASSERT_EFI_ERROR (Status);\r
387 return Status;\r
388}\r
389\r
390/**\r
391 Wait for all processors enterring SMM until all CPUs are already synchronized or not.\r
392\r
393 If BlockingMode is False, timeout value is zero.\r
394\r
395 @param This A pointer to the EDKII_SMM_CPU_RENDEZVOUS_PROTOCOL instance.\r
396 @param BlockingMode Blocking mode or non-blocking mode.\r
397\r
398 @retval EFI_SUCCESS All avaiable APs arrived.\r
399 @retval EFI_TIMEOUT Wait for all APs until timeout.\r
400\r
401**/\r
402EFI_STATUS\r
403EFIAPI\r
404SmmCpuRendezvous (\r
405 IN EDKII_SMM_CPU_RENDEZVOUS_PROTOCOL *This,\r
406 IN BOOLEAN BlockingMode\r
407 )\r
408{\r
409 EFI_STATUS Status;\r
410\r
411 //\r
412 // Return success immediately if all CPUs are already synchronized.\r
413 //\r
414 if (mSmmMpSyncData->AllApArrivedWithException) {\r
415 Status = EFI_SUCCESS;\r
416 goto ON_EXIT;\r
417 }\r
418\r
419 if (!BlockingMode) {\r
420 Status = EFI_TIMEOUT;\r
421 goto ON_EXIT;\r
422 }\r
423\r
424 //\r
425 // There are some APs outside SMM, Wait for all avaiable APs to arrive.\r
426 //\r
427 SmmWaitForApArrival ();\r
428 Status = mSmmMpSyncData->AllApArrivedWithException ? EFI_SUCCESS : EFI_TIMEOUT;\r
429\r
430ON_EXIT:\r
431 if (!mSmmMpSyncData->AllApArrivedWithException) {\r
432 DEBUG ((DEBUG_INFO, "EdkiiSmmWaitForAllApArrival: Timeout to wait all APs arrival\n"));\r
433 }\r
434\r
529a5a86
MK
435 return Status;\r
436}\r