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