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