]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Implementation of MpInitLibEnableDisableAP()
[mirror_edk2.git] / UefiCpuPkg / Library / MpInitLib / MpLib.c
1 /** @file
2 CPU MP Initialize Library common functions.
3
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "MpLib.h"
16
17 EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
18
19 /**
20 The function will check if BSP Execute Disable is enabled.
21 DxeIpl may have enabled Execute Disable for BSP,
22 APs need to get the status and sync up the settings.
23
24 @retval TRUE BSP Execute Disable is enabled.
25 @retval FALSE BSP Execute Disable is not enabled.
26 **/
27 BOOLEAN
28 IsBspExecuteDisableEnabled (
29 VOID
30 )
31 {
32 UINT32 Eax;
33 CPUID_EXTENDED_CPU_SIG_EDX Edx;
34 MSR_IA32_EFER_REGISTER EferMsr;
35 BOOLEAN Enabled;
36
37 Enabled = FALSE;
38 AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);
39 if (Eax >= CPUID_EXTENDED_CPU_SIG) {
40 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);
41 //
42 // CPUID 0x80000001
43 // Bit 20: Execute Disable Bit available.
44 //
45 if (Edx.Bits.NX != 0) {
46 EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);
47 //
48 // MSR 0xC0000080
49 // Bit 11: Execute Disable Bit enable.
50 //
51 if (EferMsr.Bits.NXE != 0) {
52 Enabled = TRUE;
53 }
54 }
55 }
56
57 return Enabled;
58 }
59
60 /**
61 Get CPU Package/Core/Thread location information.
62
63 @param[in] InitialApicId CPU APIC ID
64 @param[out] Location Pointer to CPU location information
65 **/
66 VOID
67 ExtractProcessorLocation (
68 IN UINT32 InitialApicId,
69 OUT EFI_CPU_PHYSICAL_LOCATION *Location
70 )
71 {
72 BOOLEAN TopologyLeafSupported;
73 UINTN ThreadBits;
74 UINTN CoreBits;
75 CPUID_VERSION_INFO_EBX VersionInfoEbx;
76 CPUID_VERSION_INFO_EDX VersionInfoEdx;
77 CPUID_CACHE_PARAMS_EAX CacheParamsEax;
78 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
79 CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx;
80 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
81 UINT32 MaxCpuIdIndex;
82 UINT32 SubIndex;
83 UINTN LevelType;
84 UINT32 MaxLogicProcessorsPerPackage;
85 UINT32 MaxCoresPerPackage;
86
87 //
88 // Check if the processor is capable of supporting more than one logical processor.
89 //
90 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
91 if (VersionInfoEdx.Bits.HTT == 0) {
92 Location->Thread = 0;
93 Location->Core = 0;
94 Location->Package = 0;
95 return;
96 }
97
98 ThreadBits = 0;
99 CoreBits = 0;
100
101 //
102 // Assume three-level mapping of APIC ID: Package:Core:SMT.
103 //
104
105 TopologyLeafSupported = FALSE;
106 //
107 // Get the max index of basic CPUID
108 //
109 AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
110
111 //
112 // If the extended topology enumeration leaf is available, it
113 // is the preferred mechanism for enumerating topology.
114 //
115 if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
116 AsmCpuidEx (
117 CPUID_EXTENDED_TOPOLOGY,
118 0,
119 &ExtendedTopologyEax.Uint32,
120 &ExtendedTopologyEbx.Uint32,
121 &ExtendedTopologyEcx.Uint32,
122 NULL
123 );
124 //
125 // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
126 // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
127 // supported on that processor.
128 //
129 if (ExtendedTopologyEbx.Uint32 != 0) {
130 TopologyLeafSupported = TRUE;
131
132 //
133 // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
134 // the SMT sub-field of x2APIC ID.
135 //
136 LevelType = ExtendedTopologyEcx.Bits.LevelType;
137 ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
138 ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
139
140 //
141 // Software must not assume any "level type" encoding
142 // value to be related to any sub-leaf index, except sub-leaf 0.
143 //
144 SubIndex = 1;
145 do {
146 AsmCpuidEx (
147 CPUID_EXTENDED_TOPOLOGY,
148 SubIndex,
149 &ExtendedTopologyEax.Uint32,
150 NULL,
151 &ExtendedTopologyEcx.Uint32,
152 NULL
153 );
154 LevelType = ExtendedTopologyEcx.Bits.LevelType;
155 if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
156 CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
157 break;
158 }
159 SubIndex++;
160 } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
161 }
162 }
163
164 if (!TopologyLeafSupported) {
165 AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
166 MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
167 if (MaxCpuIdIndex >= CPUID_CACHE_PARAMS) {
168 AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
169 MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
170 } else {
171 //
172 // Must be a single-core processor.
173 //
174 MaxCoresPerPackage = 1;
175 }
176
177 ThreadBits = (UINTN) (HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
178 CoreBits = (UINTN) (HighBitSet32 (MaxCoresPerPackage - 1) + 1);
179 }
180
181 Location->Thread = InitialApicId & ((1 << ThreadBits) - 1);
182 Location->Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
183 Location->Package = (InitialApicId >> (ThreadBits + CoreBits));
184 }
185
186 /**
187 Worker function for SwitchBSP().
188
189 Worker function for SwitchBSP(), assigned to the AP which is intended
190 to become BSP.
191
192 @param[in] Buffer Pointer to CPU MP Data
193 **/
194 VOID
195 EFIAPI
196 FutureBSPProc (
197 IN VOID *Buffer
198 )
199 {
200 CPU_MP_DATA *DataInHob;
201
202 DataInHob = (CPU_MP_DATA *) Buffer;
203 AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
204 }
205
206 /**
207 Get the Application Processors state.
208
209 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
210
211 @return The AP status
212 **/
213 CPU_STATE
214 GetApState (
215 IN CPU_AP_DATA *CpuData
216 )
217 {
218 return CpuData->State;
219 }
220
221 /**
222 Set the Application Processors state.
223
224 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
225 @param[in] State The AP status
226 **/
227 VOID
228 SetApState (
229 IN CPU_AP_DATA *CpuData,
230 IN CPU_STATE State
231 )
232 {
233 AcquireSpinLock (&CpuData->ApLock);
234 CpuData->State = State;
235 ReleaseSpinLock (&CpuData->ApLock);
236 }
237
238 /**
239 Save the volatile registers required to be restored following INIT IPI.
240
241 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
242 **/
243 VOID
244 SaveVolatileRegisters (
245 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
246 )
247 {
248 CPUID_VERSION_INFO_EDX VersionInfoEdx;
249
250 VolatileRegisters->Cr0 = AsmReadCr0 ();
251 VolatileRegisters->Cr3 = AsmReadCr3 ();
252 VolatileRegisters->Cr4 = AsmReadCr4 ();
253
254 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
255 if (VersionInfoEdx.Bits.DE != 0) {
256 //
257 // If processor supports Debugging Extensions feature
258 // by CPUID.[EAX=01H]:EDX.BIT2
259 //
260 VolatileRegisters->Dr0 = AsmReadDr0 ();
261 VolatileRegisters->Dr1 = AsmReadDr1 ();
262 VolatileRegisters->Dr2 = AsmReadDr2 ();
263 VolatileRegisters->Dr3 = AsmReadDr3 ();
264 VolatileRegisters->Dr6 = AsmReadDr6 ();
265 VolatileRegisters->Dr7 = AsmReadDr7 ();
266 }
267 }
268
269 /**
270 Restore the volatile registers following INIT IPI.
271
272 @param[in] VolatileRegisters Pointer to volatile resisters
273 @param[in] IsRestoreDr TRUE: Restore DRx if supported
274 FALSE: Do not restore DRx
275 **/
276 VOID
277 RestoreVolatileRegisters (
278 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
279 IN BOOLEAN IsRestoreDr
280 )
281 {
282 CPUID_VERSION_INFO_EDX VersionInfoEdx;
283
284 AsmWriteCr0 (VolatileRegisters->Cr0);
285 AsmWriteCr3 (VolatileRegisters->Cr3);
286 AsmWriteCr4 (VolatileRegisters->Cr4);
287
288 if (IsRestoreDr) {
289 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
290 if (VersionInfoEdx.Bits.DE != 0) {
291 //
292 // If processor supports Debugging Extensions feature
293 // by CPUID.[EAX=01H]:EDX.BIT2
294 //
295 AsmWriteDr0 (VolatileRegisters->Dr0);
296 AsmWriteDr1 (VolatileRegisters->Dr1);
297 AsmWriteDr2 (VolatileRegisters->Dr2);
298 AsmWriteDr3 (VolatileRegisters->Dr3);
299 AsmWriteDr6 (VolatileRegisters->Dr6);
300 AsmWriteDr7 (VolatileRegisters->Dr7);
301 }
302 }
303 }
304
305 /**
306 Detect whether Mwait-monitor feature is supported.
307
308 @retval TRUE Mwait-monitor feature is supported.
309 @retval FALSE Mwait-monitor feature is not supported.
310 **/
311 BOOLEAN
312 IsMwaitSupport (
313 VOID
314 )
315 {
316 CPUID_VERSION_INFO_ECX VersionInfoEcx;
317
318 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);
319 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;
320 }
321
322 /**
323 Get AP loop mode.
324
325 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
326
327 @return The AP loop mode.
328 **/
329 UINT8
330 GetApLoopMode (
331 OUT UINT32 *MonitorFilterSize
332 )
333 {
334 UINT8 ApLoopMode;
335 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;
336
337 ASSERT (MonitorFilterSize != NULL);
338
339 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
340 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
341 if (ApLoopMode == ApInMwaitLoop) {
342 if (!IsMwaitSupport ()) {
343 //
344 // If processor does not support MONITOR/MWAIT feature,
345 // force AP in Hlt-loop mode
346 //
347 ApLoopMode = ApInHltLoop;
348 }
349 }
350
351 if (ApLoopMode != ApInMwaitLoop) {
352 *MonitorFilterSize = sizeof (UINT32);
353 } else {
354 //
355 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
356 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
357 //
358 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);
359 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;
360 }
361
362 return ApLoopMode;
363 }
364
365 /**
366 Sort the APIC ID of all processors.
367
368 This function sorts the APIC ID of all processors so that processor number is
369 assigned in the ascending order of APIC ID which eases MP debugging.
370
371 @param[in] CpuMpData Pointer to PEI CPU MP Data
372 **/
373 VOID
374 SortApicId (
375 IN CPU_MP_DATA *CpuMpData
376 )
377 {
378 UINTN Index1;
379 UINTN Index2;
380 UINTN Index3;
381 UINT32 ApicId;
382 CPU_AP_DATA CpuData;
383 UINT32 ApCount;
384 CPU_INFO_IN_HOB *CpuInfoInHob;
385
386 ApCount = CpuMpData->CpuCount - 1;
387
388 if (ApCount != 0) {
389 for (Index1 = 0; Index1 < ApCount; Index1++) {
390 Index3 = Index1;
391 //
392 // Sort key is the hardware default APIC ID
393 //
394 ApicId = CpuMpData->CpuData[Index1].ApicId;
395 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
396 if (ApicId > CpuMpData->CpuData[Index2].ApicId) {
397 Index3 = Index2;
398 ApicId = CpuMpData->CpuData[Index2].ApicId;
399 }
400 }
401 if (Index3 != Index1) {
402 CopyMem (&CpuData, &CpuMpData->CpuData[Index3], sizeof (CPU_AP_DATA));
403 CopyMem (
404 &CpuMpData->CpuData[Index3],
405 &CpuMpData->CpuData[Index1],
406 sizeof (CPU_AP_DATA)
407 );
408 CopyMem (&CpuMpData->CpuData[Index1], &CpuData, sizeof (CPU_AP_DATA));
409 }
410 }
411
412 //
413 // Get the processor number for the BSP
414 //
415 ApicId = GetInitialApicId ();
416 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
417 if (CpuMpData->CpuData[Index1].ApicId == ApicId) {
418 CpuMpData->BspNumber = (UINT32) Index1;
419 break;
420 }
421 }
422
423 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
424 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
425 CpuInfoInHob[Index1].InitialApicId = CpuMpData->CpuData[Index1].InitialApicId;
426 CpuInfoInHob[Index1].ApicId = CpuMpData->CpuData[Index1].ApicId;
427 CpuInfoInHob[Index1].Health = CpuMpData->CpuData[Index1].Health;
428 }
429 }
430 }
431
432 /**
433 Enable x2APIC mode on APs.
434
435 @param[in, out] Buffer Pointer to private data buffer.
436 **/
437 VOID
438 EFIAPI
439 ApFuncEnableX2Apic (
440 IN OUT VOID *Buffer
441 )
442 {
443 SetApicMode (LOCAL_APIC_MODE_X2APIC);
444 }
445
446 /**
447 Do sync on APs.
448
449 @param[in, out] Buffer Pointer to private data buffer.
450 **/
451 VOID
452 EFIAPI
453 ApInitializeSync (
454 IN OUT VOID *Buffer
455 )
456 {
457 CPU_MP_DATA *CpuMpData;
458
459 CpuMpData = (CPU_MP_DATA *) Buffer;
460 //
461 // Sync BSP's MTRR table to AP
462 //
463 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);
464 //
465 // Load microcode on AP
466 //
467 MicrocodeDetect (CpuMpData);
468 }
469
470 /**
471 Find the current Processor number by APIC ID.
472
473 @param[in] CpuMpData Pointer to PEI CPU MP Data
474 @param[in] ProcessorNumber Return the pocessor number found
475
476 @retval EFI_SUCCESS ProcessorNumber is found and returned.
477 @retval EFI_NOT_FOUND ProcessorNumber is not found.
478 **/
479 EFI_STATUS
480 GetProcessorNumber (
481 IN CPU_MP_DATA *CpuMpData,
482 OUT UINTN *ProcessorNumber
483 )
484 {
485 UINTN TotalProcessorNumber;
486 UINTN Index;
487
488 TotalProcessorNumber = CpuMpData->CpuCount;
489 for (Index = 0; Index < TotalProcessorNumber; Index ++) {
490 if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {
491 *ProcessorNumber = Index;
492 return EFI_SUCCESS;
493 }
494 }
495 return EFI_NOT_FOUND;
496 }
497
498 /**
499 This function will get CPU count in the system.
500
501 @param[in] CpuMpData Pointer to PEI CPU MP Data
502
503 @return CPU count detected
504 **/
505 UINTN
506 CollectProcessorCount (
507 IN CPU_MP_DATA *CpuMpData
508 )
509 {
510 //
511 // Send 1st broadcast IPI to APs to wakeup APs
512 //
513 CpuMpData->InitFlag = ApInitConfig;
514 CpuMpData->X2ApicEnable = FALSE;
515 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);
516 //
517 // Wait for AP task to complete and then exit.
518 //
519 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));
520 CpuMpData->InitFlag = ApInitDone;
521 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
522 //
523 // Wait for all APs finished the initialization
524 //
525 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
526 CpuPause ();
527 }
528
529 if (CpuMpData->X2ApicEnable) {
530 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));
531 //
532 // Wakeup all APs to enable x2APIC mode
533 //
534 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);
535 //
536 // Wait for all known APs finished
537 //
538 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
539 CpuPause ();
540 }
541 //
542 // Enable x2APIC on BSP
543 //
544 SetApicMode (LOCAL_APIC_MODE_X2APIC);
545 }
546 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));
547 //
548 // Sort BSP/Aps by CPU APIC ID in ascending order
549 //
550 SortApicId (CpuMpData);
551
552 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
553
554 return CpuMpData->CpuCount;
555 }
556
557 /*
558 Initialize CPU AP Data when AP is wakeup at the first time.
559
560 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
561 @param[in] ProcessorNumber The handle number of processor
562 @param[in] BistData Processor BIST data
563
564 **/
565 VOID
566 InitializeApData (
567 IN OUT CPU_MP_DATA *CpuMpData,
568 IN UINTN ProcessorNumber,
569 IN UINT32 BistData
570 )
571 {
572 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
573 CpuMpData->CpuData[ProcessorNumber].Health = BistData;
574 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
575 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
576 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
577 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {
578 //
579 // Set x2APIC mode if there are any logical processor reporting
580 // an Initial APIC ID of 255 or greater.
581 //
582 AcquireSpinLock(&CpuMpData->MpLock);
583 CpuMpData->X2ApicEnable = TRUE;
584 ReleaseSpinLock(&CpuMpData->MpLock);
585 }
586
587 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);
588 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
589 }
590
591 /**
592 This function will be called from AP reset code if BSP uses WakeUpAP.
593
594 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
595 @param[in] NumApsExecuting Number of current executing AP
596 **/
597 VOID
598 EFIAPI
599 ApWakeupFunction (
600 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
601 IN UINTN NumApsExecuting
602 )
603 {
604 CPU_MP_DATA *CpuMpData;
605 UINTN ProcessorNumber;
606 EFI_AP_PROCEDURE Procedure;
607 VOID *Parameter;
608 UINT32 BistData;
609 volatile UINT32 *ApStartupSignalBuffer;
610
611 //
612 // AP finished assembly code and begin to execute C code
613 //
614 CpuMpData = ExchangeInfo->CpuMpData;
615
616 ProgramVirtualWireMode ();
617
618 while (TRUE) {
619 if (CpuMpData->InitFlag == ApInitConfig) {
620 //
621 // Add CPU number
622 //
623 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);
624 ProcessorNumber = NumApsExecuting;
625 //
626 // This is first time AP wakeup, get BIST information from AP stack
627 //
628 BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));
629 //
630 // Do some AP initialize sync
631 //
632 ApInitializeSync (CpuMpData);
633 //
634 // Sync BSP's Control registers to APs
635 //
636 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
637 InitializeApData (CpuMpData, ProcessorNumber, BistData);
638 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
639 } else {
640 //
641 // Execute AP function if AP is ready
642 //
643 GetProcessorNumber (CpuMpData, &ProcessorNumber);
644 //
645 // Clear AP start-up signal when AP waken up
646 //
647 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
648 InterlockedCompareExchange32 (
649 (UINT32 *) ApStartupSignalBuffer,
650 WAKEUP_AP_SIGNAL,
651 0
652 );
653 if (CpuMpData->ApLoopMode == ApInHltLoop) {
654 //
655 // Restore AP's volatile registers saved
656 //
657 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
658 }
659
660 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
661 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
662 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
663 if (Procedure != NULL) {
664 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
665 //
666 // Invoke AP function here
667 //
668 Procedure (Parameter);
669 if (CpuMpData->SwitchBspFlag) {
670 //
671 // Re-get the processor number due to BSP/AP maybe exchange in AP function
672 //
673 GetProcessorNumber (CpuMpData, &ProcessorNumber);
674 CpuMpData->CpuData[ProcessorNumber].ApFunction = 0;
675 CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument = 0;
676 } else {
677 //
678 // Re-get the CPU APICID and Initial APICID
679 //
680 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
681 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
682 }
683 }
684 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
685 }
686 }
687
688 //
689 // AP finished executing C code
690 //
691 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);
692
693 //
694 // Place AP is specified loop mode
695 //
696 if (CpuMpData->ApLoopMode == ApInHltLoop) {
697 //
698 // Save AP volatile registers
699 //
700 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
701 //
702 // Place AP in HLT-loop
703 //
704 while (TRUE) {
705 DisableInterrupts ();
706 CpuSleep ();
707 CpuPause ();
708 }
709 }
710 while (TRUE) {
711 DisableInterrupts ();
712 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
713 //
714 // Place AP in MWAIT-loop
715 //
716 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);
717 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
718 //
719 // Check AP start-up signal again.
720 // If AP start-up signal is not set, place AP into
721 // the specified C-state
722 //
723 AsmMwait (CpuMpData->ApTargetCState << 4, 0);
724 }
725 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {
726 //
727 // Place AP in Run-loop
728 //
729 CpuPause ();
730 } else {
731 ASSERT (FALSE);
732 }
733
734 //
735 // If AP start-up signal is written, AP is waken up
736 // otherwise place AP in loop again
737 //
738 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
739 break;
740 }
741 }
742 }
743 }
744
745 /**
746 Wait for AP wakeup and write AP start-up signal till AP is waken up.
747
748 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
749 **/
750 VOID
751 WaitApWakeup (
752 IN volatile UINT32 *ApStartupSignalBuffer
753 )
754 {
755 //
756 // If AP is waken up, StartupApSignal should be cleared.
757 // Otherwise, write StartupApSignal again till AP waken up.
758 //
759 while (InterlockedCompareExchange32 (
760 (UINT32 *) ApStartupSignalBuffer,
761 WAKEUP_AP_SIGNAL,
762 WAKEUP_AP_SIGNAL
763 ) != 0) {
764 CpuPause ();
765 }
766 }
767
768 /**
769 This function will fill the exchange info structure.
770
771 @param[in] CpuMpData Pointer to CPU MP Data
772
773 **/
774 VOID
775 FillExchangeInfoData (
776 IN CPU_MP_DATA *CpuMpData
777 )
778 {
779 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
780
781 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
782 ExchangeInfo->Lock = 0;
783 ExchangeInfo->StackStart = CpuMpData->Buffer;
784 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;
785 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;
786 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;
787
788 ExchangeInfo->CodeSegment = AsmReadCs ();
789 ExchangeInfo->DataSegment = AsmReadDs ();
790
791 ExchangeInfo->Cr3 = AsmReadCr3 ();
792
793 ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;
794 ExchangeInfo->NumApsExecuting = 0;
795 ExchangeInfo->CpuMpData = CpuMpData;
796
797 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();
798
799 //
800 // Get the BSP's data of GDT and IDT
801 //
802 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
803 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
804 }
805
806 /**
807 This function will be called by BSP to wakeup AP.
808
809 @param[in] CpuMpData Pointer to CPU MP Data
810 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
811 FALSE: Send IPI to AP by ApicId
812 @param[in] ProcessorNumber The handle number of specified processor
813 @param[in] Procedure The function to be invoked by AP
814 @param[in] ProcedureArgument The argument to be passed into AP function
815 **/
816 VOID
817 WakeUpAP (
818 IN CPU_MP_DATA *CpuMpData,
819 IN BOOLEAN Broadcast,
820 IN UINTN ProcessorNumber,
821 IN EFI_AP_PROCEDURE Procedure, OPTIONAL
822 IN VOID *ProcedureArgument OPTIONAL
823 )
824 {
825 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
826 UINTN Index;
827 CPU_AP_DATA *CpuData;
828 BOOLEAN ResetVectorRequired;
829
830 CpuMpData->FinishedCount = 0;
831 ResetVectorRequired = FALSE;
832
833 if (CpuMpData->ApLoopMode == ApInHltLoop ||
834 CpuMpData->InitFlag != ApInitDone) {
835 ResetVectorRequired = TRUE;
836 AllocateResetVector (CpuMpData);
837 FillExchangeInfoData (CpuMpData);
838 } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
839 //
840 // Get AP target C-state each time when waking up AP,
841 // for it maybe updated by platform again
842 //
843 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
844 }
845
846 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
847
848 if (Broadcast) {
849 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
850 if (Index != CpuMpData->BspNumber) {
851 CpuData = &CpuMpData->CpuData[Index];
852 CpuData->ApFunction = (UINTN) Procedure;
853 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
854 SetApState (CpuData, CpuStateReady);
855 if (CpuMpData->InitFlag != ApInitConfig) {
856 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
857 }
858 }
859 }
860 if (ResetVectorRequired) {
861 //
862 // Wakeup all APs
863 //
864 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
865 }
866 if (CpuMpData->InitFlag != ApInitConfig) {
867 //
868 // Wait all APs waken up if this is not the 1st broadcast of SIPI
869 //
870 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
871 CpuData = &CpuMpData->CpuData[Index];
872 if (Index != CpuMpData->BspNumber) {
873 WaitApWakeup (CpuData->StartupApSignal);
874 }
875 }
876 }
877 } else {
878 CpuData = &CpuMpData->CpuData[ProcessorNumber];
879 CpuData->ApFunction = (UINTN) Procedure;
880 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
881 SetApState (CpuData, CpuStateReady);
882 //
883 // Wakeup specified AP
884 //
885 ASSERT (CpuMpData->InitFlag != ApInitConfig);
886 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
887 if (ResetVectorRequired) {
888 SendInitSipiSipi (
889 CpuData->ApicId,
890 (UINT32) ExchangeInfo->BufferStart
891 );
892 }
893 //
894 // Wait specified AP waken up
895 //
896 WaitApWakeup (CpuData->StartupApSignal);
897 }
898
899 if (ResetVectorRequired) {
900 FreeResetVector (CpuMpData);
901 }
902 }
903
904 /**
905 MP Initialize Library initialization.
906
907 This service will allocate AP reset vector and wakeup all APs to do APs
908 initialization.
909
910 This service must be invoked before all other MP Initialize Library
911 service are invoked.
912
913 @retval EFI_SUCCESS MP initialization succeeds.
914 @retval Others MP initialization fails.
915
916 **/
917 EFI_STATUS
918 EFIAPI
919 MpInitLibInitialize (
920 VOID
921 )
922 {
923 CPU_MP_DATA *OldCpuMpData;
924 CPU_INFO_IN_HOB *CpuInfoInHob;
925 UINT32 MaxLogicalProcessorNumber;
926 UINT32 ApStackSize;
927 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
928 UINTN BufferSize;
929 UINT32 MonitorFilterSize;
930 VOID *MpBuffer;
931 UINTN Buffer;
932 CPU_MP_DATA *CpuMpData;
933 UINT8 ApLoopMode;
934 UINT8 *MonitorBuffer;
935 UINTN Index;
936 UINTN ApResetVectorSize;
937 UINTN BackupBufferAddr;
938
939 OldCpuMpData = GetCpuMpDataFromGuidedHob ();
940 if (OldCpuMpData == NULL) {
941 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
942 } else {
943 MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
944 }
945
946 AsmGetAddressMap (&AddressMap);
947 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
948 ApStackSize = PcdGet32(PcdCpuApStackSize);
949 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
950
951 BufferSize = ApStackSize * MaxLogicalProcessorNumber;
952 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
953 BufferSize += sizeof (CPU_MP_DATA);
954 BufferSize += ApResetVectorSize;
955 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
956 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
957 ASSERT (MpBuffer != NULL);
958 ZeroMem (MpBuffer, BufferSize);
959 Buffer = (UINTN) MpBuffer;
960
961 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);
962 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
963 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);
964 CpuMpData->Buffer = Buffer;
965 CpuMpData->CpuApStackSize = ApStackSize;
966 CpuMpData->BackupBuffer = BackupBufferAddr;
967 CpuMpData->BackupBufferSize = ApResetVectorSize;
968 CpuMpData->EndOfPeiFlag = FALSE;
969 CpuMpData->WakeupBuffer = (UINTN) -1;
970 CpuMpData->CpuCount = 1;
971 CpuMpData->BspNumber = 0;
972 CpuMpData->WaitEvent = NULL;
973 CpuMpData->SwitchBspFlag = FALSE;
974 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);
975 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
976 InitializeSpinLock(&CpuMpData->MpLock);
977 //
978 // Save BSP's Control registers to APs
979 //
980 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);
981 //
982 // Set BSP basic information
983 //
984 InitializeApData (CpuMpData, 0, 0);
985 //
986 // Save assembly code information
987 //
988 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
989 //
990 // Finally set AP loop mode
991 //
992 CpuMpData->ApLoopMode = ApLoopMode;
993 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
994 //
995 // Set up APs wakeup signal buffer
996 //
997 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
998 CpuMpData->CpuData[Index].StartupApSignal =
999 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
1000 }
1001 //
1002 // Load Microcode on BSP
1003 //
1004 MicrocodeDetect (CpuMpData);
1005 //
1006 // Store BSP's MTRR setting
1007 //
1008 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
1009
1010 if (OldCpuMpData == NULL) {
1011 //
1012 // Wakeup all APs and calculate the processor count in system
1013 //
1014 CollectProcessorCount (CpuMpData);
1015 } else {
1016 //
1017 // APs have been wakeup before, just get the CPU Information
1018 // from HOB
1019 //
1020 CpuMpData->CpuCount = OldCpuMpData->CpuCount;
1021 CpuMpData->BspNumber = OldCpuMpData->BspNumber;
1022 CpuMpData->InitFlag = ApInitReconfig;
1023 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) OldCpuMpData->CpuInfoInHob;
1024 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1025 InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);
1026 CpuMpData->CpuData[Index].ApicId = CpuInfoInHob[Index].ApicId;
1027 CpuMpData->CpuData[Index].InitialApicId = CpuInfoInHob[Index].InitialApicId;
1028 if (CpuMpData->CpuData[Index].InitialApicId >= 255) {
1029 CpuMpData->X2ApicEnable = TRUE;
1030 }
1031 CpuMpData->CpuData[Index].Health = CpuInfoInHob[Index].Health;
1032 CpuMpData->CpuData[Index].CpuHealthy = (CpuMpData->CpuData[Index].Health == 0)? TRUE:FALSE;
1033 CpuMpData->CpuData[Index].ApFunction = 0;
1034 CopyMem (
1035 &CpuMpData->CpuData[Index].VolatileRegisters,
1036 &CpuMpData->CpuData[0].VolatileRegisters,
1037 sizeof (CPU_VOLATILE_REGISTERS)
1038 );
1039 }
1040 //
1041 // Wakeup APs to do some AP initialize sync
1042 //
1043 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData);
1044 //
1045 // Wait for all APs finished initialization
1046 //
1047 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
1048 CpuPause ();
1049 }
1050 CpuMpData->InitFlag = ApInitDone;
1051 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1052 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
1053 }
1054 }
1055
1056 //
1057 // Initialize global data for MP support
1058 //
1059 InitMpGlobalData (CpuMpData);
1060
1061 return EFI_SUCCESS;
1062 }
1063
1064 /**
1065 Gets detailed MP-related information on the requested processor at the
1066 instant this call is made. This service may only be called from the BSP.
1067
1068 @param[in] ProcessorNumber The handle number of processor.
1069 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
1070 the requested processor is deposited.
1071 @param[out] HealthData Return processor health data.
1072
1073 @retval EFI_SUCCESS Processor information was returned.
1074 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1075 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
1076 @retval EFI_NOT_FOUND The processor with the handle specified by
1077 ProcessorNumber does not exist in the platform.
1078 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1079
1080 **/
1081 EFI_STATUS
1082 EFIAPI
1083 MpInitLibGetProcessorInfo (
1084 IN UINTN ProcessorNumber,
1085 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
1086 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
1087 )
1088 {
1089 CPU_MP_DATA *CpuMpData;
1090 UINTN CallerNumber;
1091
1092 CpuMpData = GetCpuMpData ();
1093
1094 //
1095 // Check whether caller processor is BSP
1096 //
1097 MpInitLibWhoAmI (&CallerNumber);
1098 if (CallerNumber != CpuMpData->BspNumber) {
1099 return EFI_DEVICE_ERROR;
1100 }
1101
1102 if (ProcessorInfoBuffer == NULL) {
1103 return EFI_INVALID_PARAMETER;
1104 }
1105
1106 if (ProcessorNumber >= CpuMpData->CpuCount) {
1107 return EFI_NOT_FOUND;
1108 }
1109
1110 ProcessorInfoBuffer->ProcessorId = (UINT64) CpuMpData->CpuData[ProcessorNumber].ApicId;
1111 ProcessorInfoBuffer->StatusFlag = 0;
1112 if (ProcessorNumber == CpuMpData->BspNumber) {
1113 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
1114 }
1115 if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
1116 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
1117 }
1118 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
1119 ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
1120 } else {
1121 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
1122 }
1123
1124 //
1125 // Get processor location information
1126 //
1127 ExtractProcessorLocation (CpuMpData->CpuData[ProcessorNumber].ApicId, &ProcessorInfoBuffer->Location);
1128
1129 if (HealthData != NULL) {
1130 HealthData->Uint32 = CpuMpData->CpuData[ProcessorNumber].Health;
1131 }
1132
1133 return EFI_SUCCESS;
1134 }
1135
1136 /**
1137 Worker function to switch the requested AP to be the BSP from that point onward.
1138
1139 @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
1140 @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
1141 enabled AP. Otherwise, it will be disabled.
1142
1143 @retval EFI_SUCCESS BSP successfully switched.
1144 @retval others Failed to switch BSP.
1145
1146 **/
1147 EFI_STATUS
1148 SwitchBSPWorker (
1149 IN UINTN ProcessorNumber,
1150 IN BOOLEAN EnableOldBSP
1151 )
1152 {
1153 CPU_MP_DATA *CpuMpData;
1154 UINTN CallerNumber;
1155 CPU_STATE State;
1156 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
1157
1158 CpuMpData = GetCpuMpData ();
1159
1160 //
1161 // Check whether caller processor is BSP
1162 //
1163 MpInitLibWhoAmI (&CallerNumber);
1164 if (CallerNumber != CpuMpData->BspNumber) {
1165 return EFI_SUCCESS;
1166 }
1167
1168 if (ProcessorNumber >= CpuMpData->CpuCount) {
1169 return EFI_NOT_FOUND;
1170 }
1171
1172 //
1173 // Check whether specified AP is disabled
1174 //
1175 State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);
1176 if (State == CpuStateDisabled) {
1177 return EFI_INVALID_PARAMETER;
1178 }
1179
1180 //
1181 // Check whether ProcessorNumber specifies the current BSP
1182 //
1183 if (ProcessorNumber == CpuMpData->BspNumber) {
1184 return EFI_INVALID_PARAMETER;
1185 }
1186
1187 //
1188 // Check whether specified AP is busy
1189 //
1190 if (State == CpuStateBusy) {
1191 return EFI_NOT_READY;
1192 }
1193
1194 CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
1195 CpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;
1196 CpuMpData->SwitchBspFlag = TRUE;
1197
1198 //
1199 // Clear the BSP bit of MSR_IA32_APIC_BASE
1200 //
1201 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
1202 ApicBaseMsr.Bits.BSP = 0;
1203 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
1204
1205 //
1206 // Need to wakeUp AP (future BSP).
1207 //
1208 WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData);
1209
1210 AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);
1211
1212 //
1213 // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
1214 //
1215 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
1216 ApicBaseMsr.Bits.BSP = 1;
1217 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
1218
1219 //
1220 // Wait for old BSP finished AP task
1221 //
1222 while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {
1223 CpuPause ();
1224 }
1225
1226 CpuMpData->SwitchBspFlag = FALSE;
1227 //
1228 // Set old BSP enable state
1229 //
1230 if (!EnableOldBSP) {
1231 SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);
1232 }
1233 //
1234 // Save new BSP number
1235 //
1236 CpuMpData->BspNumber = (UINT32) ProcessorNumber;
1237
1238 return EFI_SUCCESS;
1239 }
1240
1241 /**
1242 Worker function to let the caller enable or disable an AP from this point onward.
1243 This service may only be called from the BSP.
1244
1245 @param[in] ProcessorNumber The handle number of AP.
1246 @param[in] EnableAP Specifies the new state for the processor for
1247 enabled, FALSE for disabled.
1248 @param[in] HealthFlag If not NULL, a pointer to a value that specifies
1249 the new health status of the AP.
1250
1251 @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
1252 @retval others Failed to Enable/Disable AP.
1253
1254 **/
1255 EFI_STATUS
1256 EnableDisableApWorker (
1257 IN UINTN ProcessorNumber,
1258 IN BOOLEAN EnableAP,
1259 IN UINT32 *HealthFlag OPTIONAL
1260 )
1261 {
1262 CPU_MP_DATA *CpuMpData;
1263 UINTN CallerNumber;
1264
1265 CpuMpData = GetCpuMpData ();
1266
1267 //
1268 // Check whether caller processor is BSP
1269 //
1270 MpInitLibWhoAmI (&CallerNumber);
1271 if (CallerNumber != CpuMpData->BspNumber) {
1272 return EFI_DEVICE_ERROR;
1273 }
1274
1275 if (ProcessorNumber == CpuMpData->BspNumber) {
1276 return EFI_INVALID_PARAMETER;
1277 }
1278
1279 if (ProcessorNumber >= CpuMpData->CpuCount) {
1280 return EFI_NOT_FOUND;
1281 }
1282
1283 if (!EnableAP) {
1284 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);
1285 } else {
1286 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
1287 }
1288
1289 if (HealthFlag != NULL) {
1290 CpuMpData->CpuData[ProcessorNumber].CpuHealthy =
1291 (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);
1292 }
1293
1294 return EFI_SUCCESS;
1295 }
1296
1297 /**
1298 This return the handle number for the calling processor. This service may be
1299 called from the BSP and APs.
1300
1301 @param[out] ProcessorNumber Pointer to the handle number of AP.
1302 The range is from 0 to the total number of
1303 logical processors minus 1. The total number of
1304 logical processors can be retrieved by
1305 MpInitLibGetNumberOfProcessors().
1306
1307 @retval EFI_SUCCESS The current processor handle number was returned
1308 in ProcessorNumber.
1309 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
1310 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1311
1312 **/
1313 EFI_STATUS
1314 EFIAPI
1315 MpInitLibWhoAmI (
1316 OUT UINTN *ProcessorNumber
1317 )
1318 {
1319 CPU_MP_DATA *CpuMpData;
1320
1321 if (ProcessorNumber == NULL) {
1322 return EFI_INVALID_PARAMETER;
1323 }
1324
1325 CpuMpData = GetCpuMpData ();
1326
1327 return GetProcessorNumber (CpuMpData, ProcessorNumber);
1328 }
1329
1330 /**
1331 Retrieves the number of logical processor in the platform and the number of
1332 those logical processors that are enabled on this boot. This service may only
1333 be called from the BSP.
1334
1335 @param[out] NumberOfProcessors Pointer to the total number of logical
1336 processors in the system, including the BSP
1337 and disabled APs.
1338 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
1339 processors that exist in system, including
1340 the BSP.
1341
1342 @retval EFI_SUCCESS The number of logical processors and enabled
1343 logical processors was retrieved.
1344 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1345 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
1346 is NULL.
1347 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1348
1349 **/
1350 EFI_STATUS
1351 EFIAPI
1352 MpInitLibGetNumberOfProcessors (
1353 OUT UINTN *NumberOfProcessors, OPTIONAL
1354 OUT UINTN *NumberOfEnabledProcessors OPTIONAL
1355 )
1356 {
1357 CPU_MP_DATA *CpuMpData;
1358 UINTN CallerNumber;
1359 UINTN ProcessorNumber;
1360 UINTN EnabledProcessorNumber;
1361 UINTN Index;
1362
1363 CpuMpData = GetCpuMpData ();
1364
1365 if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
1366 return EFI_INVALID_PARAMETER;
1367 }
1368
1369 //
1370 // Check whether caller processor is BSP
1371 //
1372 MpInitLibWhoAmI (&CallerNumber);
1373 if (CallerNumber != CpuMpData->BspNumber) {
1374 return EFI_DEVICE_ERROR;
1375 }
1376
1377 ProcessorNumber = CpuMpData->CpuCount;
1378 EnabledProcessorNumber = 0;
1379 for (Index = 0; Index < ProcessorNumber; Index++) {
1380 if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {
1381 EnabledProcessorNumber ++;
1382 }
1383 }
1384
1385 if (NumberOfProcessors != NULL) {
1386 *NumberOfProcessors = ProcessorNumber;
1387 }
1388 if (NumberOfEnabledProcessors != NULL) {
1389 *NumberOfEnabledProcessors = EnabledProcessorNumber;
1390 }
1391
1392 return EFI_SUCCESS;
1393 }
1394
1395
1396 /**
1397 Get pointer to CPU MP Data structure from GUIDed HOB.
1398
1399 @return The pointer to CPU MP Data structure.
1400 **/
1401 CPU_MP_DATA *
1402 GetCpuMpDataFromGuidedHob (
1403 VOID
1404 )
1405 {
1406 EFI_HOB_GUID_TYPE *GuidHob;
1407 VOID *DataInHob;
1408 CPU_MP_DATA *CpuMpData;
1409
1410 CpuMpData = NULL;
1411 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
1412 if (GuidHob != NULL) {
1413 DataInHob = GET_GUID_HOB_DATA (GuidHob);
1414 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);
1415 }
1416 return CpuMpData;
1417 }