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