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