1 /** @file
2   Local APIC Library.
3 
4   This local APIC library instance supports x2APIC capable processors
5   which have xAPIC and x2APIC modes.
6 
7   Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
8   Copyright (c) 2017, AMD Inc. All rights reserved.<BR>
9 
10   SPDX-License-Identifier: BSD-2-Clause-Patent
11 
12 **/
13 
14 #include <Register/Cpuid.h>
15 #include <Register/Amd/Cpuid.h>
16 #include <Register/Msr.h>
17 #include <Register/LocalApic.h>
18 
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/LocalApicLib.h>
22 #include <Library/IoLib.h>
23 #include <Library/TimerLib.h>
24 #include <Library/PcdLib.h>
25 
26 //
27 // Library internal functions
28 //
29 
30 /**
31   Determine if the standard CPU signature is "AuthenticAMD".
32 
33   @retval TRUE  The CPU signature matches.
34   @retval FALSE The CPU signature does not match.
35 
36 **/
37 BOOLEAN
StandardSignatureIsAuthenticAMD(VOID)38 StandardSignatureIsAuthenticAMD (
39   VOID
40   )
41 {
42   UINT32  RegEbx;
43   UINT32  RegEcx;
44   UINT32  RegEdx;
45 
46   AsmCpuid (CPUID_SIGNATURE, NULL, &RegEbx, &RegEcx, &RegEdx);
47   return (RegEbx == CPUID_SIGNATURE_AUTHENTIC_AMD_EBX &&
48           RegEcx == CPUID_SIGNATURE_AUTHENTIC_AMD_ECX &&
49           RegEdx == CPUID_SIGNATURE_AUTHENTIC_AMD_EDX);
50 }
51 
52 /**
53   Determine if the CPU supports the Local APIC Base Address MSR.
54 
55   @retval TRUE  The CPU supports the Local APIC Base Address MSR.
56   @retval FALSE The CPU does not support the Local APIC Base Address MSR.
57 
58 **/
59 BOOLEAN
LocalApicBaseAddressMsrSupported(VOID)60 LocalApicBaseAddressMsrSupported (
61   VOID
62   )
63 {
64   UINT32  RegEax;
65   UINTN   FamilyId;
66 
67   AsmCpuid (1, &RegEax, NULL, NULL, NULL);
68   FamilyId = BitFieldRead32 (RegEax, 8, 11);
69   if (FamilyId == 0x04 || FamilyId == 0x05) {
70     //
71     // CPUs with a FamilyId of 0x04 or 0x05 do not support the
72     // Local APIC Base Address MSR
73     //
74     return FALSE;
75   }
76   return TRUE;
77 }
78 
79 /**
80   Retrieve the base address of local APIC.
81 
82   @return The base address of local APIC.
83 
84 **/
85 UINTN
86 EFIAPI
GetLocalApicBaseAddress(VOID)87 GetLocalApicBaseAddress (
88   VOID
89   )
90 {
91   MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
92 
93   if (!LocalApicBaseAddressMsrSupported ()) {
94     //
95     // If CPU does not support Local APIC Base Address MSR, then retrieve
96     // Local APIC Base Address from PCD
97     //
98     return PcdGet32 (PcdCpuLocalApicBaseAddress);
99   }
100 
101   ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
102 
103   return (UINTN)(LShiftU64 ((UINT64) ApicBaseMsr.Bits.ApicBaseHi, 32)) +
104            (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
105 }
106 
107 /**
108   Set the base address of local APIC.
109 
110   If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
111 
112   @param[in] BaseAddress   Local APIC base address to be set.
113 
114 **/
115 VOID
116 EFIAPI
SetLocalApicBaseAddress(IN UINTN BaseAddress)117 SetLocalApicBaseAddress (
118   IN UINTN                BaseAddress
119   )
120 {
121   MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
122 
123   ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
124 
125   if (!LocalApicBaseAddressMsrSupported ()) {
126     //
127     // Ignore set request of the CPU does not support APIC Base Address MSR
128     //
129     return;
130   }
131 
132   ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
133 
134   ApicBaseMsr.Bits.ApicBase   = (UINT32) (BaseAddress >> 12);
135   ApicBaseMsr.Bits.ApicBaseHi = (UINT32) (RShiftU64((UINT64) BaseAddress, 32));
136 
137   AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
138 }
139 
140 /**
141   Read from a local APIC register.
142 
143   This function reads from a local APIC register either in xAPIC or x2APIC mode.
144   It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
145   accessed using multiple 32-bit loads or stores, so this function only performs
146   32-bit read.
147 
148   @param  MmioOffset  The MMIO offset of the local APIC register in xAPIC mode.
149                       It must be 16-byte aligned.
150 
151   @return 32-bit      Value read from the register.
152 **/
153 UINT32
154 EFIAPI
ReadLocalApicReg(IN UINTN MmioOffset)155 ReadLocalApicReg (
156   IN UINTN  MmioOffset
157   )
158 {
159   UINT32 MsrIndex;
160 
161   ASSERT ((MmioOffset & 0xf) == 0);
162 
163   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
164     return MmioRead32 (GetLocalApicBaseAddress() + MmioOffset);
165   } else {
166     //
167     // DFR is not supported in x2APIC mode.
168     //
169     ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
170     //
171     // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
172     // is not supported in this function for simplicity.
173     //
174     ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
175 
176     MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
177     return AsmReadMsr32 (MsrIndex);
178   }
179 }
180 
181 /**
182   Write to a local APIC register.
183 
184   This function writes to a local APIC register either in xAPIC or x2APIC mode.
185   It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
186   accessed using multiple 32-bit loads or stores, so this function only performs
187   32-bit write.
188 
189   if the register index is invalid or unsupported in current APIC mode, then ASSERT.
190 
191   @param  MmioOffset  The MMIO offset of the local APIC register in xAPIC mode.
192                       It must be 16-byte aligned.
193   @param  Value       Value to be written to the register.
194 **/
195 VOID
196 EFIAPI
WriteLocalApicReg(IN UINTN MmioOffset,IN UINT32 Value)197 WriteLocalApicReg (
198   IN UINTN  MmioOffset,
199   IN UINT32 Value
200   )
201 {
202   UINT32 MsrIndex;
203 
204   ASSERT ((MmioOffset & 0xf) == 0);
205 
206   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
207     MmioWrite32 (GetLocalApicBaseAddress() + MmioOffset, Value);
208   } else {
209     //
210     // DFR is not supported in x2APIC mode.
211     //
212     ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
213     //
214     // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
215     // is not supported in this function for simplicity.
216     //
217     ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
218     ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET);
219 
220     MsrIndex =  (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
221     //
222     // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.
223     // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
224     //
225     MemoryFence ();
226     AsmWriteMsr32 (MsrIndex, Value);
227   }
228 }
229 
230 /**
231   Send an IPI by writing to ICR.
232 
233   This function returns after the IPI has been accepted by the target processor.
234 
235   @param  IcrLow 32-bit value to be written to the low half of ICR.
236   @param  ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
237 **/
238 VOID
SendIpi(IN UINT32 IcrLow,IN UINT32 ApicId)239 SendIpi (
240   IN UINT32          IcrLow,
241   IN UINT32          ApicId
242   )
243 {
244   UINT64             MsrValue;
245   LOCAL_APIC_ICR_LOW IcrLowReg;
246   UINTN              LocalApciBaseAddress;
247   UINT32             IcrHigh;
248   BOOLEAN            InterruptState;
249 
250   //
251   // Legacy APIC or X2APIC?
252   //
253   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
254     ASSERT (ApicId <= 0xff);
255 
256     InterruptState = SaveAndDisableInterrupts ();
257 
258     //
259     // Get base address of this LAPIC
260     //
261     LocalApciBaseAddress = GetLocalApicBaseAddress();
262 
263     //
264     // Save existing contents of ICR high 32 bits
265     //
266     IcrHigh = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET);
267 
268     //
269     // Wait for DeliveryStatus clear in case a previous IPI
270     //  is still being sent
271     //
272     do {
273       IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
274     } while (IcrLowReg.Bits.DeliveryStatus != 0);
275 
276     //
277     // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
278     //
279     MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
280     MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);
281 
282     //
283     // Wait for DeliveryStatus clear again
284     //
285     do {
286       IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
287     } while (IcrLowReg.Bits.DeliveryStatus != 0);
288 
289     //
290     // And restore old contents of ICR high
291     //
292     MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, IcrHigh);
293 
294     SetInterruptState (InterruptState);
295 
296   } else {
297     //
298     // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an
299     // interrupt in x2APIC mode.
300     //
301     MsrValue = LShiftU64 ((UINT64) ApicId, 32) | IcrLow;
302     AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);
303   }
304 }
305 
306 //
307 // Library API implementation functions
308 //
309 
310 /**
311   Get the current local APIC mode.
312 
313   If local APIC is disabled, then ASSERT.
314 
315   @retval LOCAL_APIC_MODE_XAPIC  current APIC mode is xAPIC.
316   @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
317 **/
318 UINTN
319 EFIAPI
GetApicMode(VOID)320 GetApicMode (
321   VOID
322   )
323 {
324   MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
325 
326   if (!LocalApicBaseAddressMsrSupported ()) {
327     //
328     // If CPU does not support APIC Base Address MSR, then return XAPIC mode
329     //
330     return LOCAL_APIC_MODE_XAPIC;
331   }
332 
333   ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
334   //
335   // Local APIC should have been enabled
336   //
337   ASSERT (ApicBaseMsr.Bits.EN != 0);
338   if (ApicBaseMsr.Bits.EXTD != 0) {
339     return LOCAL_APIC_MODE_X2APIC;
340   } else {
341     return LOCAL_APIC_MODE_XAPIC;
342   }
343 }
344 
345 /**
346   Set the current local APIC mode.
347 
348   If the specified local APIC mode is not valid, then ASSERT.
349   If the specified local APIC mode can't be set as current, then ASSERT.
350 
351   @param ApicMode APIC mode to be set.
352 
353   @note  This API must not be called from an interrupt handler or SMI handler.
354          It may result in unpredictable behavior.
355 **/
356 VOID
357 EFIAPI
SetApicMode(IN UINTN ApicMode)358 SetApicMode (
359   IN UINTN  ApicMode
360   )
361 {
362   UINTN                        CurrentMode;
363   MSR_IA32_APIC_BASE_REGISTER  ApicBaseMsr;
364 
365   if (!LocalApicBaseAddressMsrSupported ()) {
366     //
367     // Ignore set request if the CPU does not support APIC Base Address MSR
368     //
369     return;
370   }
371 
372   CurrentMode = GetApicMode ();
373   if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {
374     switch (ApicMode) {
375       case LOCAL_APIC_MODE_XAPIC:
376         break;
377       case LOCAL_APIC_MODE_X2APIC:
378         ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
379         ApicBaseMsr.Bits.EXTD = 1;
380         AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
381         break;
382       default:
383         ASSERT (FALSE);
384     }
385   } else {
386     switch (ApicMode) {
387       case LOCAL_APIC_MODE_XAPIC:
388         //
389         //  Transition from x2APIC mode to xAPIC mode is a two-step process:
390         //    x2APIC -> Local APIC disabled -> xAPIC
391         //
392         ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
393         ApicBaseMsr.Bits.EXTD = 0;
394         ApicBaseMsr.Bits.EN = 0;
395         AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
396         ApicBaseMsr.Bits.EN = 1;
397         AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
398         break;
399       case LOCAL_APIC_MODE_X2APIC:
400         break;
401       default:
402         ASSERT (FALSE);
403     }
404   }
405 }
406 
407 /**
408   Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
409 
410   In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
411   In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
412   the 32-bit local APIC ID is returned as initial APIC ID.
413 
414   @return  32-bit initial local APIC ID of the executing processor.
415 **/
416 UINT32
417 EFIAPI
GetInitialApicId(VOID)418 GetInitialApicId (
419   VOID
420   )
421 {
422   UINT32 ApicId;
423   UINT32 MaxCpuIdIndex;
424   UINT32 RegEbx;
425 
426   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
427     //
428     // Get the max index of basic CPUID
429     //
430     AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
431     //
432     // If CPUID Leaf B is supported,
433     // And CPUID.0BH:EBX[15:0] reports a non-zero value,
434     // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
435     // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
436     //
437     if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
438       AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);
439       if ((RegEbx & (BIT16 - 1)) != 0) {
440         return ApicId;
441       }
442     }
443     AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
444     return RegEbx >> 24;
445   } else {
446     return GetApicId ();
447   }
448 }
449 
450 /**
451   Get the local APIC ID of the executing processor.
452 
453   @return  32-bit local APIC ID of the executing processor.
454 **/
455 UINT32
456 EFIAPI
GetApicId(VOID)457 GetApicId (
458   VOID
459   )
460 {
461   UINT32 ApicId;
462   UINT32 InitApicId;
463 
464   ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
465   if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
466     ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;
467   }
468 
469   return ApicId;
470 }
471 
472 /**
473   Get the value of the local APIC version register.
474 
475   @return  the value of the local APIC version register.
476 **/
477 UINT32
478 EFIAPI
GetApicVersion(VOID)479 GetApicVersion (
480   VOID
481   )
482 {
483   return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
484 }
485 
486 /**
487   Send a Fixed IPI to a specified target processor.
488 
489   This function returns after the IPI has been accepted by the target processor.
490 
491   @param  ApicId   The local APIC ID of the target processor.
492   @param  Vector   The vector number of the interrupt being sent.
493 **/
494 VOID
495 EFIAPI
SendFixedIpi(IN UINT32 ApicId,IN UINT8 Vector)496 SendFixedIpi (
497   IN UINT32          ApicId,
498   IN UINT8           Vector
499   )
500 {
501   LOCAL_APIC_ICR_LOW IcrLow;
502 
503   IcrLow.Uint32 = 0;
504   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
505   IcrLow.Bits.Level = 1;
506   IcrLow.Bits.Vector = Vector;
507   SendIpi (IcrLow.Uint32, ApicId);
508 }
509 
510 /**
511   Send a Fixed IPI to all processors excluding self.
512 
513   This function returns after the IPI has been accepted by the target processors.
514 
515   @param  Vector   The vector number of the interrupt being sent.
516 **/
517 VOID
518 EFIAPI
SendFixedIpiAllExcludingSelf(IN UINT8 Vector)519 SendFixedIpiAllExcludingSelf (
520   IN UINT8           Vector
521   )
522 {
523   LOCAL_APIC_ICR_LOW IcrLow;
524 
525   IcrLow.Uint32 = 0;
526   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
527   IcrLow.Bits.Level = 1;
528   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
529   IcrLow.Bits.Vector = Vector;
530   SendIpi (IcrLow.Uint32, 0);
531 }
532 
533 /**
534   Send a SMI IPI to a specified target processor.
535 
536   This function returns after the IPI has been accepted by the target processor.
537 
538   @param  ApicId   Specify the local APIC ID of the target processor.
539 **/
540 VOID
541 EFIAPI
SendSmiIpi(IN UINT32 ApicId)542 SendSmiIpi (
543   IN UINT32          ApicId
544   )
545 {
546   LOCAL_APIC_ICR_LOW IcrLow;
547 
548   IcrLow.Uint32 = 0;
549   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
550   IcrLow.Bits.Level = 1;
551   SendIpi (IcrLow.Uint32, ApicId);
552 }
553 
554 /**
555   Send a SMI IPI to all processors excluding self.
556 
557   This function returns after the IPI has been accepted by the target processors.
558 **/
559 VOID
560 EFIAPI
SendSmiIpiAllExcludingSelf(VOID)561 SendSmiIpiAllExcludingSelf (
562   VOID
563   )
564 {
565   LOCAL_APIC_ICR_LOW IcrLow;
566 
567   IcrLow.Uint32 = 0;
568   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
569   IcrLow.Bits.Level = 1;
570   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
571   SendIpi (IcrLow.Uint32, 0);
572 }
573 
574 /**
575   Send an INIT IPI to a specified target processor.
576 
577   This function returns after the IPI has been accepted by the target processor.
578 
579   @param  ApicId   Specify the local APIC ID of the target processor.
580 **/
581 VOID
582 EFIAPI
SendInitIpi(IN UINT32 ApicId)583 SendInitIpi (
584   IN UINT32          ApicId
585   )
586 {
587   LOCAL_APIC_ICR_LOW IcrLow;
588 
589   IcrLow.Uint32 = 0;
590   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
591   IcrLow.Bits.Level = 1;
592   SendIpi (IcrLow.Uint32, ApicId);
593 }
594 
595 /**
596   Send an INIT IPI to all processors excluding self.
597 
598   This function returns after the IPI has been accepted by the target processors.
599 **/
600 VOID
601 EFIAPI
SendInitIpiAllExcludingSelf(VOID)602 SendInitIpiAllExcludingSelf (
603   VOID
604   )
605 {
606   LOCAL_APIC_ICR_LOW IcrLow;
607 
608   IcrLow.Uint32 = 0;
609   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
610   IcrLow.Bits.Level = 1;
611   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
612   SendIpi (IcrLow.Uint32, 0);
613 }
614 
615 /**
616   Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
617 
618   This function returns after the IPI has been accepted by the target processor.
619 
620   if StartupRoutine >= 1M, then ASSERT.
621   if StartupRoutine is not multiple of 4K, then ASSERT.
622 
623   @param  ApicId          Specify the local APIC ID of the target processor.
624   @param  StartupRoutine  Points to a start-up routine which is below 1M physical
625                           address and 4K aligned.
626 **/
627 VOID
628 EFIAPI
SendInitSipiSipi(IN UINT32 ApicId,IN UINT32 StartupRoutine)629 SendInitSipiSipi (
630   IN UINT32          ApicId,
631   IN UINT32          StartupRoutine
632   )
633 {
634   LOCAL_APIC_ICR_LOW IcrLow;
635 
636   ASSERT (StartupRoutine < 0x100000);
637   ASSERT ((StartupRoutine & 0xfff) == 0);
638 
639   SendInitIpi (ApicId);
640   MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
641   IcrLow.Uint32 = 0;
642   IcrLow.Bits.Vector = (StartupRoutine >> 12);
643   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
644   IcrLow.Bits.Level = 1;
645   SendIpi (IcrLow.Uint32, ApicId);
646   if (!StandardSignatureIsAuthenticAMD ()) {
647     MicroSecondDelay (200);
648     SendIpi (IcrLow.Uint32, ApicId);
649   }
650 }
651 
652 /**
653   Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
654 
655   This function returns after the IPI has been accepted by the target processors.
656 
657   if StartupRoutine >= 1M, then ASSERT.
658   if StartupRoutine is not multiple of 4K, then ASSERT.
659 
660   @param  StartupRoutine    Points to a start-up routine which is below 1M physical
661                             address and 4K aligned.
662 **/
663 VOID
664 EFIAPI
SendInitSipiSipiAllExcludingSelf(IN UINT32 StartupRoutine)665 SendInitSipiSipiAllExcludingSelf (
666   IN UINT32          StartupRoutine
667   )
668 {
669   LOCAL_APIC_ICR_LOW IcrLow;
670 
671   ASSERT (StartupRoutine < 0x100000);
672   ASSERT ((StartupRoutine & 0xfff) == 0);
673 
674   SendInitIpiAllExcludingSelf ();
675   MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
676   IcrLow.Uint32 = 0;
677   IcrLow.Bits.Vector = (StartupRoutine >> 12);
678   IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
679   IcrLow.Bits.Level = 1;
680   IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
681   SendIpi (IcrLow.Uint32, 0);
682   if (!StandardSignatureIsAuthenticAMD ()) {
683     MicroSecondDelay (200);
684     SendIpi (IcrLow.Uint32, 0);
685   }
686 }
687 
688 /**
689   Initialize the state of the SoftwareEnable bit in the Local APIC
690   Spurious Interrupt Vector register.
691 
692   @param  Enable  If TRUE, then set SoftwareEnable to 1
693                   If FALSE, then set SoftwareEnable to 0.
694 
695 **/
696 VOID
697 EFIAPI
InitializeLocalApicSoftwareEnable(IN BOOLEAN Enable)698 InitializeLocalApicSoftwareEnable (
699   IN BOOLEAN  Enable
700   )
701 {
702   LOCAL_APIC_SVR  Svr;
703 
704   //
705   // Set local APIC software-enabled bit.
706   //
707   Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
708   if (Enable) {
709     if (Svr.Bits.SoftwareEnable == 0) {
710       Svr.Bits.SoftwareEnable = 1;
711       WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
712     }
713   } else {
714     if (Svr.Bits.SoftwareEnable == 1) {
715       Svr.Bits.SoftwareEnable = 0;
716       WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
717     }
718   }
719 }
720 
721 /**
722   Programming Virtual Wire Mode.
723 
724   This function programs the local APIC for virtual wire mode following
725   the example described in chapter A.3 of the MP 1.4 spec.
726 
727   IOxAPIC is not involved in this type of virtual wire mode.
728 **/
729 VOID
730 EFIAPI
ProgramVirtualWireMode(VOID)731 ProgramVirtualWireMode (
732   VOID
733   )
734 {
735   LOCAL_APIC_SVR      Svr;
736   LOCAL_APIC_LVT_LINT Lint;
737 
738   //
739   // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
740   //
741   Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
742   Svr.Bits.SpuriousVector = 0xf;
743   Svr.Bits.SoftwareEnable = 1;
744   WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
745 
746   //
747   // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
748   //
749   Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
750   Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
751   Lint.Bits.InputPinPolarity = 0;
752   Lint.Bits.TriggerMode = 0;
753   Lint.Bits.Mask = 0;
754   WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
755 
756   //
757   // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
758   //
759   Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
760   Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
761   Lint.Bits.InputPinPolarity = 0;
762   Lint.Bits.TriggerMode = 0;
763   Lint.Bits.Mask = 0;
764   WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
765 }
766 
767 /**
768   Disable LINT0 & LINT1 interrupts.
769 
770   This function sets the mask flag in the LVT LINT0 & LINT1 registers.
771 **/
772 VOID
773 EFIAPI
DisableLvtInterrupts(VOID)774 DisableLvtInterrupts (
775   VOID
776   )
777 {
778   LOCAL_APIC_LVT_LINT LvtLint;
779 
780   LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
781   LvtLint.Bits.Mask = 1;
782   WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
783 
784   LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
785   LvtLint.Bits.Mask = 1;
786   WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
787 }
788 
789 /**
790   Read the initial count value from the init-count register.
791 
792   @return The initial count value read from the init-count register.
793 **/
794 UINT32
795 EFIAPI
GetApicTimerInitCount(VOID)796 GetApicTimerInitCount (
797   VOID
798   )
799 {
800   return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
801 }
802 
803 /**
804   Read the current count value from the current-count register.
805 
806   @return The current count value read from the current-count register.
807 **/
808 UINT32
809 EFIAPI
GetApicTimerCurrentCount(VOID)810 GetApicTimerCurrentCount (
811   VOID
812   )
813 {
814   return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
815 }
816 
817 /**
818   Initialize the local APIC timer.
819 
820   The local APIC timer is initialized and enabled.
821 
822   @param DivideValue   The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
823                        If it is 0, then use the current divide value in the DCR.
824   @param InitCount     The initial count value.
825   @param PeriodicMode  If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
826   @param Vector        The timer interrupt vector number.
827 **/
828 VOID
829 EFIAPI
InitializeApicTimer(IN UINTN DivideValue,IN UINT32 InitCount,IN BOOLEAN PeriodicMode,IN UINT8 Vector)830 InitializeApicTimer (
831   IN UINTN   DivideValue,
832   IN UINT32  InitCount,
833   IN BOOLEAN PeriodicMode,
834   IN UINT8   Vector
835   )
836 {
837   LOCAL_APIC_DCR       Dcr;
838   LOCAL_APIC_LVT_TIMER LvtTimer;
839   UINT32               Divisor;
840 
841   //
842   // Ensure local APIC is in software-enabled state.
843   //
844   InitializeLocalApicSoftwareEnable (TRUE);
845 
846   //
847   // Program init-count register.
848   //
849   WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
850 
851   if (DivideValue != 0) {
852     ASSERT (DivideValue <= 128);
853     ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));
854     Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
855 
856     Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
857     Dcr.Bits.DivideValue1 = (Divisor & 0x3);
858     Dcr.Bits.DivideValue2 = (Divisor >> 2);
859     WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
860   }
861 
862   //
863   // Enable APIC timer interrupt with specified timer mode.
864   //
865   LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
866   if (PeriodicMode) {
867     LvtTimer.Bits.TimerMode = 1;
868   } else {
869     LvtTimer.Bits.TimerMode = 0;
870   }
871   LvtTimer.Bits.Mask = 0;
872   LvtTimer.Bits.Vector = Vector;
873   WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
874 }
875 
876 /**
877   Get the state of the local APIC timer.
878 
879   This function will ASSERT if the local APIC is not software enabled.
880 
881   @param DivideValue   Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
882   @param PeriodicMode  Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
883   @param Vector        Return the timer interrupt vector number.
884 **/
885 VOID
886 EFIAPI
GetApicTimerState(OUT UINTN * DivideValue OPTIONAL,OUT BOOLEAN * PeriodicMode OPTIONAL,OUT UINT8 * Vector OPTIONAL)887 GetApicTimerState (
888   OUT UINTN    *DivideValue  OPTIONAL,
889   OUT BOOLEAN  *PeriodicMode  OPTIONAL,
890   OUT UINT8    *Vector  OPTIONAL
891   )
892 {
893   UINT32 Divisor;
894   LOCAL_APIC_DCR Dcr;
895   LOCAL_APIC_LVT_TIMER LvtTimer;
896 
897   //
898   // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
899   // Vector Register.
900   // This bit will be 1, if local APIC is software enabled.
901   //
902   ASSERT ((ReadLocalApicReg(XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
903 
904   if (DivideValue != NULL) {
905     Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
906     Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
907     Divisor = (Divisor + 1) & 0x7;
908     *DivideValue = ((UINTN)1) << Divisor;
909   }
910 
911   if (PeriodicMode != NULL || Vector != NULL) {
912     LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
913     if (PeriodicMode != NULL) {
914       if (LvtTimer.Bits.TimerMode == 1) {
915         *PeriodicMode = TRUE;
916       } else {
917         *PeriodicMode = FALSE;
918       }
919     }
920     if (Vector != NULL) {
921       *Vector = (UINT8) LvtTimer.Bits.Vector;
922     }
923   }
924 }
925 
926 /**
927   Enable the local APIC timer interrupt.
928 **/
929 VOID
930 EFIAPI
EnableApicTimerInterrupt(VOID)931 EnableApicTimerInterrupt (
932   VOID
933   )
934 {
935   LOCAL_APIC_LVT_TIMER LvtTimer;
936 
937   LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
938   LvtTimer.Bits.Mask = 0;
939   WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
940 }
941 
942 /**
943   Disable the local APIC timer interrupt.
944 **/
945 VOID
946 EFIAPI
DisableApicTimerInterrupt(VOID)947 DisableApicTimerInterrupt (
948   VOID
949   )
950 {
951   LOCAL_APIC_LVT_TIMER LvtTimer;
952 
953   LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
954   LvtTimer.Bits.Mask = 1;
955   WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
956 }
957 
958 /**
959   Get the local APIC timer interrupt state.
960 
961   @retval TRUE  The local APIC timer interrupt is enabled.
962   @retval FALSE The local APIC timer interrupt is disabled.
963 **/
964 BOOLEAN
965 EFIAPI
GetApicTimerInterruptState(VOID)966 GetApicTimerInterruptState (
967   VOID
968   )
969 {
970   LOCAL_APIC_LVT_TIMER LvtTimer;
971 
972   LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
973   return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
974 }
975 
976 /**
977   Send EOI to the local APIC.
978 **/
979 VOID
980 EFIAPI
SendApicEoi(VOID)981 SendApicEoi (
982   VOID
983   )
984 {
985   WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
986 }
987 
988 /**
989   Get the 32-bit address that a device should use to send a Message Signaled
990   Interrupt (MSI) to the Local APIC of the currently executing processor.
991 
992   @return 32-bit address used to send an MSI to the Local APIC.
993 **/
994 UINT32
995 EFIAPI
GetApicMsiAddress(VOID)996 GetApicMsiAddress (
997   VOID
998   )
999 {
1000   LOCAL_APIC_MSI_ADDRESS  MsiAddress;
1001 
1002   //
1003   // Return address for an MSI interrupt to be delivered only to the APIC ID
1004   // of the currently executing processor.
1005   //
1006   MsiAddress.Uint32             = 0;
1007   MsiAddress.Bits.BaseAddress   = 0xFEE;
1008   MsiAddress.Bits.DestinationId = GetApicId ();
1009   return MsiAddress.Uint32;
1010 }
1011 
1012 /**
1013   Get the 64-bit data value that a device should use to send a Message Signaled
1014   Interrupt (MSI) to the Local APIC of the currently executing processor.
1015 
1016   If Vector is not in range 0x10..0xFE, then ASSERT().
1017   If DeliveryMode is not supported, then ASSERT().
1018 
1019   @param  Vector          The 8-bit interrupt vector associated with the MSI.
1020                           Must be in the range 0x10..0xFE
1021   @param  DeliveryMode    A 3-bit value that specifies how the recept of the MSI
1022                           is handled.  The only supported values are:
1023                             0: LOCAL_APIC_DELIVERY_MODE_FIXED
1024                             1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
1025                             2: LOCAL_APIC_DELIVERY_MODE_SMI
1026                             4: LOCAL_APIC_DELIVERY_MODE_NMI
1027                             5: LOCAL_APIC_DELIVERY_MODE_INIT
1028                             7: LOCAL_APIC_DELIVERY_MODE_EXTINT
1029 
1030   @param  LevelTriggered  TRUE specifies a level triggered interrupt.
1031                           FALSE specifies an edge triggered interrupt.
1032   @param  AssertionLevel  Ignored if LevelTriggered is FALSE.
1033                           TRUE specifies a level triggered interrupt that active
1034                           when the interrupt line is asserted.
1035                           FALSE specifies a level triggered interrupt that active
1036                           when the interrupt line is deasserted.
1037 
1038   @return 64-bit data value used to send an MSI to the Local APIC.
1039 **/
1040 UINT64
1041 EFIAPI
GetApicMsiValue(IN UINT8 Vector,IN UINTN DeliveryMode,IN BOOLEAN LevelTriggered,IN BOOLEAN AssertionLevel)1042 GetApicMsiValue (
1043   IN UINT8    Vector,
1044   IN UINTN    DeliveryMode,
1045   IN BOOLEAN  LevelTriggered,
1046   IN BOOLEAN  AssertionLevel
1047   )
1048 {
1049   LOCAL_APIC_MSI_DATA  MsiData;
1050 
1051   ASSERT (Vector >= 0x10 && Vector <= 0xFE);
1052   ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
1053 
1054   MsiData.Uint64            = 0;
1055   MsiData.Bits.Vector       = Vector;
1056   MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
1057   if (LevelTriggered) {
1058     MsiData.Bits.TriggerMode = 1;
1059     if (AssertionLevel) {
1060       MsiData.Bits.Level = 1;
1061     }
1062   }
1063   return MsiData.Uint64;
1064 }
1065 
1066 /**
1067   Get Package ID/Core ID/Thread ID of a processor.
1068 
1069   The algorithm assumes the target system has symmetry across physical
1070   package  boundaries with respect to the number of logical processors
1071   per package,  number of cores per package.
1072 
1073   @param[in]  InitialApicId  Initial APIC ID of the target logical processor.
1074   @param[out]  Package       Returns the processor package ID.
1075   @param[out]  Core          Returns the processor core ID.
1076   @param[out]  Thread        Returns the processor thread ID.
1077 **/
1078 VOID
1079 EFIAPI
GetProcessorLocationByApicId(IN UINT32 InitialApicId,OUT UINT32 * Package OPTIONAL,OUT UINT32 * Core OPTIONAL,OUT UINT32 * Thread OPTIONAL)1080 GetProcessorLocationByApicId (
1081   IN  UINT32  InitialApicId,
1082   OUT UINT32  *Package  OPTIONAL,
1083   OUT UINT32  *Core    OPTIONAL,
1084   OUT UINT32  *Thread  OPTIONAL
1085   )
1086 {
1087   BOOLEAN                             TopologyLeafSupported;
1088   CPUID_VERSION_INFO_EBX              VersionInfoEbx;
1089   CPUID_VERSION_INFO_EDX              VersionInfoEdx;
1090   CPUID_CACHE_PARAMS_EAX              CacheParamsEax;
1091   CPUID_EXTENDED_TOPOLOGY_EAX         ExtendedTopologyEax;
1092   CPUID_EXTENDED_TOPOLOGY_EBX         ExtendedTopologyEbx;
1093   CPUID_EXTENDED_TOPOLOGY_ECX         ExtendedTopologyEcx;
1094   CPUID_AMD_EXTENDED_CPU_SIG_ECX      AmdExtendedCpuSigEcx;
1095   CPUID_AMD_PROCESSOR_TOPOLOGY_EBX    AmdProcessorTopologyEbx;
1096   CPUID_AMD_VIR_PHY_ADDRESS_SIZE_ECX  AmdVirPhyAddressSizeEcx;
1097   UINT32                              MaxStandardCpuIdIndex;
1098   UINT32                              MaxExtendedCpuIdIndex;
1099   UINT32                              SubIndex;
1100   UINTN                               LevelType;
1101   UINT32                              MaxLogicProcessorsPerPackage;
1102   UINT32                              MaxCoresPerPackage;
1103   UINTN                               ThreadBits;
1104   UINTN                               CoreBits;
1105 
1106   //
1107   // Check if the processor is capable of supporting more than one logical processor.
1108   //
1109   AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
1110   if (VersionInfoEdx.Bits.HTT == 0) {
1111     if (Thread != NULL) {
1112       *Thread = 0;
1113     }
1114     if (Core != NULL) {
1115       *Core = 0;
1116     }
1117     if (Package != NULL) {
1118       *Package = 0;
1119     }
1120     return;
1121   }
1122 
1123   //
1124   // Assume three-level mapping of APIC ID: Package|Core|Thread.
1125   //
1126   ThreadBits = 0;
1127   CoreBits = 0;
1128 
1129   //
1130   // Get max index of CPUID
1131   //
1132   AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
1133   AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedCpuIdIndex, NULL, NULL, NULL);
1134 
1135   //
1136   // If the extended topology enumeration leaf is available, it
1137   // is the preferred mechanism for enumerating topology.
1138   //
1139   TopologyLeafSupported = FALSE;
1140   if (MaxStandardCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
1141     AsmCpuidEx(
1142       CPUID_EXTENDED_TOPOLOGY,
1143       0,
1144       &ExtendedTopologyEax.Uint32,
1145       &ExtendedTopologyEbx.Uint32,
1146       &ExtendedTopologyEcx.Uint32,
1147       NULL
1148       );
1149     //
1150     // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
1151     // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
1152     // supported on that processor.
1153     //
1154     if (ExtendedTopologyEbx.Uint32 != 0) {
1155       TopologyLeafSupported = TRUE;
1156 
1157       //
1158       // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
1159       // the SMT sub-field of x2APIC ID.
1160       //
1161       LevelType = ExtendedTopologyEcx.Bits.LevelType;
1162       ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
1163       ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
1164 
1165       //
1166       // Software must not assume any "level type" encoding
1167       // value to be related to any sub-leaf index, except sub-leaf 0.
1168       //
1169       SubIndex = 1;
1170       do {
1171         AsmCpuidEx (
1172           CPUID_EXTENDED_TOPOLOGY,
1173           SubIndex,
1174           &ExtendedTopologyEax.Uint32,
1175           NULL,
1176           &ExtendedTopologyEcx.Uint32,
1177           NULL
1178           );
1179         LevelType = ExtendedTopologyEcx.Bits.LevelType;
1180         if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
1181           CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
1182           break;
1183         }
1184         SubIndex++;
1185       } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
1186     }
1187   }
1188 
1189   if (!TopologyLeafSupported) {
1190     //
1191     // Get logical processor count
1192     //
1193     AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
1194     MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
1195 
1196     //
1197     // Assume single-core processor
1198     //
1199     MaxCoresPerPackage = 1;
1200 
1201     //
1202     // Check for topology extensions on AMD processor
1203     //
1204     if (StandardSignatureIsAuthenticAMD()) {
1205       if (MaxExtendedCpuIdIndex >= CPUID_AMD_PROCESSOR_TOPOLOGY) {
1206         AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, &AmdExtendedCpuSigEcx.Uint32, NULL);
1207         if (AmdExtendedCpuSigEcx.Bits.TopologyExtensions != 0) {
1208           //
1209           // Account for max possible thread count to decode ApicId
1210           //
1211           AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, NULL, NULL, &AmdVirPhyAddressSizeEcx.Uint32, NULL);
1212           MaxLogicProcessorsPerPackage = 1 << AmdVirPhyAddressSizeEcx.Bits.ApicIdCoreIdSize;
1213 
1214           //
1215           // Get cores per processor package
1216           //
1217           AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY, NULL, &AmdProcessorTopologyEbx.Uint32, NULL, NULL);
1218           MaxCoresPerPackage = MaxLogicProcessorsPerPackage / (AmdProcessorTopologyEbx.Bits.ThreadsPerCore + 1);
1219         }
1220       }
1221     }
1222     else {
1223       //
1224       // Extract core count based on CACHE information
1225       //
1226       if (MaxStandardCpuIdIndex >= CPUID_CACHE_PARAMS) {
1227         AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
1228         if (CacheParamsEax.Uint32 != 0) {
1229           MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
1230         }
1231       }
1232     }
1233 
1234     ThreadBits = (UINTN)(HighBitSet32(MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
1235     CoreBits = (UINTN)(HighBitSet32(MaxCoresPerPackage - 1) + 1);
1236   }
1237 
1238   if (Thread != NULL) {
1239     *Thread = InitialApicId & ((1 << ThreadBits) - 1);
1240   }
1241   if (Core != NULL) {
1242     *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
1243   }
1244   if (Package != NULL) {
1245     *Package = (InitialApicId >> (ThreadBits + CoreBits));
1246   }
1247 }
1248 
1249 /**
1250   Get Package ID/Die ID/Tile ID/Module ID/Core ID/Thread ID of a processor.
1251 
1252   The algorithm assumes the target system has symmetry across physical
1253   package boundaries with respect to the number of threads per core, number of
1254   cores per module, number of modules per tile, number of tiles per die, number
1255   of dies per package.
1256 
1257   @param[in]   InitialApicId Initial APIC ID of the target logical processor.
1258   @param[out]  Package       Returns the processor package ID.
1259   @param[out]  Die           Returns the processor die ID.
1260   @param[out]  Tile          Returns the processor tile ID.
1261   @param[out]  Module        Returns the processor module ID.
1262   @param[out]  Core          Returns the processor core ID.
1263   @param[out]  Thread        Returns the processor thread ID.
1264 **/
1265 VOID
1266 EFIAPI
GetProcessorLocation2ByApicId(IN UINT32 InitialApicId,OUT UINT32 * Package OPTIONAL,OUT UINT32 * Die OPTIONAL,OUT UINT32 * Tile OPTIONAL,OUT UINT32 * Module OPTIONAL,OUT UINT32 * Core OPTIONAL,OUT UINT32 * Thread OPTIONAL)1267 GetProcessorLocation2ByApicId (
1268   IN  UINT32  InitialApicId,
1269   OUT UINT32  *Package  OPTIONAL,
1270   OUT UINT32  *Die      OPTIONAL,
1271   OUT UINT32  *Tile     OPTIONAL,
1272   OUT UINT32  *Module   OPTIONAL,
1273   OUT UINT32  *Core     OPTIONAL,
1274   OUT UINT32  *Thread   OPTIONAL
1275   )
1276 {
1277   CPUID_EXTENDED_TOPOLOGY_EAX         ExtendedTopologyEax;
1278   CPUID_EXTENDED_TOPOLOGY_ECX         ExtendedTopologyEcx;
1279   UINT32                              MaxStandardCpuIdIndex;
1280   UINT32                              Index;
1281   UINTN                               LevelType;
1282   UINT32                              Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
1283   UINT32                              *Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
1284 
1285   for (LevelType = 0; LevelType < ARRAY_SIZE (Bits); LevelType++) {
1286     Bits[LevelType] = 0;
1287   }
1288 
1289   //
1290   // Get max index of CPUID
1291   //
1292   AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
1293   if (MaxStandardCpuIdIndex < CPUID_V2_EXTENDED_TOPOLOGY) {
1294     if (Die != NULL) {
1295       *Die = 0;
1296     }
1297     if (Tile != NULL) {
1298       *Tile = 0;
1299     }
1300     if (Module != NULL) {
1301       *Module = 0;
1302     }
1303     GetProcessorLocationByApicId (InitialApicId, Package, Core, Thread);
1304     return;
1305   }
1306 
1307   //
1308   // If the V2 extended topology enumeration leaf is available, it
1309   // is the preferred mechanism for enumerating topology.
1310   //
1311   for (Index = 0; ; Index++) {
1312     AsmCpuidEx(
1313       CPUID_V2_EXTENDED_TOPOLOGY,
1314       Index,
1315       &ExtendedTopologyEax.Uint32,
1316       NULL,
1317       &ExtendedTopologyEcx.Uint32,
1318       NULL
1319       );
1320 
1321     LevelType = ExtendedTopologyEcx.Bits.LevelType;
1322 
1323     //
1324     // first level reported should be SMT.
1325     //
1326     ASSERT ((Index != 0) || (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT));
1327     if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID) {
1328       break;
1329     }
1330     ASSERT (LevelType < ARRAY_SIZE (Bits));
1331     Bits[LevelType] = ExtendedTopologyEax.Bits.ApicIdShift;
1332   }
1333 
1334   for (LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE; LevelType < ARRAY_SIZE (Bits); LevelType++) {
1335     //
1336     // If there are more levels between level-1 (low-level) and level-2 (high-level), the unknown levels will be ignored
1337     // and treated as an extension of the last known level (i.e., level-1 in this case).
1338     //
1339     if (Bits[LevelType] == 0) {
1340       Bits[LevelType] = Bits[LevelType - 1];
1341     }
1342   }
1343 
1344   Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = Package;
1345   Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE    ] = Die;
1346   Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_TILE   ] = Tile;
1347   Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_MODULE ] = Module;
1348   Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE   ]    = Core;
1349   Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT    ]    = Thread;
1350 
1351   Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = 32;
1352 
1353   for ( LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
1354       ; LevelType <= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1
1355       ; LevelType ++
1356       ) {
1357     if (Location[LevelType] != NULL) {
1358       //
1359       // Bits[i] holds the number of bits to shift right on x2APIC ID to get a unique
1360       // topology ID of the next level type.
1361       //
1362       *Location[LevelType] = InitialApicId >> Bits[LevelType - 1];
1363 
1364       //
1365       // Bits[i] - Bits[i-1] holds the number of bits for the next ONE level type.
1366       //
1367       *Location[LevelType] &= (1 << (Bits[LevelType] - Bits[LevelType - 1])) - 1;
1368     }
1369   }
1370 }
1371