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