1 /** @file
2 CPU DXE Module.
3
4 Copyright (c) 2008 - 2015, 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 EFI_EVENT mExitBootServicesEvent = (EFI_EVENT)NULL;
25
26 VOID *mCommonStack = 0;
27 VOID *mTopOfApCommonStack = 0;
28 VOID *mApStackStart = 0;
29
30 volatile BOOLEAN mAPsAlreadyInitFinished = FALSE;
31 volatile BOOLEAN mStopCheckAllAPsStatus = TRUE;
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
GetMpSpinLock(IN CPU_DATA_BLOCK * CpuData)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
ReleaseMpSpinLock(IN CPU_DATA_BLOCK * CpuData)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
IsBSP(VOID)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 CPU_STATE
GetApState(IN CPU_DATA_BLOCK * CpuData)106 GetApState (
107 IN CPU_DATA_BLOCK *CpuData
108 )
109 {
110 CPU_STATE State;
111
112 GetMpSpinLock (CpuData);
113 State = CpuData->State;
114 ReleaseMpSpinLock (CpuData);
115
116 return State;
117 }
118
119 /**
120 Set the Application Processors state.
121
122 @param CpuData The pointer to CPU_DATA_BLOCK of specified AP
123 @param State The AP status
124
125 **/
126 VOID
SetApState(IN CPU_DATA_BLOCK * CpuData,IN CPU_STATE State)127 SetApState (
128 IN CPU_DATA_BLOCK *CpuData,
129 IN CPU_STATE State
130 )
131 {
132 GetMpSpinLock (CpuData);
133 CpuData->State = State;
134 ReleaseMpSpinLock (CpuData);
135 }
136
137 /**
138 Set the Application Processor prepare to run a function specified
139 by Params.
140
141 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
142 @param Procedure A pointer to the function to be run on enabled APs of the system
143 @param ProcedureArgument Pointer to the optional parameter of the assigned function
144
145 **/
146 VOID
SetApProcedure(IN CPU_DATA_BLOCK * CpuData,IN EFI_AP_PROCEDURE Procedure,IN VOID * ProcedureArgument)147 SetApProcedure (
148 IN CPU_DATA_BLOCK *CpuData,
149 IN EFI_AP_PROCEDURE Procedure,
150 IN VOID *ProcedureArgument
151 )
152 {
153 GetMpSpinLock (CpuData);
154 CpuData->Parameter = ProcedureArgument;
155 CpuData->Procedure = Procedure;
156 ReleaseMpSpinLock (CpuData);
157 }
158
159 /**
160 Check the Application Processors Status whether contains the Flags.
161
162 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
163 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
164
165 @retval TRUE the AP status includes the StatusFlag
166 @retval FALSE the AP status excludes the StatusFlag
167
168 **/
169 BOOLEAN
TestCpuStatusFlag(IN CPU_DATA_BLOCK * CpuData,IN UINT32 Flags)170 TestCpuStatusFlag (
171 IN CPU_DATA_BLOCK *CpuData,
172 IN UINT32 Flags
173 )
174 {
175 UINT32 Ret;
176
177 GetMpSpinLock (CpuData);
178 Ret = CpuData->Info.StatusFlag & Flags;
179 ReleaseMpSpinLock (CpuData);
180
181 return (BOOLEAN) (Ret != 0);
182 }
183
184 /**
185 Bitwise-Or of the Application Processors Status with the Flags.
186
187 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
188 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
189
190 **/
191 VOID
CpuStatusFlagOr(IN CPU_DATA_BLOCK * CpuData,IN UINT32 Flags)192 CpuStatusFlagOr (
193 IN CPU_DATA_BLOCK *CpuData,
194 IN UINT32 Flags
195 )
196 {
197 GetMpSpinLock (CpuData);
198 CpuData->Info.StatusFlag |= Flags;
199 ReleaseMpSpinLock (CpuData);
200 }
201
202 /**
203 Bitwise-AndNot of the Application Processors Status with the Flags.
204
205 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
206 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
207
208 **/
209 VOID
CpuStatusFlagAndNot(IN CPU_DATA_BLOCK * CpuData,IN UINT32 Flags)210 CpuStatusFlagAndNot (
211 IN CPU_DATA_BLOCK *CpuData,
212 IN UINT32 Flags
213 )
214 {
215 GetMpSpinLock (CpuData);
216 CpuData->Info.StatusFlag &= ~Flags;
217 ReleaseMpSpinLock (CpuData);
218 }
219
220 /**
221 Searches for the next blocking AP.
222
223 Search for the next AP that is put in blocking state by single-threaded StartupAllAPs().
224
225 @param NextNumber Pointer to the processor number of the next blocking AP.
226
227 @retval EFI_SUCCESS The next blocking AP has been found.
228 @retval EFI_NOT_FOUND No blocking AP exists.
229
230 **/
231 EFI_STATUS
GetNextBlockedNumber(OUT UINTN * NextNumber)232 GetNextBlockedNumber (
233 OUT UINTN *NextNumber
234 )
235 {
236 UINTN Number;
237 CPU_STATE CpuState;
238 CPU_DATA_BLOCK *CpuData;
239
240 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
241 CpuData = &mMpSystemData.CpuDatas[Number];
242 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
243 //
244 // Skip BSP
245 //
246 continue;
247 }
248
249 CpuState = GetApState (CpuData);
250 if (CpuState == CpuStateBlocked) {
251 *NextNumber = Number;
252 return EFI_SUCCESS;
253 }
254 }
255
256 return EFI_NOT_FOUND;
257 }
258
259 /**
260 Check if the APs state are finished, and update them to idle state
261 by StartupAllAPs().
262
263 **/
264 VOID
CheckAndUpdateAllAPsToIdleState(VOID)265 CheckAndUpdateAllAPsToIdleState (
266 VOID
267 )
268 {
269 UINTN ProcessorNumber;
270 UINTN NextNumber;
271 CPU_DATA_BLOCK *CpuData;
272 EFI_STATUS Status;
273 CPU_STATE CpuState;
274
275 for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
276 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
277 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
278 //
279 // Skip BSP
280 //
281 continue;
282 }
283
284 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
285 //
286 // Skip Disabled processors
287 //
288 continue;
289 }
290
291 CpuState = GetApState (CpuData);
292 if (CpuState == CpuStateFinished) {
293 mMpSystemData.FinishCount++;
294 if (mMpSystemData.SingleThread) {
295 Status = GetNextBlockedNumber (&NextNumber);
296 if (!EFI_ERROR (Status)) {
297 SetApState (&mMpSystemData.CpuDatas[NextNumber], CpuStateReady);
298 SetApProcedure (&mMpSystemData.CpuDatas[NextNumber],
299 mMpSystemData.Procedure,
300 mMpSystemData.ProcedureArgument);
301 //
302 // If this AP previous state is blocked, we should
303 // wake up this AP by sent a SIPI. and avoid
304 // re-involve the sleeping state. we must call
305 // SetApProcedure() first.
306 //
307 ResetProcessorToIdleState (&mMpSystemData.CpuDatas[NextNumber]);
308 }
309 }
310 SetApState (CpuData, CpuStateIdle);
311 }
312 }
313 }
314
315 /**
316 Check if all APs are in state CpuStateSleeping.
317
318 Return TRUE if all APs are in the CpuStateSleeping state. Do not
319 check the state of the BSP or any disabled APs.
320
321 @retval TRUE All APs are in CpuStateSleeping state.
322 @retval FALSE One or more APs are not in CpuStateSleeping state.
323
324 **/
325 BOOLEAN
CheckAllAPsSleeping(VOID)326 CheckAllAPsSleeping (
327 VOID
328 )
329 {
330 UINTN ProcessorNumber;
331 CPU_DATA_BLOCK *CpuData;
332
333 for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
334 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
335 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
336 //
337 // Skip BSP
338 //
339 continue;
340 }
341
342 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
343 //
344 // Skip Disabled processors
345 //
346 continue;
347 }
348
349 if (GetApState (CpuData) != CpuStateSleeping) {
350 return FALSE;
351 }
352 }
353 return TRUE;
354 }
355
356 /**
357 If the timeout expires before all APs returns from Procedure,
358 we should forcibly terminate the executing AP and fill FailedList back
359 by StartupAllAPs().
360
361 **/
362 VOID
ResetAllFailedAPs(VOID)363 ResetAllFailedAPs (
364 VOID
365 )
366 {
367 CPU_DATA_BLOCK *CpuData;
368 UINTN Number;
369 CPU_STATE CpuState;
370
371 if (mMpSystemData.FailedList != NULL) {
372 *mMpSystemData.FailedList = AllocatePool ((mMpSystemData.StartCount - mMpSystemData.FinishCount + 1) * sizeof(UINTN));
373 ASSERT (*mMpSystemData.FailedList != NULL);
374 }
375
376 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
377 CpuData = &mMpSystemData.CpuDatas[Number];
378 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
379 //
380 // Skip BSP
381 //
382 continue;
383 }
384
385 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
386 //
387 // Skip Disabled processors
388 //
389 continue;
390 }
391
392 CpuState = GetApState (CpuData);
393 if (CpuState != CpuStateIdle &&
394 CpuState != CpuStateSleeping) {
395 if (mMpSystemData.FailedList != NULL) {
396 (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex++] = Number;
397 }
398 ResetProcessorToIdleState (CpuData);
399 }
400 }
401
402 if (mMpSystemData.FailedList != NULL) {
403 (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex] = END_OF_CPU_LIST;
404 }
405 }
406
407 /**
408 This service retrieves the number of logical processor in the platform
409 and the number of those logical processors that are enabled on this boot.
410 This service may only be called from the BSP.
411
412 This function is used to retrieve the following information:
413 - The number of logical processors that are present in the system.
414 - The number of enabled logical processors in the system at the instant
415 this call is made.
416
417 Because MP Service Protocol provides services to enable and disable processors
418 dynamically, the number of enabled logical processors may vary during the
419 course of a boot session.
420
421 If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
422 If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
423 EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
424 is returned in NumberOfProcessors, the number of currently enabled processor
425 is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
426
427 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
428 instance.
429 @param[out] NumberOfProcessors Pointer to the total number of logical
430 processors in the system, including the BSP
431 and disabled APs.
432 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
433 processors that exist in system, including
434 the BSP.
435
436 @retval EFI_SUCCESS The number of logical processors and enabled
437 logical processors was retrieved.
438 @retval EFI_DEVICE_ERROR The calling processor is an AP.
439 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
440 @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
441
442 **/
443 EFI_STATUS
444 EFIAPI
GetNumberOfProcessors(IN EFI_MP_SERVICES_PROTOCOL * This,OUT UINTN * NumberOfProcessors,OUT UINTN * NumberOfEnabledProcessors)445 GetNumberOfProcessors (
446 IN EFI_MP_SERVICES_PROTOCOL *This,
447 OUT UINTN *NumberOfProcessors,
448 OUT UINTN *NumberOfEnabledProcessors
449 )
450 {
451 if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
452 return EFI_INVALID_PARAMETER;
453 }
454
455 if (!IsBSP ()) {
456 return EFI_DEVICE_ERROR;
457 }
458
459 *NumberOfProcessors = mMpSystemData.NumberOfProcessors;
460 *NumberOfEnabledProcessors = mMpSystemData.NumberOfEnabledProcessors;
461 return EFI_SUCCESS;
462 }
463
464 /**
465 Gets detailed MP-related information on the requested processor at the
466 instant this call is made. This service may only be called from the BSP.
467
468 This service retrieves detailed MP-related information about any processor
469 on the platform. Note the following:
470 - The processor information may change during the course of a boot session.
471 - The information presented here is entirely MP related.
472
473 Information regarding the number of caches and their sizes, frequency of operation,
474 slot numbers is all considered platform-related information and is not provided
475 by this service.
476
477 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
478 instance.
479 @param[in] ProcessorNumber The handle number of processor.
480 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
481 the requested processor is deposited.
482
483 @retval EFI_SUCCESS Processor information was returned.
484 @retval EFI_DEVICE_ERROR The calling processor is an AP.
485 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
486 @retval EFI_NOT_FOUND The processor with the handle specified by
487 ProcessorNumber does not exist in the platform.
488
489 **/
490 EFI_STATUS
491 EFIAPI
GetProcessorInfo(IN EFI_MP_SERVICES_PROTOCOL * This,IN UINTN ProcessorNumber,OUT EFI_PROCESSOR_INFORMATION * ProcessorInfoBuffer)492 GetProcessorInfo (
493 IN EFI_MP_SERVICES_PROTOCOL *This,
494 IN UINTN ProcessorNumber,
495 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
496 )
497 {
498 if (ProcessorInfoBuffer == NULL) {
499 return EFI_INVALID_PARAMETER;
500 }
501
502 if (!IsBSP ()) {
503 return EFI_DEVICE_ERROR;
504 }
505
506 if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
507 return EFI_NOT_FOUND;
508 }
509
510 CopyMem (ProcessorInfoBuffer, &mMpSystemData.CpuDatas[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION));
511 return EFI_SUCCESS;
512 }
513
514 /**
515 This service executes a caller provided function on all enabled APs. APs can
516 run either simultaneously or one at a time in sequence. This service supports
517 both blocking and non-blocking requests. The non-blocking requests use EFI
518 events so the BSP can detect when the APs have finished. This service may only
519 be called from the BSP.
520
521 This function is used to dispatch all the enabled APs to the function specified
522 by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
523 immediately and Procedure is not started on any AP.
524
525 If SingleThread is TRUE, all the enabled APs execute the function specified by
526 Procedure one by one, in ascending order of processor handle number. Otherwise,
527 all the enabled APs execute the function specified by Procedure simultaneously.
528
529 If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
530 APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking
531 mode, and the BSP returns from this service without waiting for APs. If a
532 non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
533 is signaled, then EFI_UNSUPPORTED must be returned.
534
535 If the timeout specified by TimeoutInMicroseconds expires before all APs return
536 from Procedure, then Procedure on the failed APs is terminated. All enabled APs
537 are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
538 and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
539 content points to the list of processor handle numbers in which Procedure was
540 terminated.
541
542 Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
543 to make sure that the nature of the code that is executed on the BSP and the
544 dispatched APs is well controlled. The MP Services Protocol does not guarantee
545 that the Procedure function is MP-safe. Hence, the tasks that can be run in
546 parallel are limited to certain independent tasks and well-controlled exclusive
547 code. EFI services and protocols may not be called by APs unless otherwise
548 specified.
549
550 In blocking execution mode, BSP waits until all APs finish or
551 TimeoutInMicroseconds expires.
552
553 In non-blocking execution mode, BSP is freed to return to the caller and then
554 proceed to the next task without having to wait for APs. The following
555 sequence needs to occur in a non-blocking execution mode:
556
557 -# The caller that intends to use this MP Services Protocol in non-blocking
558 mode creates WaitEvent by calling the EFI CreateEvent() service. The caller
559 invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
560 is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
561 the function specified by Procedure to be started on all the enabled APs,
562 and releases the BSP to continue with other tasks.
563 -# The caller can use the CheckEvent() and WaitForEvent() services to check
564 the state of the WaitEvent created in step 1.
565 -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
566 Service signals WaitEvent by calling the EFI SignalEvent() function. If
567 FailedCpuList is not NULL, its content is available when WaitEvent is
568 signaled. If all APs returned from Procedure prior to the timeout, then
569 FailedCpuList is set to NULL. If not all APs return from Procedure before
570 the timeout, then FailedCpuList is filled in with the list of the failed
571 APs. The buffer is allocated by MP Service Protocol using AllocatePool().
572 It is the caller's responsibility to free the buffer with FreePool() service.
573 -# This invocation of SignalEvent() function informs the caller that invoked
574 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
575 the specified task or a timeout occurred. The contents of FailedCpuList
576 can be examined to determine which APs did not complete the specified task
577 prior to the timeout.
578
579 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
580 instance.
581 @param[in] Procedure A pointer to the function to be run on
582 enabled APs of the system. See type
583 EFI_AP_PROCEDURE.
584 @param[in] SingleThread If TRUE, then all the enabled APs execute
585 the function specified by Procedure one by
586 one, in ascending order of processor handle
587 number. If FALSE, then all the enabled APs
588 execute the function specified by Procedure
589 simultaneously.
590 @param[in] WaitEvent The event created by the caller with CreateEvent()
591 service. If it is NULL, then execute in
592 blocking mode. BSP waits until all APs finish
593 or TimeoutInMicroseconds expires. If it's
594 not NULL, then execute in non-blocking mode.
595 BSP requests the function specified by
596 Procedure to be started on all the enabled
597 APs, and go on executing immediately. If
598 all return from Procedure, or TimeoutInMicroseconds
599 expires, this event is signaled. The BSP
600 can use the CheckEvent() or WaitForEvent()
601 services to check the state of event. Type
602 EFI_EVENT is defined in CreateEvent() in
603 the Unified Extensible Firmware Interface
604 Specification.
605 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
606 APs to return from Procedure, either for
607 blocking or non-blocking mode. Zero means
608 infinity. If the timeout expires before
609 all APs return from Procedure, then Procedure
610 on the failed APs is terminated. All enabled
611 APs are available for next function assigned
612 by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
613 or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
614 If the timeout expires in blocking mode,
615 BSP returns EFI_TIMEOUT. If the timeout
616 expires in non-blocking mode, WaitEvent
617 is signaled with SignalEvent().
618 @param[in] ProcedureArgument The parameter passed into Procedure for
619 all APs.
620 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
621 if all APs finish successfully, then its
622 content is set to NULL. If not all APs
623 finish before timeout expires, then its
624 content is set to address of the buffer
625 holding handle numbers of the failed APs.
626 The buffer is allocated by MP Service Protocol,
627 and it's the caller's responsibility to
628 free the buffer with FreePool() service.
629 In blocking mode, it is ready for consumption
630 when the call returns. In non-blocking mode,
631 it is ready when WaitEvent is signaled. The
632 list of failed CPU is terminated by
633 END_OF_CPU_LIST.
634
635 @retval EFI_SUCCESS In blocking mode, all APs have finished before
636 the timeout expired.
637 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
638 to all enabled APs.
639 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
640 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
641 signaled.
642 @retval EFI_DEVICE_ERROR Caller processor is AP.
643 @retval EFI_NOT_STARTED No enabled APs exist in the system.
644 @retval EFI_NOT_READY Any enabled APs are busy.
645 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
646 all enabled APs have finished.
647 @retval EFI_INVALID_PARAMETER Procedure is NULL.
648
649 **/
650 EFI_STATUS
651 EFIAPI
StartupAllAPs(IN EFI_MP_SERVICES_PROTOCOL * This,IN EFI_AP_PROCEDURE Procedure,IN BOOLEAN SingleThread,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT UINTN ** FailedCpuList OPTIONAL)652 StartupAllAPs (
653 IN EFI_MP_SERVICES_PROTOCOL *This,
654 IN EFI_AP_PROCEDURE Procedure,
655 IN BOOLEAN SingleThread,
656 IN EFI_EVENT WaitEvent OPTIONAL,
657 IN UINTN TimeoutInMicroseconds,
658 IN VOID *ProcedureArgument OPTIONAL,
659 OUT UINTN **FailedCpuList OPTIONAL
660 )
661 {
662 EFI_STATUS Status;
663 CPU_DATA_BLOCK *CpuData;
664 UINTN Number;
665 CPU_STATE APInitialState;
666 CPU_STATE CpuState;
667
668 CpuData = NULL;
669
670 if (FailedCpuList != NULL) {
671 *FailedCpuList = NULL;
672 }
673
674 if (!IsBSP ()) {
675 return EFI_DEVICE_ERROR;
676 }
677
678 if (mMpSystemData.NumberOfProcessors == 1) {
679 return EFI_NOT_STARTED;
680 }
681
682 if (Procedure == NULL) {
683 return EFI_INVALID_PARAMETER;
684 }
685
686 //
687 // temporarily stop checkAllAPsStatus for avoid resource dead-lock.
688 //
689 mStopCheckAllAPsStatus = TRUE;
690
691 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
692 CpuData = &mMpSystemData.CpuDatas[Number];
693 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
694 //
695 // Skip BSP
696 //
697 continue;
698 }
699
700 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
701 //
702 // Skip Disabled processors
703 //
704 continue;
705 }
706
707 CpuState = GetApState (CpuData);
708 if (CpuState != CpuStateIdle &&
709 CpuState != CpuStateSleeping) {
710 return EFI_NOT_READY;
711 }
712 }
713
714 mMpSystemData.Procedure = Procedure;
715 mMpSystemData.ProcedureArgument = ProcedureArgument;
716 mMpSystemData.WaitEvent = WaitEvent;
717 mMpSystemData.Timeout = TimeoutInMicroseconds;
718 mMpSystemData.TimeoutActive = (BOOLEAN) (TimeoutInMicroseconds != 0);
719 mMpSystemData.FinishCount = 0;
720 mMpSystemData.StartCount = 0;
721 mMpSystemData.SingleThread = SingleThread;
722 mMpSystemData.FailedList = FailedCpuList;
723 mMpSystemData.FailedListIndex = 0;
724 APInitialState = CpuStateReady;
725
726 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
727 CpuData = &mMpSystemData.CpuDatas[Number];
728 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
729 //
730 // Skip BSP
731 //
732 continue;
733 }
734
735 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
736 //
737 // Skip Disabled processors
738 //
739 continue;
740 }
741
742 //
743 // Get APs prepared, and put failing APs into FailedCpuList
744 // if "SingleThread", only 1 AP will put to ready state, other AP will be put to ready
745 // state 1 by 1, until the previous 1 finished its task
746 // if not "SingleThread", all APs are put to ready state from the beginning
747 //
748 CpuState = GetApState (CpuData);
749 if (CpuState == CpuStateIdle ||
750 CpuState == CpuStateSleeping) {
751 mMpSystemData.StartCount++;
752
753 SetApState (CpuData, APInitialState);
754
755 if (APInitialState == CpuStateReady) {
756 SetApProcedure (CpuData, Procedure, ProcedureArgument);
757 //
758 // If this AP previous state is Sleeping, we should
759 // wake up this AP by sent a SIPI. and avoid
760 // re-involve the sleeping state. we must call
761 // SetApProcedure() first.
762 //
763 if (CpuState == CpuStateSleeping) {
764 ResetProcessorToIdleState (CpuData);
765 }
766 }
767
768 if (SingleThread) {
769 APInitialState = CpuStateBlocked;
770 }
771 }
772 }
773
774 mStopCheckAllAPsStatus = FALSE;
775
776 if (WaitEvent != NULL) {
777 //
778 // non blocking
779 //
780 return EFI_SUCCESS;
781 }
782
783 //
784 // Blocking temporarily stop CheckAllAPsStatus()
785 //
786 mStopCheckAllAPsStatus = TRUE;
787
788 while (TRUE) {
789 CheckAndUpdateAllAPsToIdleState ();
790 if (mMpSystemData.FinishCount == mMpSystemData.StartCount) {
791 Status = EFI_SUCCESS;
792 goto Done;
793 }
794
795 //
796 // task timeout
797 //
798 if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {
799 ResetAllFailedAPs();
800 Status = EFI_TIMEOUT;
801 goto Done;
802 }
803
804 MicroSecondDelay (gPollInterval);
805 mMpSystemData.Timeout -= gPollInterval;
806 }
807
808 Done:
809
810 return Status;
811 }
812
813 /**
814 This service lets the caller get one enabled AP to execute a caller-provided
815 function. The caller can request the BSP to either wait for the completion
816 of the AP or just proceed with the next task by using the EFI event mechanism.
817 See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
818 execution support. This service may only be called from the BSP.
819
820 This function is used to dispatch one enabled AP to the function specified by
821 Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
822 is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
823 TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
824 BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
825 is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
826 then EFI_UNSUPPORTED must be returned.
827
828 If the timeout specified by TimeoutInMicroseconds expires before the AP returns
829 from Procedure, then execution of Procedure by the AP is terminated. The AP is
830 available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
831 EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
832
833 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
834 instance.
835 @param[in] Procedure A pointer to the function to be run on
836 enabled APs of the system. See type
837 EFI_AP_PROCEDURE.
838 @param[in] ProcessorNumber The handle number of the AP. The range is
839 from 0 to the total number of logical
840 processors minus 1. The total number of
841 logical processors can be retrieved by
842 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
843 @param[in] WaitEvent The event created by the caller with CreateEvent()
844 service. If it is NULL, then execute in
845 blocking mode. BSP waits until all APs finish
846 or TimeoutInMicroseconds expires. If it's
847 not NULL, then execute in non-blocking mode.
848 BSP requests the function specified by
849 Procedure to be started on all the enabled
850 APs, and go on executing immediately. If
851 all return from Procedure or TimeoutInMicroseconds
852 expires, this event is signaled. The BSP
853 can use the CheckEvent() or WaitForEvent()
854 services to check the state of event. Type
855 EFI_EVENT is defined in CreateEvent() in
856 the Unified Extensible Firmware Interface
857 Specification.
858 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
859 APs to return from Procedure, either for
860 blocking or non-blocking mode. Zero means
861 infinity. If the timeout expires before
862 all APs return from Procedure, then Procedure
863 on the failed APs is terminated. All enabled
864 APs are available for next function assigned
865 by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
866 or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
867 If the timeout expires in blocking mode,
868 BSP returns EFI_TIMEOUT. If the timeout
869 expires in non-blocking mode, WaitEvent
870 is signaled with SignalEvent().
871 @param[in] ProcedureArgument The parameter passed into Procedure for
872 all APs.
873 @param[out] Finished If NULL, this parameter is ignored. In
874 blocking mode, this parameter is ignored.
875 In non-blocking mode, if AP returns from
876 Procedure before the timeout expires, its
877 content is set to TRUE. Otherwise, the
878 value is set to FALSE. The caller can
879 determine if the AP returned from Procedure
880 by evaluating this value.
881
882 @retval EFI_SUCCESS In blocking mode, specified AP finished before
883 the timeout expires.
884 @retval EFI_SUCCESS In non-blocking mode, the function has been
885 dispatched to specified AP.
886 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
887 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
888 signaled.
889 @retval EFI_DEVICE_ERROR The calling processor is an AP.
890 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
891 the specified AP has finished.
892 @retval EFI_NOT_READY The specified AP is busy.
893 @retval EFI_NOT_FOUND The processor with the handle specified by
894 ProcessorNumber does not exist.
895 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
896 @retval EFI_INVALID_PARAMETER Procedure is NULL.
897
898 **/
899 EFI_STATUS
900 EFIAPI
StartupThisAP(IN EFI_MP_SERVICES_PROTOCOL * This,IN EFI_AP_PROCEDURE Procedure,IN UINTN ProcessorNumber,IN EFI_EVENT WaitEvent OPTIONAL,IN UINTN TimeoutInMicroseconds,IN VOID * ProcedureArgument OPTIONAL,OUT BOOLEAN * Finished OPTIONAL)901 StartupThisAP (
902 IN EFI_MP_SERVICES_PROTOCOL *This,
903 IN EFI_AP_PROCEDURE Procedure,
904 IN UINTN ProcessorNumber,
905 IN EFI_EVENT WaitEvent OPTIONAL,
906 IN UINTN TimeoutInMicroseconds,
907 IN VOID *ProcedureArgument OPTIONAL,
908 OUT BOOLEAN *Finished OPTIONAL
909 )
910 {
911 CPU_DATA_BLOCK *CpuData;
912 CPU_STATE CpuState;
913
914 CpuData = NULL;
915
916 if (Finished != NULL) {
917 *Finished = FALSE;
918 }
919
920 if (!IsBSP ()) {
921 return EFI_DEVICE_ERROR;
922 }
923
924 if (Procedure == NULL) {
925 return EFI_INVALID_PARAMETER;
926 }
927
928 if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
929 return EFI_NOT_FOUND;
930 }
931
932 //
933 // temporarily stop checkAllAPsStatus for avoid resource dead-lock.
934 //
935 mStopCheckAllAPsStatus = TRUE;
936
937 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
938 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT) ||
939 !TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
940 return EFI_INVALID_PARAMETER;
941 }
942
943 CpuState = GetApState (CpuData);
944 if (CpuState != CpuStateIdle &&
945 CpuState != CpuStateSleeping) {
946 return EFI_NOT_READY;
947 }
948
949 SetApState (CpuData, CpuStateReady);
950
951 SetApProcedure (CpuData, Procedure, ProcedureArgument);
952 //
953 // If this AP previous state is Sleeping, we should
954 // wake up this AP by sent a SIPI. and avoid
955 // re-involve the sleeping state. we must call
956 // SetApProcedure() first.
957 //
958 if (CpuState == CpuStateSleeping) {
959 ResetProcessorToIdleState (CpuData);
960 }
961
962 CpuData->Timeout = TimeoutInMicroseconds;
963 CpuData->WaitEvent = WaitEvent;
964 CpuData->TimeoutActive = (BOOLEAN) (TimeoutInMicroseconds != 0);
965 CpuData->Finished = Finished;
966
967 mStopCheckAllAPsStatus = FALSE;
968
969 if (WaitEvent != NULL) {
970 //
971 // Non Blocking
972 //
973 return EFI_SUCCESS;
974 }
975
976 //
977 // Blocking
978 //
979 while (TRUE) {
980 if (GetApState (CpuData) == CpuStateFinished) {
981 SetApState (CpuData, CpuStateIdle);
982 break;
983 }
984
985 if (CpuData->TimeoutActive && CpuData->Timeout < 0) {
986 ResetProcessorToIdleState (CpuData);
987 return EFI_TIMEOUT;
988 }
989
990 MicroSecondDelay (gPollInterval);
991 CpuData->Timeout -= gPollInterval;
992 }
993
994 return EFI_SUCCESS;
995 }
996
997 /**
998 This service switches the requested AP to be the BSP from that point onward.
999 This service changes the BSP for all purposes. This call can only be performed
1000 by the current BSP.
1001
1002 This service switches the requested AP to be the BSP from that point onward.
1003 This service changes the BSP for all purposes. The new BSP can take over the
1004 execution of the old BSP and continue seamlessly from where the old one left
1005 off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
1006 is signaled.
1007
1008 If the BSP cannot be switched prior to the return from this service, then
1009 EFI_UNSUPPORTED must be returned.
1010
1011 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
1012 @param[in] ProcessorNumber The handle number of AP that is to become the new
1013 BSP. The range is from 0 to the total number of
1014 logical processors minus 1. The total number of
1015 logical processors can be retrieved by
1016 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
1017 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
1018 enabled AP. Otherwise, it will be disabled.
1019
1020 @retval EFI_SUCCESS BSP successfully switched.
1021 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
1022 this service returning.
1023 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
1024 @retval EFI_SUCCESS The calling processor is an AP.
1025 @retval EFI_NOT_FOUND The processor with the handle specified by
1026 ProcessorNumber does not exist.
1027 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
1028 a disabled AP.
1029 @retval EFI_NOT_READY The specified AP is busy.
1030
1031 **/
1032 EFI_STATUS
1033 EFIAPI
SwitchBSP(IN EFI_MP_SERVICES_PROTOCOL * This,IN UINTN ProcessorNumber,IN BOOLEAN EnableOldBSP)1034 SwitchBSP (
1035 IN EFI_MP_SERVICES_PROTOCOL *This,
1036 IN UINTN ProcessorNumber,
1037 IN BOOLEAN EnableOldBSP
1038 )
1039 {
1040 //
1041 // Current always return unsupported.
1042 //
1043 return EFI_UNSUPPORTED;
1044 }
1045
1046 /**
1047 This service lets the caller enable or disable an AP from this point onward.
1048 This service may only be called from the BSP.
1049
1050 This service allows the caller enable or disable an AP from this point onward.
1051 The caller can optionally specify the health status of the AP by Health. If
1052 an AP is being disabled, then the state of the disabled AP is implementation
1053 dependent. If an AP is enabled, then the implementation must guarantee that a
1054 complete initialization sequence is performed on the AP, so the AP is in a state
1055 that is compatible with an MP operating system. This service may not be supported
1056 after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
1057
1058 If the enable or disable AP operation cannot be completed prior to the return
1059 from this service, then EFI_UNSUPPORTED must be returned.
1060
1061 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
1062 @param[in] ProcessorNumber The handle number of AP that is to become the new
1063 BSP. The range is from 0 to the total number of
1064 logical processors minus 1. The total number of
1065 logical processors can be retrieved by
1066 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
1067 @param[in] EnableAP Specifies the new state for the processor for
1068 enabled, FALSE for disabled.
1069 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
1070 the new health status of the AP. This flag
1071 corresponds to StatusFlag defined in
1072 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
1073 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
1074 bits are ignored. If it is NULL, this parameter
1075 is ignored.
1076
1077 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
1078 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
1079 prior to this service returning.
1080 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
1081 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1082 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
1083 does not exist.
1084 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
1085
1086 **/
1087 EFI_STATUS
1088 EFIAPI
EnableDisableAP(IN EFI_MP_SERVICES_PROTOCOL * This,IN UINTN ProcessorNumber,IN BOOLEAN EnableAP,IN UINT32 * HealthFlag OPTIONAL)1089 EnableDisableAP (
1090 IN EFI_MP_SERVICES_PROTOCOL *This,
1091 IN UINTN ProcessorNumber,
1092 IN BOOLEAN EnableAP,
1093 IN UINT32 *HealthFlag OPTIONAL
1094 )
1095 {
1096 CPU_DATA_BLOCK *CpuData;
1097 BOOLEAN TempStopCheckState;
1098 CPU_STATE CpuState;
1099
1100 CpuData = NULL;
1101 TempStopCheckState = FALSE;
1102
1103 if (!IsBSP ()) {
1104 return EFI_DEVICE_ERROR;
1105 }
1106
1107 if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
1108 return EFI_NOT_FOUND;
1109 }
1110
1111 //
1112 // temporarily stop checkAllAPsStatus for initialize parameters.
1113 //
1114 if (!mStopCheckAllAPsStatus) {
1115 mStopCheckAllAPsStatus = TRUE;
1116 TempStopCheckState = TRUE;
1117 }
1118
1119 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1120 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
1121 return EFI_INVALID_PARAMETER;
1122 }
1123
1124 CpuState = GetApState (CpuData);
1125 if (CpuState != CpuStateIdle &&
1126 CpuState != CpuStateSleeping) {
1127 return EFI_UNSUPPORTED;
1128 }
1129
1130 if (EnableAP) {
1131 if (!(TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT))) {
1132 mMpSystemData.NumberOfEnabledProcessors++;
1133 }
1134 CpuStatusFlagOr (CpuData, PROCESSOR_ENABLED_BIT);
1135 } else {
1136 if (TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
1137 mMpSystemData.NumberOfEnabledProcessors--;
1138 }
1139 CpuStatusFlagAndNot (CpuData, PROCESSOR_ENABLED_BIT);
1140 }
1141
1142 if (HealthFlag != NULL) {
1143 CpuStatusFlagAndNot (CpuData, (UINT32)~PROCESSOR_HEALTH_STATUS_BIT);
1144 CpuStatusFlagOr (CpuData, (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT));
1145 }
1146
1147 if (TempStopCheckState) {
1148 mStopCheckAllAPsStatus = FALSE;
1149 }
1150
1151 return EFI_SUCCESS;
1152 }
1153
1154 /**
1155 This return the handle number for the calling processor. This service may be
1156 called from the BSP and APs.
1157
1158 This service returns the processor handle number for the calling processor.
1159 The returned value is in the range from 0 to the total number of logical
1160 processors minus 1. The total number of logical processors can be retrieved
1161 with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
1162 called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
1163 is returned. Otherwise, the current processors handle number is returned in
1164 ProcessorNumber, and EFI_SUCCESS is returned.
1165
1166 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
1167 @param[out] ProcessorNumber The handle number of AP that is to become the new
1168 BSP. The range is from 0 to the total number of
1169 logical processors minus 1. The total number of
1170 logical processors can be retrieved by
1171 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
1172
1173 @retval EFI_SUCCESS The current processor handle number was returned
1174 in ProcessorNumber.
1175 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
1176
1177 **/
1178 EFI_STATUS
1179 EFIAPI
WhoAmI(IN EFI_MP_SERVICES_PROTOCOL * This,OUT UINTN * ProcessorNumber)1180 WhoAmI (
1181 IN EFI_MP_SERVICES_PROTOCOL *This,
1182 OUT UINTN *ProcessorNumber
1183 )
1184 {
1185 UINTN Index;
1186 UINT32 ProcessorId;
1187
1188 if (ProcessorNumber == NULL) {
1189 return EFI_INVALID_PARAMETER;
1190 }
1191
1192 ProcessorId = GetApicId ();
1193 for (Index = 0; Index < mMpSystemData.NumberOfProcessors; Index++) {
1194 if (mMpSystemData.CpuDatas[Index].Info.ProcessorId == ProcessorId) {
1195 break;
1196 }
1197 }
1198
1199 *ProcessorNumber = Index;
1200 return EFI_SUCCESS;
1201 }
1202
1203 /**
1204 Terminate AP's task and set it to idle state.
1205
1206 This function terminates AP's task due to timeout by sending INIT-SIPI,
1207 and sends it to idle state.
1208
1209 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
1210
1211 **/
1212 VOID
ResetProcessorToIdleState(IN CPU_DATA_BLOCK * CpuData)1213 ResetProcessorToIdleState (
1214 IN CPU_DATA_BLOCK *CpuData
1215 )
1216 {
1217 ResetApStackless ((UINT32)CpuData->Info.ProcessorId);
1218 }
1219
1220 /**
1221 Application Processors do loop routine
1222 after switch to its own stack.
1223
1224 @param Context1 A pointer to the context to pass into the function.
1225 @param Context2 A pointer to the context to pass into the function.
1226
1227 **/
1228 VOID
ProcessorToIdleState(IN VOID * Context1,OPTIONAL IN VOID * Context2 OPTIONAL)1229 ProcessorToIdleState (
1230 IN VOID *Context1, OPTIONAL
1231 IN VOID *Context2 OPTIONAL
1232 )
1233 {
1234 UINTN ProcessorNumber;
1235 CPU_DATA_BLOCK *CpuData;
1236 EFI_AP_PROCEDURE Procedure;
1237 volatile VOID *ProcedureArgument;
1238
1239 AsmApDoneWithCommonStack ();
1240
1241 while (!mAPsAlreadyInitFinished) {
1242 CpuPause ();
1243 }
1244
1245 WhoAmI (&mMpServicesTemplate, &ProcessorNumber);
1246 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1247
1248 //
1249 // Avoid forcibly reset AP caused the AP got lock not release.
1250 //
1251 if (CpuData->LockSelf == (INTN) GetApicId ()) {
1252 ReleaseSpinLock (&CpuData->CpuDataLock);
1253 }
1254
1255 //
1256 // Avoid forcibly reset AP caused the timeout AP State is not
1257 // updated.
1258 //
1259 GetMpSpinLock (CpuData);
1260 if (CpuData->State == CpuStateBusy) {
1261 CpuData->Procedure = NULL;
1262 }
1263 CpuData->State = CpuStateIdle;
1264 ReleaseMpSpinLock (CpuData);
1265
1266 while (TRUE) {
1267 GetMpSpinLock (CpuData);
1268 ProcedureArgument = CpuData->Parameter;
1269 Procedure = CpuData->Procedure;
1270 ReleaseMpSpinLock (CpuData);
1271
1272 if (Procedure != NULL) {
1273 SetApState (CpuData, CpuStateBusy);
1274
1275 Procedure ((VOID*) ProcedureArgument);
1276
1277 GetMpSpinLock (CpuData);
1278 CpuData->Procedure = NULL;
1279 CpuData->State = CpuStateFinished;
1280 ReleaseMpSpinLock (CpuData);
1281 } else {
1282 //
1283 // if no procedure to execution, we simply put AP
1284 // into sleeping state, and waiting BSP sent SIPI.
1285 //
1286 GetMpSpinLock (CpuData);
1287 if (CpuData->State == CpuStateIdle) {
1288 CpuData->State = CpuStateSleeping;
1289 }
1290 ReleaseMpSpinLock (CpuData);
1291 }
1292
1293 if (GetApState (CpuData) == CpuStateSleeping) {
1294 CpuSleep ();
1295 }
1296
1297 CpuPause ();
1298 }
1299
1300 CpuSleep ();
1301 CpuDeadLoop ();
1302 }
1303
1304 /**
1305 Checks AP' status periodically.
1306
1307 This function is triggerred by timer perodically to check the
1308 state of AP forStartupThisAP() executed in non-blocking mode.
1309
1310 @param Event Event triggered.
1311 @param Context Parameter passed with the event.
1312
1313 **/
1314 VOID
1315 EFIAPI
CheckThisAPStatus(IN EFI_EVENT Event,IN VOID * Context)1316 CheckThisAPStatus (
1317 IN EFI_EVENT Event,
1318 IN VOID *Context
1319 )
1320 {
1321 CPU_DATA_BLOCK *CpuData;
1322 CPU_STATE CpuState;
1323
1324 CpuData = (CPU_DATA_BLOCK *) Context;
1325 if (CpuData->TimeoutActive) {
1326 CpuData->Timeout -= gPollInterval;
1327 }
1328
1329 CpuState = GetApState (CpuData);
1330
1331 if (CpuState == CpuStateFinished) {
1332 if (CpuData->Finished) {
1333 *CpuData->Finished = TRUE;
1334 }
1335 SetApState (CpuData, CpuStateIdle);
1336 goto out;
1337 }
1338
1339 if (CpuData->TimeoutActive && CpuData->Timeout < 0) {
1340 if (CpuState != CpuStateIdle &&
1341 CpuData->Finished) {
1342 *CpuData->Finished = FALSE;
1343 }
1344 ResetProcessorToIdleState (CpuData);
1345 goto out;
1346 }
1347
1348 return;
1349
1350 out:
1351 CpuData->TimeoutActive = FALSE;
1352 gBS->SignalEvent (CpuData->WaitEvent);
1353 CpuData->WaitEvent = NULL;
1354 }
1355
1356 /**
1357 Checks APs' status periodically.
1358
1359 This function is triggerred by timer perodically to check the
1360 state of APs for StartupAllAPs() executed in non-blocking mode.
1361
1362 @param Event Event triggered.
1363 @param Context Parameter passed with the event.
1364
1365 **/
1366 VOID
1367 EFIAPI
CheckAllAPsStatus(IN EFI_EVENT Event,IN VOID * Context)1368 CheckAllAPsStatus (
1369 IN EFI_EVENT Event,
1370 IN VOID *Context
1371 )
1372 {
1373 CPU_DATA_BLOCK *CpuData;
1374 UINTN Number;
1375 EFI_STATUS Status;
1376
1377 if (mMpSystemData.TimeoutActive) {
1378 mMpSystemData.Timeout -= gPollInterval;
1379 }
1380
1381 if (mStopCheckAllAPsStatus) {
1382 return;
1383 }
1384
1385 //
1386 // avoid next timer enter.
1387 //
1388 Status = gBS->SetTimer (
1389 mMpSystemData.CheckAllAPsEvent,
1390 TimerCancel,
1391 0
1392 );
1393 ASSERT_EFI_ERROR (Status);
1394
1395 if (mMpSystemData.WaitEvent != NULL) {
1396 CheckAndUpdateAllAPsToIdleState ();
1397 //
1398 // task timeout
1399 //
1400 if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {
1401 ResetAllFailedAPs();
1402 //
1403 // force exit
1404 //
1405 mMpSystemData.FinishCount = mMpSystemData.StartCount;
1406 }
1407
1408 if (mMpSystemData.FinishCount != mMpSystemData.StartCount) {
1409 goto EXIT;
1410 }
1411
1412 mMpSystemData.TimeoutActive = FALSE;
1413 gBS->SignalEvent (mMpSystemData.WaitEvent);
1414 mMpSystemData.WaitEvent = NULL;
1415 mStopCheckAllAPsStatus = TRUE;
1416
1417 goto EXIT;
1418 }
1419
1420 //
1421 // check each AP status for StartupThisAP
1422 //
1423 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
1424 CpuData = &mMpSystemData.CpuDatas[Number];
1425 if (CpuData->WaitEvent) {
1426 CheckThisAPStatus (NULL, (VOID *)CpuData);
1427 }
1428 }
1429
1430 EXIT:
1431 Status = gBS->SetTimer (
1432 mMpSystemData.CheckAllAPsEvent,
1433 TimerPeriodic,
1434 EFI_TIMER_PERIOD_MICROSECONDS (100)
1435 );
1436 ASSERT_EFI_ERROR (Status);
1437 }
1438
1439 /**
1440 Application Processor C code entry point.
1441
1442 **/
1443 VOID
1444 EFIAPI
ApEntryPointInC(VOID)1445 ApEntryPointInC (
1446 VOID
1447 )
1448 {
1449 VOID* TopOfApStack;
1450 UINTN ProcessorNumber;
1451
1452 if (!mAPsAlreadyInitFinished) {
1453 FillInProcessorInformation (FALSE, mMpSystemData.NumberOfProcessors);
1454 TopOfApStack = (UINT8*)mApStackStart + gApStackSize;
1455 mApStackStart = TopOfApStack;
1456
1457 //
1458 // Store the Stack address, when reset the AP, We can found the original address.
1459 //
1460 mMpSystemData.CpuDatas[mMpSystemData.NumberOfProcessors].TopOfStack = TopOfApStack;
1461 mMpSystemData.NumberOfProcessors++;
1462 mMpSystemData.NumberOfEnabledProcessors++;
1463 } else {
1464 WhoAmI (&mMpServicesTemplate, &ProcessorNumber);
1465 //
1466 // Get the original stack address.
1467 //
1468 TopOfApStack = mMpSystemData.CpuDatas[ProcessorNumber].TopOfStack;
1469 }
1470
1471 SwitchStack (
1472 (SWITCH_STACK_ENTRY_POINT)(UINTN)ProcessorToIdleState,
1473 NULL,
1474 NULL,
1475 TopOfApStack);
1476 }
1477
1478 /**
1479 This function is called by all processors (both BSP and AP) once and collects MP related data.
1480
1481 @param Bsp TRUE if the CPU is BSP
1482 @param ProcessorNumber The specific processor number
1483
1484 @retval EFI_SUCCESS Data for the processor collected and filled in
1485
1486 **/
1487 EFI_STATUS
FillInProcessorInformation(IN BOOLEAN Bsp,IN UINTN ProcessorNumber)1488 FillInProcessorInformation (
1489 IN BOOLEAN Bsp,
1490 IN UINTN ProcessorNumber
1491 )
1492 {
1493 CPU_DATA_BLOCK *CpuData;
1494 UINT32 ProcessorId;
1495
1496 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1497 ProcessorId = GetApicId ();
1498 CpuData->Info.ProcessorId = ProcessorId;
1499 CpuData->Info.StatusFlag = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT;
1500 if (Bsp) {
1501 CpuData->Info.StatusFlag |= PROCESSOR_AS_BSP_BIT;
1502 }
1503 CpuData->Info.Location.Package = ProcessorId;
1504 CpuData->Info.Location.Core = 0;
1505 CpuData->Info.Location.Thread = 0;
1506 CpuData->State = Bsp ? CpuStateBusy : CpuStateIdle;
1507
1508 CpuData->Procedure = NULL;
1509 CpuData->Parameter = NULL;
1510 InitializeSpinLock (&CpuData->CpuDataLock);
1511 CpuData->LockSelf = -1;
1512
1513 return EFI_SUCCESS;
1514 }
1515
1516 /**
1517 Prepare the System Data.
1518
1519 @retval EFI_SUCCESS the System Data finished initilization.
1520
1521 **/
1522 EFI_STATUS
InitMpSystemData(VOID)1523 InitMpSystemData (
1524 VOID
1525 )
1526 {
1527 EFI_STATUS Status;
1528
1529 ZeroMem (&mMpSystemData, sizeof (MP_SYSTEM_DATA));
1530
1531 mMpSystemData.NumberOfProcessors = 1;
1532 mMpSystemData.NumberOfEnabledProcessors = 1;
1533
1534 mMpSystemData.CpuDatas = AllocateZeroPool (sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber);
1535 ASSERT(mMpSystemData.CpuDatas != NULL);
1536
1537 Status = gBS->CreateEvent (
1538 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1539 TPL_CALLBACK,
1540 CheckAllAPsStatus,
1541 NULL,
1542 &mMpSystemData.CheckAllAPsEvent
1543 );
1544 ASSERT_EFI_ERROR (Status);
1545
1546 //
1547 // Set timer to check all APs status.
1548 //
1549 Status = gBS->SetTimer (
1550 mMpSystemData.CheckAllAPsEvent,
1551 TimerPeriodic,
1552 EFI_TIMER_PERIOD_MICROSECONDS (100)
1553 );
1554 ASSERT_EFI_ERROR (Status);
1555
1556 //
1557 // BSP
1558 //
1559 FillInProcessorInformation (TRUE, 0);
1560
1561 return EFI_SUCCESS;
1562 }
1563
1564 /**
1565 Collects BIST data from HOB.
1566
1567 This function collects BIST data from HOB built from Sec Platform Information
1568 PPI or SEC Platform Information2 PPI.
1569
1570 **/
1571 VOID
CollectBistDataFromHob(VOID)1572 CollectBistDataFromHob (
1573 VOID
1574 )
1575 {
1576 EFI_HOB_GUID_TYPE *GuidHob;
1577 EFI_SEC_PLATFORM_INFORMATION_RECORD2 *SecPlatformInformation2;
1578 EFI_SEC_PLATFORM_INFORMATION_RECORD *SecPlatformInformation;
1579 UINTN NumberOfData;
1580 EFI_SEC_PLATFORM_INFORMATION_CPU *CpuInstance;
1581 EFI_SEC_PLATFORM_INFORMATION_CPU BspCpuInstance;
1582 UINTN ProcessorNumber;
1583 UINT32 InitialLocalApicId;
1584 CPU_DATA_BLOCK *CpuData;
1585
1586 SecPlatformInformation2 = NULL;
1587 SecPlatformInformation = NULL;
1588
1589 //
1590 // Get gEfiSecPlatformInformation2PpiGuid Guided HOB firstly
1591 //
1592 GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformation2PpiGuid);
1593 if (GuidHob != NULL) {
1594 //
1595 // Sec Platform Information2 PPI includes BSP/APs' BIST information
1596 //
1597 SecPlatformInformation2 = GET_GUID_HOB_DATA (GuidHob);
1598 NumberOfData = SecPlatformInformation2->NumberOfCpus;
1599 CpuInstance = SecPlatformInformation2->CpuInstance;
1600 } else {
1601 //
1602 // Otherwise, get gEfiSecPlatformInformationPpiGuid Guided HOB
1603 //
1604 GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformationPpiGuid);
1605 if (GuidHob != NULL) {
1606 SecPlatformInformation = GET_GUID_HOB_DATA (GuidHob);
1607 NumberOfData = 1;
1608 //
1609 // SEC Platform Information only includes BSP's BIST information
1610 // does not have BSP's APIC ID
1611 //
1612 BspCpuInstance.CpuLocation = GetApicId ();
1613 BspCpuInstance.InfoRecord.IA32HealthFlags.Uint32 = SecPlatformInformation->IA32HealthFlags.Uint32;
1614 CpuInstance = &BspCpuInstance;
1615 } else {
1616 DEBUG ((EFI_D_INFO, "Does not find any HOB stored CPU BIST information!\n"));
1617 //
1618 // Does not find any HOB stored BIST information
1619 //
1620 return;
1621 }
1622 }
1623
1624 while ((NumberOfData--) > 0) {
1625 for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
1626 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1627 InitialLocalApicId = (UINT32) CpuData->Info.ProcessorId;
1628 if (InitialLocalApicId == CpuInstance[NumberOfData].CpuLocation) {
1629 //
1630 // Update CPU health status for MP Services Protocol according to BIST data.
1631 //
1632 if (CpuInstance[NumberOfData].InfoRecord.IA32HealthFlags.Uint32 != 0) {
1633 CpuData->Info.StatusFlag &= ~PROCESSOR_HEALTH_STATUS_BIT;
1634 //
1635 // Report Status Code that self test is failed
1636 //
1637 REPORT_STATUS_CODE (
1638 EFI_ERROR_CODE | EFI_ERROR_MAJOR,
1639 (EFI_COMPUTING_UNIT_HOST_PROCESSOR | EFI_CU_HP_EC_SELF_TEST)
1640 );
1641 }
1642 }
1643 }
1644 }
1645 }
1646
1647 /**
1648 Callback function for ExitBootServices.
1649
1650 @param Event Event whose notification function is being invoked.
1651 @param Context The pointer to the notification function's context,
1652 which is implementation-dependent.
1653
1654 **/
1655 VOID
1656 EFIAPI
ExitBootServicesCallback(IN EFI_EVENT Event,IN VOID * Context)1657 ExitBootServicesCallback (
1658 IN EFI_EVENT Event,
1659 IN VOID *Context
1660 )
1661 {
1662 //
1663 // Avoid APs access invalid buff datas which allocated by BootServices,
1664 // so we send INIT IPI to APs to let them wait for SIPI state.
1665 //
1666 SendInitIpiAllExcludingSelf ();
1667 }
1668
1669 /**
1670 A minimal wrapper function that allows MtrrSetAllMtrrs() to be passed to
1671 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() as Procedure.
1672
1673 @param[in] Buffer Pointer to an MTRR_SETTINGS object, to be passed to
1674 MtrrSetAllMtrrs().
1675 **/
1676 VOID
1677 EFIAPI
SetMtrrsFromBuffer(IN VOID * Buffer)1678 SetMtrrsFromBuffer (
1679 IN VOID *Buffer
1680 )
1681 {
1682 MtrrSetAllMtrrs (Buffer);
1683 }
1684
1685 /**
1686 Initialize Multi-processor support.
1687
1688 **/
1689 VOID
InitializeMpSupport(VOID)1690 InitializeMpSupport (
1691 VOID
1692 )
1693 {
1694 EFI_STATUS Status;
1695 MTRR_SETTINGS MtrrSettings;
1696 UINTN Timeout;
1697
1698 gMaxLogicalProcessorNumber = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
1699 if (gMaxLogicalProcessorNumber < 1) {
1700 DEBUG ((DEBUG_ERROR, "Setting PcdCpuMaxLogicalProcessorNumber should be more than zero.\n"));
1701 return;
1702 }
1703
1704
1705
1706 InitMpSystemData ();
1707
1708 //
1709 // Only perform AP detection if PcdCpuMaxLogicalProcessorNumber is greater than 1
1710 //
1711 if (gMaxLogicalProcessorNumber > 1) {
1712
1713 gApStackSize = (UINTN) PcdGet32 (PcdCpuApStackSize);
1714 ASSERT ((gApStackSize & (SIZE_4KB - 1)) == 0);
1715
1716 mApStackStart = AllocatePages (EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));
1717 ASSERT (mApStackStart != NULL);
1718
1719 //
1720 // the first buffer of stack size used for common stack, when the amount of AP
1721 // more than 1, we should never free the common stack which maybe used for AP reset.
1722 //
1723 mCommonStack = mApStackStart;
1724 mTopOfApCommonStack = (UINT8*) mApStackStart + gApStackSize;
1725 mApStackStart = mTopOfApCommonStack;
1726
1727 PrepareAPStartupCode ();
1728
1729 StartApsStackless ();
1730 }
1731
1732 DEBUG ((DEBUG_INFO, "Detect CPU count: %d\n", mMpSystemData.NumberOfProcessors));
1733 if (mMpSystemData.NumberOfProcessors == 1) {
1734 FreeApStartupCode ();
1735 if (mCommonStack != NULL) {
1736 FreePages (mCommonStack, EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));
1737 }
1738 }
1739
1740 mMpSystemData.CpuDatas = ReallocatePool (
1741 sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber,
1742 sizeof (CPU_DATA_BLOCK) * mMpSystemData.NumberOfProcessors,
1743 mMpSystemData.CpuDatas);
1744
1745 //
1746 // Release all APs to complete initialization and enter idle loop
1747 //
1748 mAPsAlreadyInitFinished = TRUE;
1749
1750 //
1751 // Wait for all APs to enter idle loop.
1752 //
1753 Timeout = 0;
1754 do {
1755 if (CheckAllAPsSleeping ()) {
1756 break;
1757 }
1758 MicroSecondDelay (gPollInterval);
1759 Timeout += gPollInterval;
1760 } while (Timeout <= PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
1761 ASSERT (Timeout <= PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds));
1762
1763 //
1764 // Update CPU healthy information from Guided HOB
1765 //
1766 CollectBistDataFromHob ();
1767
1768 //
1769 // Synchronize MTRR settings to APs.
1770 //
1771 MtrrGetAllMtrrs (&MtrrSettings);
1772 Status = mMpServicesTemplate.StartupAllAPs (
1773 &mMpServicesTemplate, // This
1774 SetMtrrsFromBuffer, // Procedure
1775 TRUE, // SingleThread
1776 NULL, // WaitEvent
1777 0, // TimeoutInMicrosecsond
1778 &MtrrSettings, // ProcedureArgument
1779 NULL // FailedCpuList
1780 );
1781 ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_STARTED);
1782
1783 Status = gBS->InstallMultipleProtocolInterfaces (
1784 &mMpServiceHandle,
1785 &gEfiMpServiceProtocolGuid, &mMpServicesTemplate,
1786 NULL
1787 );
1788 ASSERT_EFI_ERROR (Status);
1789
1790 if (mMpSystemData.NumberOfProcessors > 1 && mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) {
1791 if (mApStackStart != NULL) {
1792 FreePages (mApStackStart, EFI_SIZE_TO_PAGES (
1793 (gMaxLogicalProcessorNumber - mMpSystemData.NumberOfProcessors) *
1794 gApStackSize));
1795 }
1796 }
1797
1798 Status = gBS->CreateEvent (
1799 EVT_SIGNAL_EXIT_BOOT_SERVICES,
1800 TPL_CALLBACK,
1801 ExitBootServicesCallback,
1802 NULL,
1803 &mExitBootServicesEvent
1804 );
1805 ASSERT_EFI_ERROR (Status);
1806 }
1807