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