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