]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuDxe/CpuMp.c
UefiCpuPkg/CpuDxe: Consume MpInitLib to produce CPU MP Protocol services
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuMp.c
1 /** @file
2 CPU DXE Module to produce CPU MP Protocol.
3
4 Copyright (c) 2008 - 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "CpuDxe.h"
16 #include "CpuMp.h"
17
18 UINTN gMaxLogicalProcessorNumber;
19 UINTN gApStackSize;
20 UINTN gPollInterval = 100; // 100 microseconds
21
22 MP_SYSTEM_DATA mMpSystemData;
23 EFI_HANDLE mMpServiceHandle = NULL;
24 UINTN mNumberOfProcessors = 1;
25 EFI_EVENT mExitBootServicesEvent = (EFI_EVENT)NULL;
26
27 VOID *mCommonStack = 0;
28 VOID *mTopOfApCommonStack = 0;
29 VOID *mApStackStart = 0;
30
31 volatile BOOLEAN mAPsAlreadyInitFinished = FALSE;
32
33 EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = {
34 GetNumberOfProcessors,
35 GetProcessorInfo,
36 StartupAllAPs,
37 StartupThisAP,
38 SwitchBSP,
39 EnableDisableAP,
40 WhoAmI
41 };
42
43 /**
44 Get Mp Service Lock.
45
46 @param CpuData the pointer to CPU_DATA_BLOCK of specified processor
47
48 **/
49 VOID
50 GetMpSpinLock (
51 IN CPU_DATA_BLOCK *CpuData
52 )
53 {
54 while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {
55 CpuPause ();
56 }
57 CpuData->LockSelf = GetApicId ();
58 }
59
60 /**
61 Release Mp Service Lock.
62
63 @param CpuData the pointer to CPU_DATA_BLOCK of specified processor
64
65 **/
66 VOID
67 ReleaseMpSpinLock (
68 IN CPU_DATA_BLOCK *CpuData
69 )
70 {
71 ReleaseSpinLock (&CpuData->CpuDataLock);
72 }
73
74 /**
75 Check whether caller processor is BSP.
76
77 @retval TRUE the caller is BSP
78 @retval FALSE the caller is AP
79
80 **/
81 BOOLEAN
82 IsBSP (
83 VOID
84 )
85 {
86 UINTN CpuIndex;
87 CPU_DATA_BLOCK *CpuData;
88
89 CpuData = NULL;
90
91 WhoAmI (&mMpServicesTemplate, &CpuIndex);
92 CpuData = &mMpSystemData.CpuDatas[CpuIndex];
93
94 return CpuData->Info.StatusFlag & PROCESSOR_AS_BSP_BIT ? TRUE : FALSE;
95 }
96
97 /**
98 Get the Application Processors state.
99
100 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
101
102 @retval CPU_STATE the AP status
103
104 **/
105 STATIC
106 CPU_STATE
107 GetApState (
108 IN CPU_DATA_BLOCK *CpuData
109 )
110 {
111 CPU_STATE State;
112
113 GetMpSpinLock (CpuData);
114 State = CpuData->State;
115 ReleaseMpSpinLock (CpuData);
116
117 return State;
118 }
119
120 /**
121 Set the Application Processors state.
122
123 @param CpuData The pointer to CPU_DATA_BLOCK of specified AP
124 @param State The AP status
125
126 **/
127 STATIC
128 VOID
129 SetApState (
130 IN CPU_DATA_BLOCK *CpuData,
131 IN CPU_STATE State
132 )
133 {
134 GetMpSpinLock (CpuData);
135 CpuData->State = State;
136 ReleaseMpSpinLock (CpuData);
137 }
138
139 /**
140 Set the Application Processor prepare to run a function specified
141 by Params.
142
143 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
144 @param Procedure A pointer to the function to be run on enabled APs of the system
145 @param ProcedureArgument Pointer to the optional parameter of the assigned function
146
147 **/
148 VOID
149 SetApProcedure (
150 IN CPU_DATA_BLOCK *CpuData,
151 IN EFI_AP_PROCEDURE Procedure,
152 IN VOID *ProcedureArgument
153 )
154 {
155 GetMpSpinLock (CpuData);
156 CpuData->Parameter = ProcedureArgument;
157 CpuData->Procedure = Procedure;
158 ReleaseMpSpinLock (CpuData);
159 }
160
161 /**
162 Check the Application Processors Status whether contains the Flags.
163
164 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
165 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
166
167 @retval TRUE the AP status includes the StatusFlag
168 @retval FALSE the AP status excludes the StatusFlag
169
170 **/
171 BOOLEAN
172 TestCpuStatusFlag (
173 IN CPU_DATA_BLOCK *CpuData,
174 IN UINT32 Flags
175 )
176 {
177 UINT32 Ret;
178
179 GetMpSpinLock (CpuData);
180 Ret = CpuData->Info.StatusFlag & Flags;
181 ReleaseMpSpinLock (CpuData);
182
183 return (BOOLEAN) (Ret != 0);
184 }
185
186 /**
187 Bitwise-Or of the Application Processors Status with the Flags.
188
189 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
190 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
191
192 **/
193 VOID
194 CpuStatusFlagOr (
195 IN CPU_DATA_BLOCK *CpuData,
196 IN UINT32 Flags
197 )
198 {
199 GetMpSpinLock (CpuData);
200 CpuData->Info.StatusFlag |= Flags;
201 ReleaseMpSpinLock (CpuData);
202 }
203
204 /**
205 Bitwise-AndNot of the Application Processors Status with the Flags.
206
207 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
208 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
209
210 **/
211 VOID
212 CpuStatusFlagAndNot (
213 IN CPU_DATA_BLOCK *CpuData,
214 IN UINT32 Flags
215 )
216 {
217 GetMpSpinLock (CpuData);
218 CpuData->Info.StatusFlag &= ~Flags;
219 ReleaseMpSpinLock (CpuData);
220 }
221
222 /**
223 Searches for the next blocking AP.
224
225 Search for the next AP that is put in blocking state by single-threaded StartupAllAPs().
226
227 @param NextNumber Pointer to the processor number of the next blocking AP.
228
229 @retval EFI_SUCCESS The next blocking AP has been found.
230 @retval EFI_NOT_FOUND No blocking AP exists.
231
232 **/
233 EFI_STATUS
234 GetNextBlockedNumber (
235 OUT UINTN *NextNumber
236 )
237 {
238 UINTN Number;
239 CPU_STATE CpuState;
240 CPU_DATA_BLOCK *CpuData;
241
242 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
243 CpuData = &mMpSystemData.CpuDatas[Number];
244 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
245 //
246 // Skip BSP
247 //
248 continue;
249 }
250
251 CpuState = GetApState (CpuData);
252 if (CpuState == CpuStateBlocked) {
253 *NextNumber = Number;
254 return EFI_SUCCESS;
255 }
256 }
257
258 return EFI_NOT_FOUND;
259 }
260
261 /**
262 Check if the APs state are finished, and update them to idle state
263 by StartupAllAPs().
264
265 **/
266 VOID
267 CheckAndUpdateAllAPsToIdleState (
268 VOID
269 )
270 {
271 UINTN ProcessorNumber;
272 UINTN NextNumber;
273 CPU_DATA_BLOCK *CpuData;
274 EFI_STATUS Status;
275 CPU_STATE CpuState;
276
277 for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
278 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
279 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
280 //
281 // Skip BSP
282 //
283 continue;
284 }
285
286 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
287 //
288 // Skip Disabled processors
289 //
290 continue;
291 }
292
293 CpuState = GetApState (CpuData);
294 if (CpuState == CpuStateFinished) {
295 mMpSystemData.FinishCount++;
296 if (mMpSystemData.SingleThread) {
297 Status = GetNextBlockedNumber (&NextNumber);
298 if (!EFI_ERROR (Status)) {
299 SetApState (&mMpSystemData.CpuDatas[NextNumber], CpuStateReady);
300 SetApProcedure (&mMpSystemData.CpuDatas[NextNumber],
301 mMpSystemData.Procedure,
302 mMpSystemData.ProcedureArgument);
303 //
304 // If this AP previous state is blocked, we should
305 // wake up this AP by sent a SIPI. and avoid
306 // re-involve the sleeping state. we must call
307 // SetApProcedure() first.
308 //
309 ResetProcessorToIdleState (&mMpSystemData.CpuDatas[NextNumber]);
310 }
311 }
312 SetApState (CpuData, CpuStateIdle);
313 }
314 }
315 }
316
317 /**
318 Check if all APs are in state CpuStateSleeping.
319
320 Return TRUE if all APs are in the CpuStateSleeping state. Do not
321 check the state of the BSP or any disabled APs.
322
323 @retval TRUE All APs are in CpuStateSleeping state.
324 @retval FALSE One or more APs are not in CpuStateSleeping state.
325
326 **/
327 BOOLEAN
328 CheckAllAPsSleeping (
329 VOID
330 )
331 {
332 UINTN ProcessorNumber;
333 CPU_DATA_BLOCK *CpuData;
334
335 for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
336 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
337 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
338 //
339 // Skip BSP
340 //
341 continue;
342 }
343
344 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
345 //
346 // Skip Disabled processors
347 //
348 continue;
349 }
350
351 if (GetApState (CpuData) != CpuStateSleeping) {
352 return FALSE;
353 }
354 }
355 return TRUE;
356 }
357
358 /**
359 If the timeout expires before all APs returns from Procedure,
360 we should forcibly terminate the executing AP and fill FailedList back
361 by StartupAllAPs().
362
363 **/
364 VOID
365 ResetAllFailedAPs (
366 VOID
367 )
368 {
369 CPU_DATA_BLOCK *CpuData;
370 UINTN Number;
371 CPU_STATE CpuState;
372
373 if (mMpSystemData.FailedList != NULL) {
374 *mMpSystemData.FailedList = AllocatePool ((mMpSystemData.StartCount - mMpSystemData.FinishCount + 1) * sizeof(UINTN));
375 ASSERT (*mMpSystemData.FailedList != NULL);
376 }
377
378 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
379 CpuData = &mMpSystemData.CpuDatas[Number];
380 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
381 //
382 // Skip BSP
383 //
384 continue;
385 }
386
387 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
388 //
389 // Skip Disabled processors
390 //
391 continue;
392 }
393
394 CpuState = GetApState (CpuData);
395 if (CpuState != CpuStateIdle &&
396 CpuState != CpuStateSleeping) {
397 if (mMpSystemData.FailedList != NULL) {
398 (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex++] = Number;
399 }
400 ResetProcessorToIdleState (CpuData);
401 }
402 }
403
404 if (mMpSystemData.FailedList != NULL) {
405 (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex] = END_OF_CPU_LIST;
406 }
407 }
408
409 /**
410 This service retrieves the number of logical processor in the platform
411 and the number of those logical processors that are enabled on this boot.
412 This service may only be called from the BSP.
413
414 This function is used to retrieve the following information:
415 - The number of logical processors that are present in the system.
416 - The number of enabled logical processors in the system at the instant
417 this call is made.
418
419 Because MP Service Protocol provides services to enable and disable processors
420 dynamically, the number of enabled logical processors may vary during the
421 course of a boot session.
422
423 If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
424 If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
425 EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
426 is returned in NumberOfProcessors, the number of currently enabled processor
427 is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
428
429 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
430 instance.
431 @param[out] NumberOfProcessors Pointer to the total number of logical
432 processors in the system, including the BSP
433 and disabled APs.
434 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
435 processors that exist in system, including
436 the BSP.
437
438 @retval EFI_SUCCESS The number of logical processors and enabled
439 logical processors was retrieved.
440 @retval EFI_DEVICE_ERROR The calling processor is an AP.
441 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
442 @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
443
444 **/
445 EFI_STATUS
446 EFIAPI
447 GetNumberOfProcessors (
448 IN EFI_MP_SERVICES_PROTOCOL *This,
449 OUT UINTN *NumberOfProcessors,
450 OUT UINTN *NumberOfEnabledProcessors
451 )
452 {
453 if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
454 return EFI_INVALID_PARAMETER;
455 }
456
457 return MpInitLibGetNumberOfProcessors (
458 NumberOfProcessors,
459 NumberOfEnabledProcessors
460 );
461 }
462
463 /**
464 Gets detailed MP-related information on the requested processor at the
465 instant this call is made. This service may only be called from the BSP.
466
467 This service retrieves detailed MP-related information about any processor
468 on the platform. Note the following:
469 - The processor information may change during the course of a boot session.
470 - The information presented here is entirely MP related.
471
472 Information regarding the number of caches and their sizes, frequency of operation,
473 slot numbers is all considered platform-related information and is not provided
474 by this service.
475
476 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
477 instance.
478 @param[in] ProcessorNumber The handle number of processor.
479 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
480 the requested processor is deposited.
481
482 @retval EFI_SUCCESS Processor information was returned.
483 @retval EFI_DEVICE_ERROR The calling processor is an AP.
484 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
485 @retval EFI_NOT_FOUND The processor with the handle specified by
486 ProcessorNumber does not exist in the platform.
487
488 **/
489 EFI_STATUS
490 EFIAPI
491 GetProcessorInfo (
492 IN EFI_MP_SERVICES_PROTOCOL *This,
493 IN UINTN ProcessorNumber,
494 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
495 )
496 {
497 return MpInitLibGetProcessorInfo (ProcessorNumber, ProcessorInfoBuffer, NULL);
498 }
499
500 /**
501 This service executes a caller provided function on all enabled APs. APs can
502 run either simultaneously or one at a time in sequence. This service supports
503 both blocking and non-blocking requests. The non-blocking requests use EFI
504 events so the BSP can detect when the APs have finished. This service may only
505 be called from the BSP.
506
507 This function is used to dispatch all the enabled APs to the function specified
508 by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
509 immediately and Procedure is not started on any AP.
510
511 If SingleThread is TRUE, all the enabled APs execute the function specified by
512 Procedure one by one, in ascending order of processor handle number. Otherwise,
513 all the enabled APs execute the function specified by Procedure simultaneously.
514
515 If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
516 APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking
517 mode, and the BSP returns from this service without waiting for APs. If a
518 non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
519 is signaled, then EFI_UNSUPPORTED must be returned.
520
521 If the timeout specified by TimeoutInMicroseconds expires before all APs return
522 from Procedure, then Procedure on the failed APs is terminated. All enabled APs
523 are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
524 and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
525 content points to the list of processor handle numbers in which Procedure was
526 terminated.
527
528 Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
529 to make sure that the nature of the code that is executed on the BSP and the
530 dispatched APs is well controlled. The MP Services Protocol does not guarantee
531 that the Procedure function is MP-safe. Hence, the tasks that can be run in
532 parallel are limited to certain independent tasks and well-controlled exclusive
533 code. EFI services and protocols may not be called by APs unless otherwise
534 specified.
535
536 In blocking execution mode, BSP waits until all APs finish or
537 TimeoutInMicroseconds expires.
538
539 In non-blocking execution mode, BSP is freed to return to the caller and then
540 proceed to the next task without having to wait for APs. The following
541 sequence needs to occur in a non-blocking execution mode:
542
543 -# The caller that intends to use this MP Services Protocol in non-blocking
544 mode creates WaitEvent by calling the EFI CreateEvent() service. The caller
545 invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
546 is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
547 the function specified by Procedure to be started on all the enabled APs,
548 and releases the BSP to continue with other tasks.
549 -# The caller can use the CheckEvent() and WaitForEvent() services to check
550 the state of the WaitEvent created in step 1.
551 -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
552 Service signals WaitEvent by calling the EFI SignalEvent() function. If
553 FailedCpuList is not NULL, its content is available when WaitEvent is
554 signaled. If all APs returned from Procedure prior to the timeout, then
555 FailedCpuList is set to NULL. If not all APs return from Procedure before
556 the timeout, then FailedCpuList is filled in with the list of the failed
557 APs. The buffer is allocated by MP Service Protocol using AllocatePool().
558 It is the caller's responsibility to free the buffer with FreePool() service.
559 -# This invocation of SignalEvent() function informs the caller that invoked
560 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
561 the specified task or a timeout occurred. The contents of FailedCpuList
562 can be examined to determine which APs did not complete the specified task
563 prior to the timeout.
564
565 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
566 instance.
567 @param[in] Procedure A pointer to the function to be run on
568 enabled APs of the system. See type
569 EFI_AP_PROCEDURE.
570 @param[in] SingleThread If TRUE, then all the enabled APs execute
571 the function specified by Procedure one by
572 one, in ascending order of processor handle
573 number. If FALSE, then all the enabled APs
574 execute the function specified by Procedure
575 simultaneously.
576 @param[in] WaitEvent The event created by the caller with CreateEvent()
577 service. If it is NULL, then execute in
578 blocking mode. BSP waits until all APs finish
579 or TimeoutInMicroseconds expires. If it's
580 not NULL, then execute in non-blocking mode.
581 BSP requests the function specified by
582 Procedure to be started on all the enabled
583 APs, and go on executing immediately. If
584 all return from Procedure, or TimeoutInMicroseconds
585 expires, this event is signaled. The BSP
586 can use the CheckEvent() or WaitForEvent()
587 services to check the state of event. Type
588 EFI_EVENT is defined in CreateEvent() in
589 the Unified Extensible Firmware Interface
590 Specification.
591 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
592 APs to return from Procedure, either for
593 blocking or non-blocking mode. Zero means
594 infinity. If the timeout expires before
595 all APs return from Procedure, then Procedure
596 on the failed APs is terminated. All enabled
597 APs are available for next function assigned
598 by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
599 or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
600 If the timeout expires in blocking mode,
601 BSP returns EFI_TIMEOUT. If the timeout
602 expires in non-blocking mode, WaitEvent
603 is signaled with SignalEvent().
604 @param[in] ProcedureArgument The parameter passed into Procedure for
605 all APs.
606 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
607 if all APs finish successfully, then its
608 content is set to NULL. If not all APs
609 finish before timeout expires, then its
610 content is set to address of the buffer
611 holding handle numbers of the failed APs.
612 The buffer is allocated by MP Service Protocol,
613 and it's the caller's responsibility to
614 free the buffer with FreePool() service.
615 In blocking mode, it is ready for consumption
616 when the call returns. In non-blocking mode,
617 it is ready when WaitEvent is signaled. The
618 list of failed CPU is terminated by
619 END_OF_CPU_LIST.
620
621 @retval EFI_SUCCESS In blocking mode, all APs have finished before
622 the timeout expired.
623 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
624 to all enabled APs.
625 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
626 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
627 signaled.
628 @retval EFI_DEVICE_ERROR Caller processor is AP.
629 @retval EFI_NOT_STARTED No enabled APs exist in the system.
630 @retval EFI_NOT_READY Any enabled APs are busy.
631 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
632 all enabled APs have finished.
633 @retval EFI_INVALID_PARAMETER Procedure is NULL.
634
635 **/
636 EFI_STATUS
637 EFIAPI
638 StartupAllAPs (
639 IN EFI_MP_SERVICES_PROTOCOL *This,
640 IN EFI_AP_PROCEDURE Procedure,
641 IN BOOLEAN SingleThread,
642 IN EFI_EVENT WaitEvent OPTIONAL,
643 IN UINTN TimeoutInMicroseconds,
644 IN VOID *ProcedureArgument OPTIONAL,
645 OUT UINTN **FailedCpuList OPTIONAL
646 )
647 {
648 return MpInitLibStartupAllAPs (
649 Procedure,
650 SingleThread,
651 WaitEvent,
652 TimeoutInMicroseconds,
653 ProcedureArgument,
654 FailedCpuList
655 );
656 }
657
658 /**
659 This service lets the caller get one enabled AP to execute a caller-provided
660 function. The caller can request the BSP to either wait for the completion
661 of the AP or just proceed with the next task by using the EFI event mechanism.
662 See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
663 execution support. This service may only be called from the BSP.
664
665 This function is used to dispatch one enabled AP to the function specified by
666 Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
667 is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
668 TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
669 BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
670 is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
671 then EFI_UNSUPPORTED must be returned.
672
673 If the timeout specified by TimeoutInMicroseconds expires before the AP returns
674 from Procedure, then execution of Procedure by the AP is terminated. The AP is
675 available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
676 EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
677
678 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
679 instance.
680 @param[in] Procedure A pointer to the function to be run on
681 enabled APs of the system. See type
682 EFI_AP_PROCEDURE.
683 @param[in] ProcessorNumber The handle number of the AP. The range is
684 from 0 to the total number of logical
685 processors minus 1. The total number of
686 logical processors can be retrieved by
687 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
688 @param[in] WaitEvent The event created by the caller with CreateEvent()
689 service. If it is NULL, then execute in
690 blocking mode. BSP waits until all APs finish
691 or TimeoutInMicroseconds expires. If it's
692 not NULL, then execute in non-blocking mode.
693 BSP requests the function specified by
694 Procedure to be started on all the enabled
695 APs, and go on executing immediately. If
696 all return from Procedure or TimeoutInMicroseconds
697 expires, this event is signaled. The BSP
698 can use the CheckEvent() or WaitForEvent()
699 services to check the state of event. Type
700 EFI_EVENT is defined in CreateEvent() in
701 the Unified Extensible Firmware Interface
702 Specification.
703 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
704 APs to return from Procedure, either for
705 blocking or non-blocking mode. Zero means
706 infinity. If the timeout expires before
707 all APs return from Procedure, then Procedure
708 on the failed APs is terminated. All enabled
709 APs are available for next function assigned
710 by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
711 or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
712 If the timeout expires in blocking mode,
713 BSP returns EFI_TIMEOUT. If the timeout
714 expires in non-blocking mode, WaitEvent
715 is signaled with SignalEvent().
716 @param[in] ProcedureArgument The parameter passed into Procedure for
717 all APs.
718 @param[out] Finished If NULL, this parameter is ignored. In
719 blocking mode, this parameter is ignored.
720 In non-blocking mode, if AP returns from
721 Procedure before the timeout expires, its
722 content is set to TRUE. Otherwise, the
723 value is set to FALSE. The caller can
724 determine if the AP returned from Procedure
725 by evaluating this value.
726
727 @retval EFI_SUCCESS In blocking mode, specified AP finished before
728 the timeout expires.
729 @retval EFI_SUCCESS In non-blocking mode, the function has been
730 dispatched to specified AP.
731 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
732 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
733 signaled.
734 @retval EFI_DEVICE_ERROR The calling processor is an AP.
735 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
736 the specified AP has finished.
737 @retval EFI_NOT_READY The specified AP is busy.
738 @retval EFI_NOT_FOUND The processor with the handle specified by
739 ProcessorNumber does not exist.
740 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
741 @retval EFI_INVALID_PARAMETER Procedure is NULL.
742
743 **/
744 EFI_STATUS
745 EFIAPI
746 StartupThisAP (
747 IN EFI_MP_SERVICES_PROTOCOL *This,
748 IN EFI_AP_PROCEDURE Procedure,
749 IN UINTN ProcessorNumber,
750 IN EFI_EVENT WaitEvent OPTIONAL,
751 IN UINTN TimeoutInMicroseconds,
752 IN VOID *ProcedureArgument OPTIONAL,
753 OUT BOOLEAN *Finished OPTIONAL
754 )
755 {
756 return MpInitLibStartupThisAP (
757 Procedure,
758 ProcessorNumber,
759 WaitEvent,
760 TimeoutInMicroseconds,
761 ProcedureArgument,
762 Finished
763 );
764 }
765
766 /**
767 This service switches the requested AP to be the BSP from that point onward.
768 This service changes the BSP for all purposes. This call can only be performed
769 by the current BSP.
770
771 This service switches the requested AP to be the BSP from that point onward.
772 This service changes the BSP for all purposes. The new BSP can take over the
773 execution of the old BSP and continue seamlessly from where the old one left
774 off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
775 is signaled.
776
777 If the BSP cannot be switched prior to the return from this service, then
778 EFI_UNSUPPORTED must be returned.
779
780 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
781 @param[in] ProcessorNumber The handle number of AP that is to become the new
782 BSP. The range is from 0 to the total number of
783 logical processors minus 1. The total number of
784 logical processors can be retrieved by
785 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
786 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
787 enabled AP. Otherwise, it will be disabled.
788
789 @retval EFI_SUCCESS BSP successfully switched.
790 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
791 this service returning.
792 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
793 @retval EFI_SUCCESS The calling processor is an AP.
794 @retval EFI_NOT_FOUND The processor with the handle specified by
795 ProcessorNumber does not exist.
796 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
797 a disabled AP.
798 @retval EFI_NOT_READY The specified AP is busy.
799
800 **/
801 EFI_STATUS
802 EFIAPI
803 SwitchBSP (
804 IN EFI_MP_SERVICES_PROTOCOL *This,
805 IN UINTN ProcessorNumber,
806 IN BOOLEAN EnableOldBSP
807 )
808 {
809 return MpInitLibSwitchBSP (ProcessorNumber, EnableOldBSP);
810 }
811
812 /**
813 This service lets the caller enable or disable an AP from this point onward.
814 This service may only be called from the BSP.
815
816 This service allows the caller enable or disable an AP from this point onward.
817 The caller can optionally specify the health status of the AP by Health. If
818 an AP is being disabled, then the state of the disabled AP is implementation
819 dependent. If an AP is enabled, then the implementation must guarantee that a
820 complete initialization sequence is performed on the AP, so the AP is in a state
821 that is compatible with an MP operating system. This service may not be supported
822 after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
823
824 If the enable or disable AP operation cannot be completed prior to the return
825 from this service, then EFI_UNSUPPORTED must be returned.
826
827 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
828 @param[in] ProcessorNumber The handle number of AP that is to become the new
829 BSP. The range is from 0 to the total number of
830 logical processors minus 1. The total number of
831 logical processors can be retrieved by
832 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
833 @param[in] EnableAP Specifies the new state for the processor for
834 enabled, FALSE for disabled.
835 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
836 the new health status of the AP. This flag
837 corresponds to StatusFlag defined in
838 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
839 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
840 bits are ignored. If it is NULL, this parameter
841 is ignored.
842
843 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
844 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
845 prior to this service returning.
846 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
847 @retval EFI_DEVICE_ERROR The calling processor is an AP.
848 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
849 does not exist.
850 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
851
852 **/
853 EFI_STATUS
854 EFIAPI
855 EnableDisableAP (
856 IN EFI_MP_SERVICES_PROTOCOL *This,
857 IN UINTN ProcessorNumber,
858 IN BOOLEAN EnableAP,
859 IN UINT32 *HealthFlag OPTIONAL
860 )
861 {
862 return MpInitLibEnableDisableAP (ProcessorNumber, EnableAP, HealthFlag);
863 }
864
865 /**
866 This return the handle number for the calling processor. This service may be
867 called from the BSP and APs.
868
869 This service returns the processor handle number for the calling processor.
870 The returned value is in the range from 0 to the total number of logical
871 processors minus 1. The total number of logical processors can be retrieved
872 with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
873 called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
874 is returned. Otherwise, the current processors handle number is returned in
875 ProcessorNumber, and EFI_SUCCESS is returned.
876
877 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
878 @param[out] ProcessorNumber The handle number of AP that is to become the new
879 BSP. The range is from 0 to the total number of
880 logical processors minus 1. The total number of
881 logical processors can be retrieved by
882 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
883
884 @retval EFI_SUCCESS The current processor handle number was returned
885 in ProcessorNumber.
886 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
887
888 **/
889 EFI_STATUS
890 EFIAPI
891 WhoAmI (
892 IN EFI_MP_SERVICES_PROTOCOL *This,
893 OUT UINTN *ProcessorNumber
894 )
895 {
896 return MpInitLibWhoAmI (ProcessorNumber);;
897 }
898
899 /**
900 Collects BIST data from HOB.
901
902 This function collects BIST data from HOB built from Sec Platform Information
903 PPI or SEC Platform Information2 PPI.
904
905 **/
906 VOID
907 CollectBistDataFromHob (
908 VOID
909 )
910 {
911 EFI_HOB_GUID_TYPE *GuidHob;
912 EFI_SEC_PLATFORM_INFORMATION_RECORD2 *SecPlatformInformation2;
913 EFI_SEC_PLATFORM_INFORMATION_RECORD *SecPlatformInformation;
914 UINTN NumberOfData;
915 EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstance;
916 EFI_SEC_PLATFORM_INFORMATION_CPU BspCpuInstance;
917 UINTN ProcessorNumber;
918 EFI_PROCESSOR_INFORMATION ProcessorInfo;
919 EFI_HEALTH_FLAGS BistData;
920
921 SecPlatformInformation2 = NULL;
922 SecPlatformInformation = NULL;
923
924 //
925 // Get gEfiSecPlatformInformation2PpiGuid Guided HOB firstly
926 //
927 GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformation2PpiGuid);
928 if (GuidHob != NULL) {
929 //
930 // Sec Platform Information2 PPI includes BSP/APs' BIST information
931 //
932 SecPlatformInformation2 = GET_GUID_HOB_DATA (GuidHob);
933 NumberOfData = SecPlatformInformation2->NumberOfCpus;
934 CpuInstance = SecPlatformInformation2->CpuInstance;
935 } else {
936 //
937 // Otherwise, get gEfiSecPlatformInformationPpiGuid Guided HOB
938 //
939 GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformationPpiGuid);
940 if (GuidHob != NULL) {
941 SecPlatformInformation = GET_GUID_HOB_DATA (GuidHob);
942 NumberOfData = 1;
943 //
944 // SEC Platform Information only includes BSP's BIST information
945 // does not have BSP's APIC ID
946 //
947 BspCpuInstance.CpuLocation = GetApicId ();
948 BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32 = SecPlatformInformation->IA32HealthFlags.Uint32;
949 CpuInstance = &BspCpuInstance;
950 } else {
951 DEBUG ((EFI_D_INFO, "Does not find any HOB stored CPU BIST information!\n"));
952 //
953 // Does not find any HOB stored BIST information
954 //
955 return;
956 }
957 }
958
959 while ((NumberOfData--) > 0) {
960 for (ProcessorNumber = 0; ProcessorNumber < mNumberOfProcessors; ProcessorNumber++) {
961 MpInitLibGetProcessorInfo (ProcessorNumber, &ProcessorInfo, &BistData);
962 if (ProcessorInfo.ProcessorId == CpuInstance[NumberOfData].CpuLocation) {
963 //
964 // Update CPU health status for MP Services Protocol according to BIST data.
965 //
966 BistData = CpuInstance[NumberOfData].InfoRecord.IA32HealthFlags;
967 }
968 if (BistData.Uint32 != 0) {
969 //
970 // Report Status Code that self test is failed
971 //
972 REPORT_STATUS_CODE (
973 EFI_ERROR_CODE | EFI_ERROR_MAJOR,
974 (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST)
975 );
976 }
977 }
978 }
979 }
980
981 /**
982 Callback function for ExitBootServices.
983
984 @param Event Event whose notification function is being invoked.
985 @param Context The pointer to the notification function's context,
986 which is implementation-dependent.
987
988 **/
989 VOID
990 EFIAPI
991 ExitBootServicesCallback (
992 IN EFI_EVENT Event,
993 IN VOID *Context
994 )
995 {
996 //
997 // Avoid APs access invalid buff datas which allocated by BootServices,
998 // so we send INIT IPI to APs to let them wait for SIPI state.
999 //
1000 SendInitIpiAllExcludingSelf ();
1001 }
1002
1003 /**
1004 A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to
1005 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure.
1006
1007 @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed to
1008 MtrrSetAllMtrrs().
1009 **/
1010 VOID
1011 EFIAPI
1012 SetMtrrsFromBuffer (
1013 IN VOID *Buffer
1014 )
1015 {
1016 MtrrSetAllMtrrs (Buffer);
1017 }
1018
1019 /**
1020 Initialize Multi-processor support.
1021
1022 **/
1023 VOID
1024 InitializeMpSupport (
1025 VOID
1026 )
1027 {
1028 EFI_STATUS Status;
1029 UINTN NumberOfProcessors;
1030 UINTN NumberOfEnabledProcessors;
1031
1032 NumberOfProcessors = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
1033 if (NumberOfProcessors < 1) {
1034 DEBUG ((DEBUG_ERROR, "Setting PcdCpuMaxLogicalProcessorNumber should be more than zero.\n"));
1035 return;
1036 }
1037
1038 //
1039 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1
1040 //
1041 if (NumberOfProcessors > 1) {
1042 Status = MpInitLibInitialize ();
1043 ASSERT_EFI_ERROR (Status);
1044
1045 MpInitLibGetNumberOfProcessors (&NumberOfProcessors, &NumberOfEnabledProcessors);
1046 mNumberOfProcessors = NumberOfProcessors;
1047 }
1048 DEBUG ((EFI_D_ERROR, "Detect CPU count: %d\n", mNumberOfProcessors));
1049
1050 //
1051 // Update CPU healthy information from Guided HOB
1052 //
1053 CollectBistDataFromHob ();
1054
1055 Status = gBS->InstallMultipleProtocolInterfaces (
1056 &mMpServiceHandle,
1057 &gEfiMpServiceProtocolGuid, &mMpServicesTemplate,
1058 NULL
1059 );
1060 ASSERT_EFI_ERROR (Status);
1061 }
1062