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