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