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