]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
UefiCpuPkg/MpInitLib: fix wrong address set as Stack Guard for APs
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / DxeMpLib.c
... / ...
CommitLineData
1/** @file\r
2 MP initialize support functions for DXE phase.\r
3\r
4 Copyright (c) 2016, 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 "MpLib.h"\r
16\r
17#include <Library/UefiLib.h>\r
18#include <Library/UefiBootServicesTableLib.h>\r
19#include <Library/DebugAgentLib.h>\r
20#include <Library/DxeServicesTableLib.h>\r
21\r
22#include <Protocol/Timer.h>\r
23\r
24#define AP_CHECK_INTERVAL (EFI_TIMER_PERIOD_MILLISECONDS (100))\r
25#define AP_SAFE_STACK_SIZE 128\r
26\r
27CPU_MP_DATA *mCpuMpData = NULL;\r
28EFI_EVENT mCheckAllApsEvent = NULL;\r
29EFI_EVENT mMpInitExitBootServicesEvent = NULL;\r
30EFI_EVENT mLegacyBootEvent = NULL;\r
31volatile BOOLEAN mStopCheckAllApsStatus = TRUE;\r
32VOID *mReservedApLoopFunc = NULL;\r
33UINTN mReservedTopOfApStack;\r
34volatile UINT32 mNumberToFinish = 0;\r
35\r
36/**\r
37 Enable Debug Agent to support source debugging on AP function.\r
38\r
39**/\r
40VOID\r
41EnableDebugAgent (\r
42 VOID\r
43 )\r
44{\r
45 //\r
46 // Initialize Debug Agent to support source level debug in DXE phase\r
47 //\r
48 InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL);\r
49}\r
50\r
51/**\r
52 Get the pointer to CPU MP Data structure.\r
53\r
54 @return The pointer to CPU MP Data structure.\r
55**/\r
56CPU_MP_DATA *\r
57GetCpuMpData (\r
58 VOID\r
59 )\r
60{\r
61 ASSERT (mCpuMpData != NULL);\r
62 return mCpuMpData;\r
63}\r
64\r
65/**\r
66 Save the pointer to CPU MP Data structure.\r
67\r
68 @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.\r
69**/\r
70VOID\r
71SaveCpuMpData (\r
72 IN CPU_MP_DATA *CpuMpData\r
73 )\r
74{\r
75 mCpuMpData = CpuMpData;\r
76}\r
77\r
78/**\r
79 Get available system memory below 1MB by specified size.\r
80\r
81 @param[in] WakeupBufferSize Wakeup buffer size required\r
82\r
83 @retval other Return wakeup buffer address below 1MB.\r
84 @retval -1 Cannot find free memory below 1MB.\r
85**/\r
86UINTN\r
87GetWakeupBuffer (\r
88 IN UINTN WakeupBufferSize\r
89 )\r
90{\r
91 EFI_STATUS Status;\r
92 EFI_PHYSICAL_ADDRESS StartAddress;\r
93\r
94 StartAddress = BASE_1MB;\r
95 Status = gBS->AllocatePages (\r
96 AllocateMaxAddress,\r
97 EfiBootServicesData,\r
98 EFI_SIZE_TO_PAGES (WakeupBufferSize),\r
99 &StartAddress\r
100 );\r
101 ASSERT_EFI_ERROR (Status);\r
102 if (!EFI_ERROR (Status)) {\r
103 Status = gBS->FreePages(\r
104 StartAddress,\r
105 EFI_SIZE_TO_PAGES (WakeupBufferSize)\r
106 );\r
107 ASSERT_EFI_ERROR (Status);\r
108 DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",\r
109 (UINTN) StartAddress, WakeupBufferSize));\r
110 } else {\r
111 StartAddress = (EFI_PHYSICAL_ADDRESS) -1;\r
112 }\r
113 return (UINTN) StartAddress;\r
114}\r
115\r
116/**\r
117 Checks APs status and updates APs status if needed.\r
118\r
119**/\r
120VOID\r
121CheckAndUpdateApsStatus (\r
122 VOID\r
123 )\r
124{\r
125 UINTN ProcessorNumber;\r
126 EFI_STATUS Status;\r
127 CPU_MP_DATA *CpuMpData;\r
128\r
129 CpuMpData = GetCpuMpData ();\r
130\r
131 //\r
132 // First, check whether pending StartupAllAPs() exists.\r
133 //\r
134 if (CpuMpData->WaitEvent != NULL) {\r
135\r
136 Status = CheckAllAPs ();\r
137 //\r
138 // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.\r
139 //\r
140 if (Status != EFI_NOT_READY) {\r
141 Status = gBS->SignalEvent (CpuMpData->WaitEvent);\r
142 CpuMpData->WaitEvent = NULL;\r
143 }\r
144 }\r
145\r
146 //\r
147 // Second, check whether pending StartupThisAPs() callings exist.\r
148 //\r
149 for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {\r
150\r
151 if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {\r
152 continue;\r
153 }\r
154\r
155 Status = CheckThisAP (ProcessorNumber);\r
156\r
157 if (Status != EFI_NOT_READY) {\r
158 gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);\r
159 CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;\r
160 }\r
161 }\r
162}\r
163\r
164/**\r
165 Checks APs' status periodically.\r
166\r
167 This function is triggered by timer periodically to check the\r
168 state of APs for StartupAllAPs() and StartupThisAP() executed\r
169 in non-blocking mode.\r
170\r
171 @param[in] Event Event triggered.\r
172 @param[in] Context Parameter passed with the event.\r
173\r
174**/\r
175VOID\r
176EFIAPI\r
177CheckApsStatus (\r
178 IN EFI_EVENT Event,\r
179 IN VOID *Context\r
180 )\r
181{\r
182 //\r
183 // If CheckApsStatus() is not stopped, otherwise return immediately.\r
184 //\r
185 if (!mStopCheckAllApsStatus) {\r
186 CheckAndUpdateApsStatus ();\r
187 }\r
188}\r
189\r
190/**\r
191 Get Protected mode code segment from current GDT table.\r
192\r
193 @return Protected mode code segment value.\r
194**/\r
195UINT16\r
196GetProtectedModeCS (\r
197 VOID\r
198 )\r
199{\r
200 IA32_DESCRIPTOR GdtrDesc;\r
201 IA32_SEGMENT_DESCRIPTOR *GdtEntry;\r
202 UINTN GdtEntryCount;\r
203 UINT16 Index;\r
204\r
205 Index = (UINT16) -1;\r
206 AsmReadGdtr (&GdtrDesc);\r
207 GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);\r
208 GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;\r
209 for (Index = 0; Index < GdtEntryCount; Index++) {\r
210 if (GdtEntry->Bits.L == 0) {\r
211 if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.L == 0) {\r
212 break;\r
213 }\r
214 }\r
215 GdtEntry++;\r
216 }\r
217 ASSERT (Index != -1);\r
218 return Index * 8;\r
219}\r
220\r
221/**\r
222 Do sync on APs.\r
223\r
224 @param[in, out] Buffer Pointer to private data buffer.\r
225**/\r
226VOID\r
227EFIAPI\r
228RelocateApLoop (\r
229 IN OUT VOID *Buffer\r
230 )\r
231{\r
232 CPU_MP_DATA *CpuMpData;\r
233 BOOLEAN MwaitSupport;\r
234 ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;\r
235 UINTN ProcessorNumber;\r
236\r
237 MpInitLibWhoAmI (&ProcessorNumber); \r
238 CpuMpData = GetCpuMpData ();\r
239 MwaitSupport = IsMwaitSupport ();\r
240 AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;\r
241 AsmRelocateApLoopFunc (\r
242 MwaitSupport,\r
243 CpuMpData->ApTargetCState,\r
244 CpuMpData->PmCodeSegment,\r
245 mReservedTopOfApStack - ProcessorNumber * AP_SAFE_STACK_SIZE,\r
246 (UINTN) &mNumberToFinish\r
247 );\r
248 //\r
249 // It should never reach here\r
250 //\r
251 ASSERT (FALSE);\r
252}\r
253\r
254/**\r
255 Callback function for ExitBootServices.\r
256\r
257 @param[in] Event Event whose notification function is being invoked.\r
258 @param[in] Context The pointer to the notification function's context,\r
259 which is implementation-dependent.\r
260\r
261**/\r
262VOID\r
263EFIAPI\r
264MpInitChangeApLoopCallback (\r
265 IN EFI_EVENT Event,\r
266 IN VOID *Context\r
267 )\r
268{\r
269 CPU_MP_DATA *CpuMpData;\r
270\r
271 CpuMpData = GetCpuMpData ();\r
272 CpuMpData->PmCodeSegment = GetProtectedModeCS ();\r
273 CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);\r
274 mNumberToFinish = CpuMpData->CpuCount - 1;\r
275 WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL);\r
276 while (mNumberToFinish > 0) {\r
277 CpuPause ();\r
278 }\r
279 DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));\r
280}\r
281\r
282/**\r
283 Initialize global data for MP support.\r
284\r
285 @param[in] CpuMpData The pointer to CPU MP Data structure.\r
286**/\r
287VOID\r
288InitMpGlobalData (\r
289 IN CPU_MP_DATA *CpuMpData\r
290 )\r
291{\r
292 EFI_STATUS Status;\r
293 EFI_PHYSICAL_ADDRESS Address;\r
294 UINTN ApSafeBufferSize;\r
295 UINTN Index;\r
296 EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;\r
297 UINTN StackBase;\r
298 CPU_INFO_IN_HOB *CpuInfoInHob;\r
299\r
300 SaveCpuMpData (CpuMpData);\r
301\r
302 if (CpuMpData->CpuCount == 1) {\r
303 //\r
304 // If only BSP exists, return\r
305 //\r
306 return;\r
307 }\r
308\r
309 if (PcdGetBool (PcdCpuStackGuard)) {\r
310 //\r
311 // One extra page at the bottom of the stack is needed for Guard page.\r
312 //\r
313 if (CpuMpData->CpuApStackSize <= EFI_PAGE_SIZE) {\r
314 DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));\r
315 ASSERT (FALSE);\r
316 }\r
317\r
318 //\r
319 // DXE will reuse stack allocated for APs at PEI phase if it's available.\r
320 // Let's check it here.\r
321 //\r
322 // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of\r
323 // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be\r
324 // set here.\r
325 //\r
326 CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;\r
327 for (Index = 0; Index < CpuMpData->CpuCount; ++Index) {\r
328 if (CpuInfoInHob != NULL && CpuInfoInHob[Index].ApTopOfStack != 0) {\r
329 StackBase = CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize;\r
330 } else {\r
331 StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize;\r
332 }\r
333\r
334 Status = gDS->GetMemorySpaceDescriptor (StackBase, &MemDesc);\r
335 ASSERT_EFI_ERROR (Status);\r
336\r
337 Status = gDS->SetMemorySpaceAttributes (\r
338 StackBase,\r
339 EFI_PAGES_TO_SIZE (1),\r
340 MemDesc.Attributes | EFI_MEMORY_RP\r
341 );\r
342 ASSERT_EFI_ERROR (Status);\r
343\r
344 DEBUG ((DEBUG_INFO, "Stack Guard set at %lx [cpu%lu]!\n",\r
345 (UINT64)StackBase, (UINT64)Index));\r
346 }\r
347 }\r
348\r
349 //\r
350 // Avoid APs access invalid buffer data which allocated by BootServices,\r
351 // so we will allocate reserved data for AP loop code. We also need to\r
352 // allocate this buffer below 4GB due to APs may be transferred to 32bit\r
353 // protected mode on long mode DXE.\r
354 // Allocating it in advance since memory services are not available in\r
355 // Exit Boot Services callback function.\r
356 //\r
357 ApSafeBufferSize = CpuMpData->AddressMap.RelocateApLoopFuncSize;\r
358 ApSafeBufferSize += CpuMpData->CpuCount * AP_SAFE_STACK_SIZE;\r
359\r
360 Address = BASE_4GB - 1;\r
361 Status = gBS->AllocatePages (\r
362 AllocateMaxAddress,\r
363 EfiReservedMemoryType,\r
364 EFI_SIZE_TO_PAGES (ApSafeBufferSize),\r
365 &Address\r
366 );\r
367 ASSERT_EFI_ERROR (Status);\r
368 mReservedApLoopFunc = (VOID *) (UINTN) Address;\r
369 ASSERT (mReservedApLoopFunc != NULL);\r
370 mReservedTopOfApStack = (UINTN) Address + EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ApSafeBufferSize));\r
371 ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);\r
372 CopyMem (\r
373 mReservedApLoopFunc,\r
374 CpuMpData->AddressMap.RelocateApLoopFuncAddress,\r
375 CpuMpData->AddressMap.RelocateApLoopFuncSize\r
376 );\r
377\r
378 Status = gBS->CreateEvent (\r
379 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
380 TPL_NOTIFY,\r
381 CheckApsStatus,\r
382 NULL,\r
383 &mCheckAllApsEvent\r
384 );\r
385 ASSERT_EFI_ERROR (Status);\r
386\r
387 //\r
388 // Set timer to check all APs status.\r
389 //\r
390 Status = gBS->SetTimer (\r
391 mCheckAllApsEvent,\r
392 TimerPeriodic,\r
393 AP_CHECK_INTERVAL\r
394 );\r
395 ASSERT_EFI_ERROR (Status);\r
396\r
397 Status = gBS->CreateEvent (\r
398 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
399 TPL_CALLBACK,\r
400 MpInitChangeApLoopCallback,\r
401 NULL,\r
402 &mMpInitExitBootServicesEvent\r
403 );\r
404 ASSERT_EFI_ERROR (Status);\r
405\r
406 Status = gBS->CreateEventEx (\r
407 EVT_NOTIFY_SIGNAL,\r
408 TPL_CALLBACK,\r
409 MpInitChangeApLoopCallback,\r
410 NULL,\r
411 &gEfiEventLegacyBootGuid,\r
412 &mLegacyBootEvent\r
413 );\r
414 ASSERT_EFI_ERROR (Status);\r
415}\r
416\r
417/**\r
418 This service executes a caller provided function on all enabled APs.\r
419\r
420 @param[in] Procedure A pointer to the function to be run on\r
421 enabled APs of the system. See type\r
422 EFI_AP_PROCEDURE.\r
423 @param[in] SingleThread If TRUE, then all the enabled APs execute\r
424 the function specified by Procedure one by\r
425 one, in ascending order of processor handle\r
426 number. If FALSE, then all the enabled APs\r
427 execute the function specified by Procedure\r
428 simultaneously.\r
429 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
430 service. If it is NULL, then execute in\r
431 blocking mode. BSP waits until all APs finish\r
432 or TimeoutInMicroSeconds expires. If it's\r
433 not NULL, then execute in non-blocking mode.\r
434 BSP requests the function specified by\r
435 Procedure to be started on all the enabled\r
436 APs, and go on executing immediately. If\r
437 all return from Procedure, or TimeoutInMicroSeconds\r
438 expires, this event is signaled. The BSP\r
439 can use the CheckEvent() or WaitForEvent()\r
440 services to check the state of event. Type\r
441 EFI_EVENT is defined in CreateEvent() in\r
442 the Unified Extensible Firmware Interface\r
443 Specification.\r
444 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
445 APs to return from Procedure, either for\r
446 blocking or non-blocking mode. Zero means\r
447 infinity. If the timeout expires before\r
448 all APs return from Procedure, then Procedure\r
449 on the failed APs is terminated. All enabled\r
450 APs are available for next function assigned\r
451 by MpInitLibStartupAllAPs() or\r
452 MPInitLibStartupThisAP().\r
453 If the timeout expires in blocking mode,\r
454 BSP returns EFI_TIMEOUT. If the timeout\r
455 expires in non-blocking mode, WaitEvent\r
456 is signaled with SignalEvent().\r
457 @param[in] ProcedureArgument The parameter passed into Procedure for\r
458 all APs.\r
459 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,\r
460 if all APs finish successfully, then its\r
461 content is set to NULL. If not all APs\r
462 finish before timeout expires, then its\r
463 content is set to address of the buffer\r
464 holding handle numbers of the failed APs.\r
465 The buffer is allocated by MP Initialization\r
466 library, and it's the caller's responsibility to\r
467 free the buffer with FreePool() service.\r
468 In blocking mode, it is ready for consumption\r
469 when the call returns. In non-blocking mode,\r
470 it is ready when WaitEvent is signaled. The\r
471 list of failed CPU is terminated by\r
472 END_OF_CPU_LIST.\r
473\r
474 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
475 the timeout expired.\r
476 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
477 to all enabled APs.\r
478 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
479 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
480 signaled.\r
481 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
482 supported.\r
483 @retval EFI_DEVICE_ERROR Caller processor is AP.\r
484 @retval EFI_NOT_STARTED No enabled APs exist in the system.\r
485 @retval EFI_NOT_READY Any enabled APs are busy.\r
486 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
487 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
488 all enabled APs have finished.\r
489 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
490\r
491**/\r
492EFI_STATUS\r
493EFIAPI\r
494MpInitLibStartupAllAPs (\r
495 IN EFI_AP_PROCEDURE Procedure,\r
496 IN BOOLEAN SingleThread,\r
497 IN EFI_EVENT WaitEvent OPTIONAL,\r
498 IN UINTN TimeoutInMicroseconds,\r
499 IN VOID *ProcedureArgument OPTIONAL,\r
500 OUT UINTN **FailedCpuList OPTIONAL\r
501 )\r
502{\r
503 EFI_STATUS Status;\r
504\r
505 //\r
506 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
507 //\r
508 mStopCheckAllApsStatus = TRUE;\r
509\r
510 Status = StartupAllAPsWorker (\r
511 Procedure,\r
512 SingleThread,\r
513 WaitEvent,\r
514 TimeoutInMicroseconds,\r
515 ProcedureArgument,\r
516 FailedCpuList\r
517 );\r
518\r
519 //\r
520 // Start checkAllApsStatus\r
521 //\r
522 mStopCheckAllApsStatus = FALSE;\r
523\r
524 return Status;\r
525}\r
526\r
527/**\r
528 This service lets the caller get one enabled AP to execute a caller-provided\r
529 function.\r
530\r
531 @param[in] Procedure A pointer to the function to be run on the\r
532 designated AP of the system. See type\r
533 EFI_AP_PROCEDURE.\r
534 @param[in] ProcessorNumber The handle number of the AP. The range is\r
535 from 0 to the total number of logical\r
536 processors minus 1. The total number of\r
537 logical processors can be retrieved by\r
538 MpInitLibGetNumberOfProcessors().\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 this AP 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 this AP,\r
546 and go on executing immediately. If this AP\r
547 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 this AP to finish this Procedure, either for\r
556 blocking or non-blocking mode. Zero means\r
557 infinity. If the timeout expires before\r
558 this AP returns from Procedure, then Procedure\r
559 on the AP is terminated. The\r
560 AP is available for next function assigned\r
561 by MpInitLibStartupAllAPs() or\r
562 MpInitLibStartupThisAP().\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 on the\r
568 specified AP.\r
569 @param[out] Finished If NULL, this parameter is ignored. In\r
570 blocking mode, this parameter is ignored.\r
571 In non-blocking mode, if AP returns from\r
572 Procedure before the timeout expires, its\r
573 content is set to TRUE. Otherwise, the\r
574 value is set to FALSE. The caller can\r
575 determine if the AP returned from Procedure\r
576 by evaluating this value.\r
577\r
578 @retval EFI_SUCCESS In blocking mode, specified AP finished before\r
579 the timeout expires.\r
580 @retval EFI_SUCCESS In non-blocking mode, the function has been\r
581 dispatched to specified AP.\r
582 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
583 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
584 signaled.\r
585 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
586 supported.\r
587 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
588 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
589 the specified AP has finished.\r
590 @retval EFI_NOT_READY The specified AP is busy.\r
591 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
592 @retval EFI_NOT_FOUND The processor with the handle specified by\r
593 ProcessorNumber does not exist.\r
594 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
595 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
596\r
597**/\r
598EFI_STATUS\r
599EFIAPI\r
600MpInitLibStartupThisAP (\r
601 IN EFI_AP_PROCEDURE Procedure,\r
602 IN UINTN ProcessorNumber,\r
603 IN EFI_EVENT WaitEvent OPTIONAL,\r
604 IN UINTN TimeoutInMicroseconds,\r
605 IN VOID *ProcedureArgument OPTIONAL,\r
606 OUT BOOLEAN *Finished OPTIONAL\r
607 )\r
608{\r
609 EFI_STATUS Status;\r
610\r
611 //\r
612 // temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
613 //\r
614 mStopCheckAllApsStatus = TRUE;\r
615\r
616 Status = StartupThisAPWorker (\r
617 Procedure,\r
618 ProcessorNumber,\r
619 WaitEvent,\r
620 TimeoutInMicroseconds,\r
621 ProcedureArgument,\r
622 Finished\r
623 );\r
624\r
625 mStopCheckAllApsStatus = FALSE;\r
626\r
627 return Status;\r
628}\r
629\r
630/**\r
631 This service switches the requested AP to be the BSP from that point onward.\r
632 This service changes the BSP for all purposes. This call can only be performed\r
633 by the current BSP.\r
634\r
635 @param[in] ProcessorNumber The handle number of AP that is to become the new\r
636 BSP. The range is from 0 to the total number of\r
637 logical processors minus 1. The total number of\r
638 logical processors can be retrieved by\r
639 MpInitLibGetNumberOfProcessors().\r
640 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
641 enabled AP. Otherwise, it will be disabled.\r
642\r
643 @retval EFI_SUCCESS BSP successfully switched.\r
644 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to\r
645 this service returning.\r
646 @retval EFI_UNSUPPORTED Switching the BSP is not supported.\r
647 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
648 @retval EFI_NOT_FOUND The processor with the handle specified by\r
649 ProcessorNumber does not exist.\r
650 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or\r
651 a disabled AP.\r
652 @retval EFI_NOT_READY The specified AP is busy.\r
653 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
654\r
655**/\r
656EFI_STATUS\r
657EFIAPI\r
658MpInitLibSwitchBSP (\r
659 IN UINTN ProcessorNumber,\r
660 IN BOOLEAN EnableOldBSP\r
661 )\r
662{\r
663 EFI_STATUS Status;\r
664 EFI_TIMER_ARCH_PROTOCOL *Timer;\r
665 UINT64 TimerPeriod;\r
666\r
667 TimerPeriod = 0;\r
668 //\r
669 // Locate Timer Arch Protocol\r
670 //\r
671 Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Timer);\r
672 if (EFI_ERROR (Status)) {\r
673 Timer = NULL;\r
674 }\r
675\r
676 if (Timer != NULL) {\r
677 //\r
678 // Save current rate of DXE Timer\r
679 //\r
680 Timer->GetTimerPeriod (Timer, &TimerPeriod);\r
681 //\r
682 // Disable DXE Timer and drain pending interrupts\r
683 //\r
684 Timer->SetTimerPeriod (Timer, 0);\r
685 }\r
686\r
687 Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
688\r
689 if (Timer != NULL) {\r
690 //\r
691 // Enable and restore rate of DXE Timer\r
692 //\r
693 Timer->SetTimerPeriod (Timer, TimerPeriod);\r
694 }\r
695\r
696 return Status;\r
697}\r
698\r
699/**\r
700 This service lets the caller enable or disable an AP from this point onward.\r
701 This service may only be called from the BSP.\r
702\r
703 @param[in] ProcessorNumber The handle number of AP.\r
704 The range is from 0 to the total number of\r
705 logical processors minus 1. The total number of\r
706 logical processors can be retrieved by\r
707 MpInitLibGetNumberOfProcessors().\r
708 @param[in] EnableAP Specifies the new state for the processor for\r
709 enabled, FALSE for disabled.\r
710 @param[in] HealthFlag If not NULL, a pointer to a value that specifies\r
711 the new health status of the AP. This flag\r
712 corresponds to StatusFlag defined in\r
713 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only\r
714 the PROCESSOR_HEALTH_STATUS_BIT is used. All other\r
715 bits are ignored. If it is NULL, this parameter\r
716 is ignored.\r
717\r
718 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.\r
719 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed\r
720 prior to this service returning.\r
721 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.\r
722 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
723 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber\r
724 does not exist.\r
725 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.\r
726 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
727\r
728**/\r
729EFI_STATUS\r
730EFIAPI\r
731MpInitLibEnableDisableAP (\r
732 IN UINTN ProcessorNumber,\r
733 IN BOOLEAN EnableAP,\r
734 IN UINT32 *HealthFlag OPTIONAL\r
735 )\r
736{\r
737 EFI_STATUS Status;\r
738 BOOLEAN TempStopCheckState;\r
739\r
740 TempStopCheckState = FALSE;\r
741 //\r
742 // temporarily stop checkAllAPsStatus for initialize parameters.\r
743 //\r
744 if (!mStopCheckAllApsStatus) {\r
745 mStopCheckAllApsStatus = TRUE;\r
746 TempStopCheckState = TRUE;\r
747 }\r
748\r
749 Status = EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);\r
750\r
751 if (TempStopCheckState) {\r
752 mStopCheckAllApsStatus = FALSE;\r
753 }\r
754\r
755 return Status;\r
756}\r