]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuDxe/CpuMp.c
UefiCpuPkg/CpuDxe: introduce ResetApStackless()
[mirror_edk2.git] / UefiCpuPkg / CpuDxe / CpuMp.c
1 /** @file
2 CPU DXE Module.
3
4 Copyright (c) 2008 - 2014, 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
24 VOID *mCommonStack = 0;
25 VOID *mTopOfApCommonStack = 0;
26 VOID *mApStackStart = 0;
27
28 BOOLEAN mAPsAlreadyInitFinished = FALSE;
29 volatile BOOLEAN mStopCheckAllAPsStatus = TRUE;
30
31 EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = {
32 GetNumberOfProcessors,
33 GetProcessorInfo,
34 StartupAllAPs,
35 StartupThisAP,
36 SwitchBSP,
37 EnableDisableAP,
38 WhoAmI
39 };
40
41 /**
42 Get Mp Service Lock.
43
44 @param CpuData the pointer to CPU_DATA_BLOCK of specified processor
45
46 **/
47 VOID
48 GetMpSpinLock (
49 IN CPU_DATA_BLOCK *CpuData
50 )
51 {
52 while (!AcquireSpinLockOrFail (&CpuData->CpuDataLock)) {
53 CpuPause ();
54 }
55 }
56
57 /**
58 Release Mp Service Lock.
59
60 @param CpuData the pointer to CPU_DATA_BLOCK of specified processor
61
62 **/
63 VOID
64 ReleaseMpSpinLock (
65 IN CPU_DATA_BLOCK *CpuData
66 )
67 {
68 ReleaseSpinLock (&CpuData->CpuDataLock);
69 }
70
71 /**
72 Check whether caller processor is BSP.
73
74 @retval TRUE the caller is BSP
75 @retval FALSE the caller is AP
76
77 **/
78 BOOLEAN
79 IsBSP (
80 VOID
81 )
82 {
83 UINTN CpuIndex;
84 CPU_DATA_BLOCK *CpuData;
85
86 CpuData = NULL;
87
88 WhoAmI (&mMpServicesTemplate, &CpuIndex);
89 CpuData = &mMpSystemData.CpuDatas[CpuIndex];
90
91 return CpuData->Info.StatusFlag & PROCESSOR_AS_BSP_BIT ? TRUE : FALSE;
92 }
93
94 /**
95 Get the Application Processors state.
96
97 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
98
99 @retval CPU_STATE the AP status
100
101 **/
102 CPU_STATE
103 GetApState (
104 IN CPU_DATA_BLOCK *CpuData
105 )
106 {
107 CPU_STATE State;
108
109 GetMpSpinLock (CpuData);
110 State = CpuData->State;
111 ReleaseMpSpinLock (CpuData);
112
113 return State;
114 }
115
116 /**
117 Set the Application Processors state.
118
119 @param CpuData The pointer to CPU_DATA_BLOCK of specified AP
120 @param State The AP status
121
122 **/
123 VOID
124 SetApState (
125 IN CPU_DATA_BLOCK *CpuData,
126 IN CPU_STATE State
127 )
128 {
129 GetMpSpinLock (CpuData);
130 CpuData->State = State;
131 ReleaseMpSpinLock (CpuData);
132 }
133
134 /**
135 Set the Application Processor prepare to run a function specified
136 by Params.
137
138 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
139 @param Procedure A pointer to the function to be run on enabled APs of the system
140 @param ProcedureArgument Pointer to the optional parameter of the assigned function
141
142 **/
143 VOID
144 SetApProcedure (
145 IN CPU_DATA_BLOCK *CpuData,
146 IN EFI_AP_PROCEDURE Procedure,
147 IN VOID *ProcedureArgument
148 )
149 {
150 GetMpSpinLock (CpuData);
151 CpuData->Parameter = ProcedureArgument;
152 CpuData->Procedure = Procedure;
153 ReleaseMpSpinLock (CpuData);
154 }
155
156 /**
157 Check the Application Processors Status whether contains the Flags.
158
159 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
160 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
161
162 @retval TRUE the AP status includes the StatusFlag
163 @retval FALSE the AP status excludes the StatusFlag
164
165 **/
166 BOOLEAN
167 TestCpuStatusFlag (
168 IN CPU_DATA_BLOCK *CpuData,
169 IN UINT32 Flags
170 )
171 {
172 UINT32 Ret;
173
174 GetMpSpinLock (CpuData);
175 Ret = CpuData->Info.StatusFlag & Flags;
176 ReleaseMpSpinLock (CpuData);
177
178 return !!(Ret);
179 }
180
181 /**
182 Bitwise-Or of the Application Processors Status with the Flags.
183
184 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
185 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
186
187 **/
188 VOID
189 CpuStatusFlagOr (
190 IN CPU_DATA_BLOCK *CpuData,
191 IN UINT32 Flags
192 )
193 {
194 GetMpSpinLock (CpuData);
195 CpuData->Info.StatusFlag |= Flags;
196 ReleaseMpSpinLock (CpuData);
197 }
198
199 /**
200 Bitwise-AndNot of the Application Processors Status with the Flags.
201
202 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
203 @param Flags the StatusFlag describing in EFI_PROCESSOR_INFORMATION
204
205 **/
206 VOID
207 CpuStatusFlagAndNot (
208 IN CPU_DATA_BLOCK *CpuData,
209 IN UINT32 Flags
210 )
211 {
212 GetMpSpinLock (CpuData);
213 CpuData->Info.StatusFlag &= ~Flags;
214 ReleaseMpSpinLock (CpuData);
215 }
216
217 /**
218 Searches for the next blocking AP.
219
220 Search for the next AP that is put in blocking state by single-threaded StartupAllAPs().
221
222 @param NextNumber Pointer to the processor number of the next blocking AP.
223
224 @retval EFI_SUCCESS The next blocking AP has been found.
225 @retval EFI_NOT_FOUND No blocking AP exists.
226
227 **/
228 EFI_STATUS
229 GetNextBlockedNumber (
230 OUT UINTN *NextNumber
231 )
232 {
233 UINTN Number;
234 CPU_STATE CpuState;
235 CPU_DATA_BLOCK *CpuData;
236
237 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
238 CpuData = &mMpSystemData.CpuDatas[Number];
239 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
240 //
241 // Skip BSP
242 //
243 continue;
244 }
245
246 CpuState = GetApState (CpuData);
247 if (CpuState == CpuStateBlocked) {
248 *NextNumber = Number;
249 return EFI_SUCCESS;
250 }
251 }
252
253 return EFI_NOT_FOUND;
254 }
255
256 /**
257 Check if the APs state are finished, and update them to idle state
258 by StartupAllAPs().
259
260 **/
261 VOID
262 CheckAndUpdateAllAPsToIdleState (
263 VOID
264 )
265 {
266 UINTN ProcessorNumber;
267 UINTN NextNumber;
268 CPU_DATA_BLOCK *CpuData;
269 EFI_STATUS Status;
270 CPU_STATE CpuState;
271
272 for (ProcessorNumber = 0; ProcessorNumber < mMpSystemData.NumberOfProcessors; ProcessorNumber++) {
273 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
274 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
275 //
276 // Skip BSP
277 //
278 continue;
279 }
280
281 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
282 //
283 // Skip Disabled processors
284 //
285 continue;
286 }
287
288 CpuState = GetApState (CpuData);
289 if (CpuState == CpuStateFinished) {
290 mMpSystemData.FinishCount++;
291 if (mMpSystemData.SingleThread) {
292 Status = GetNextBlockedNumber (&NextNumber);
293 if (!EFI_ERROR (Status)) {
294 SetApState (&mMpSystemData.CpuDatas[NextNumber], CpuStateReady);
295 SetApProcedure (&mMpSystemData.CpuDatas[NextNumber],
296 mMpSystemData.Procedure,
297 mMpSystemData.ProcedureArgument);
298 }
299 }
300
301 SetApState (CpuData, CpuStateIdle);
302 }
303 }
304 }
305
306 /**
307 If the timeout expires before all APs returns from Procedure,
308 we should forcibly terminate the executing AP and fill FailedList back
309 by StartupAllAPs().
310
311 **/
312 VOID
313 ResetAllFailedAPs (
314 VOID
315 )
316 {
317 CPU_DATA_BLOCK *CpuData;
318 UINTN Number;
319 CPU_STATE CpuState;
320
321 if (mMpSystemData.FailedList != NULL) {
322 *mMpSystemData.FailedList = AllocatePool ((mMpSystemData.StartCount - mMpSystemData.FinishCount + 1) * sizeof(UINTN));
323 ASSERT (*mMpSystemData.FailedList != NULL);
324 }
325
326 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
327 CpuData = &mMpSystemData.CpuDatas[Number];
328 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
329 //
330 // Skip BSP
331 //
332 continue;
333 }
334
335 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
336 //
337 // Skip Disabled processors
338 //
339 continue;
340 }
341
342 CpuState = GetApState (CpuData);
343 if (CpuState != CpuStateIdle) {
344 if (mMpSystemData.FailedList != NULL) {
345 (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex++] = Number;
346 }
347 ResetProcessorToIdleState (CpuData);
348 }
349 }
350
351 if (mMpSystemData.FailedList != NULL) {
352 (*mMpSystemData.FailedList)[mMpSystemData.FailedListIndex] = END_OF_CPU_LIST;
353 }
354 }
355
356 /**
357 This service retrieves the number of logical processor in the platform
358 and the number of those logical processors that are enabled on this boot.
359 This service may only be called from the BSP.
360
361 This function is used to retrieve the following information:
362 - The number of logical processors that are present in the system.
363 - The number of enabled logical processors in the system at the instant
364 this call is made.
365
366 Because MP Service Protocol provides services to enable and disable processors
367 dynamically, the number of enabled logical processors may vary during the
368 course of a boot session.
369
370 If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
371 If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
372 EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
373 is returned in NumberOfProcessors, the number of currently enabled processor
374 is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
375
376 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
377 instance.
378 @param[out] NumberOfProcessors Pointer to the total number of logical
379 processors in the system, including the BSP
380 and disabled APs.
381 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
382 processors that exist in system, including
383 the BSP.
384
385 @retval EFI_SUCCESS The number of logical processors and enabled
386 logical processors was retrieved.
387 @retval EFI_DEVICE_ERROR The calling processor is an AP.
388 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
389 @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
390
391 **/
392 EFI_STATUS
393 EFIAPI
394 GetNumberOfProcessors (
395 IN EFI_MP_SERVICES_PROTOCOL *This,
396 OUT UINTN *NumberOfProcessors,
397 OUT UINTN *NumberOfEnabledProcessors
398 )
399 {
400 if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
401 return EFI_INVALID_PARAMETER;
402 }
403
404 if (!IsBSP ()) {
405 return EFI_DEVICE_ERROR;
406 }
407
408 *NumberOfProcessors = mMpSystemData.NumberOfProcessors;
409 *NumberOfEnabledProcessors = mMpSystemData.NumberOfEnabledProcessors;
410 return EFI_SUCCESS;
411 }
412
413 /**
414 Gets detailed MP-related information on the requested processor at the
415 instant this call is made. This service may only be called from the BSP.
416
417 This service retrieves detailed MP-related information about any processor
418 on the platform. Note the following:
419 - The processor information may change during the course of a boot session.
420 - The information presented here is entirely MP related.
421
422 Information regarding the number of caches and their sizes, frequency of operation,
423 slot numbers is all considered platform-related information and is not provided
424 by this service.
425
426 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
427 instance.
428 @param[in] ProcessorNumber The handle number of processor.
429 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
430 the requested processor is deposited.
431
432 @retval EFI_SUCCESS Processor information was returned.
433 @retval EFI_DEVICE_ERROR The calling processor is an AP.
434 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
435 @retval EFI_NOT_FOUND The processor with the handle specified by
436 ProcessorNumber does not exist in the platform.
437
438 **/
439 EFI_STATUS
440 EFIAPI
441 GetProcessorInfo (
442 IN EFI_MP_SERVICES_PROTOCOL *This,
443 IN UINTN ProcessorNumber,
444 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
445 )
446 {
447 if (ProcessorInfoBuffer == NULL) {
448 return EFI_INVALID_PARAMETER;
449 }
450
451 if (!IsBSP ()) {
452 return EFI_DEVICE_ERROR;
453 }
454
455 if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
456 return EFI_NOT_FOUND;
457 }
458
459 CopyMem (ProcessorInfoBuffer, &mMpSystemData.CpuDatas[ProcessorNumber], sizeof (EFI_PROCESSOR_INFORMATION));
460 return EFI_SUCCESS;
461 }
462
463 /**
464 This service executes a caller provided function on all enabled APs. APs can
465 run either simultaneously or one at a time in sequence. This service supports
466 both blocking and non-blocking requests. The non-blocking requests use EFI
467 events so the BSP can detect when the APs have finished. This service may only
468 be called from the BSP.
469
470 This function is used to dispatch all the enabled APs to the function specified
471 by Procedure. If any enabled AP is busy, then EFI_NOT_READY is returned
472 immediately and Procedure is not started on any AP.
473
474 If SingleThread is TRUE, all the enabled APs execute the function specified by
475 Procedure one by one, in ascending order of processor handle number. Otherwise,
476 all the enabled APs execute the function specified by Procedure simultaneously.
477
478 If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
479 APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in non-blocking
480 mode, and the BSP returns from this service without waiting for APs. If a
481 non-blocking mode is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
482 is signaled, then EFI_UNSUPPORTED must be returned.
483
484 If the timeout specified by TimeoutInMicroseconds expires before all APs return
485 from Procedure, then Procedure on the failed APs is terminated. All enabled APs
486 are always available for further calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
487 and EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
488 content points to the list of processor handle numbers in which Procedure was
489 terminated.
490
491 Note: It is the responsibility of the consumer of the EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
492 to make sure that the nature of the code that is executed on the BSP and the
493 dispatched APs is well controlled. The MP Services Protocol does not guarantee
494 that the Procedure function is MP-safe. Hence, the tasks that can be run in
495 parallel are limited to certain independent tasks and well-controlled exclusive
496 code. EFI services and protocols may not be called by APs unless otherwise
497 specified.
498
499 In blocking execution mode, BSP waits until all APs finish or
500 TimeoutInMicroseconds expires.
501
502 In non-blocking execution mode, BSP is freed to return to the caller and then
503 proceed to the next task without having to wait for APs. The following
504 sequence needs to occur in a non-blocking execution mode:
505
506 -# The caller that intends to use this MP Services Protocol in non-blocking
507 mode creates WaitEvent by calling the EFI CreateEvent() service. The caller
508 invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter WaitEvent
509 is not NULL, then StartupAllAPs() executes in non-blocking mode. It requests
510 the function specified by Procedure to be started on all the enabled APs,
511 and releases the BSP to continue with other tasks.
512 -# The caller can use the CheckEvent() and WaitForEvent() services to check
513 the state of the WaitEvent created in step 1.
514 -# When the APs complete their task or TimeoutInMicroSecondss expires, the MP
515 Service signals WaitEvent by calling the EFI SignalEvent() function. If
516 FailedCpuList is not NULL, its content is available when WaitEvent is
517 signaled. If all APs returned from Procedure prior to the timeout, then
518 FailedCpuList is set to NULL. If not all APs return from Procedure before
519 the timeout, then FailedCpuList is filled in with the list of the failed
520 APs. The buffer is allocated by MP Service Protocol using AllocatePool().
521 It is the caller's responsibility to free the buffer with FreePool() service.
522 -# This invocation of SignalEvent() function informs the caller that invoked
523 EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs completed
524 the specified task or a timeout occurred. The contents of FailedCpuList
525 can be examined to determine which APs did not complete the specified task
526 prior to the timeout.
527
528 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
529 instance.
530 @param[in] Procedure A pointer to the function to be run on
531 enabled APs of the system. See type
532 EFI_AP_PROCEDURE.
533 @param[in] SingleThread If TRUE, then all the enabled APs execute
534 the function specified by Procedure one by
535 one, in ascending order of processor handle
536 number. If FALSE, then all the enabled APs
537 execute the function specified by Procedure
538 simultaneously.
539 @param[in] WaitEvent The event created by the caller with CreateEvent()
540 service. If it is NULL, then execute in
541 blocking mode. BSP waits until all APs finish
542 or TimeoutInMicroseconds expires. If it's
543 not NULL, then execute in non-blocking mode.
544 BSP requests the function specified by
545 Procedure to be started on all the enabled
546 APs, and go on executing immediately. If
547 all return from Procedure, or TimeoutInMicroseconds
548 expires, this event is signaled. The BSP
549 can use the CheckEvent() or WaitForEvent()
550 services to check the state of event. Type
551 EFI_EVENT is defined in CreateEvent() in
552 the Unified Extensible Firmware Interface
553 Specification.
554 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
555 APs to return from Procedure, either for
556 blocking or non-blocking mode. Zero means
557 infinity. If the timeout expires before
558 all APs return from Procedure, then Procedure
559 on the failed APs is terminated. All enabled
560 APs are available for next function assigned
561 by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
562 or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
563 If the timeout expires in blocking mode,
564 BSP returns EFI_TIMEOUT. If the timeout
565 expires in non-blocking mode, WaitEvent
566 is signaled with SignalEvent().
567 @param[in] ProcedureArgument The parameter passed into Procedure for
568 all APs.
569 @param[out] FailedCpuList If NULL, this parameter is ignored. Otherwise,
570 if all APs finish successfully, then its
571 content is set to NULL. If not all APs
572 finish before timeout expires, then its
573 content is set to address of the buffer
574 holding handle numbers of the failed APs.
575 The buffer is allocated by MP Service Protocol,
576 and it's the caller's responsibility to
577 free the buffer with FreePool() service.
578 In blocking mode, it is ready for consumption
579 when the call returns. In non-blocking mode,
580 it is ready when WaitEvent is signaled. The
581 list of failed CPU is terminated by
582 END_OF_CPU_LIST.
583
584 @retval EFI_SUCCESS In blocking mode, all APs have finished before
585 the timeout expired.
586 @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
587 to all enabled APs.
588 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
589 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
590 signaled.
591 @retval EFI_DEVICE_ERROR Caller processor is AP.
592 @retval EFI_NOT_STARTED No enabled APs exist in the system.
593 @retval EFI_NOT_READY Any enabled APs are busy.
594 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
595 all enabled APs have finished.
596 @retval EFI_INVALID_PARAMETER Procedure is NULL.
597
598 **/
599 EFI_STATUS
600 EFIAPI
601 StartupAllAPs (
602 IN EFI_MP_SERVICES_PROTOCOL *This,
603 IN EFI_AP_PROCEDURE Procedure,
604 IN BOOLEAN SingleThread,
605 IN EFI_EVENT WaitEvent OPTIONAL,
606 IN UINTN TimeoutInMicroseconds,
607 IN VOID *ProcedureArgument OPTIONAL,
608 OUT UINTN **FailedCpuList OPTIONAL
609 )
610 {
611 EFI_STATUS Status;
612 CPU_DATA_BLOCK *CpuData;
613 UINTN Number;
614 CPU_STATE APInitialState;
615
616 CpuData = NULL;
617
618 if (FailedCpuList != NULL) {
619 *FailedCpuList = NULL;
620 }
621
622 if (!IsBSP ()) {
623 return EFI_DEVICE_ERROR;
624 }
625
626 if (mMpSystemData.NumberOfProcessors == 1) {
627 return EFI_NOT_STARTED;
628 }
629
630 if (Procedure == NULL) {
631 return EFI_INVALID_PARAMETER;
632 }
633
634 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
635 CpuData = &mMpSystemData.CpuDatas[Number];
636 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
637 //
638 // Skip BSP
639 //
640 continue;
641 }
642
643 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
644 //
645 // Skip Disabled processors
646 //
647 continue;
648 }
649
650 if (GetApState (CpuData) != CpuStateIdle) {
651 return EFI_NOT_READY;
652 }
653 }
654
655 //
656 // temporarily stop checkAllAPsStatus for initialize parameters.
657 //
658 mStopCheckAllAPsStatus = TRUE;
659
660 mMpSystemData.Procedure = Procedure;
661 mMpSystemData.ProcedureArgument = ProcedureArgument;
662 mMpSystemData.WaitEvent = WaitEvent;
663 mMpSystemData.Timeout = TimeoutInMicroseconds;
664 mMpSystemData.TimeoutActive = !!(TimeoutInMicroseconds);
665 mMpSystemData.FinishCount = 0;
666 mMpSystemData.StartCount = 0;
667 mMpSystemData.SingleThread = SingleThread;
668 mMpSystemData.FailedList = FailedCpuList;
669 mMpSystemData.FailedListIndex = 0;
670 APInitialState = CpuStateReady;
671
672 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
673 CpuData = &mMpSystemData.CpuDatas[Number];
674 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
675 //
676 // Skip BSP
677 //
678 continue;
679 }
680
681 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
682 //
683 // Skip Disabled processors
684 //
685 continue;
686 }
687
688 //
689 // Get APs prepared, and put failing APs into FailedCpuList
690 // if "SingleThread", only 1 AP will put to ready state, other AP will be put to ready
691 // state 1 by 1, until the previous 1 finished its task
692 // if not "SingleThread", all APs are put to ready state from the beginning
693 //
694 if (GetApState (CpuData) == CpuStateIdle) {
695 mMpSystemData.StartCount++;
696
697 SetApState (CpuData, APInitialState);
698
699 if (APInitialState == CpuStateReady) {
700 SetApProcedure (CpuData, Procedure, ProcedureArgument);
701 }
702
703 if (SingleThread) {
704 APInitialState = CpuStateBlocked;
705 }
706 }
707 }
708
709 mStopCheckAllAPsStatus = FALSE;
710
711 if (WaitEvent != NULL) {
712 //
713 // non blocking
714 //
715 return EFI_SUCCESS;
716 }
717
718 while (TRUE) {
719 CheckAndUpdateAllAPsToIdleState ();
720 if (mMpSystemData.FinishCount == mMpSystemData.StartCount) {
721 Status = EFI_SUCCESS;
722 goto Done;
723 }
724
725 //
726 // task timeout
727 //
728 if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {
729 ResetAllFailedAPs();
730 Status = EFI_TIMEOUT;
731 goto Done;
732 }
733
734 gBS->Stall (gPollInterval);
735 mMpSystemData.Timeout -= gPollInterval;
736 }
737
738 Done:
739
740 return Status;
741 }
742
743 /**
744 This service lets the caller get one enabled AP to execute a caller-provided
745 function. The caller can request the BSP to either wait for the completion
746 of the AP or just proceed with the next task by using the EFI event mechanism.
747 See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
748 execution support. This service may only be called from the BSP.
749
750 This function is used to dispatch one enabled AP to the function specified by
751 Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
752 is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
753 TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
754 BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
755 is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
756 then EFI_UNSUPPORTED must be returned.
757
758 If the timeout specified by TimeoutInMicroseconds expires before the AP returns
759 from Procedure, then execution of Procedure by the AP is terminated. The AP is
760 available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
761 EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
762
763 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
764 instance.
765 @param[in] Procedure A pointer to the function to be run on
766 enabled APs of the system. See type
767 EFI_AP_PROCEDURE.
768 @param[in] ProcessorNumber The handle number of the AP. The range is
769 from 0 to the total number of logical
770 processors minus 1. The total number of
771 logical processors can be retrieved by
772 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
773 @param[in] WaitEvent The event created by the caller with CreateEvent()
774 service. If it is NULL, then execute in
775 blocking mode. BSP waits until all APs finish
776 or TimeoutInMicroseconds expires. If it's
777 not NULL, then execute in non-blocking mode.
778 BSP requests the function specified by
779 Procedure to be started on all the enabled
780 APs, and go on executing immediately. If
781 all return from Procedure or TimeoutInMicroseconds
782 expires, this event is signaled. The BSP
783 can use the CheckEvent() or WaitForEvent()
784 services to check the state of event. Type
785 EFI_EVENT is defined in CreateEvent() in
786 the Unified Extensible Firmware Interface
787 Specification.
788 @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
789 APs to return from Procedure, either for
790 blocking or non-blocking mode. Zero means
791 infinity. If the timeout expires before
792 all APs return from Procedure, then Procedure
793 on the failed APs is terminated. All enabled
794 APs are available for next function assigned
795 by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
796 or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
797 If the timeout expires in blocking mode,
798 BSP returns EFI_TIMEOUT. If the timeout
799 expires in non-blocking mode, WaitEvent
800 is signaled with SignalEvent().
801 @param[in] ProcedureArgument The parameter passed into Procedure for
802 all APs.
803 @param[out] Finished If NULL, this parameter is ignored. In
804 blocking mode, this parameter is ignored.
805 In non-blocking mode, if AP returns from
806 Procedure before the timeout expires, its
807 content is set to TRUE. Otherwise, the
808 value is set to FALSE. The caller can
809 determine if the AP returned from Procedure
810 by evaluating this value.
811
812 @retval EFI_SUCCESS In blocking mode, specified AP finished before
813 the timeout expires.
814 @retval EFI_SUCCESS In non-blocking mode, the function has been
815 dispatched to specified AP.
816 @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
817 UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
818 signaled.
819 @retval EFI_DEVICE_ERROR The calling processor is an AP.
820 @retval EFI_TIMEOUT In blocking mode, the timeout expired before
821 the specified AP has finished.
822 @retval EFI_NOT_READY The specified AP is busy.
823 @retval EFI_NOT_FOUND The processor with the handle specified by
824 ProcessorNumber does not exist.
825 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
826 @retval EFI_INVALID_PARAMETER Procedure is NULL.
827
828 **/
829 EFI_STATUS
830 EFIAPI
831 StartupThisAP (
832 IN EFI_MP_SERVICES_PROTOCOL *This,
833 IN EFI_AP_PROCEDURE Procedure,
834 IN UINTN ProcessorNumber,
835 IN EFI_EVENT WaitEvent OPTIONAL,
836 IN UINTN TimeoutInMicroseconds,
837 IN VOID *ProcedureArgument OPTIONAL,
838 OUT BOOLEAN *Finished OPTIONAL
839 )
840 {
841 CPU_DATA_BLOCK *CpuData;
842
843 CpuData = NULL;
844
845 if (Finished != NULL) {
846 *Finished = FALSE;
847 }
848
849 if (!IsBSP ()) {
850 return EFI_DEVICE_ERROR;
851 }
852
853 if (Procedure == NULL) {
854 return EFI_INVALID_PARAMETER;
855 }
856
857 if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
858 return EFI_NOT_FOUND;
859 }
860
861 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
862 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT) ||
863 !TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
864 return EFI_INVALID_PARAMETER;
865 }
866
867 if (GetApState (CpuData) != CpuStateIdle) {
868 return EFI_NOT_READY;
869 }
870
871 //
872 // temporarily stop checkAllAPsStatus for initialize parameters.
873 //
874 mStopCheckAllAPsStatus = TRUE;
875
876 SetApState (CpuData, CpuStateReady);
877
878 SetApProcedure (CpuData, Procedure, ProcedureArgument);
879
880 CpuData->Timeout = TimeoutInMicroseconds;
881 CpuData->WaitEvent = WaitEvent;
882 CpuData->TimeoutActive = !!(TimeoutInMicroseconds);
883 CpuData->Finished = Finished;
884
885 mStopCheckAllAPsStatus = FALSE;
886
887 if (WaitEvent != NULL) {
888 //
889 // Non Blocking
890 //
891 return EFI_SUCCESS;
892 }
893
894 //
895 // Blocking
896 //
897 while (TRUE) {
898 if (GetApState (CpuData) == CpuStateFinished) {
899 SetApState (CpuData, CpuStateIdle);
900 break;
901 }
902
903 if (CpuData->TimeoutActive && CpuData->Timeout < 0) {
904 ResetProcessorToIdleState (CpuData);
905 return EFI_TIMEOUT;
906 }
907
908 gBS->Stall (gPollInterval);
909 CpuData->Timeout -= gPollInterval;
910 }
911
912 return EFI_SUCCESS;
913 }
914
915 /**
916 This service switches the requested AP to be the BSP from that point onward.
917 This service changes the BSP for all purposes. This call can only be performed
918 by the current BSP.
919
920 This service switches the requested AP to be the BSP from that point onward.
921 This service changes the BSP for all purposes. The new BSP can take over the
922 execution of the old BSP and continue seamlessly from where the old one left
923 off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
924 is signaled.
925
926 If the BSP cannot be switched prior to the return from this service, then
927 EFI_UNSUPPORTED must be returned.
928
929 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
930 @param[in] ProcessorNumber The handle number of AP that is to become the new
931 BSP. The range is from 0 to the total number of
932 logical processors minus 1. The total number of
933 logical processors can be retrieved by
934 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
935 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
936 enabled AP. Otherwise, it will be disabled.
937
938 @retval EFI_SUCCESS BSP successfully switched.
939 @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
940 this service returning.
941 @retval EFI_UNSUPPORTED Switching the BSP is not supported.
942 @retval EFI_SUCCESS The calling processor is an AP.
943 @retval EFI_NOT_FOUND The processor with the handle specified by
944 ProcessorNumber does not exist.
945 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
946 a disabled AP.
947 @retval EFI_NOT_READY The specified AP is busy.
948
949 **/
950 EFI_STATUS
951 EFIAPI
952 SwitchBSP (
953 IN EFI_MP_SERVICES_PROTOCOL *This,
954 IN UINTN ProcessorNumber,
955 IN BOOLEAN EnableOldBSP
956 )
957 {
958 //
959 // Current always return unsupported.
960 //
961 return EFI_UNSUPPORTED;
962 }
963
964 /**
965 This service lets the caller enable or disable an AP from this point onward.
966 This service may only be called from the BSP.
967
968 This service allows the caller enable or disable an AP from this point onward.
969 The caller can optionally specify the health status of the AP by Health. If
970 an AP is being disabled, then the state of the disabled AP is implementation
971 dependent. If an AP is enabled, then the implementation must guarantee that a
972 complete initialization sequence is performed on the AP, so the AP is in a state
973 that is compatible with an MP operating system. This service may not be supported
974 after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
975
976 If the enable or disable AP operation cannot be completed prior to the return
977 from this service, then EFI_UNSUPPORTED must be returned.
978
979 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
980 @param[in] ProcessorNumber The handle number of AP that is to become the new
981 BSP. The range is from 0 to the total number of
982 logical processors minus 1. The total number of
983 logical processors can be retrieved by
984 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
985 @param[in] EnableAP Specifies the new state for the processor for
986 enabled, FALSE for disabled.
987 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
988 the new health status of the AP. This flag
989 corresponds to StatusFlag defined in
990 EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
991 the PROCESSOR_HEALTH_STATUS_BIT is used. All other
992 bits are ignored. If it is NULL, this parameter
993 is ignored.
994
995 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
996 @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
997 prior to this service returning.
998 @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
999 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1000 @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
1001 does not exist.
1002 @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
1003
1004 **/
1005 EFI_STATUS
1006 EFIAPI
1007 EnableDisableAP (
1008 IN EFI_MP_SERVICES_PROTOCOL *This,
1009 IN UINTN ProcessorNumber,
1010 IN BOOLEAN EnableAP,
1011 IN UINT32 *HealthFlag OPTIONAL
1012 )
1013 {
1014 CPU_DATA_BLOCK *CpuData;
1015
1016 if (!IsBSP ()) {
1017 return EFI_DEVICE_ERROR;
1018 }
1019
1020 if (ProcessorNumber >= mMpSystemData.NumberOfProcessors) {
1021 return EFI_NOT_FOUND;
1022 }
1023
1024 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1025 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
1026 return EFI_INVALID_PARAMETER;
1027 }
1028
1029 if (GetApState (CpuData) != CpuStateIdle) {
1030 return EFI_UNSUPPORTED;
1031 }
1032
1033 if (EnableAP) {
1034 if (!(TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT))) {
1035 mMpSystemData.NumberOfEnabledProcessors++;
1036 }
1037 CpuStatusFlagOr (CpuData, PROCESSOR_ENABLED_BIT);
1038 } else {
1039 if (TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
1040 mMpSystemData.NumberOfEnabledProcessors--;
1041 }
1042 CpuStatusFlagAndNot (CpuData, PROCESSOR_ENABLED_BIT);
1043 }
1044
1045 if (HealthFlag != NULL) {
1046 CpuStatusFlagAndNot (CpuData, (UINT32)~PROCESSOR_HEALTH_STATUS_BIT);
1047 CpuStatusFlagOr (CpuData, (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT));
1048 }
1049
1050 return EFI_SUCCESS;
1051 }
1052
1053 /**
1054 This return the handle number for the calling processor. This service may be
1055 called from the BSP and APs.
1056
1057 This service returns the processor handle number for the calling processor.
1058 The returned value is in the range from 0 to the total number of logical
1059 processors minus 1. The total number of logical processors can be retrieved
1060 with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
1061 called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
1062 is returned. Otherwise, the current processors handle number is returned in
1063 ProcessorNumber, and EFI_SUCCESS is returned.
1064
1065 @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
1066 @param[out] ProcessorNumber The handle number of AP that is to become the new
1067 BSP. The range is from 0 to the total number of
1068 logical processors minus 1. The total number of
1069 logical processors can be retrieved by
1070 EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
1071
1072 @retval EFI_SUCCESS The current processor handle number was returned
1073 in ProcessorNumber.
1074 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
1075
1076 **/
1077 EFI_STATUS
1078 EFIAPI
1079 WhoAmI (
1080 IN EFI_MP_SERVICES_PROTOCOL *This,
1081 OUT UINTN *ProcessorNumber
1082 )
1083 {
1084 UINTN Index;
1085 UINT32 ProcessorId;
1086
1087 if (ProcessorNumber == NULL) {
1088 return EFI_INVALID_PARAMETER;
1089 }
1090
1091 ProcessorId = GetApicId ();
1092 for (Index = 0; Index < mMpSystemData.NumberOfProcessors; Index++) {
1093 if (mMpSystemData.CpuDatas[Index].Info.ProcessorId == ProcessorId) {
1094 break;
1095 }
1096 }
1097
1098 *ProcessorNumber = Index;
1099 return EFI_SUCCESS;
1100 }
1101
1102 /**
1103 Terminate AP's task and set it to idle state.
1104
1105 This function terminates AP's task due to timeout by sending INIT-SIPI,
1106 and sends it to idle state.
1107
1108 @param CpuData the pointer to CPU_DATA_BLOCK of specified AP
1109
1110 **/
1111 VOID
1112 ResetProcessorToIdleState (
1113 IN CPU_DATA_BLOCK *CpuData
1114 )
1115 {
1116 ResetApStackless ((UINT32)CpuData->Info.ProcessorId);
1117 }
1118
1119 /**
1120 Application Processors do loop routine
1121 after switch to its own stack.
1122
1123 @param Context1 A pointer to the context to pass into the function.
1124 @param Context2 A pointer to the context to pass into the function.
1125
1126 **/
1127 VOID
1128 ProcessorToIdleState (
1129 IN VOID *Context1, OPTIONAL
1130 IN VOID *Context2 OPTIONAL
1131 )
1132 {
1133 UINTN ProcessorNumber;
1134 CPU_DATA_BLOCK *CpuData;
1135 EFI_AP_PROCEDURE Procedure;
1136 VOID *ProcedureArgument;
1137
1138 WhoAmI (&mMpServicesTemplate, &ProcessorNumber);
1139 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1140
1141 AsmApDoneWithCommonStack ();
1142
1143 //
1144 // Avoid forcibly reset AP caused the AP State is not updated.
1145 //
1146 GetMpSpinLock (CpuData);
1147 CpuData->State = CpuStateIdle;
1148 CpuData->Procedure = NULL;
1149 ReleaseMpSpinLock (CpuData);
1150
1151 while (TRUE) {
1152 GetMpSpinLock (CpuData);
1153 ProcedureArgument = CpuData->Parameter;
1154 Procedure = CpuData->Procedure;
1155 ReleaseMpSpinLock (CpuData);
1156
1157 if (Procedure != NULL) {
1158 Procedure (ProcedureArgument);
1159
1160 GetMpSpinLock (CpuData);
1161 CpuData->Procedure = NULL;
1162 CpuData->State = CpuStateFinished;
1163 ReleaseMpSpinLock (CpuData);
1164 }
1165
1166 CpuPause ();
1167 }
1168
1169 CpuSleep ();
1170 CpuDeadLoop ();
1171 }
1172
1173 /**
1174 Checks AP' status periodically.
1175
1176 This function is triggerred by timer perodically to check the
1177 state of AP forStartupThisAP() executed in non-blocking mode.
1178
1179 @param Event Event triggered.
1180 @param Context Parameter passed with the event.
1181
1182 **/
1183 VOID
1184 EFIAPI
1185 CheckThisAPStatus (
1186 IN EFI_EVENT Event,
1187 IN VOID *Context
1188 )
1189 {
1190 CPU_DATA_BLOCK *CpuData;
1191 CPU_STATE CpuState;
1192
1193 CpuData = (CPU_DATA_BLOCK *) Context;
1194 if (CpuData->TimeoutActive) {
1195 CpuData->Timeout -= gPollInterval;
1196 }
1197
1198 CpuState = GetApState (CpuData);
1199
1200 if (CpuState == CpuStateFinished) {
1201 if (CpuData->Finished) {
1202 *CpuData->Finished = TRUE;
1203 }
1204 SetApState (CpuData, CpuStateIdle);
1205 goto out;
1206 }
1207
1208 if (CpuData->TimeoutActive && CpuData->Timeout < 0) {
1209 if (CpuState != CpuStateIdle &&
1210 CpuData->Finished) {
1211 *CpuData->Finished = FALSE;
1212 }
1213 ResetProcessorToIdleState (CpuData);
1214 goto out;
1215 }
1216
1217 return;
1218
1219 out:
1220 CpuData->TimeoutActive = FALSE;
1221 gBS->SignalEvent (CpuData->WaitEvent);
1222 CpuData->WaitEvent = NULL;
1223 }
1224
1225 /**
1226 Checks APs' status periodically.
1227
1228 This function is triggerred by timer perodically to check the
1229 state of APs for StartupAllAPs() executed in non-blocking mode.
1230
1231 @param Event Event triggered.
1232 @param Context Parameter passed with the event.
1233
1234 **/
1235 VOID
1236 EFIAPI
1237 CheckAllAPsStatus (
1238 IN EFI_EVENT Event,
1239 IN VOID *Context
1240 )
1241 {
1242 CPU_DATA_BLOCK *CpuData;
1243 UINTN Number;
1244 EFI_STATUS Status;
1245
1246 if (mMpSystemData.TimeoutActive) {
1247 mMpSystemData.Timeout -= gPollInterval;
1248 }
1249
1250 if (mStopCheckAllAPsStatus) {
1251 return;
1252 }
1253
1254 //
1255 // avoid next timer enter.
1256 //
1257 Status = gBS->SetTimer (
1258 mMpSystemData.CheckAllAPsEvent,
1259 TimerCancel,
1260 0
1261 );
1262 ASSERT_EFI_ERROR (Status);
1263
1264 if (mMpSystemData.WaitEvent != NULL) {
1265 CheckAndUpdateAllAPsToIdleState ();
1266 //
1267 // task timeout
1268 //
1269 if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {
1270 ResetAllFailedAPs();
1271 //
1272 // force exit
1273 //
1274 mMpSystemData.FinishCount = mMpSystemData.StartCount;
1275 }
1276
1277 if (mMpSystemData.FinishCount != mMpSystemData.StartCount) {
1278 goto EXIT;
1279 }
1280
1281 mMpSystemData.TimeoutActive = FALSE;
1282 gBS->SignalEvent (mMpSystemData.WaitEvent);
1283 mMpSystemData.WaitEvent = NULL;
1284 mStopCheckAllAPsStatus = TRUE;
1285
1286 goto EXIT;
1287 }
1288
1289 //
1290 // check each AP status for StartupThisAP
1291 //
1292 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
1293 CpuData = &mMpSystemData.CpuDatas[Number];
1294 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
1295 //
1296 // Skip BSP
1297 //
1298 continue;
1299 }
1300
1301 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
1302 //
1303 // Skip Disabled processors
1304 //
1305 continue;
1306 }
1307
1308 if (CpuData->WaitEvent) {
1309 CheckThisAPStatus (NULL, (VOID *)CpuData);
1310 }
1311 }
1312
1313 EXIT:
1314 Status = gBS->SetTimer (
1315 mMpSystemData.CheckAllAPsEvent,
1316 TimerPeriodic,
1317 EFI_TIMER_PERIOD_MICROSECONDS (100)
1318 );
1319 ASSERT_EFI_ERROR (Status);
1320 }
1321
1322 /**
1323 Application Processor C code entry point.
1324
1325 **/
1326 VOID
1327 EFIAPI
1328 ApEntryPointInC (
1329 VOID
1330 )
1331 {
1332 VOID* TopOfApStack;
1333 UINTN ProcessorNumber;
1334
1335 if (!mAPsAlreadyInitFinished) {
1336 FillInProcessorInformation (FALSE, mMpSystemData.NumberOfProcessors);
1337 TopOfApStack = (UINT8*)mApStackStart + gApStackSize;
1338 mApStackStart = TopOfApStack;
1339
1340 //
1341 // Store the Stack address, when reset the AP, We can found the original address.
1342 //
1343 mMpSystemData.CpuDatas[mMpSystemData.NumberOfProcessors].TopOfStack = TopOfApStack;
1344 mMpSystemData.NumberOfProcessors++;
1345 mMpSystemData.NumberOfEnabledProcessors++;
1346 } else {
1347 WhoAmI (&mMpServicesTemplate, &ProcessorNumber);
1348 //
1349 // Get the original stack address.
1350 //
1351 TopOfApStack = mMpSystemData.CpuDatas[ProcessorNumber].TopOfStack;
1352 }
1353
1354 SwitchStack (
1355 (SWITCH_STACK_ENTRY_POINT)(UINTN)ProcessorToIdleState,
1356 NULL,
1357 NULL,
1358 TopOfApStack);
1359 }
1360
1361 /**
1362 This function is called by all processors (both BSP and AP) once and collects MP related data.
1363
1364 @param Bsp TRUE if the CPU is BSP
1365 @param ProcessorNumber The specific processor number
1366
1367 @retval EFI_SUCCESS Data for the processor collected and filled in
1368
1369 **/
1370 EFI_STATUS
1371 FillInProcessorInformation (
1372 IN BOOLEAN Bsp,
1373 IN UINTN ProcessorNumber
1374 )
1375 {
1376 CPU_DATA_BLOCK *CpuData;
1377 UINT32 ProcessorId;
1378
1379 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1380 ProcessorId = GetApicId ();
1381 CpuData->Info.ProcessorId = ProcessorId;
1382 CpuData->Info.StatusFlag = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT;
1383 if (Bsp) {
1384 CpuData->Info.StatusFlag |= PROCESSOR_AS_BSP_BIT;
1385 }
1386 CpuData->Info.Location.Package = ProcessorId;
1387 CpuData->Info.Location.Core = 0;
1388 CpuData->Info.Location.Thread = 0;
1389 CpuData->State = Bsp ? CpuStateBuzy : CpuStateIdle;
1390
1391 CpuData->Procedure = NULL;
1392 CpuData->Parameter = NULL;
1393 InitializeSpinLock (&CpuData->CpuDataLock);
1394
1395 return EFI_SUCCESS;
1396 }
1397
1398 /**
1399 Prepare the System Data.
1400
1401 @retval EFI_SUCCESS the System Data finished initilization.
1402
1403 **/
1404 EFI_STATUS
1405 InitMpSystemData (
1406 VOID
1407 )
1408 {
1409 EFI_STATUS Status;
1410
1411 ZeroMem (&mMpSystemData, sizeof (MP_SYSTEM_DATA));
1412
1413 mMpSystemData.NumberOfProcessors = 1;
1414 mMpSystemData.NumberOfEnabledProcessors = 1;
1415
1416 mMpSystemData.CpuDatas = AllocateZeroPool (sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber);
1417 ASSERT(mMpSystemData.CpuDatas != NULL);
1418
1419 Status = gBS->CreateEvent (
1420 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1421 TPL_CALLBACK,
1422 CheckAllAPsStatus,
1423 NULL,
1424 &mMpSystemData.CheckAllAPsEvent
1425 );
1426 ASSERT_EFI_ERROR (Status);
1427
1428 //
1429 // Set timer to check all APs status.
1430 //
1431 Status = gBS->SetTimer (
1432 mMpSystemData.CheckAllAPsEvent,
1433 TimerPeriodic,
1434 EFI_TIMER_PERIOD_MICROSECONDS (100)
1435 );
1436 ASSERT_EFI_ERROR (Status);
1437
1438 //
1439 // BSP
1440 //
1441 FillInProcessorInformation (TRUE, 0);
1442
1443 return EFI_SUCCESS;
1444 }
1445
1446 /**
1447 Initialize Multi-processor support.
1448
1449 **/
1450 VOID
1451 InitializeMpSupport (
1452 VOID
1453 )
1454 {
1455 gMaxLogicalProcessorNumber = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
1456 if (gMaxLogicalProcessorNumber < 1) {
1457 DEBUG ((DEBUG_ERROR, "Setting PcdCpuMaxLogicalProcessorNumber should be more than zero.\n"));
1458 return;
1459 }
1460
1461 if (gMaxLogicalProcessorNumber == 1) {
1462 return;
1463 }
1464
1465 gApStackSize = (UINTN) PcdGet32 (PcdCpuApStackSize);
1466 ASSERT ((gApStackSize & (SIZE_4KB - 1)) == 0);
1467
1468 mApStackStart = AllocatePages (EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));
1469 ASSERT (mApStackStart != NULL);
1470
1471 //
1472 // the first buffer of stack size used for common stack, when the amount of AP
1473 // more than 1, we should never free the common stack which maybe used for AP reset.
1474 //
1475 mCommonStack = mApStackStart;
1476 mTopOfApCommonStack = (UINT8*) mApStackStart + gApStackSize;
1477 mApStackStart = mTopOfApCommonStack;
1478
1479 InitMpSystemData ();
1480
1481 PrepareAPStartupCode ();
1482
1483 if (mMpSystemData.NumberOfProcessors == 1) {
1484 FreeApStartupCode ();
1485 FreePages (mCommonStack, EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));
1486 return;
1487 }
1488
1489 mAPsAlreadyInitFinished = TRUE;
1490
1491 if (mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) {
1492 FreePages (mApStackStart, EFI_SIZE_TO_PAGES (
1493 (gMaxLogicalProcessorNumber - mMpSystemData.NumberOfProcessors) *
1494 gApStackSize));
1495 }
1496 }