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