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