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