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