]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuDxe/CpuMp.c
UefiCpuPkg/MpService: Put APs to sleep when not busy.
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuMp.c
CommitLineData
6022e28c
JJ
1/** @file\r
2 CPU DXE Module.\r
3\r
4 Copyright (c) 2008 - 2014, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "CpuDxe.h"\r
16#include "CpuMp.h"\r
17\r
6a26a597
CF
18UINTN gMaxLogicalProcessorNumber;\r
19UINTN gApStackSize;\r
3f4f0af8 20UINTN gPollInterval = 100; // 100 microseconds\r
6a26a597 21\r
03673ae1 22MP_SYSTEM_DATA mMpSystemData;\r
9840b129
CF
23EFI_HANDLE mMpServiceHandle = NULL;\r
24EFI_EVENT mExitBootServicesEvent = (EFI_EVENT)NULL;\r
03673ae1 25\r
fab82c18
JJ
26VOID *mCommonStack = 0;\r
27VOID *mTopOfApCommonStack = 0;\r
6a26a597 28VOID *mApStackStart = 0;\r
fab82c18 29\r
232eb4c8 30volatile BOOLEAN mAPsAlreadyInitFinished = FALSE;\r
acb2172d
CF
31volatile BOOLEAN mStopCheckAllAPsStatus = TRUE;\r
32\r
003973d9 33EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = {\r
d894d8b7 34 GetNumberOfProcessors,\r
e7938b5a 35 GetProcessorInfo,\r
5fee172f 36 StartupAllAPs,\r
3f4f0af8 37 StartupThisAP,\r
b7c05ba5 38 SwitchBSP,\r
fa7ce675 39 EnableDisableAP,\r
cfa2fac1 40 WhoAmI\r
003973d9
CF
41};\r
42\r
d16cf36d
CF
43/**\r
44 Get Mp Service Lock.\r
45\r
46 @param CpuData the pointer to CPU_DATA_BLOCK of specified processor\r
47\r
48**/\r
49VOID\r
50GetMpSpinLock (\r
51 IN CPU_DATA_BLOCK *CpuData\r
52 )\r
53{\r
54 while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {\r
55 CpuPause ();\r
56 }\r
0e724fc1 57 CpuData->LockSelf = GetApicId ();\r
d16cf36d
CF
58}\r
59\r
60/**\r
61 Release Mp Service Lock.\r
62\r
63 @param CpuData the pointer to CPU_DATA_BLOCK of specified processor\r
64\r
65**/\r
66VOID\r
67ReleaseMpSpinLock (\r
68 IN CPU_DATA_BLOCK *CpuData\r
69 )\r
70{\r
71 ReleaseSpinLock (&CpuData->CpuDataLock);\r
72}\r
73\r
d894d8b7
CF
74/**\r
75 Check whether caller processor is BSP.\r
76\r
77 @retval TRUE the caller is BSP\r
78 @retval FALSE the caller is AP\r
79\r
80**/\r
81BOOLEAN\r
82IsBSP (\r
83 VOID\r
84 )\r
85{\r
86 UINTN CpuIndex;\r
87 CPU_DATA_BLOCK *CpuData;\r
88\r
89 CpuData = NULL;\r
90\r
91 WhoAmI (&mMpServicesTemplate, &CpuIndex);\r
92 CpuData = &mMpSystemData.CpuDatas[CpuIndex];\r
93\r
94 return CpuData->Info.StatusFlag & PROCESSOR_AS_BSP_BIT ? TRUE : FALSE;\r
95}\r
96\r
fa7ce675
CF
97/**\r
98 Get the Application Processors state.\r
99\r
100 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP\r
101\r
102 @retval CPU_STATE the AP status\r
103\r
104**/\r
105CPU_STATE\r
106GetApState (\r
107 IN CPU_DATA_BLOCK *CpuData\r
108 )\r
109{\r
110 CPU_STATE State;\r
111\r
d16cf36d 112 GetMpSpinLock (CpuData);\r
fa7ce675 113 State = CpuData->State;\r
d16cf36d 114 ReleaseMpSpinLock (CpuData);\r
fa7ce675
CF
115\r
116 return State;\r
117}\r
118\r
3f4f0af8
CF
119/**\r
120 Set the Application Processors state.\r
121\r
122 @param CpuData The pointer to CPU_DATA_BLOCK of specified AP\r
123 @param State The AP status\r
124\r
125**/\r
126VOID\r
127SetApState (\r
128 IN CPU_DATA_BLOCK *CpuData,\r
129 IN CPU_STATE State\r
130 )\r
131{\r
d16cf36d 132 GetMpSpinLock (CpuData);\r
3f4f0af8 133 CpuData->State = State;\r
d16cf36d 134 ReleaseMpSpinLock (CpuData);\r
3f4f0af8
CF
135}\r
136\r
137/**\r
138 Set the Application Processor prepare to run a function specified\r
139 by Params.\r
140\r
141 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP\r
142 @param Procedure A pointer to the function to be run on enabled APs of the system\r
143 @param ProcedureArgument Pointer to the optional parameter of the assigned function\r
144\r
145**/\r
146VOID\r
147SetApProcedure (\r
148 IN CPU_DATA_BLOCK *CpuData,\r
149 IN EFI_AP_PROCEDURE Procedure,\r
150 IN VOID *ProcedureArgument\r
151 )\r
152{\r
d16cf36d 153 GetMpSpinLock (CpuData);\r
3f4f0af8
CF
154 CpuData->Parameter = ProcedureArgument;\r
155 CpuData->Procedure = Procedure;\r
d16cf36d 156 ReleaseMpSpinLock (CpuData);\r
3f4f0af8
CF
157}\r
158\r
fa7ce675
CF
159/**\r
160 Check the Application Processors Status whether contains the Flags.\r
161\r
162 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP\r
163 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION\r
164\r
165 @retval TRUE the AP status includes the StatusFlag\r
166 @retval FALSE the AP status excludes the StatusFlag\r
167\r
168**/\r
169BOOLEAN\r
170TestCpuStatusFlag (\r
171 IN CPU_DATA_BLOCK *CpuData,\r
172 IN UINT32 Flags\r
173 )\r
174{\r
175 UINT32 Ret;\r
176\r
d16cf36d 177 GetMpSpinLock (CpuData);\r
fa7ce675 178 Ret = CpuData->Info.StatusFlag & Flags;\r
d16cf36d 179 ReleaseMpSpinLock (CpuData);\r
fa7ce675 180\r
7475d138 181 return (BOOLEAN) (Ret != 0);\r
fa7ce675
CF
182}\r
183\r
184/**\r
185 Bitwise-Or of the Application Processors Status with the Flags.\r
186\r
187 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP\r
188 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION\r
189\r
190**/\r
191VOID\r
192CpuStatusFlagOr (\r
193 IN CPU_DATA_BLOCK *CpuData,\r
194 IN UINT32 Flags\r
195 )\r
196{\r
d16cf36d 197 GetMpSpinLock (CpuData);\r
fa7ce675 198 CpuData->Info.StatusFlag |= Flags;\r
d16cf36d 199 ReleaseMpSpinLock (CpuData);\r
fa7ce675
CF
200}\r
201\r
202/**\r
203 Bitwise-AndNot of the Application Processors Status with the Flags.\r
204\r
205 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP\r
206 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION\r
207\r
208**/\r
209VOID\r
210CpuStatusFlagAndNot (\r
211 IN CPU_DATA_BLOCK *CpuData,\r
212 IN UINT32 Flags\r
213 )\r
214{\r
d16cf36d 215 GetMpSpinLock (CpuData);\r
fa7ce675 216 CpuData->Info.StatusFlag &= ~Flags;\r
d16cf36d 217 ReleaseMpSpinLock (CpuData);\r
fa7ce675
CF
218}\r
219\r
3f4f0af8
CF
220/**\r
221 Searches for the next blocking AP.\r
222\r
223 Search for the next AP that is put in blocking state by single-threaded StartupAllAPs().\r
224\r
225 @param NextNumber Pointer to the processor number of the next blocking AP.\r
226\r
227 @retval EFI_SUCCESS The next blocking AP has been found.\r
228 @retval EFI_NOT_FOUND No blocking AP exists.\r
229\r
230**/\r
231EFI_STATUS\r
232GetNextBlockedNumber (\r
233 OUT UINTN *NextNumber\r
234 )\r
235{\r
236 UINTN Number;\r
237 CPU_STATE CpuState;\r
238 CPU_DATA_BLOCK *CpuData;\r
239\r
240 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {\r
241 CpuData = &mMpSystemData.CpuDatas[Number];\r
242 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
243 //\r
244 // Skip BSP\r
245 //\r
246 continue;\r
247 }\r
248\r
249 CpuState = GetApState (CpuData);\r
250 if (CpuState == CpuStateBlocked) {\r
251 *NextNumber = Number;\r
252 return EFI_SUCCESS;\r
253 }\r
254 }\r
255\r
256 return EFI_NOT_FOUND;\r
257}\r
258\r
5fee172f
CF
259/**\r
260 Check if the APs state are finished, and update them to idle state\r
261 by StartupAllAPs().\r
262\r
263**/\r
264VOID\r
265CheckAndUpdateAllAPsToIdleState (\r
266 VOID\r
267 )\r
268{\r
269 UINTN ProcessorNumber;\r
270 UINTN NextNumber;\r
271 CPU_DATA_BLOCK *CpuData;\r
272 EFI_STATUS Status;\r
273 CPU_STATE CpuState;\r
274\r
275 for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {\r
276 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
277 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
278 //\r
279 // Skip BSP\r
280 //\r
281 continue;\r
282 }\r
283\r
284 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {\r
285 //\r
286 // Skip Disabled processors\r
287 //\r
288 continue;\r
289 }\r
290\r
291 CpuState = GetApState (CpuData);\r
292 if (CpuState == CpuStateFinished) {\r
293 mMpSystemData.FinishCount++;\r
294 if (mMpSystemData.SingleThread) {\r
295 Status = GetNextBlockedNumber (&NextNumber);\r
296 if (!EFI_ERROR (Status)) {\r
297 SetApState (&mMpSystemData.CpuDatas[NextNumber], CpuStateReady);\r
298 SetApProcedure (&mMpSystemData.CpuDatas[NextNumber],\r
299 mMpSystemData.Procedure,\r
300 mMpSystemData.ProcedureArgument);\r
68f06742
CF
301 //\r
302 // If this AP previous state is blocked, we should\r
303 // wake up this AP by sent a SIPI. and avoid\r
304 // re-involve the sleeping state. we must call\r
305 // SetApProcedure() first.\r
306 //\r
307 ResetProcessorToIdleState (&mMpSystemData.CpuDatas[NextNumber]);\r
5fee172f
CF
308 }\r
309 }\r
5fee172f
CF
310 SetApState (CpuData, CpuStateIdle);\r
311 }\r
312 }\r
313}\r
314\r
315/**\r
316 If the timeout expires before all APs returns from Procedure,\r
317 we should forcibly terminate the executing AP and fill FailedList back\r
318 by StartupAllAPs().\r
319\r
320**/\r
321VOID\r
322ResetAllFailedAPs (\r
323 VOID\r
324 )\r
325{\r
326 CPU_DATA_BLOCK *CpuData;\r
327 UINTN Number;\r
328 CPU_STATE CpuState;\r
329\r
330 if (mMpSystemData.FailedList != NULL) {\r
331 *mMpSystemData.FailedList = AllocatePool ((mMpSystemData.StartCount - mMpSystemData.FinishCount + 1) * sizeof(UINTN));\r
332 ASSERT (*mMpSystemData.FailedList != NULL);\r
333 }\r
334\r
335 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {\r
336 CpuData = &mMpSystemData.CpuDatas[Number];\r
337 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
338 //\r
339 // Skip BSP\r
340 //\r
341 continue;\r
342 }\r
343\r
344 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {\r
345 //\r
346 // Skip Disabled processors\r
347 //\r
348 continue;\r
349 }\r
350\r
351 CpuState = GetApState (CpuData);\r
68f06742
CF
352 if (CpuState != CpuStateIdle &&\r
353 CpuState != CpuStateSleeping) {\r
5fee172f
CF
354 if (mMpSystemData.FailedList != NULL) {\r
355 (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex++] = Number;\r
356 }\r
357 ResetProcessorToIdleState (CpuData);\r
358 }\r
359 }\r
360\r
361 if (mMpSystemData.FailedList != NULL) {\r
362 (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex] = END_OF_CPU_LIST;\r
363 }\r
364}\r
365\r
d894d8b7
CF
366/**\r
367 This service retrieves the number of logical processor in the platform\r
368 and the number of those logical processors that are enabled on this boot.\r
369 This service may only be called from the BSP.\r
370\r
371 This function is used to retrieve the following information:\r
372 - The number of logical processors that are present in the system.\r
373 - The number of enabled logical processors in the system at the instant\r
374 this call is made.\r
375\r
376 Because MP Service Protocol provides services to enable and disable processors\r
377 dynamically, the number of enabled logical processors may vary during the\r
378 course of a boot session.\r
379\r
380 If this service is called from an AP, then EFI_DEVICE_ERROR is returned.\r
381 If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then\r
382 EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors\r
383 is returned in NumberOfProcessors, the number of currently enabled processor\r
384 is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.\r
385\r
386 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL\r
387 instance.\r
388 @param[out] NumberOfProcessors Pointer to the total number of logical\r
389 processors in the system, including the BSP\r
390 and disabled APs.\r
391 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical\r
392 processors that exist in system, including\r
393 the BSP.\r
394\r
395 @retval EFI_SUCCESS The number of logical processors and enabled\r
396 logical processors was retrieved.\r
397 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
398 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.\r
399 @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.\r
400\r
401**/\r
402EFI_STATUS\r
403EFIAPI\r
404GetNumberOfProcessors (\r
405 IN EFI_MP_SERVICES_PROTOCOL *This,\r
406 OUT UINTN *NumberOfProcessors,\r
407 OUT UINTN *NumberOfEnabledProcessors\r
408 )\r
409{\r
410 if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {\r
411 return EFI_INVALID_PARAMETER;\r
412 }\r
413\r
414 if (!IsBSP ()) {\r
415 return EFI_DEVICE_ERROR;\r
416 }\r
417\r
418 *NumberOfProcessors = mMpSystemData.NumberOfProcessors;\r
419 *NumberOfEnabledProcessors = mMpSystemData.NumberOfEnabledProcessors;\r
420 return EFI_SUCCESS;\r
421}\r
422\r
e7938b5a
CF
423/**\r
424 Gets detailed MP-related information on the requested processor at the\r
425 instant this call is made. This service may only be called from the BSP.\r
426\r
427 This service retrieves detailed MP-related information about any processor\r
428 on the platform. Note the following:\r
429 - The processor information may change during the course of a boot session.\r
430 - The information presented here is entirely MP related.\r
431\r
432 Information regarding the number of caches and their sizes, frequency of operation,\r
433 slot numbers is all considered platform-related information and is not provided\r
434 by this service.\r
435\r
436 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL\r
437 instance.\r
438 @param[in] ProcessorNumber The handle number of processor.\r
439 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for\r
440 the requested processor is deposited.\r
441\r
442 @retval EFI_SUCCESS Processor information was returned.\r
443 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
444 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.\r
445 @retval EFI_NOT_FOUND The processor with the handle specified by\r
446 ProcessorNumber does not exist in the platform.\r
447\r
448**/\r
449EFI_STATUS\r
450EFIAPI\r
451GetProcessorInfo (\r
452 IN EFI_MP_SERVICES_PROTOCOL *This,\r
453 IN UINTN ProcessorNumber,\r
454 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer\r
455 )\r
456{\r
457 if (ProcessorInfoBuffer == NULL) {\r
458 return EFI_INVALID_PARAMETER;\r
459 }\r
460\r
461 if (!IsBSP ()) {\r
462 return EFI_DEVICE_ERROR;\r
463 }\r
464\r
465 if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {\r
466 return EFI_NOT_FOUND;\r
467 }\r
468\r
469 CopyMem (ProcessorInfoBuffer, &mMpSystemData.CpuDatas[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION));\r
470 return EFI_SUCCESS;\r
471}\r
472\r
5fee172f
CF
473/**\r
474 This service executes a caller provided function on all enabled APs. APs can\r
475 run either simultaneously or one at a time in sequence. This service supports\r
476 both blocking and non-blocking requests. The non-blocking requests use EFI\r
477 events so the BSP can detect when the APs have finished. This service may only\r
478 be called from the BSP.\r
479\r
480 This function is used to dispatch all the enabled APs to the function specified\r
481 by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned\r
482 immediately and Procedure is not started on any AP.\r
483\r
484 If SingleThread is TRUE, all the enabled APs execute the function specified by\r
485 Procedure one by one, in ascending order of processor handle number. Otherwise,\r
486 all the enabled APs execute the function specified by Procedure simultaneously.\r
487\r
488 If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all\r
489 APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking\r
490 mode, and the BSP returns from this service without waiting for APs. If a\r
491 non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT\r
492 is signaled, then EFI_UNSUPPORTED must be returned.\r
493\r
494 If the timeout specified by TimeoutInMicroseconds expires before all APs return\r
495 from Procedure, then Procedure on the failed APs is terminated. All enabled APs\r
496 are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()\r
497 and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its\r
498 content points to the list of processor handle numbers in which Procedure was\r
499 terminated.\r
500\r
501 Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()\r
502 to make sure that the nature of the code that is executed on the BSP and the\r
503 dispatched APs is well controlled. The MP Services Protocol does not guarantee\r
504 that the Procedure function is MP-safe. Hence, the tasks that can be run in\r
505 parallel are limited to certain independent tasks and well-controlled exclusive\r
506 code. EFI services and protocols may not be called by APs unless otherwise\r
507 specified.\r
508\r
509 In blocking execution mode, BSP waits until all APs finish or\r
510 TimeoutInMicroseconds expires.\r
511\r
512 In non-blocking execution mode, BSP is freed to return to the caller and then\r
513 proceed to the next task without having to wait for APs. The following\r
514 sequence needs to occur in a non-blocking execution mode:\r
515\r
516 -# The caller that intends to use this MP Services Protocol in non-blocking\r
517 mode creates WaitEvent by calling the EFI CreateEvent() service. The caller\r
518 invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent\r
519 is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests\r
520 the function specified by Procedure to be started on all the enabled APs,\r
521 and releases the BSP to continue with other tasks.\r
522 -# The caller can use the CheckEvent() and WaitForEvent() services to check\r
523 the state of the WaitEvent created in step 1.\r
524 -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP\r
525 Service signals WaitEvent by calling the EFI SignalEvent() function. If\r
526 FailedCpuList is not NULL, its content is available when WaitEvent is\r
527 signaled. If all APs returned from Procedure prior to the timeout, then\r
528 FailedCpuList is set to NULL. If not all APs return from Procedure before\r
529 the timeout, then FailedCpuList is filled in with the list of the failed\r
530 APs. The buffer is allocated by MP Service Protocol using AllocatePool().\r
531 It is the caller's responsibility to free the buffer with FreePool() service.\r
532 -# This invocation of SignalEvent() function informs the caller that invoked\r
533 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed\r
534 the specified task or a timeout occurred. The contents of FailedCpuList\r
535 can be examined to determine which APs did not complete the specified task\r
536 prior to the timeout.\r
537\r
538 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL\r
539 instance.\r
540 @param[in] Procedure A pointer to the function to be run on\r
541 enabled APs of the system. See type\r
542 EFI_AP_PROCEDURE.\r
543 @param[in] SingleThread If TRUE, then all the enabled APs execute\r
544 the function specified by Procedure one by\r
545 one, in ascending order of processor handle\r
546 number. If FALSE, then all the enabled APs\r
547 execute the function specified by Procedure\r
548 simultaneously.\r
549 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
550 service. If it is NULL, then execute in\r
551 blocking mode. BSP waits until all APs finish\r
552 or TimeoutInMicroseconds expires. If it's\r
553 not NULL, then execute in non-blocking mode.\r
554 BSP requests the function specified by\r
555 Procedure to be started on all the enabled\r
556 APs, and go on executing immediately. If\r
557 all return from Procedure, or TimeoutInMicroseconds\r
558 expires, this event is signaled. The BSP\r
559 can use the CheckEvent() or WaitForEvent()\r
560 services to check the state of event. Type\r
561 EFI_EVENT is defined in CreateEvent() in\r
562 the Unified Extensible Firmware Interface\r
563 Specification.\r
564 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
565 APs to return from Procedure, either for\r
566 blocking or non-blocking mode. Zero means\r
567 infinity. If the timeout expires before\r
568 all APs return from Procedure, then Procedure\r
569 on the failed APs is terminated. All enabled\r
570 APs are available for next function assigned\r
571 by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()\r
572 or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().\r
573 If the timeout expires in blocking mode,\r
574 BSP returns EFI_TIMEOUT. If the timeout\r
575 expires in non-blocking mode, WaitEvent\r
576 is signaled with SignalEvent().\r
577 @param[in] ProcedureArgument The parameter passed into Procedure for\r
578 all APs.\r
579 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,\r
580 if all APs finish successfully, then its\r
581 content is set to NULL. If not all APs\r
582 finish before timeout expires, then its\r
583 content is set to address of the buffer\r
584 holding handle numbers of the failed APs.\r
585 The buffer is allocated by MP Service Protocol,\r
586 and it's the caller's responsibility to\r
587 free the buffer with FreePool() service.\r
588 In blocking mode, it is ready for consumption\r
589 when the call returns. In non-blocking mode,\r
590 it is ready when WaitEvent is signaled. The\r
591 list of failed CPU is terminated by\r
592 END_OF_CPU_LIST.\r
593\r
594 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
595 the timeout expired.\r
596 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
597 to all enabled APs.\r
598 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
599 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
600 signaled.\r
601 @retval EFI_DEVICE_ERROR Caller processor is AP.\r
602 @retval EFI_NOT_STARTED No enabled APs exist in the system.\r
603 @retval EFI_NOT_READY Any enabled APs are busy.\r
604 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
605 all enabled APs have finished.\r
606 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
607\r
608**/\r
609EFI_STATUS\r
610EFIAPI\r
611StartupAllAPs (\r
612 IN EFI_MP_SERVICES_PROTOCOL *This,\r
613 IN EFI_AP_PROCEDURE Procedure,\r
614 IN BOOLEAN SingleThread,\r
615 IN EFI_EVENT WaitEvent OPTIONAL,\r
616 IN UINTN TimeoutInMicroseconds,\r
617 IN VOID *ProcedureArgument OPTIONAL,\r
618 OUT UINTN **FailedCpuList OPTIONAL\r
619 )\r
620{\r
621 EFI_STATUS Status;\r
622 CPU_DATA_BLOCK *CpuData;\r
623 UINTN Number;\r
624 CPU_STATE APInitialState;\r
68f06742 625 CPU_STATE CpuState;\r
5fee172f
CF
626\r
627 CpuData = NULL;\r
628\r
629 if (FailedCpuList != NULL) {\r
630 *FailedCpuList = NULL;\r
631 }\r
632\r
633 if (!IsBSP ()) {\r
634 return EFI_DEVICE_ERROR;\r
635 }\r
636\r
637 if (mMpSystemData.NumberOfProcessors == 1) {\r
638 return EFI_NOT_STARTED;\r
639 }\r
640\r
641 if (Procedure == NULL) {\r
642 return EFI_INVALID_PARAMETER;\r
643 }\r
644\r
cd8c700b
CF
645 //\r
646 // temporarily stop checkAllAPsStatus for avoid resource dead-lock.\r
647 //\r
648 mStopCheckAllAPsStatus = TRUE;\r
649\r
5fee172f
CF
650 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {\r
651 CpuData = &mMpSystemData.CpuDatas[Number];\r
652 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
653 //\r
654 // Skip BSP\r
655 //\r
656 continue;\r
657 }\r
658\r
659 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {\r
660 //\r
661 // Skip Disabled processors\r
662 //\r
663 continue;\r
664 }\r
665\r
68f06742
CF
666 CpuState = GetApState (CpuData);\r
667 if (CpuState != CpuStateIdle &&\r
668 CpuState != CpuStateSleeping) {\r
5fee172f
CF
669 return EFI_NOT_READY;\r
670 }\r
671 }\r
672\r
673 mMpSystemData.Procedure = Procedure;\r
674 mMpSystemData.ProcedureArgument = ProcedureArgument;\r
675 mMpSystemData.WaitEvent = WaitEvent;\r
676 mMpSystemData.Timeout = TimeoutInMicroseconds;\r
7475d138 677 mMpSystemData.TimeoutActive = (BOOLEAN) (TimeoutInMicroseconds != 0);\r
5fee172f
CF
678 mMpSystemData.FinishCount = 0;\r
679 mMpSystemData.StartCount = 0;\r
680 mMpSystemData.SingleThread = SingleThread;\r
681 mMpSystemData.FailedList = FailedCpuList;\r
682 mMpSystemData.FailedListIndex = 0;\r
683 APInitialState = CpuStateReady;\r
684\r
685 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {\r
686 CpuData = &mMpSystemData.CpuDatas[Number];\r
687 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
688 //\r
689 // Skip BSP\r
690 //\r
691 continue;\r
692 }\r
693\r
694 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {\r
695 //\r
696 // Skip Disabled processors\r
697 //\r
698 continue;\r
699 }\r
700\r
701 //\r
702 // Get APs prepared, and put failing APs into FailedCpuList\r
703 // if "SingleThread", only 1 AP will put to ready state, other AP will be put to ready\r
704 // state 1 by 1, until the previous 1 finished its task\r
705 // if not "SingleThread", all APs are put to ready state from the beginning\r
706 //\r
68f06742
CF
707 CpuState = GetApState (CpuData);\r
708 if (CpuState == CpuStateIdle ||\r
709 CpuState == CpuStateSleeping) {\r
5fee172f
CF
710 mMpSystemData.StartCount++;\r
711\r
712 SetApState (CpuData, APInitialState);\r
713\r
714 if (APInitialState == CpuStateReady) {\r
715 SetApProcedure (CpuData, Procedure, ProcedureArgument);\r
68f06742
CF
716 //\r
717 // If this AP previous state is Sleeping, we should\r
718 // wake up this AP by sent a SIPI. and avoid\r
719 // re-involve the sleeping state. we must call\r
720 // SetApProcedure() first.\r
721 //\r
722 if (CpuState == CpuStateSleeping) {\r
723 ResetProcessorToIdleState (CpuData);\r
724 }\r
5fee172f
CF
725 }\r
726\r
727 if (SingleThread) {\r
728 APInitialState = CpuStateBlocked;\r
729 }\r
730 }\r
731 }\r
732\r
acb2172d
CF
733 mStopCheckAllAPsStatus = FALSE;\r
734\r
5fee172f 735 if (WaitEvent != NULL) {\r
acb2172d
CF
736 //\r
737 // non blocking\r
738 //\r
739 return EFI_SUCCESS;\r
5fee172f
CF
740 }\r
741\r
cd8c700b
CF
742 //\r
743 // Blocking temporarily stop CheckAllAPsStatus()\r
744 //\r
745 mStopCheckAllAPsStatus = TRUE;\r
746\r
5fee172f
CF
747 while (TRUE) {\r
748 CheckAndUpdateAllAPsToIdleState ();\r
749 if (mMpSystemData.FinishCount == mMpSystemData.StartCount) {\r
750 Status = EFI_SUCCESS;\r
751 goto Done;\r
752 }\r
753\r
754 //\r
755 // task timeout\r
756 //\r
757 if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {\r
758 ResetAllFailedAPs();\r
759 Status = EFI_TIMEOUT;\r
760 goto Done;\r
761 }\r
762\r
763 gBS->Stall (gPollInterval);\r
764 mMpSystemData.Timeout -= gPollInterval;\r
765 }\r
766\r
767Done:\r
768\r
769 return Status;\r
770}\r
771\r
3f4f0af8
CF
772/**\r
773 This service lets the caller get one enabled AP to execute a caller-provided\r
774 function. The caller can request the BSP to either wait for the completion\r
775 of the AP or just proceed with the next task by using the EFI event mechanism.\r
776 See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking\r
777 execution support. This service may only be called from the BSP.\r
778\r
779 This function is used to dispatch one enabled AP to the function specified by\r
780 Procedure passing in the argument specified by ProcedureArgument. If WaitEvent\r
781 is NULL, execution is in blocking mode. The BSP waits until the AP finishes or\r
782 TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.\r
783 BSP proceeds to the next task without waiting for the AP. If a non-blocking mode\r
784 is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,\r
785 then EFI_UNSUPPORTED must be returned.\r
786\r
787 If the timeout specified by TimeoutInMicroseconds expires before the AP returns\r
788 from Procedure, then execution of Procedure by the AP is terminated. The AP is\r
789 available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and\r
790 EFI_MP_SERVICES_PROTOCOL.StartupThisAP().\r
791\r
792 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL\r
793 instance.\r
794 @param[in] Procedure A pointer to the function to be run on\r
795 enabled APs of the system. See type\r
796 EFI_AP_PROCEDURE.\r
797 @param[in] ProcessorNumber The handle number of the AP. The range is\r
798 from 0 to the total number of logical\r
799 processors minus 1. The total number of\r
800 logical processors can be retrieved by\r
801 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().\r
802 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
803 service. If it is NULL, then execute in\r
804 blocking mode. BSP waits until all APs finish\r
805 or TimeoutInMicroseconds expires. If it's\r
806 not NULL, then execute in non-blocking mode.\r
807 BSP requests the function specified by\r
808 Procedure to be started on all the enabled\r
809 APs, and go on executing immediately. If\r
810 all return from Procedure or TimeoutInMicroseconds\r
811 expires, this event is signaled. The BSP\r
812 can use the CheckEvent() or WaitForEvent()\r
813 services to check the state of event. Type\r
814 EFI_EVENT is defined in CreateEvent() in\r
815 the Unified Extensible Firmware Interface\r
816 Specification.\r
817 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
818 APs to return from Procedure, either for\r
819 blocking or non-blocking mode. Zero means\r
820 infinity. If the timeout expires before\r
821 all APs return from Procedure, then Procedure\r
822 on the failed APs is terminated. All enabled\r
823 APs are available for next function assigned\r
824 by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()\r
825 or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().\r
826 If the timeout expires in blocking mode,\r
827 BSP returns EFI_TIMEOUT. If the timeout\r
828 expires in non-blocking mode, WaitEvent\r
829 is signaled with SignalEvent().\r
830 @param[in] ProcedureArgument The parameter passed into Procedure for\r
831 all APs.\r
832 @param[out] Finished If NULL, this parameter is ignored. In\r
833 blocking mode, this parameter is ignored.\r
834 In non-blocking mode, if AP returns from\r
835 Procedure before the timeout expires, its\r
836 content is set to TRUE. Otherwise, the\r
837 value is set to FALSE. The caller can\r
838 determine if the AP returned from Procedure\r
839 by evaluating this value.\r
840\r
841 @retval EFI_SUCCESS In blocking mode, specified AP finished before\r
842 the timeout expires.\r
843 @retval EFI_SUCCESS In non-blocking mode, the function has been\r
844 dispatched to specified AP.\r
845 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
846 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
847 signaled.\r
848 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
849 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
850 the specified AP has finished.\r
851 @retval EFI_NOT_READY The specified AP is busy.\r
852 @retval EFI_NOT_FOUND The processor with the handle specified by\r
853 ProcessorNumber does not exist.\r
854 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
855 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
856\r
857**/\r
858EFI_STATUS\r
859EFIAPI\r
860StartupThisAP (\r
861 IN EFI_MP_SERVICES_PROTOCOL *This,\r
862 IN EFI_AP_PROCEDURE Procedure,\r
863 IN UINTN ProcessorNumber,\r
864 IN EFI_EVENT WaitEvent OPTIONAL,\r
865 IN UINTN TimeoutInMicroseconds,\r
866 IN VOID *ProcedureArgument OPTIONAL,\r
867 OUT BOOLEAN *Finished OPTIONAL\r
868 )\r
869{\r
870 CPU_DATA_BLOCK *CpuData;\r
68f06742 871 CPU_STATE CpuState;\r
3f4f0af8
CF
872\r
873 CpuData = NULL;\r
874\r
875 if (Finished != NULL) {\r
876 *Finished = FALSE;\r
877 }\r
878\r
879 if (!IsBSP ()) {\r
880 return EFI_DEVICE_ERROR;\r
881 }\r
882\r
883 if (Procedure == NULL) {\r
884 return EFI_INVALID_PARAMETER;\r
885 }\r
886\r
887 if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {\r
888 return EFI_NOT_FOUND;\r
889 }\r
890\r
cd8c700b
CF
891 //\r
892 // temporarily stop checkAllAPsStatus for avoid resource dead-lock.\r
893 //\r
894 mStopCheckAllAPsStatus = TRUE;\r
895\r
3f4f0af8
CF
896 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
897 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT) ||\r
898 !TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {\r
899 return EFI_INVALID_PARAMETER;\r
900 }\r
901\r
68f06742
CF
902 CpuState = GetApState (CpuData);\r
903 if (CpuState != CpuStateIdle &&\r
904 CpuState != CpuStateSleeping) {\r
3f4f0af8
CF
905 return EFI_NOT_READY;\r
906 }\r
907\r
908 SetApState (CpuData, CpuStateReady);\r
909\r
910 SetApProcedure (CpuData, Procedure, ProcedureArgument);\r
68f06742
CF
911 //\r
912 // If this AP previous state is Sleeping, we should\r
913 // wake up this AP by sent a SIPI. and avoid\r
914 // re-involve the sleeping state. we must call\r
915 // SetApProcedure() first.\r
916 //\r
917 if (CpuState == CpuStateSleeping) {\r
918 ResetProcessorToIdleState (CpuData);\r
919 }\r
3f4f0af8
CF
920\r
921 CpuData->Timeout = TimeoutInMicroseconds;\r
922 CpuData->WaitEvent = WaitEvent;\r
7475d138 923 CpuData->TimeoutActive = (BOOLEAN) (TimeoutInMicroseconds != 0);\r
3f4f0af8
CF
924 CpuData->Finished = Finished;\r
925\r
acb2172d
CF
926 mStopCheckAllAPsStatus = FALSE;\r
927\r
3f4f0af8
CF
928 if (WaitEvent != NULL) {\r
929 //\r
930 // Non Blocking\r
931 //\r
acb2172d 932 return EFI_SUCCESS;\r
3f4f0af8
CF
933 }\r
934\r
935 //\r
936 // Blocking\r
937 //\r
938 while (TRUE) {\r
939 if (GetApState (CpuData) == CpuStateFinished) {\r
940 SetApState (CpuData, CpuStateIdle);\r
941 break;\r
942 }\r
943\r
944 if (CpuData->TimeoutActive && CpuData->Timeout < 0) {\r
945 ResetProcessorToIdleState (CpuData);\r
946 return EFI_TIMEOUT;\r
947 }\r
948\r
949 gBS->Stall (gPollInterval);\r
950 CpuData->Timeout -= gPollInterval;\r
951 }\r
952\r
953 return EFI_SUCCESS;\r
954}\r
955\r
b7c05ba5
CF
956/**\r
957 This service switches the requested AP to be the BSP from that point onward.\r
958 This service changes the BSP for all purposes. This call can only be performed\r
959 by the current BSP.\r
960\r
961 This service switches the requested AP to be the BSP from that point onward.\r
962 This service changes the BSP for all purposes. The new BSP can take over the\r
963 execution of the old BSP and continue seamlessly from where the old one left\r
964 off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT\r
965 is signaled.\r
966\r
967 If the BSP cannot be switched prior to the return from this service, then\r
968 EFI_UNSUPPORTED must be returned.\r
969\r
970 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
971 @param[in] ProcessorNumber The handle number of AP that is to become the new\r
972 BSP. The range is from 0 to the total number of\r
973 logical processors minus 1. The total number of\r
974 logical processors can be retrieved by\r
975 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().\r
976 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
977 enabled AP. Otherwise, it will be disabled.\r
978\r
979 @retval EFI_SUCCESS BSP successfully switched.\r
980 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to\r
981 this service returning.\r
982 @retval EFI_UNSUPPORTED Switching the BSP is not supported.\r
983 @retval EFI_SUCCESS The calling processor is an AP.\r
984 @retval EFI_NOT_FOUND The processor with the handle specified by\r
985 ProcessorNumber does not exist.\r
986 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or\r
987 a disabled AP.\r
988 @retval EFI_NOT_READY The specified AP is busy.\r
989\r
990**/\r
991EFI_STATUS\r
992EFIAPI\r
993SwitchBSP (\r
994 IN EFI_MP_SERVICES_PROTOCOL *This,\r
995 IN UINTN ProcessorNumber,\r
996 IN BOOLEAN EnableOldBSP\r
997 )\r
998{\r
999 //\r
1000 // Current always return unsupported.\r
1001 //\r
1002 return EFI_UNSUPPORTED;\r
1003}\r
1004\r
fa7ce675
CF
1005/**\r
1006 This service lets the caller enable or disable an AP from this point onward.\r
1007 This service may only be called from the BSP.\r
1008\r
1009 This service allows the caller enable or disable an AP from this point onward.\r
1010 The caller can optionally specify the health status of the AP by Health. If\r
1011 an AP is being disabled, then the state of the disabled AP is implementation\r
1012 dependent. If an AP is enabled, then the implementation must guarantee that a\r
1013 complete initialization sequence is performed on the AP, so the AP is in a state\r
1014 that is compatible with an MP operating system. This service may not be supported\r
1015 after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.\r
1016\r
1017 If the enable or disable AP operation cannot be completed prior to the return\r
1018 from this service, then EFI_UNSUPPORTED must be returned.\r
1019\r
1020 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
1021 @param[in] ProcessorNumber The handle number of AP that is to become the new\r
1022 BSP. The range is from 0 to the total number of\r
1023 logical processors minus 1. The total number of\r
1024 logical processors can be retrieved by\r
1025 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().\r
1026 @param[in] EnableAP Specifies the new state for the processor for\r
1027 enabled, FALSE for disabled.\r
1028 @param[in] HealthFlag If not NULL, a pointer to a value that specifies\r
1029 the new health status of the AP. This flag\r
1030 corresponds to StatusFlag defined in\r
1031 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only\r
1032 the PROCESSOR_HEALTH_STATUS_BIT is used. All other\r
1033 bits are ignored. If it is NULL, this parameter\r
1034 is ignored.\r
1035\r
1036 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.\r
1037 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed\r
1038 prior to this service returning.\r
1039 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.\r
1040 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
1041 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber\r
1042 does not exist.\r
1043 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.\r
1044\r
1045**/\r
1046EFI_STATUS\r
1047EFIAPI\r
1048EnableDisableAP (\r
1049 IN EFI_MP_SERVICES_PROTOCOL *This,\r
1050 IN UINTN ProcessorNumber,\r
1051 IN BOOLEAN EnableAP,\r
1052 IN UINT32 *HealthFlag OPTIONAL\r
1053 )\r
1054{\r
1055 CPU_DATA_BLOCK *CpuData;\r
cd8c700b 1056 BOOLEAN TempStopCheckState;\r
68f06742 1057 CPU_STATE CpuState;\r
cd8c700b
CF
1058\r
1059 CpuData = NULL;\r
1060 TempStopCheckState = FALSE;\r
fa7ce675
CF
1061\r
1062 if (!IsBSP ()) {\r
1063 return EFI_DEVICE_ERROR;\r
1064 }\r
1065\r
1066 if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {\r
1067 return EFI_NOT_FOUND;\r
1068 }\r
1069\r
cd8c700b
CF
1070 //\r
1071 // temporarily stop checkAllAPsStatus for initialize parameters.\r
1072 //\r
1073 if (!mStopCheckAllAPsStatus) {\r
1074 mStopCheckAllAPsStatus = TRUE;\r
1075 TempStopCheckState = TRUE;\r
1076 }\r
1077\r
fa7ce675
CF
1078 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
1079 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {\r
1080 return EFI_INVALID_PARAMETER;\r
1081 }\r
1082\r
68f06742
CF
1083 CpuState = GetApState (CpuData);\r
1084 if (CpuState != CpuStateIdle &&\r
1085 CpuState != CpuStateSleeping) {\r
fa7ce675
CF
1086 return EFI_UNSUPPORTED;\r
1087 }\r
1088\r
1089 if (EnableAP) {\r
1090 if (!(TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT))) {\r
1091 mMpSystemData.NumberOfEnabledProcessors++;\r
1092 }\r
1093 CpuStatusFlagOr (CpuData, PROCESSOR_ENABLED_BIT);\r
1094 } else {\r
1095 if (TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {\r
1096 mMpSystemData.NumberOfEnabledProcessors--;\r
1097 }\r
1098 CpuStatusFlagAndNot (CpuData, PROCESSOR_ENABLED_BIT);\r
1099 }\r
1100\r
1101 if (HealthFlag != NULL) {\r
1102 CpuStatusFlagAndNot (CpuData, (UINT32)~PROCESSOR_HEALTH_STATUS_BIT);\r
1103 CpuStatusFlagOr (CpuData, (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT));\r
1104 }\r
1105\r
cd8c700b
CF
1106 if (TempStopCheckState) {\r
1107 mStopCheckAllAPsStatus = FALSE;\r
1108 }\r
1109\r
fa7ce675
CF
1110 return EFI_SUCCESS;\r
1111}\r
1112\r
cfa2fac1
CF
1113/**\r
1114 This return the handle number for the calling processor. This service may be\r
1115 called from the BSP and APs.\r
1116\r
1117 This service returns the processor handle number for the calling processor.\r
1118 The returned value is in the range from 0 to the total number of logical\r
1119 processors minus 1. The total number of logical processors can be retrieved\r
1120 with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be\r
1121 called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER\r
1122 is returned. Otherwise, the current processors handle number is returned in\r
1123 ProcessorNumber, and EFI_SUCCESS is returned.\r
1124\r
1125 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.\r
1126 @param[out] ProcessorNumber The handle number of AP that is to become the new\r
1127 BSP. The range is from 0 to the total number of\r
1128 logical processors minus 1. The total number of\r
1129 logical processors can be retrieved by\r
1130 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().\r
1131\r
1132 @retval EFI_SUCCESS The current processor handle number was returned\r
1133 in ProcessorNumber.\r
1134 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.\r
1135\r
1136**/\r
1137EFI_STATUS\r
1138EFIAPI\r
1139WhoAmI (\r
1140 IN EFI_MP_SERVICES_PROTOCOL *This,\r
1141 OUT UINTN *ProcessorNumber\r
1142 )\r
1143{\r
1144 UINTN Index;\r
1145 UINT32 ProcessorId;\r
1146\r
1147 if (ProcessorNumber == NULL) {\r
1148 return EFI_INVALID_PARAMETER;\r
1149 }\r
1150\r
1151 ProcessorId = GetApicId ();\r
1152 for (Index = 0; Index < mMpSystemData.NumberOfProcessors; Index++) {\r
1153 if (mMpSystemData.CpuDatas[Index].Info.ProcessorId == ProcessorId) {\r
1154 break;\r
1155 }\r
1156 }\r
1157\r
1158 *ProcessorNumber = Index;\r
1159 return EFI_SUCCESS;\r
1160}\r
1161\r
3f4f0af8
CF
1162/**\r
1163 Terminate AP's task and set it to idle state.\r
1164\r
1165 This function terminates AP's task due to timeout by sending INIT-SIPI,\r
1166 and sends it to idle state.\r
1167\r
1168 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP\r
1169\r
1170**/\r
1171VOID\r
1172ResetProcessorToIdleState (\r
1173 IN CPU_DATA_BLOCK *CpuData\r
1174 )\r
1175{\r
ac9dbb3b 1176 ResetApStackless ((UINT32)CpuData->Info.ProcessorId);\r
3f4f0af8
CF
1177}\r
1178\r
e343f8f7
CF
1179/**\r
1180 Application Processors do loop routine\r
1181 after switch to its own stack.\r
1182\r
1183 @param Context1 A pointer to the context to pass into the function.\r
1184 @param Context2 A pointer to the context to pass into the function.\r
1185\r
1186**/\r
1187VOID\r
1188ProcessorToIdleState (\r
1189 IN VOID *Context1, OPTIONAL\r
1190 IN VOID *Context2 OPTIONAL\r
1191 )\r
1192{\r
9908a829
CF
1193 UINTN ProcessorNumber;\r
1194 CPU_DATA_BLOCK *CpuData;\r
1195 EFI_AP_PROCEDURE Procedure;\r
1196 VOID *ProcedureArgument;\r
1197\r
232eb4c8
CF
1198 AsmApDoneWithCommonStack ();\r
1199\r
1200 while (!mAPsAlreadyInitFinished) {\r
1201 CpuPause ();\r
1202 }\r
1203\r
9908a829
CF
1204 WhoAmI (&mMpServicesTemplate, &ProcessorNumber);\r
1205 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
e343f8f7 1206\r
0e724fc1
CF
1207 //\r
1208 // Avoid forcibly reset AP caused the AP got lock not release.\r
1209 //\r
1210 if (CpuData->LockSelf == (INTN) GetApicId ()) {\r
1211 ReleaseSpinLock (&CpuData->CpuDataLock);\r
1212 }\r
1213\r
ac9dbb3b 1214 //\r
e033a1a8
CF
1215 // Avoid forcibly reset AP caused the timeout AP State is not\r
1216 // updated.\r
ac9dbb3b
CF
1217 //\r
1218 GetMpSpinLock (CpuData);\r
e033a1a8
CF
1219 if (CpuData->State == CpuStateBusy) {\r
1220 CpuData->Procedure = NULL;\r
1221 }\r
ac9dbb3b 1222 CpuData->State = CpuStateIdle;\r
ac9dbb3b
CF
1223 ReleaseMpSpinLock (CpuData);\r
1224\r
9908a829 1225 while (TRUE) {\r
d16cf36d 1226 GetMpSpinLock (CpuData);\r
9908a829
CF
1227 ProcedureArgument = CpuData->Parameter;\r
1228 Procedure = CpuData->Procedure;\r
d16cf36d 1229 ReleaseMpSpinLock (CpuData);\r
9908a829
CF
1230\r
1231 if (Procedure != NULL) {\r
e033a1a8
CF
1232 SetApState (CpuData, CpuStateBusy);\r
1233\r
9908a829
CF
1234 Procedure (ProcedureArgument);\r
1235\r
d16cf36d 1236 GetMpSpinLock (CpuData);\r
9908a829 1237 CpuData->Procedure = NULL;\r
d16cf36d
CF
1238 CpuData->State = CpuStateFinished;\r
1239 ReleaseMpSpinLock (CpuData);\r
68f06742
CF
1240 } else {\r
1241 //\r
1242 // if no procedure to execution, we simply put AP\r
1243 // into sleeping state, and waiting BSP sent SIPI.\r
1244 //\r
1245 GetMpSpinLock (CpuData);\r
1246 if (CpuData->State == CpuStateIdle) {\r
1247 CpuData->State = CpuStateSleeping;\r
1248 }\r
1249 ReleaseMpSpinLock (CpuData);\r
1250 }\r
1251\r
1252 if (GetApState (CpuData) == CpuStateSleeping) {\r
1253 CpuSleep ();\r
9908a829
CF
1254 }\r
1255\r
1256 CpuPause ();\r
1257 }\r
1258\r
e343f8f7
CF
1259 CpuSleep ();\r
1260 CpuDeadLoop ();\r
1261}\r
1262\r
3f4f0af8
CF
1263/**\r
1264 Checks AP' status periodically.\r
1265\r
1266 This function is triggerred by timer perodically to check the\r
1267 state of AP forStartupThisAP() executed in non-blocking mode.\r
1268\r
1269 @param Event Event triggered.\r
1270 @param Context Parameter passed with the event.\r
1271\r
1272**/\r
1273VOID\r
1274EFIAPI\r
1275CheckThisAPStatus (\r
1276 IN EFI_EVENT Event,\r
1277 IN VOID *Context\r
1278 )\r
1279{\r
1280 CPU_DATA_BLOCK *CpuData;\r
1281 CPU_STATE CpuState;\r
1282\r
1283 CpuData = (CPU_DATA_BLOCK *) Context;\r
1284 if (CpuData->TimeoutActive) {\r
1285 CpuData->Timeout -= gPollInterval;\r
1286 }\r
1287\r
1288 CpuState = GetApState (CpuData);\r
1289\r
1290 if (CpuState == CpuStateFinished) {\r
1291 if (CpuData->Finished) {\r
1292 *CpuData->Finished = TRUE;\r
1293 }\r
1294 SetApState (CpuData, CpuStateIdle);\r
1295 goto out;\r
1296 }\r
1297\r
1298 if (CpuData->TimeoutActive && CpuData->Timeout < 0) {\r
1299 if (CpuState != CpuStateIdle &&\r
1300 CpuData->Finished) {\r
1301 *CpuData->Finished = FALSE;\r
1302 }\r
1303 ResetProcessorToIdleState (CpuData);\r
1304 goto out;\r
1305 }\r
1306\r
1307 return;\r
1308\r
1309out:\r
acb2172d
CF
1310 CpuData->TimeoutActive = FALSE;\r
1311 gBS->SignalEvent (CpuData->WaitEvent);\r
1312 CpuData->WaitEvent = NULL;\r
3f4f0af8
CF
1313}\r
1314\r
5fee172f
CF
1315/**\r
1316 Checks APs' status periodically.\r
1317\r
1318 This function is triggerred by timer perodically to check the\r
1319 state of APs for StartupAllAPs() executed in non-blocking mode.\r
1320\r
1321 @param Event Event triggered.\r
1322 @param Context Parameter passed with the event.\r
1323\r
1324**/\r
1325VOID\r
1326EFIAPI\r
1327CheckAllAPsStatus (\r
1328 IN EFI_EVENT Event,\r
1329 IN VOID *Context\r
1330 )\r
1331{\r
acb2172d
CF
1332 CPU_DATA_BLOCK *CpuData;\r
1333 UINTN Number;\r
e4aaf764 1334 EFI_STATUS Status;\r
acb2172d 1335\r
5fee172f
CF
1336 if (mMpSystemData.TimeoutActive) {\r
1337 mMpSystemData.Timeout -= gPollInterval;\r
1338 }\r
1339\r
acb2172d
CF
1340 if (mStopCheckAllAPsStatus) {\r
1341 return;\r
1342 }\r
5fee172f 1343\r
e4aaf764
CF
1344 //\r
1345 // avoid next timer enter.\r
1346 //\r
1347 Status = gBS->SetTimer (\r
1348 mMpSystemData.CheckAllAPsEvent,\r
1349 TimerCancel,\r
1350 0\r
1351 );\r
1352 ASSERT_EFI_ERROR (Status);\r
1353\r
acb2172d
CF
1354 if (mMpSystemData.WaitEvent != NULL) {\r
1355 CheckAndUpdateAllAPsToIdleState ();\r
5fee172f 1356 //\r
acb2172d 1357 // task timeout\r
5fee172f 1358 //\r
acb2172d
CF
1359 if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {\r
1360 ResetAllFailedAPs();\r
1361 //\r
1362 // force exit\r
1363 //\r
1364 mMpSystemData.FinishCount = mMpSystemData.StartCount;\r
1365 }\r
5fee172f 1366\r
acb2172d 1367 if (mMpSystemData.FinishCount != mMpSystemData.StartCount) {\r
e4aaf764 1368 goto EXIT;\r
acb2172d 1369 }\r
5fee172f 1370\r
acb2172d 1371 mMpSystemData.TimeoutActive = FALSE;\r
5fee172f
CF
1372 gBS->SignalEvent (mMpSystemData.WaitEvent);\r
1373 mMpSystemData.WaitEvent = NULL;\r
acb2172d 1374 mStopCheckAllAPsStatus = TRUE;\r
e4aaf764
CF
1375\r
1376 goto EXIT;\r
acb2172d
CF
1377 }\r
1378\r
1379 //\r
1380 // check each AP status for StartupThisAP\r
1381 //\r
1382 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {\r
1383 CpuData = &mMpSystemData.CpuDatas[Number];\r
acb2172d
CF
1384 if (CpuData->WaitEvent) {\r
1385 CheckThisAPStatus (NULL, (VOID *)CpuData);\r
1386 }\r
5fee172f 1387 }\r
e4aaf764
CF
1388\r
1389EXIT:\r
1390 Status = gBS->SetTimer (\r
1391 mMpSystemData.CheckAllAPsEvent,\r
1392 TimerPeriodic,\r
1393 EFI_TIMER_PERIOD_MICROSECONDS (100)\r
1394 );\r
1395 ASSERT_EFI_ERROR (Status);\r
5fee172f
CF
1396}\r
1397\r
1535c888
JJ
1398/**\r
1399 Application Processor C code entry point.\r
1400\r
1401**/\r
1402VOID\r
1403EFIAPI\r
1404ApEntryPointInC (\r
1405 VOID\r
1406 )\r
1407{\r
ac9dbb3b
CF
1408 VOID* TopOfApStack;\r
1409 UINTN ProcessorNumber;\r
03673ae1 1410\r
ac9dbb3b
CF
1411 if (!mAPsAlreadyInitFinished) {\r
1412 FillInProcessorInformation (FALSE, mMpSystemData.NumberOfProcessors);\r
1413 TopOfApStack = (UINT8*)mApStackStart + gApStackSize;\r
1414 mApStackStart = TopOfApStack;\r
03673ae1 1415\r
ac9dbb3b
CF
1416 //\r
1417 // Store the Stack address, when reset the AP, We can found the original address.\r
1418 //\r
1419 mMpSystemData.CpuDatas[mMpSystemData.NumberOfProcessors].TopOfStack = TopOfApStack;\r
1420 mMpSystemData.NumberOfProcessors++;\r
1421 mMpSystemData.NumberOfEnabledProcessors++;\r
1422 } else {\r
1423 WhoAmI (&mMpServicesTemplate, &ProcessorNumber);\r
1424 //\r
1425 // Get the original stack address.\r
1426 //\r
1427 TopOfApStack = mMpSystemData.CpuDatas[ProcessorNumber].TopOfStack;\r
1428 }\r
e343f8f7
CF
1429\r
1430 SwitchStack (\r
1431 (SWITCH_STACK_ENTRY_POINT)(UINTN)ProcessorToIdleState,\r
1432 NULL,\r
1433 NULL,\r
03673ae1
CF
1434 TopOfApStack);\r
1435}\r
1436\r
1437/**\r
1438 This function is called by all processors (both BSP and AP) once and collects MP related data.\r
1439\r
1440 @param Bsp TRUE if the CPU is BSP\r
1441 @param ProcessorNumber The specific processor number\r
1442\r
1443 @retval EFI_SUCCESS Data for the processor collected and filled in\r
1444\r
1445**/\r
1446EFI_STATUS\r
1447FillInProcessorInformation (\r
1448 IN BOOLEAN Bsp,\r
1449 IN UINTN ProcessorNumber\r
1450 )\r
1451{\r
1452 CPU_DATA_BLOCK *CpuData;\r
1453 UINT32 ProcessorId;\r
1454\r
1455 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];\r
1456 ProcessorId = GetApicId ();\r
1457 CpuData->Info.ProcessorId = ProcessorId;\r
1458 CpuData->Info.StatusFlag = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT;\r
1459 if (Bsp) {\r
1460 CpuData->Info.StatusFlag |= PROCESSOR_AS_BSP_BIT;\r
1461 }\r
1462 CpuData->Info.Location.Package = ProcessorId;\r
1463 CpuData->Info.Location.Core = 0;\r
1464 CpuData->Info.Location.Thread = 0;\r
b302a978 1465 CpuData->State = Bsp ? CpuStateBusy : CpuStateIdle;\r
03673ae1
CF
1466\r
1467 CpuData->Procedure = NULL;\r
1468 CpuData->Parameter = NULL;\r
1469 InitializeSpinLock (&CpuData->CpuDataLock);\r
0e724fc1 1470 CpuData->LockSelf = -1;\r
03673ae1
CF
1471\r
1472 return EFI_SUCCESS;\r
1535c888
JJ
1473}\r
1474\r
03673ae1
CF
1475/**\r
1476 Prepare the System Data.\r
1477\r
1478 @retval EFI_SUCCESS the System Data finished initilization.\r
1479\r
1480**/\r
1481EFI_STATUS\r
1482InitMpSystemData (\r
1483 VOID\r
1484 )\r
1485{\r
3f4f0af8
CF
1486 EFI_STATUS Status;\r
1487\r
03673ae1
CF
1488 ZeroMem (&mMpSystemData, sizeof (MP_SYSTEM_DATA));\r
1489\r
1490 mMpSystemData.NumberOfProcessors = 1;\r
1491 mMpSystemData.NumberOfEnabledProcessors = 1;\r
1492\r
1493 mMpSystemData.CpuDatas = AllocateZeroPool (sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber);\r
1494 ASSERT(mMpSystemData.CpuDatas != NULL);\r
1495\r
5fee172f
CF
1496 Status = gBS->CreateEvent (\r
1497 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
1498 TPL_CALLBACK,\r
1499 CheckAllAPsStatus,\r
1500 NULL,\r
1501 &mMpSystemData.CheckAllAPsEvent\r
1502 );\r
1503 ASSERT_EFI_ERROR (Status);\r
1504\r
acb2172d
CF
1505 //\r
1506 // Set timer to check all APs status.\r
1507 //\r
1508 Status = gBS->SetTimer (\r
1509 mMpSystemData.CheckAllAPsEvent,\r
1510 TimerPeriodic,\r
1511 EFI_TIMER_PERIOD_MICROSECONDS (100)\r
1512 );\r
1513 ASSERT_EFI_ERROR (Status);\r
3f4f0af8 1514\r
03673ae1
CF
1515 //\r
1516 // BSP\r
1517 //\r
1518 FillInProcessorInformation (TRUE, 0);\r
1519\r
1520 return EFI_SUCCESS;\r
1521}\r
1535c888 1522\r
9840b129
CF
1523/**\r
1524 Callback function for ExitBootServices.\r
1525\r
1526 @param Event Event whose notification function is being invoked.\r
1527 @param Context The pointer to the notification function's context,\r
1528 which is implementation-dependent.\r
1529\r
1530**/\r
1531VOID\r
1532EFIAPI\r
1533ExitBootServicesCallback (\r
1534 IN EFI_EVENT Event,\r
1535 IN VOID *Context\r
1536 )\r
1537{\r
1538 //\r
1539 // Avoid APs access invalid buff datas which allocated by BootServices,\r
1540 // so we send INIT IPI to APs to let them wait for SIPI state.\r
1541 //\r
1542 SendInitIpiAllExcludingSelf ();\r
1543}\r
1544\r
6022e28c
JJ
1545/**\r
1546 Initialize Multi-processor support.\r
1547\r
1548**/\r
1549VOID\r
1550InitializeMpSupport (\r
1551 VOID\r
1552 )\r
1553{\r
4a50c272
CF
1554 EFI_STATUS Status;\r
1555\r
6a26a597
CF
1556 gMaxLogicalProcessorNumber = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber);\r
1557 if (gMaxLogicalProcessorNumber < 1) {\r
1558 DEBUG ((DEBUG_ERROR, "Setting PcdCpuMaxLogicalProcessorNumber should be more than zero.\n"));\r
1559 return;\r
1560 }\r
1561\r
1562 if (gMaxLogicalProcessorNumber == 1) {\r
1563 return;\r
1564 }\r
1565\r
1566 gApStackSize = (UINTN) PcdGet32 (PcdCpuApStackSize);\r
1567 ASSERT ((gApStackSize & (SIZE_4KB - 1)) == 0);\r
1568\r
1569 mApStackStart = AllocatePages (EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));\r
1570 ASSERT (mApStackStart != NULL);\r
6022e28c 1571\r
6a26a597
CF
1572 //\r
1573 // the first buffer of stack size used for common stack, when the amount of AP\r
1574 // more than 1, we should never free the common stack which maybe used for AP reset.\r
1575 //\r
1576 mCommonStack = mApStackStart;\r
1577 mTopOfApCommonStack = (UINT8*) mApStackStart + gApStackSize;\r
1578 mApStackStart = mTopOfApCommonStack;\r
1579\r
03673ae1 1580 InitMpSystemData ();\r
6a26a597 1581\r
fe078dd5
CF
1582 PrepareAPStartupCode ();\r
1583\r
dee9376f
JJ
1584 StartApsStackless ();\r
1585\r
1586 DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mMpSystemData.NumberOfProcessors));\r
03673ae1 1587 if (mMpSystemData.NumberOfProcessors == 1) {\r
fe078dd5 1588 FreeApStartupCode ();\r
6a26a597
CF
1589 FreePages (mCommonStack, EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));\r
1590 return;\r
1591 }\r
1592\r
232eb4c8
CF
1593 mMpSystemData.CpuDatas = ReallocatePool (\r
1594 sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber,\r
1595 sizeof (CPU_DATA_BLOCK) * mMpSystemData.NumberOfProcessors,\r
1596 mMpSystemData.CpuDatas);\r
1597\r
ac9dbb3b
CF
1598 mAPsAlreadyInitFinished = TRUE;\r
1599\r
4a50c272
CF
1600 Status = gBS->InstallMultipleProtocolInterfaces (\r
1601 &mMpServiceHandle,\r
1602 &gEfiMpServiceProtocolGuid, &mMpServicesTemplate,\r
1603 NULL\r
1604 );\r
1605 ASSERT_EFI_ERROR (Status);\r
1606\r
03673ae1
CF
1607 if (mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) {\r
1608 FreePages (mApStackStart, EFI_SIZE_TO_PAGES (\r
1609 (gMaxLogicalProcessorNumber - mMpSystemData.NumberOfProcessors) *\r
1610 gApStackSize));\r
6a26a597 1611 }\r
9840b129
CF
1612\r
1613 Status = gBS->CreateEvent (\r
1614 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
1615 TPL_CALLBACK,\r
1616 ExitBootServicesCallback,\r
1617 NULL,\r
1618 &mExitBootServicesEvent\r
1619 );\r
1620 ASSERT_EFI_ERROR (Status);\r
6a26a597 1621}\r