]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
UefiCpuPkg/MpInitLib: fix incorrect stack top init for cpu0
[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
96378861 298\r
93ca4c0f
JF
299 SaveCpuMpData (CpuMpData);\r
300\r
14e8137c
JF
301 if (CpuMpData->CpuCount == 1) {\r
302 //\r
303 // If only BSP exists, return\r
304 //\r
305 return;\r
306 }\r
307\r
15720a6c
JW
308 if (PcdGetBool (PcdCpuStackGuard)) {\r
309 //\r
310 // One extra page at the bottom of the stack is needed for Guard page.\r
311 //\r
312 if (CpuMpData->CpuApStackSize <= EFI_PAGE_SIZE) {\r
313 DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));\r
314 ASSERT (FALSE);\r
315 }\r
316\r
317 for (Index = 0; Index < CpuMpData->CpuCount; ++Index) {\r
318 StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize;\r
319\r
320 Status = gDS->GetMemorySpaceDescriptor (StackBase, &MemDesc);\r
321 ASSERT_EFI_ERROR (Status);\r
322\r
323 Status = gDS->SetMemorySpaceAttributes (\r
324 StackBase,\r
325 EFI_PAGES_TO_SIZE (1),\r
326 MemDesc.Attributes | EFI_MEMORY_RP\r
327 );\r
328 ASSERT_EFI_ERROR (Status);\r
329 }\r
330 }\r
331\r
5183fb37 332 //\r
ffd6b0b1
JF
333 // Avoid APs access invalid buffer data which allocated by BootServices,\r
334 // so we will allocate reserved data for AP loop code. We also need to\r
335 // allocate this buffer below 4GB due to APs may be transferred to 32bit\r
336 // protected mode on long mode DXE.\r
5183fb37
JF
337 // Allocating it in advance since memory services are not available in\r
338 // Exit Boot Services callback function.\r
339 //\r
bf2786dc
JF
340 ApSafeBufferSize = CpuMpData->AddressMap.RelocateApLoopFuncSize;\r
341 ApSafeBufferSize += CpuMpData->CpuCount * AP_SAFE_STACK_SIZE;\r
342\r
ffd6b0b1
JF
343 Address = BASE_4GB - 1;\r
344 Status = gBS->AllocatePages (\r
345 AllocateMaxAddress,\r
346 EfiReservedMemoryType,\r
bf2786dc 347 EFI_SIZE_TO_PAGES (ApSafeBufferSize),\r
ffd6b0b1
JF
348 &Address\r
349 );\r
350 ASSERT_EFI_ERROR (Status);\r
351 mReservedApLoopFunc = (VOID *) (UINTN) Address;\r
5183fb37 352 ASSERT (mReservedApLoopFunc != NULL);\r
bf2786dc
JF
353 mReservedTopOfApStack = (UINTN) Address + EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ApSafeBufferSize));\r
354 ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);\r
ffd6b0b1
JF
355 CopyMem (\r
356 mReservedApLoopFunc,\r
357 CpuMpData->AddressMap.RelocateApLoopFuncAddress,\r
358 CpuMpData->AddressMap.RelocateApLoopFuncSize\r
359 );\r
5183fb37 360\r
96378861
JF
361 Status = gBS->CreateEvent (\r
362 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
363 TPL_NOTIFY,\r
364 CheckApsStatus,\r
365 NULL,\r
366 &mCheckAllApsEvent\r
367 );\r
368 ASSERT_EFI_ERROR (Status);\r
369\r
370 //\r
371 // Set timer to check all APs status.\r
372 //\r
373 Status = gBS->SetTimer (\r
374 mCheckAllApsEvent,\r
375 TimerPeriodic,\r
376 AP_CHECK_INTERVAL\r
377 );\r
378 ASSERT_EFI_ERROR (Status);\r
8677a56a 379\r
4d3314f6
JF
380 Status = gBS->CreateEvent (\r
381 EVT_SIGNAL_EXIT_BOOT_SERVICES,\r
382 TPL_CALLBACK,\r
86af2eb8 383 MpInitChangeApLoopCallback,\r
4d3314f6
JF
384 NULL,\r
385 &mMpInitExitBootServicesEvent\r
386 );\r
387 ASSERT_EFI_ERROR (Status);\r
8677a56a
JF
388\r
389 Status = gBS->CreateEventEx (\r
390 EVT_NOTIFY_SIGNAL,\r
391 TPL_CALLBACK,\r
392 MpInitChangeApLoopCallback,\r
393 NULL,\r
394 &gEfiEventLegacyBootGuid,\r
395 &mLegacyBootEvent\r
396 );\r
397 ASSERT_EFI_ERROR (Status);\r
93ca4c0f 398}\r
3e8ad6bd
JF
399\r
400/**\r
401 This service executes a caller provided function on all enabled APs.\r
402\r
403 @param[in] Procedure A pointer to the function to be run on\r
404 enabled APs of the system. See type\r
405 EFI_AP_PROCEDURE.\r
406 @param[in] SingleThread If TRUE, then all the enabled APs execute\r
407 the function specified by Procedure one by\r
408 one, in ascending order of processor handle\r
409 number. If FALSE, then all the enabled APs\r
410 execute the function specified by Procedure\r
411 simultaneously.\r
412 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
413 service. If it is NULL, then execute in\r
414 blocking mode. BSP waits until all APs finish\r
415 or TimeoutInMicroSeconds expires. If it's\r
416 not NULL, then execute in non-blocking mode.\r
417 BSP requests the function specified by\r
418 Procedure to be started on all the enabled\r
419 APs, and go on executing immediately. If\r
420 all return from Procedure, or TimeoutInMicroSeconds\r
421 expires, this event is signaled. The BSP\r
422 can use the CheckEvent() or WaitForEvent()\r
423 services to check the state of event. Type\r
424 EFI_EVENT is defined in CreateEvent() in\r
425 the Unified Extensible Firmware Interface\r
426 Specification.\r
367284e7 427 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
3e8ad6bd
JF
428 APs to return from Procedure, either for\r
429 blocking or non-blocking mode. Zero means\r
430 infinity. If the timeout expires before\r
431 all APs return from Procedure, then Procedure\r
432 on the failed APs is terminated. All enabled\r
433 APs are available for next function assigned\r
434 by MpInitLibStartupAllAPs() or\r
435 MPInitLibStartupThisAP().\r
436 If the timeout expires in blocking mode,\r
437 BSP returns EFI_TIMEOUT. If the timeout\r
438 expires in non-blocking mode, WaitEvent\r
439 is signaled with SignalEvent().\r
440 @param[in] ProcedureArgument The parameter passed into Procedure for\r
441 all APs.\r
442 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,\r
443 if all APs finish successfully, then its\r
444 content is set to NULL. If not all APs\r
445 finish before timeout expires, then its\r
446 content is set to address of the buffer\r
447 holding handle numbers of the failed APs.\r
448 The buffer is allocated by MP Initialization\r
449 library, and it's the caller's responsibility to\r
450 free the buffer with FreePool() service.\r
451 In blocking mode, it is ready for consumption\r
452 when the call returns. In non-blocking mode,\r
453 it is ready when WaitEvent is signaled. The\r
454 list of failed CPU is terminated by\r
455 END_OF_CPU_LIST.\r
456\r
457 @retval EFI_SUCCESS In blocking mode, all APs have finished before\r
458 the timeout expired.\r
459 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched\r
460 to all enabled APs.\r
461 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
462 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
463 signaled.\r
464 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
465 supported.\r
466 @retval EFI_DEVICE_ERROR Caller processor is AP.\r
467 @retval EFI_NOT_STARTED No enabled APs exist in the system.\r
468 @retval EFI_NOT_READY Any enabled APs are busy.\r
469 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
470 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
471 all enabled APs have finished.\r
472 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
473\r
474**/\r
475EFI_STATUS\r
476EFIAPI\r
477MpInitLibStartupAllAPs (\r
478 IN EFI_AP_PROCEDURE Procedure,\r
479 IN BOOLEAN SingleThread,\r
480 IN EFI_EVENT WaitEvent OPTIONAL,\r
481 IN UINTN TimeoutInMicroseconds,\r
482 IN VOID *ProcedureArgument OPTIONAL,\r
483 OUT UINTN **FailedCpuList OPTIONAL\r
484 )\r
485{\r
86efe976
JF
486 EFI_STATUS Status;\r
487\r
488 //\r
489 // Temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
490 //\r
491 mStopCheckAllApsStatus = TRUE;\r
492\r
493 Status = StartupAllAPsWorker (\r
494 Procedure,\r
495 SingleThread,\r
496 WaitEvent,\r
497 TimeoutInMicroseconds,\r
498 ProcedureArgument,\r
499 FailedCpuList\r
500 );\r
501\r
502 //\r
503 // Start checkAllApsStatus\r
504 //\r
505 mStopCheckAllApsStatus = FALSE;\r
506\r
507 return Status;\r
3e8ad6bd
JF
508}\r
509\r
510/**\r
511 This service lets the caller get one enabled AP to execute a caller-provided\r
512 function.\r
513\r
514 @param[in] Procedure A pointer to the function to be run on the\r
515 designated AP of the system. See type\r
516 EFI_AP_PROCEDURE.\r
517 @param[in] ProcessorNumber The handle number of the AP. The range is\r
518 from 0 to the total number of logical\r
519 processors minus 1. The total number of\r
520 logical processors can be retrieved by\r
521 MpInitLibGetNumberOfProcessors().\r
522 @param[in] WaitEvent The event created by the caller with CreateEvent()\r
523 service. If it is NULL, then execute in\r
524 blocking mode. BSP waits until this AP finish\r
525 or TimeoutInMicroSeconds expires. If it's\r
526 not NULL, then execute in non-blocking mode.\r
527 BSP requests the function specified by\r
528 Procedure to be started on this AP,\r
529 and go on executing immediately. If this AP\r
530 return from Procedure or TimeoutInMicroSeconds\r
531 expires, this event is signaled. The BSP\r
532 can use the CheckEvent() or WaitForEvent()\r
533 services to check the state of event. Type\r
534 EFI_EVENT is defined in CreateEvent() in\r
535 the Unified Extensible Firmware Interface\r
536 Specification.\r
367284e7 537 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for\r
3e8ad6bd
JF
538 this AP to finish this Procedure, either for\r
539 blocking or non-blocking mode. Zero means\r
540 infinity. If the timeout expires before\r
541 this AP returns from Procedure, then Procedure\r
542 on the AP is terminated. The\r
543 AP is available for next function assigned\r
544 by MpInitLibStartupAllAPs() or\r
545 MpInitLibStartupThisAP().\r
546 If the timeout expires in blocking mode,\r
547 BSP returns EFI_TIMEOUT. If the timeout\r
548 expires in non-blocking mode, WaitEvent\r
549 is signaled with SignalEvent().\r
550 @param[in] ProcedureArgument The parameter passed into Procedure on the\r
551 specified AP.\r
552 @param[out] Finished If NULL, this parameter is ignored. In\r
553 blocking mode, this parameter is ignored.\r
554 In non-blocking mode, if AP returns from\r
555 Procedure before the timeout expires, its\r
556 content is set to TRUE. Otherwise, the\r
557 value is set to FALSE. The caller can\r
558 determine if the AP returned from Procedure\r
559 by evaluating this value.\r
560\r
561 @retval EFI_SUCCESS In blocking mode, specified AP finished before\r
562 the timeout expires.\r
563 @retval EFI_SUCCESS In non-blocking mode, the function has been\r
564 dispatched to specified AP.\r
565 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the\r
566 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was\r
567 signaled.\r
568 @retval EFI_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not\r
569 supported.\r
570 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
571 @retval EFI_TIMEOUT In blocking mode, the timeout expired before\r
572 the specified AP has finished.\r
573 @retval EFI_NOT_READY The specified AP is busy.\r
574 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
575 @retval EFI_NOT_FOUND The processor with the handle specified by\r
576 ProcessorNumber does not exist.\r
577 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.\r
578 @retval EFI_INVALID_PARAMETER Procedure is NULL.\r
579\r
580**/\r
581EFI_STATUS\r
582EFIAPI\r
583MpInitLibStartupThisAP (\r
584 IN EFI_AP_PROCEDURE Procedure,\r
585 IN UINTN ProcessorNumber,\r
586 IN EFI_EVENT WaitEvent OPTIONAL,\r
587 IN UINTN TimeoutInMicroseconds,\r
588 IN VOID *ProcedureArgument OPTIONAL,\r
589 OUT BOOLEAN *Finished OPTIONAL\r
590 )\r
591{\r
20ae5774
JF
592 EFI_STATUS Status;\r
593\r
594 //\r
595 // temporarily stop checkAllApsStatus for avoid resource dead-lock.\r
596 //\r
597 mStopCheckAllApsStatus = TRUE;\r
598\r
599 Status = StartupThisAPWorker (\r
600 Procedure,\r
601 ProcessorNumber,\r
602 WaitEvent,\r
603 TimeoutInMicroseconds,\r
604 ProcedureArgument,\r
605 Finished\r
606 );\r
607\r
608 mStopCheckAllApsStatus = FALSE;\r
609\r
610 return Status;\r
3e8ad6bd
JF
611}\r
612\r
613/**\r
614 This service switches the requested AP to be the BSP from that point onward.\r
615 This service changes the BSP for all purposes. This call can only be performed\r
616 by the current BSP.\r
617\r
618 @param[in] ProcessorNumber The handle number of AP that is to become the new\r
619 BSP. The range is from 0 to the total number of\r
620 logical processors minus 1. The total number of\r
621 logical processors can be retrieved by\r
622 MpInitLibGetNumberOfProcessors().\r
623 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an\r
624 enabled AP. Otherwise, it will be disabled.\r
625\r
626 @retval EFI_SUCCESS BSP successfully switched.\r
627 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to\r
628 this service returning.\r
629 @retval EFI_UNSUPPORTED Switching the BSP is not supported.\r
630 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
631 @retval EFI_NOT_FOUND The processor with the handle specified by\r
632 ProcessorNumber does not exist.\r
633 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or\r
634 a disabled AP.\r
635 @retval EFI_NOT_READY The specified AP is busy.\r
636 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
637\r
638**/\r
639EFI_STATUS\r
640EFIAPI\r
641MpInitLibSwitchBSP (\r
642 IN UINTN ProcessorNumber,\r
643 IN BOOLEAN EnableOldBSP\r
644 )\r
645{\r
b6e45716
JF
646 EFI_STATUS Status;\r
647 EFI_TIMER_ARCH_PROTOCOL *Timer;\r
648 UINT64 TimerPeriod;\r
41be0da5 649\r
8ad05bd2 650 TimerPeriod = 0;\r
b6e45716
JF
651 //\r
652 // Locate Timer Arch Protocol\r
653 //\r
654 Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Timer);\r
655 if (EFI_ERROR (Status)) {\r
656 Timer = NULL;\r
657 }\r
658\r
659 if (Timer != NULL) {\r
660 //\r
661 // Save current rate of DXE Timer\r
662 //\r
663 Timer->GetTimerPeriod (Timer, &TimerPeriod);\r
664 //\r
665 // Disable DXE Timer and drain pending interrupts\r
666 //\r
667 Timer->SetTimerPeriod (Timer, 0);\r
668 }\r
41be0da5
JF
669\r
670 Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);\r
671\r
b6e45716
JF
672 if (Timer != NULL) {\r
673 //\r
674 // Enable and restore rate of DXE Timer\r
675 //\r
676 Timer->SetTimerPeriod (Timer, TimerPeriod);\r
677 }\r
678\r
41be0da5 679 return Status;\r
3e8ad6bd
JF
680}\r
681\r
682/**\r
683 This service lets the caller enable or disable an AP from this point onward.\r
684 This service may only be called from the BSP.\r
685\r
686 @param[in] ProcessorNumber The handle number of AP.\r
687 The range is from 0 to the total number of\r
688 logical processors minus 1. The total number of\r
689 logical processors can be retrieved by\r
690 MpInitLibGetNumberOfProcessors().\r
691 @param[in] EnableAP Specifies the new state for the processor for\r
692 enabled, FALSE for disabled.\r
693 @param[in] HealthFlag If not NULL, a pointer to a value that specifies\r
694 the new health status of the AP. This flag\r
695 corresponds to StatusFlag defined in\r
696 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only\r
697 the PROCESSOR_HEALTH_STATUS_BIT is used. All other\r
698 bits are ignored. If it is NULL, this parameter\r
699 is ignored.\r
700\r
701 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.\r
702 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed\r
703 prior to this service returning.\r
704 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.\r
705 @retval EFI_DEVICE_ERROR The calling processor is an AP.\r
706 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber\r
707 does not exist.\r
708 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.\r
709 @retval EFI_NOT_READY MP Initialize Library is not initialized.\r
710\r
711**/\r
712EFI_STATUS\r
713EFIAPI\r
714MpInitLibEnableDisableAP (\r
715 IN UINTN ProcessorNumber,\r
716 IN BOOLEAN EnableAP,\r
717 IN UINT32 *HealthFlag OPTIONAL\r
718 )\r
719{\r
e37109bc
JF
720 EFI_STATUS Status;\r
721 BOOLEAN TempStopCheckState;\r
722\r
723 TempStopCheckState = FALSE;\r
724 //\r
725 // temporarily stop checkAllAPsStatus for initialize parameters.\r
726 //\r
727 if (!mStopCheckAllApsStatus) {\r
728 mStopCheckAllApsStatus = TRUE;\r
729 TempStopCheckState = TRUE;\r
730 }\r
731\r
732 Status = EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);\r
733\r
734 if (TempStopCheckState) {\r
735 mStopCheckAllApsStatus = FALSE;\r
736 }\r
737\r
738 return Status;\r
3e8ad6bd 739}\r