]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/CpuDxe/CpuMp.c
UefiCpuPkg/MpService: free the unused cpu data buffer
[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 volatile 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 AsmApDoneWithCommonStack ();
1139
1140 while (!mAPsAlreadyInitFinished) {
1141 CpuPause ();
1142 }
1143
1144 WhoAmI (&mMpServicesTemplate, &ProcessorNumber);
1145 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1146
1147 //
1148 // Avoid forcibly reset AP caused the AP State is not updated.
1149 //
1150 GetMpSpinLock (CpuData);
1151 CpuData->State = CpuStateIdle;
1152 CpuData->Procedure = NULL;
1153 ReleaseMpSpinLock (CpuData);
1154
1155 while (TRUE) {
1156 GetMpSpinLock (CpuData);
1157 ProcedureArgument = CpuData->Parameter;
1158 Procedure = CpuData->Procedure;
1159 ReleaseMpSpinLock (CpuData);
1160
1161 if (Procedure != NULL) {
1162 Procedure (ProcedureArgument);
1163
1164 GetMpSpinLock (CpuData);
1165 CpuData->Procedure = NULL;
1166 CpuData->State = CpuStateFinished;
1167 ReleaseMpSpinLock (CpuData);
1168 }
1169
1170 CpuPause ();
1171 }
1172
1173 CpuSleep ();
1174 CpuDeadLoop ();
1175 }
1176
1177 /**
1178 Checks AP' status periodically.
1179
1180 This function is triggerred by timer perodically to check the
1181 state of AP forStartupThisAP() executed in non-blocking mode.
1182
1183 @param Event Event triggered.
1184 @param Context Parameter passed with the event.
1185
1186 **/
1187 VOID
1188 EFIAPI
1189 CheckThisAPStatus (
1190 IN EFI_EVENT Event,
1191 IN VOID *Context
1192 )
1193 {
1194 CPU_DATA_BLOCK *CpuData;
1195 CPU_STATE CpuState;
1196
1197 CpuData = (CPU_DATA_BLOCK *) Context;
1198 if (CpuData->TimeoutActive) {
1199 CpuData->Timeout -= gPollInterval;
1200 }
1201
1202 CpuState = GetApState (CpuData);
1203
1204 if (CpuState == CpuStateFinished) {
1205 if (CpuData->Finished) {
1206 *CpuData->Finished = TRUE;
1207 }
1208 SetApState (CpuData, CpuStateIdle);
1209 goto out;
1210 }
1211
1212 if (CpuData->TimeoutActive && CpuData->Timeout < 0) {
1213 if (CpuState != CpuStateIdle &&
1214 CpuData->Finished) {
1215 *CpuData->Finished = FALSE;
1216 }
1217 ResetProcessorToIdleState (CpuData);
1218 goto out;
1219 }
1220
1221 return;
1222
1223 out:
1224 CpuData->TimeoutActive = FALSE;
1225 gBS->SignalEvent (CpuData->WaitEvent);
1226 CpuData->WaitEvent = NULL;
1227 }
1228
1229 /**
1230 Checks APs' status periodically.
1231
1232 This function is triggerred by timer perodically to check the
1233 state of APs for StartupAllAPs() executed in non-blocking mode.
1234
1235 @param Event Event triggered.
1236 @param Context Parameter passed with the event.
1237
1238 **/
1239 VOID
1240 EFIAPI
1241 CheckAllAPsStatus (
1242 IN EFI_EVENT Event,
1243 IN VOID *Context
1244 )
1245 {
1246 CPU_DATA_BLOCK *CpuData;
1247 UINTN Number;
1248 EFI_STATUS Status;
1249
1250 if (mMpSystemData.TimeoutActive) {
1251 mMpSystemData.Timeout -= gPollInterval;
1252 }
1253
1254 if (mStopCheckAllAPsStatus) {
1255 return;
1256 }
1257
1258 //
1259 // avoid next timer enter.
1260 //
1261 Status = gBS->SetTimer (
1262 mMpSystemData.CheckAllAPsEvent,
1263 TimerCancel,
1264 0
1265 );
1266 ASSERT_EFI_ERROR (Status);
1267
1268 if (mMpSystemData.WaitEvent != NULL) {
1269 CheckAndUpdateAllAPsToIdleState ();
1270 //
1271 // task timeout
1272 //
1273 if (mMpSystemData.TimeoutActive && mMpSystemData.Timeout < 0) {
1274 ResetAllFailedAPs();
1275 //
1276 // force exit
1277 //
1278 mMpSystemData.FinishCount = mMpSystemData.StartCount;
1279 }
1280
1281 if (mMpSystemData.FinishCount != mMpSystemData.StartCount) {
1282 goto EXIT;
1283 }
1284
1285 mMpSystemData.TimeoutActive = FALSE;
1286 gBS->SignalEvent (mMpSystemData.WaitEvent);
1287 mMpSystemData.WaitEvent = NULL;
1288 mStopCheckAllAPsStatus = TRUE;
1289
1290 goto EXIT;
1291 }
1292
1293 //
1294 // check each AP status for StartupThisAP
1295 //
1296 for (Number = 0; Number < mMpSystemData.NumberOfProcessors; Number++) {
1297 CpuData = &mMpSystemData.CpuDatas[Number];
1298 if (TestCpuStatusFlag (CpuData, PROCESSOR_AS_BSP_BIT)) {
1299 //
1300 // Skip BSP
1301 //
1302 continue;
1303 }
1304
1305 if (!TestCpuStatusFlag (CpuData, PROCESSOR_ENABLED_BIT)) {
1306 //
1307 // Skip Disabled processors
1308 //
1309 continue;
1310 }
1311
1312 if (CpuData->WaitEvent) {
1313 CheckThisAPStatus (NULL, (VOID *)CpuData);
1314 }
1315 }
1316
1317 EXIT:
1318 Status = gBS->SetTimer (
1319 mMpSystemData.CheckAllAPsEvent,
1320 TimerPeriodic,
1321 EFI_TIMER_PERIOD_MICROSECONDS (100)
1322 );
1323 ASSERT_EFI_ERROR (Status);
1324 }
1325
1326 /**
1327 Application Processor C code entry point.
1328
1329 **/
1330 VOID
1331 EFIAPI
1332 ApEntryPointInC (
1333 VOID
1334 )
1335 {
1336 VOID* TopOfApStack;
1337 UINTN ProcessorNumber;
1338
1339 if (!mAPsAlreadyInitFinished) {
1340 FillInProcessorInformation (FALSE, mMpSystemData.NumberOfProcessors);
1341 TopOfApStack = (UINT8*)mApStackStart + gApStackSize;
1342 mApStackStart = TopOfApStack;
1343
1344 //
1345 // Store the Stack address, when reset the AP, We can found the original address.
1346 //
1347 mMpSystemData.CpuDatas[mMpSystemData.NumberOfProcessors].TopOfStack = TopOfApStack;
1348 mMpSystemData.NumberOfProcessors++;
1349 mMpSystemData.NumberOfEnabledProcessors++;
1350 } else {
1351 WhoAmI (&mMpServicesTemplate, &ProcessorNumber);
1352 //
1353 // Get the original stack address.
1354 //
1355 TopOfApStack = mMpSystemData.CpuDatas[ProcessorNumber].TopOfStack;
1356 }
1357
1358 SwitchStack (
1359 (SWITCH_STACK_ENTRY_POINT)(UINTN)ProcessorToIdleState,
1360 NULL,
1361 NULL,
1362 TopOfApStack);
1363 }
1364
1365 /**
1366 This function is called by all processors (both BSP and AP) once and collects MP related data.
1367
1368 @param Bsp TRUE if the CPU is BSP
1369 @param ProcessorNumber The specific processor number
1370
1371 @retval EFI_SUCCESS Data for the processor collected and filled in
1372
1373 **/
1374 EFI_STATUS
1375 FillInProcessorInformation (
1376 IN BOOLEAN Bsp,
1377 IN UINTN ProcessorNumber
1378 )
1379 {
1380 CPU_DATA_BLOCK *CpuData;
1381 UINT32 ProcessorId;
1382
1383 CpuData = &mMpSystemData.CpuDatas[ProcessorNumber];
1384 ProcessorId = GetApicId ();
1385 CpuData->Info.ProcessorId = ProcessorId;
1386 CpuData->Info.StatusFlag = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT;
1387 if (Bsp) {
1388 CpuData->Info.StatusFlag |= PROCESSOR_AS_BSP_BIT;
1389 }
1390 CpuData->Info.Location.Package = ProcessorId;
1391 CpuData->Info.Location.Core = 0;
1392 CpuData->Info.Location.Thread = 0;
1393 CpuData->State = Bsp ? CpuStateBuzy : CpuStateIdle;
1394
1395 CpuData->Procedure = NULL;
1396 CpuData->Parameter = NULL;
1397 InitializeSpinLock (&CpuData->CpuDataLock);
1398
1399 return EFI_SUCCESS;
1400 }
1401
1402 /**
1403 Prepare the System Data.
1404
1405 @retval EFI_SUCCESS the System Data finished initilization.
1406
1407 **/
1408 EFI_STATUS
1409 InitMpSystemData (
1410 VOID
1411 )
1412 {
1413 EFI_STATUS Status;
1414
1415 ZeroMem (&mMpSystemData, sizeof (MP_SYSTEM_DATA));
1416
1417 mMpSystemData.NumberOfProcessors = 1;
1418 mMpSystemData.NumberOfEnabledProcessors = 1;
1419
1420 mMpSystemData.CpuDatas = AllocateZeroPool (sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber);
1421 ASSERT(mMpSystemData.CpuDatas != NULL);
1422
1423 Status = gBS->CreateEvent (
1424 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1425 TPL_CALLBACK,
1426 CheckAllAPsStatus,
1427 NULL,
1428 &mMpSystemData.CheckAllAPsEvent
1429 );
1430 ASSERT_EFI_ERROR (Status);
1431
1432 //
1433 // Set timer to check all APs status.
1434 //
1435 Status = gBS->SetTimer (
1436 mMpSystemData.CheckAllAPsEvent,
1437 TimerPeriodic,
1438 EFI_TIMER_PERIOD_MICROSECONDS (100)
1439 );
1440 ASSERT_EFI_ERROR (Status);
1441
1442 //
1443 // BSP
1444 //
1445 FillInProcessorInformation (TRUE, 0);
1446
1447 return EFI_SUCCESS;
1448 }
1449
1450 /**
1451 Initialize Multi-processor support.
1452
1453 **/
1454 VOID
1455 InitializeMpSupport (
1456 VOID
1457 )
1458 {
1459 gMaxLogicalProcessorNumber = (UINTN) PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
1460 if (gMaxLogicalProcessorNumber < 1) {
1461 DEBUG ((DEBUG_ERROR, "Setting PcdCpuMaxLogicalProcessorNumber should be more than zero.\n"));
1462 return;
1463 }
1464
1465 if (gMaxLogicalProcessorNumber == 1) {
1466 return;
1467 }
1468
1469 gApStackSize = (UINTN) PcdGet32 (PcdCpuApStackSize);
1470 ASSERT ((gApStackSize & (SIZE_4KB - 1)) == 0);
1471
1472 mApStackStart = AllocatePages (EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));
1473 ASSERT (mApStackStart != NULL);
1474
1475 //
1476 // the first buffer of stack size used for common stack, when the amount of AP
1477 // more than 1, we should never free the common stack which maybe used for AP reset.
1478 //
1479 mCommonStack = mApStackStart;
1480 mTopOfApCommonStack = (UINT8*) mApStackStart + gApStackSize;
1481 mApStackStart = mTopOfApCommonStack;
1482
1483 InitMpSystemData ();
1484
1485 PrepareAPStartupCode ();
1486
1487 if (mMpSystemData.NumberOfProcessors == 1) {
1488 FreeApStartupCode ();
1489 FreePages (mCommonStack, EFI_SIZE_TO_PAGES (gMaxLogicalProcessorNumber * gApStackSize));
1490 return;
1491 }
1492
1493 mMpSystemData.CpuDatas = ReallocatePool (
1494 sizeof (CPU_DATA_BLOCK) * gMaxLogicalProcessorNumber,
1495 sizeof (CPU_DATA_BLOCK) * mMpSystemData.NumberOfProcessors,
1496 mMpSystemData.CpuDatas);
1497
1498 mAPsAlreadyInitFinished = TRUE;
1499
1500 if (mMpSystemData.NumberOfProcessors < gMaxLogicalProcessorNumber) {
1501 FreePages (mApStackStart, EFI_SIZE_TO_PAGES (
1502 (gMaxLogicalProcessorNumber - mMpSystemData.NumberOfProcessors) *
1503 gApStackSize));
1504 }
1505 }