]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/MpInitLib/MpLib.c
UefiCpuPkg/MpInitLib: Implementation of MpInitLibWhoAmI()
[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 Get the Application Processors state.
188
189 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
190
191 @return The AP status
192 **/
193 CPU_STATE
194 GetApState (
195 IN CPU_AP_DATA *CpuData
196 )
197 {
198 return CpuData->State;
199 }
200
201 /**
202 Set the Application Processors state.
203
204 @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
205 @param[in] State The AP status
206 **/
207 VOID
208 SetApState (
209 IN CPU_AP_DATA *CpuData,
210 IN CPU_STATE State
211 )
212 {
213 AcquireSpinLock (&CpuData->ApLock);
214 CpuData->State = State;
215 ReleaseSpinLock (&CpuData->ApLock);
216 }
217
218 /**
219 Save the volatile registers required to be restored following INIT IPI.
220
221 @param[out] VolatileRegisters Returns buffer saved the volatile resisters
222 **/
223 VOID
224 SaveVolatileRegisters (
225 OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
226 )
227 {
228 CPUID_VERSION_INFO_EDX VersionInfoEdx;
229
230 VolatileRegisters->Cr0 = AsmReadCr0 ();
231 VolatileRegisters->Cr3 = AsmReadCr3 ();
232 VolatileRegisters->Cr4 = AsmReadCr4 ();
233
234 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
235 if (VersionInfoEdx.Bits.DE != 0) {
236 //
237 // If processor supports Debugging Extensions feature
238 // by CPUID.[EAX=01H]:EDX.BIT2
239 //
240 VolatileRegisters->Dr0 = AsmReadDr0 ();
241 VolatileRegisters->Dr1 = AsmReadDr1 ();
242 VolatileRegisters->Dr2 = AsmReadDr2 ();
243 VolatileRegisters->Dr3 = AsmReadDr3 ();
244 VolatileRegisters->Dr6 = AsmReadDr6 ();
245 VolatileRegisters->Dr7 = AsmReadDr7 ();
246 }
247 }
248
249 /**
250 Restore the volatile registers following INIT IPI.
251
252 @param[in] VolatileRegisters Pointer to volatile resisters
253 @param[in] IsRestoreDr TRUE: Restore DRx if supported
254 FALSE: Do not restore DRx
255 **/
256 VOID
257 RestoreVolatileRegisters (
258 IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
259 IN BOOLEAN IsRestoreDr
260 )
261 {
262 CPUID_VERSION_INFO_EDX VersionInfoEdx;
263
264 AsmWriteCr0 (VolatileRegisters->Cr0);
265 AsmWriteCr3 (VolatileRegisters->Cr3);
266 AsmWriteCr4 (VolatileRegisters->Cr4);
267
268 if (IsRestoreDr) {
269 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
270 if (VersionInfoEdx.Bits.DE != 0) {
271 //
272 // If processor supports Debugging Extensions feature
273 // by CPUID.[EAX=01H]:EDX.BIT2
274 //
275 AsmWriteDr0 (VolatileRegisters->Dr0);
276 AsmWriteDr1 (VolatileRegisters->Dr1);
277 AsmWriteDr2 (VolatileRegisters->Dr2);
278 AsmWriteDr3 (VolatileRegisters->Dr3);
279 AsmWriteDr6 (VolatileRegisters->Dr6);
280 AsmWriteDr7 (VolatileRegisters->Dr7);
281 }
282 }
283 }
284
285 /**
286 Detect whether Mwait-monitor feature is supported.
287
288 @retval TRUE Mwait-monitor feature is supported.
289 @retval FALSE Mwait-monitor feature is not supported.
290 **/
291 BOOLEAN
292 IsMwaitSupport (
293 VOID
294 )
295 {
296 CPUID_VERSION_INFO_ECX VersionInfoEcx;
297
298 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);
299 return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;
300 }
301
302 /**
303 Get AP loop mode.
304
305 @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
306
307 @return The AP loop mode.
308 **/
309 UINT8
310 GetApLoopMode (
311 OUT UINT32 *MonitorFilterSize
312 )
313 {
314 UINT8 ApLoopMode;
315 CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;
316
317 ASSERT (MonitorFilterSize != NULL);
318
319 ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
320 ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
321 if (ApLoopMode == ApInMwaitLoop) {
322 if (!IsMwaitSupport ()) {
323 //
324 // If processor does not support MONITOR/MWAIT feature,
325 // force AP in Hlt-loop mode
326 //
327 ApLoopMode = ApInHltLoop;
328 }
329 }
330
331 if (ApLoopMode != ApInMwaitLoop) {
332 *MonitorFilterSize = sizeof (UINT32);
333 } else {
334 //
335 // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
336 // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
337 //
338 AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);
339 *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;
340 }
341
342 return ApLoopMode;
343 }
344
345 /**
346 Sort the APIC ID of all processors.
347
348 This function sorts the APIC ID of all processors so that processor number is
349 assigned in the ascending order of APIC ID which eases MP debugging.
350
351 @param[in] CpuMpData Pointer to PEI CPU MP Data
352 **/
353 VOID
354 SortApicId (
355 IN CPU_MP_DATA *CpuMpData
356 )
357 {
358 UINTN Index1;
359 UINTN Index2;
360 UINTN Index3;
361 UINT32 ApicId;
362 CPU_AP_DATA CpuData;
363 UINT32 ApCount;
364 CPU_INFO_IN_HOB *CpuInfoInHob;
365
366 ApCount = CpuMpData->CpuCount - 1;
367
368 if (ApCount != 0) {
369 for (Index1 = 0; Index1 < ApCount; Index1++) {
370 Index3 = Index1;
371 //
372 // Sort key is the hardware default APIC ID
373 //
374 ApicId = CpuMpData->CpuData[Index1].ApicId;
375 for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
376 if (ApicId > CpuMpData->CpuData[Index2].ApicId) {
377 Index3 = Index2;
378 ApicId = CpuMpData->CpuData[Index2].ApicId;
379 }
380 }
381 if (Index3 != Index1) {
382 CopyMem (&CpuData, &CpuMpData->CpuData[Index3], sizeof (CPU_AP_DATA));
383 CopyMem (
384 &CpuMpData->CpuData[Index3],
385 &CpuMpData->CpuData[Index1],
386 sizeof (CPU_AP_DATA)
387 );
388 CopyMem (&CpuMpData->CpuData[Index1], &CpuData, sizeof (CPU_AP_DATA));
389 }
390 }
391
392 //
393 // Get the processor number for the BSP
394 //
395 ApicId = GetInitialApicId ();
396 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
397 if (CpuMpData->CpuData[Index1].ApicId == ApicId) {
398 CpuMpData->BspNumber = (UINT32) Index1;
399 break;
400 }
401 }
402
403 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
404 for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
405 CpuInfoInHob[Index1].InitialApicId = CpuMpData->CpuData[Index1].InitialApicId;
406 CpuInfoInHob[Index1].ApicId = CpuMpData->CpuData[Index1].ApicId;
407 CpuInfoInHob[Index1].Health = CpuMpData->CpuData[Index1].Health;
408 }
409 }
410 }
411
412 /**
413 Enable x2APIC mode on APs.
414
415 @param[in, out] Buffer Pointer to private data buffer.
416 **/
417 VOID
418 EFIAPI
419 ApFuncEnableX2Apic (
420 IN OUT VOID *Buffer
421 )
422 {
423 SetApicMode (LOCAL_APIC_MODE_X2APIC);
424 }
425
426 /**
427 Do sync on APs.
428
429 @param[in, out] Buffer Pointer to private data buffer.
430 **/
431 VOID
432 EFIAPI
433 ApInitializeSync (
434 IN OUT VOID *Buffer
435 )
436 {
437 CPU_MP_DATA *CpuMpData;
438
439 CpuMpData = (CPU_MP_DATA *) Buffer;
440 //
441 // Sync BSP's MTRR table to AP
442 //
443 MtrrSetAllMtrrs (&CpuMpData->MtrrTable);
444 //
445 // Load microcode on AP
446 //
447 MicrocodeDetect (CpuMpData);
448 }
449
450 /**
451 Find the current Processor number by APIC ID.
452
453 @param[in] CpuMpData Pointer to PEI CPU MP Data
454 @param[in] ProcessorNumber Return the pocessor number found
455
456 @retval EFI_SUCCESS ProcessorNumber is found and returned.
457 @retval EFI_NOT_FOUND ProcessorNumber is not found.
458 **/
459 EFI_STATUS
460 GetProcessorNumber (
461 IN CPU_MP_DATA *CpuMpData,
462 OUT UINTN *ProcessorNumber
463 )
464 {
465 UINTN TotalProcessorNumber;
466 UINTN Index;
467
468 TotalProcessorNumber = CpuMpData->CpuCount;
469 for (Index = 0; Index < TotalProcessorNumber; Index ++) {
470 if (CpuMpData->CpuData[Index].ApicId == GetApicId ()) {
471 *ProcessorNumber = Index;
472 return EFI_SUCCESS;
473 }
474 }
475 return EFI_NOT_FOUND;
476 }
477
478 /**
479 This function will get CPU count in the system.
480
481 @param[in] CpuMpData Pointer to PEI CPU MP Data
482
483 @return CPU count detected
484 **/
485 UINTN
486 CollectProcessorCount (
487 IN CPU_MP_DATA *CpuMpData
488 )
489 {
490 //
491 // Send 1st broadcast IPI to APs to wakeup APs
492 //
493 CpuMpData->InitFlag = ApInitConfig;
494 CpuMpData->X2ApicEnable = FALSE;
495 WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL);
496 //
497 // Wait for AP task to complete and then exit.
498 //
499 MicroSecondDelay (PcdGet32(PcdCpuApInitTimeOutInMicroSeconds));
500 CpuMpData->InitFlag = ApInitDone;
501 ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
502 //
503 // Wait for all APs finished the initialization
504 //
505 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
506 CpuPause ();
507 }
508
509 if (CpuMpData->X2ApicEnable) {
510 DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));
511 //
512 // Wakeup all APs to enable x2APIC mode
513 //
514 WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL);
515 //
516 // Wait for all known APs finished
517 //
518 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
519 CpuPause ();
520 }
521 //
522 // Enable x2APIC on BSP
523 //
524 SetApicMode (LOCAL_APIC_MODE_X2APIC);
525 }
526 DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));
527 //
528 // Sort BSP/Aps by CPU APIC ID in ascending order
529 //
530 SortApicId (CpuMpData);
531
532 DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
533
534 return CpuMpData->CpuCount;
535 }
536
537 /*
538 Initialize CPU AP Data when AP is wakeup at the first time.
539
540 @param[in, out] CpuMpData Pointer to PEI CPU MP Data
541 @param[in] ProcessorNumber The handle number of processor
542 @param[in] BistData Processor BIST data
543
544 **/
545 VOID
546 InitializeApData (
547 IN OUT CPU_MP_DATA *CpuMpData,
548 IN UINTN ProcessorNumber,
549 IN UINT32 BistData
550 )
551 {
552 CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
553 CpuMpData->CpuData[ProcessorNumber].Health = BistData;
554 CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
555 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
556 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
557 if (CpuMpData->CpuData[ProcessorNumber].InitialApicId >= 0xFF) {
558 //
559 // Set x2APIC mode if there are any logical processor reporting
560 // an Initial APIC ID of 255 or greater.
561 //
562 AcquireSpinLock(&CpuMpData->MpLock);
563 CpuMpData->X2ApicEnable = TRUE;
564 ReleaseSpinLock(&CpuMpData->MpLock);
565 }
566
567 InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);
568 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
569 }
570
571 /**
572 This function will be called from AP reset code if BSP uses WakeUpAP.
573
574 @param[in] ExchangeInfo Pointer to the MP exchange info buffer
575 @param[in] NumApsExecuting Number of current executing AP
576 **/
577 VOID
578 EFIAPI
579 ApWakeupFunction (
580 IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
581 IN UINTN NumApsExecuting
582 )
583 {
584 CPU_MP_DATA *CpuMpData;
585 UINTN ProcessorNumber;
586 EFI_AP_PROCEDURE Procedure;
587 VOID *Parameter;
588 UINT32 BistData;
589 volatile UINT32 *ApStartupSignalBuffer;
590
591 //
592 // AP finished assembly code and begin to execute C code
593 //
594 CpuMpData = ExchangeInfo->CpuMpData;
595
596 ProgramVirtualWireMode ();
597
598 while (TRUE) {
599 if (CpuMpData->InitFlag == ApInitConfig) {
600 //
601 // Add CPU number
602 //
603 InterlockedIncrement ((UINT32 *) &CpuMpData->CpuCount);
604 ProcessorNumber = NumApsExecuting;
605 //
606 // This is first time AP wakeup, get BIST information from AP stack
607 //
608 BistData = *(UINT32 *) (CpuMpData->Buffer + ProcessorNumber * CpuMpData->CpuApStackSize - sizeof (UINTN));
609 //
610 // Do some AP initialize sync
611 //
612 ApInitializeSync (CpuMpData);
613 //
614 // Sync BSP's Control registers to APs
615 //
616 RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
617 InitializeApData (CpuMpData, ProcessorNumber, BistData);
618 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
619 } else {
620 //
621 // Execute AP function if AP is ready
622 //
623 GetProcessorNumber (CpuMpData, &ProcessorNumber);
624 //
625 // Clear AP start-up signal when AP waken up
626 //
627 ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
628 InterlockedCompareExchange32 (
629 (UINT32 *) ApStartupSignalBuffer,
630 WAKEUP_AP_SIGNAL,
631 0
632 );
633 if (CpuMpData->ApLoopMode == ApInHltLoop) {
634 //
635 // Restore AP's volatile registers saved
636 //
637 RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
638 }
639
640 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
641 Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
642 Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
643 if (Procedure != NULL) {
644 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
645 //
646 // Invoke AP function here
647 //
648 Procedure (Parameter);
649 //
650 // Re-get the CPU APICID and Initial APICID
651 //
652 CpuMpData->CpuData[ProcessorNumber].ApicId = GetApicId ();
653 CpuMpData->CpuData[ProcessorNumber].InitialApicId = GetInitialApicId ();
654 }
655 SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
656 }
657 }
658
659 //
660 // AP finished executing C code
661 //
662 InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);
663
664 //
665 // Place AP is specified loop mode
666 //
667 if (CpuMpData->ApLoopMode == ApInHltLoop) {
668 //
669 // Save AP volatile registers
670 //
671 SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
672 //
673 // Place AP in HLT-loop
674 //
675 while (TRUE) {
676 DisableInterrupts ();
677 CpuSleep ();
678 CpuPause ();
679 }
680 }
681 while (TRUE) {
682 DisableInterrupts ();
683 if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
684 //
685 // Place AP in MWAIT-loop
686 //
687 AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);
688 if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
689 //
690 // Check AP start-up signal again.
691 // If AP start-up signal is not set, place AP into
692 // the specified C-state
693 //
694 AsmMwait (CpuMpData->ApTargetCState << 4, 0);
695 }
696 } else if (CpuMpData->ApLoopMode == ApInRunLoop) {
697 //
698 // Place AP in Run-loop
699 //
700 CpuPause ();
701 } else {
702 ASSERT (FALSE);
703 }
704
705 //
706 // If AP start-up signal is written, AP is waken up
707 // otherwise place AP in loop again
708 //
709 if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
710 break;
711 }
712 }
713 }
714 }
715
716 /**
717 Wait for AP wakeup and write AP start-up signal till AP is waken up.
718
719 @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
720 **/
721 VOID
722 WaitApWakeup (
723 IN volatile UINT32 *ApStartupSignalBuffer
724 )
725 {
726 //
727 // If AP is waken up, StartupApSignal should be cleared.
728 // Otherwise, write StartupApSignal again till AP waken up.
729 //
730 while (InterlockedCompareExchange32 (
731 (UINT32 *) ApStartupSignalBuffer,
732 WAKEUP_AP_SIGNAL,
733 WAKEUP_AP_SIGNAL
734 ) != 0) {
735 CpuPause ();
736 }
737 }
738
739 /**
740 This function will fill the exchange info structure.
741
742 @param[in] CpuMpData Pointer to CPU MP Data
743
744 **/
745 VOID
746 FillExchangeInfoData (
747 IN CPU_MP_DATA *CpuMpData
748 )
749 {
750 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
751
752 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
753 ExchangeInfo->Lock = 0;
754 ExchangeInfo->StackStart = CpuMpData->Buffer;
755 ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;
756 ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;
757 ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;
758
759 ExchangeInfo->CodeSegment = AsmReadCs ();
760 ExchangeInfo->DataSegment = AsmReadDs ();
761
762 ExchangeInfo->Cr3 = AsmReadCr3 ();
763
764 ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;
765 ExchangeInfo->NumApsExecuting = 0;
766 ExchangeInfo->CpuMpData = CpuMpData;
767
768 ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();
769
770 //
771 // Get the BSP's data of GDT and IDT
772 //
773 AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
774 AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
775 }
776
777 /**
778 This function will be called by BSP to wakeup AP.
779
780 @param[in] CpuMpData Pointer to CPU MP Data
781 @param[in] Broadcast TRUE: Send broadcast IPI to all APs
782 FALSE: Send IPI to AP by ApicId
783 @param[in] ProcessorNumber The handle number of specified processor
784 @param[in] Procedure The function to be invoked by AP
785 @param[in] ProcedureArgument The argument to be passed into AP function
786 **/
787 VOID
788 WakeUpAP (
789 IN CPU_MP_DATA *CpuMpData,
790 IN BOOLEAN Broadcast,
791 IN UINTN ProcessorNumber,
792 IN EFI_AP_PROCEDURE Procedure, OPTIONAL
793 IN VOID *ProcedureArgument OPTIONAL
794 )
795 {
796 volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
797 UINTN Index;
798 CPU_AP_DATA *CpuData;
799 BOOLEAN ResetVectorRequired;
800
801 CpuMpData->FinishedCount = 0;
802 ResetVectorRequired = FALSE;
803
804 if (CpuMpData->ApLoopMode == ApInHltLoop ||
805 CpuMpData->InitFlag != ApInitDone) {
806 ResetVectorRequired = TRUE;
807 AllocateResetVector (CpuMpData);
808 FillExchangeInfoData (CpuMpData);
809 } else if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
810 //
811 // Get AP target C-state each time when waking up AP,
812 // for it maybe updated by platform again
813 //
814 CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
815 }
816
817 ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
818
819 if (Broadcast) {
820 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
821 if (Index != CpuMpData->BspNumber) {
822 CpuData = &CpuMpData->CpuData[Index];
823 CpuData->ApFunction = (UINTN) Procedure;
824 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
825 SetApState (CpuData, CpuStateReady);
826 if (CpuMpData->InitFlag != ApInitConfig) {
827 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
828 }
829 }
830 }
831 if (ResetVectorRequired) {
832 //
833 // Wakeup all APs
834 //
835 SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
836 }
837 if (CpuMpData->InitFlag != ApInitConfig) {
838 //
839 // Wait all APs waken up if this is not the 1st broadcast of SIPI
840 //
841 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
842 CpuData = &CpuMpData->CpuData[Index];
843 if (Index != CpuMpData->BspNumber) {
844 WaitApWakeup (CpuData->StartupApSignal);
845 }
846 }
847 }
848 } else {
849 CpuData = &CpuMpData->CpuData[ProcessorNumber];
850 CpuData->ApFunction = (UINTN) Procedure;
851 CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
852 SetApState (CpuData, CpuStateReady);
853 //
854 // Wakeup specified AP
855 //
856 ASSERT (CpuMpData->InitFlag != ApInitConfig);
857 *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
858 if (ResetVectorRequired) {
859 SendInitSipiSipi (
860 CpuData->ApicId,
861 (UINT32) ExchangeInfo->BufferStart
862 );
863 }
864 //
865 // Wait specified AP waken up
866 //
867 WaitApWakeup (CpuData->StartupApSignal);
868 }
869
870 if (ResetVectorRequired) {
871 FreeResetVector (CpuMpData);
872 }
873 }
874
875 /**
876 MP Initialize Library initialization.
877
878 This service will allocate AP reset vector and wakeup all APs to do APs
879 initialization.
880
881 This service must be invoked before all other MP Initialize Library
882 service are invoked.
883
884 @retval EFI_SUCCESS MP initialization succeeds.
885 @retval Others MP initialization fails.
886
887 **/
888 EFI_STATUS
889 EFIAPI
890 MpInitLibInitialize (
891 VOID
892 )
893 {
894 CPU_MP_DATA *OldCpuMpData;
895 CPU_INFO_IN_HOB *CpuInfoInHob;
896 UINT32 MaxLogicalProcessorNumber;
897 UINT32 ApStackSize;
898 MP_ASSEMBLY_ADDRESS_MAP AddressMap;
899 UINTN BufferSize;
900 UINT32 MonitorFilterSize;
901 VOID *MpBuffer;
902 UINTN Buffer;
903 CPU_MP_DATA *CpuMpData;
904 UINT8 ApLoopMode;
905 UINT8 *MonitorBuffer;
906 UINTN Index;
907 UINTN ApResetVectorSize;
908 UINTN BackupBufferAddr;
909
910 OldCpuMpData = GetCpuMpDataFromGuidedHob ();
911 if (OldCpuMpData == NULL) {
912 MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
913 } else {
914 MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
915 }
916
917 AsmGetAddressMap (&AddressMap);
918 ApResetVectorSize = AddressMap.RendezvousFunnelSize + sizeof (MP_CPU_EXCHANGE_INFO);
919 ApStackSize = PcdGet32(PcdCpuApStackSize);
920 ApLoopMode = GetApLoopMode (&MonitorFilterSize);
921
922 BufferSize = ApStackSize * MaxLogicalProcessorNumber;
923 BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
924 BufferSize += sizeof (CPU_MP_DATA);
925 BufferSize += ApResetVectorSize;
926 BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
927 MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
928 ASSERT (MpBuffer != NULL);
929 ZeroMem (MpBuffer, BufferSize);
930 Buffer = (UINTN) MpBuffer;
931
932 MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);
933 BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
934 CpuMpData = (CPU_MP_DATA *) (BackupBufferAddr + ApResetVectorSize);
935 CpuMpData->Buffer = Buffer;
936 CpuMpData->CpuApStackSize = ApStackSize;
937 CpuMpData->BackupBuffer = BackupBufferAddr;
938 CpuMpData->BackupBufferSize = ApResetVectorSize;
939 CpuMpData->EndOfPeiFlag = FALSE;
940 CpuMpData->WakeupBuffer = (UINTN) -1;
941 CpuMpData->CpuCount = 1;
942 CpuMpData->BspNumber = 0;
943 CpuMpData->WaitEvent = NULL;
944 CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);
945 CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
946 InitializeSpinLock(&CpuMpData->MpLock);
947 //
948 // Save BSP's Control registers to APs
949 //
950 SaveVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters);
951 //
952 // Set BSP basic information
953 //
954 InitializeApData (CpuMpData, 0, 0);
955 //
956 // Save assembly code information
957 //
958 CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
959 //
960 // Finally set AP loop mode
961 //
962 CpuMpData->ApLoopMode = ApLoopMode;
963 DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
964 //
965 // Set up APs wakeup signal buffer
966 //
967 for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
968 CpuMpData->CpuData[Index].StartupApSignal =
969 (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
970 }
971 //
972 // Load Microcode on BSP
973 //
974 MicrocodeDetect (CpuMpData);
975 //
976 // Store BSP's MTRR setting
977 //
978 MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
979
980 if (OldCpuMpData == NULL) {
981 //
982 // Wakeup all APs and calculate the processor count in system
983 //
984 CollectProcessorCount (CpuMpData);
985 } else {
986 //
987 // APs have been wakeup before, just get the CPU Information
988 // from HOB
989 //
990 CpuMpData->CpuCount = OldCpuMpData->CpuCount;
991 CpuMpData->BspNumber = OldCpuMpData->BspNumber;
992 CpuMpData->InitFlag = ApInitReconfig;
993 CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) OldCpuMpData->CpuInfoInHob;
994 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
995 InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);
996 CpuMpData->CpuData[Index].ApicId = CpuInfoInHob[Index].ApicId;
997 CpuMpData->CpuData[Index].InitialApicId = CpuInfoInHob[Index].InitialApicId;
998 if (CpuMpData->CpuData[Index].InitialApicId >= 255) {
999 CpuMpData->X2ApicEnable = TRUE;
1000 }
1001 CpuMpData->CpuData[Index].Health = CpuInfoInHob[Index].Health;
1002 CpuMpData->CpuData[Index].CpuHealthy = (CpuMpData->CpuData[Index].Health == 0)? TRUE:FALSE;
1003 CpuMpData->CpuData[Index].ApFunction = 0;
1004 CopyMem (
1005 &CpuMpData->CpuData[Index].VolatileRegisters,
1006 &CpuMpData->CpuData[0].VolatileRegisters,
1007 sizeof (CPU_VOLATILE_REGISTERS)
1008 );
1009 }
1010 //
1011 // Wakeup APs to do some AP initialize sync
1012 //
1013 WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData);
1014 //
1015 // Wait for all APs finished initialization
1016 //
1017 while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
1018 CpuPause ();
1019 }
1020 CpuMpData->InitFlag = ApInitDone;
1021 for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
1022 SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
1023 }
1024 }
1025
1026 //
1027 // Initialize global data for MP support
1028 //
1029 InitMpGlobalData (CpuMpData);
1030
1031 return EFI_SUCCESS;
1032 }
1033
1034 /**
1035 Gets detailed MP-related information on the requested processor at the
1036 instant this call is made. This service may only be called from the BSP.
1037
1038 @param[in] ProcessorNumber The handle number of processor.
1039 @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
1040 the requested processor is deposited.
1041 @param[out] HealthData Return processor health data.
1042
1043 @retval EFI_SUCCESS Processor information was returned.
1044 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1045 @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
1046 @retval EFI_NOT_FOUND The processor with the handle specified by
1047 ProcessorNumber does not exist in the platform.
1048 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1049
1050 **/
1051 EFI_STATUS
1052 EFIAPI
1053 MpInitLibGetProcessorInfo (
1054 IN UINTN ProcessorNumber,
1055 OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
1056 OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
1057 )
1058 {
1059 CPU_MP_DATA *CpuMpData;
1060 UINTN CallerNumber;
1061
1062 CpuMpData = GetCpuMpData ();
1063
1064 //
1065 // Check whether caller processor is BSP
1066 //
1067 MpInitLibWhoAmI (&CallerNumber);
1068 if (CallerNumber != CpuMpData->BspNumber) {
1069 return EFI_DEVICE_ERROR;
1070 }
1071
1072 if (ProcessorInfoBuffer == NULL) {
1073 return EFI_INVALID_PARAMETER;
1074 }
1075
1076 if (ProcessorNumber >= CpuMpData->CpuCount) {
1077 return EFI_NOT_FOUND;
1078 }
1079
1080 ProcessorInfoBuffer->ProcessorId = (UINT64) CpuMpData->CpuData[ProcessorNumber].ApicId;
1081 ProcessorInfoBuffer->StatusFlag = 0;
1082 if (ProcessorNumber == CpuMpData->BspNumber) {
1083 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
1084 }
1085 if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
1086 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
1087 }
1088 if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
1089 ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
1090 } else {
1091 ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
1092 }
1093
1094 //
1095 // Get processor location information
1096 //
1097 ExtractProcessorLocation (CpuMpData->CpuData[ProcessorNumber].ApicId, &ProcessorInfoBuffer->Location);
1098
1099 if (HealthData != NULL) {
1100 HealthData->Uint32 = CpuMpData->CpuData[ProcessorNumber].Health;
1101 }
1102
1103 return EFI_SUCCESS;
1104 }
1105
1106
1107 /**
1108 This return the handle number for the calling processor. This service may be
1109 called from the BSP and APs.
1110
1111 @param[out] ProcessorNumber Pointer to the handle number of AP.
1112 The range is from 0 to the total number of
1113 logical processors minus 1. The total number of
1114 logical processors can be retrieved by
1115 MpInitLibGetNumberOfProcessors().
1116
1117 @retval EFI_SUCCESS The current processor handle number was returned
1118 in ProcessorNumber.
1119 @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
1120 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1121
1122 **/
1123 EFI_STATUS
1124 EFIAPI
1125 MpInitLibWhoAmI (
1126 OUT UINTN *ProcessorNumber
1127 )
1128 {
1129 CPU_MP_DATA *CpuMpData;
1130
1131 if (ProcessorNumber == NULL) {
1132 return EFI_INVALID_PARAMETER;
1133 }
1134
1135 CpuMpData = GetCpuMpData ();
1136
1137 return GetProcessorNumber (CpuMpData, ProcessorNumber);
1138 }
1139
1140 /**
1141 Retrieves the number of logical processor in the platform and the number of
1142 those logical processors that are enabled on this boot. This service may only
1143 be called from the BSP.
1144
1145 @param[out] NumberOfProcessors Pointer to the total number of logical
1146 processors in the system, including the BSP
1147 and disabled APs.
1148 @param[out] NumberOfEnabledProcessors Pointer to the number of enabled logical
1149 processors that exist in system, including
1150 the BSP.
1151
1152 @retval EFI_SUCCESS The number of logical processors and enabled
1153 logical processors was retrieved.
1154 @retval EFI_DEVICE_ERROR The calling processor is an AP.
1155 @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL and NumberOfEnabledProcessors
1156 is NULL.
1157 @retval EFI_NOT_READY MP Initialize Library is not initialized.
1158
1159 **/
1160 EFI_STATUS
1161 EFIAPI
1162 MpInitLibGetNumberOfProcessors (
1163 OUT UINTN *NumberOfProcessors, OPTIONAL
1164 OUT UINTN *NumberOfEnabledProcessors OPTIONAL
1165 )
1166 {
1167 CPU_MP_DATA *CpuMpData;
1168 UINTN CallerNumber;
1169 UINTN ProcessorNumber;
1170 UINTN EnabledProcessorNumber;
1171 UINTN Index;
1172
1173 CpuMpData = GetCpuMpData ();
1174
1175 if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
1176 return EFI_INVALID_PARAMETER;
1177 }
1178
1179 //
1180 // Check whether caller processor is BSP
1181 //
1182 MpInitLibWhoAmI (&CallerNumber);
1183 if (CallerNumber != CpuMpData->BspNumber) {
1184 return EFI_DEVICE_ERROR;
1185 }
1186
1187 ProcessorNumber = CpuMpData->CpuCount;
1188 EnabledProcessorNumber = 0;
1189 for (Index = 0; Index < ProcessorNumber; Index++) {
1190 if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {
1191 EnabledProcessorNumber ++;
1192 }
1193 }
1194
1195 if (NumberOfProcessors != NULL) {
1196 *NumberOfProcessors = ProcessorNumber;
1197 }
1198 if (NumberOfEnabledProcessors != NULL) {
1199 *NumberOfEnabledProcessors = EnabledProcessorNumber;
1200 }
1201
1202 return EFI_SUCCESS;
1203 }
1204
1205
1206 /**
1207 Get pointer to CPU MP Data structure from GUIDed HOB.
1208
1209 @return The pointer to CPU MP Data structure.
1210 **/
1211 CPU_MP_DATA *
1212 GetCpuMpDataFromGuidedHob (
1213 VOID
1214 )
1215 {
1216 EFI_HOB_GUID_TYPE *GuidHob;
1217 VOID *DataInHob;
1218 CPU_MP_DATA *CpuMpData;
1219
1220 CpuMpData = NULL;
1221 GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
1222 if (GuidHob != NULL) {
1223 DataInHob = GET_GUID_HOB_DATA (GuidHob);
1224 CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);
1225 }
1226 return CpuMpData;
1227 }