]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
05039427b1ff3480a641d85b4410767c979ac9aa
[mirror_edk2.git] / UefiCpuPkg / Library / BaseXApicX2ApicLib / BaseXApicX2ApicLib.c
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 - 2015, 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/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
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
67 GetLocalApicBaseAddress (
68 VOID
69 )
70 {
71 MSR_IA32_APIC_BASE 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_ADDRESS);
82
83 return (UINTN)(LShiftU64 ((UINT64) ApicBaseMsr.Bits.ApicBaseHigh, 32)) +
84 (((UINTN)ApicBaseMsr.Bits.ApicBaseLow) << 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
97 SetLocalApicBaseAddress (
98 IN UINTN BaseAddress
99 )
100 {
101 MSR_IA32_APIC_BASE ApicBaseMsr;
102
103 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
104
105 if (!LocalApicBaseAddressMsrSupported ()) {
106 //
107 // Ignore set request of the CPU does not support APIC Base Address MSR
108 //
109 return;
110 }
111
112 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
113
114 ApicBaseMsr.Bits.ApicBaseLow = (UINT32) (BaseAddress >> 12);
115 ApicBaseMsr.Bits.ApicBaseHigh = (UINT32) (RShiftU64((UINT64) BaseAddress, 32));
116
117 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, 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
135 ReadLocalApicReg (
136 IN UINTN MmioOffset
137 )
138 {
139 UINT32 MsrIndex;
140
141 ASSERT ((MmioOffset & 0xf) == 0);
142
143 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
144 return MmioRead32 (GetLocalApicBaseAddress() + MmioOffset);
145 } else {
146 //
147 // DFR is not supported in x2APIC mode.
148 //
149 ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
150 //
151 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
152 // is not supported in this function for simplicity.
153 //
154 ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
155
156 MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
157 return AsmReadMsr32 (MsrIndex);
158 }
159 }
160
161 /**
162 Write to a local APIC register.
163
164 This function writes to a local APIC register either in xAPIC or x2APIC mode.
165 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
166 accessed using multiple 32-bit loads or stores, so this function only performs
167 32-bit write.
168
169 if the register index is invalid or unsupported in current APIC mode, then ASSERT.
170
171 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
172 It must be 16-byte aligned.
173 @param Value Value to be written to the register.
174 **/
175 VOID
176 EFIAPI
177 WriteLocalApicReg (
178 IN UINTN MmioOffset,
179 IN UINT32 Value
180 )
181 {
182 UINT32 MsrIndex;
183
184 ASSERT ((MmioOffset & 0xf) == 0);
185
186 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
187 MmioWrite32 (GetLocalApicBaseAddress() + MmioOffset, Value);
188 } else {
189 //
190 // DFR is not supported in x2APIC mode.
191 //
192 ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
193 //
194 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
195 // is not supported in this function for simplicity.
196 //
197 ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
198 ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET);
199
200 MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
201 //
202 // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.
203 // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
204 //
205 MemoryFence ();
206 AsmWriteMsr32 (MsrIndex, Value);
207 }
208 }
209
210 /**
211 Send an IPI by writing to ICR.
212
213 This function returns after the IPI has been accepted by the target processor.
214
215 @param IcrLow 32-bit value to be written to the low half of ICR.
216 @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
217 **/
218 VOID
219 SendIpi (
220 IN UINT32 IcrLow,
221 IN UINT32 ApicId
222 )
223 {
224 UINT64 MsrValue;
225 LOCAL_APIC_ICR_LOW IcrLowReg;
226 UINTN LocalApciBaseAddress;
227 UINT32 IcrHigh;
228 BOOLEAN InterruptState;
229
230 //
231 // Legacy APIC or X2APIC?
232 //
233 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
234 ASSERT (ApicId <= 0xff);
235
236 InterruptState = SaveAndDisableInterrupts ();
237
238 //
239 // Get base address of this LAPIC
240 //
241 LocalApciBaseAddress = GetLocalApicBaseAddress();
242
243 //
244 // Save existing contents of ICR high 32 bits
245 //
246 IcrHigh = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET);
247
248 //
249 // Wait for DeliveryStatus clear in case a previous IPI
250 // is still being sent
251 //
252 do {
253 IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
254 } while (IcrLowReg.Bits.DeliveryStatus != 0);
255
256 //
257 // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
258 //
259 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
260 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);
261
262 //
263 // Wait for DeliveryStatus clear again
264 //
265 do {
266 IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
267 } while (IcrLowReg.Bits.DeliveryStatus != 0);
268
269 //
270 // And restore old contents of ICR high
271 //
272 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, IcrHigh);
273
274 SetInterruptState (InterruptState);
275
276 } else {
277 //
278 // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an
279 // interrupt in x2APIC mode.
280 //
281 MsrValue = LShiftU64 ((UINT64) ApicId, 32) | IcrLow;
282 AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);
283 }
284 }
285
286 //
287 // Library API implementation functions
288 //
289
290 /**
291 Get the current local APIC mode.
292
293 If local APIC is disabled, then ASSERT.
294
295 @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.
296 @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
297 **/
298 UINTN
299 EFIAPI
300 GetApicMode (
301 VOID
302 )
303 {
304 MSR_IA32_APIC_BASE ApicBaseMsr;
305
306 if (!LocalApicBaseAddressMsrSupported ()) {
307 //
308 // If CPU does not support APIC Base Address MSR, then return XAPIC mode
309 //
310 return LOCAL_APIC_MODE_XAPIC;
311 }
312
313 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
314 //
315 // Local APIC should have been enabled
316 //
317 ASSERT (ApicBaseMsr.Bits.En != 0);
318 if (ApicBaseMsr.Bits.Extd != 0) {
319 return LOCAL_APIC_MODE_X2APIC;
320 } else {
321 return LOCAL_APIC_MODE_XAPIC;
322 }
323 }
324
325 /**
326 Set the current local APIC mode.
327
328 If the specified local APIC mode is not valid, then ASSERT.
329 If the specified local APIC mode can't be set as current, then ASSERT.
330
331 @param ApicMode APIC mode to be set.
332
333 @note This API must not be called from an interrupt handler or SMI handler.
334 It may result in unpredictable behavior.
335 **/
336 VOID
337 EFIAPI
338 SetApicMode (
339 IN UINTN ApicMode
340 )
341 {
342 UINTN CurrentMode;
343 MSR_IA32_APIC_BASE ApicBaseMsr;
344
345 if (!LocalApicBaseAddressMsrSupported ()) {
346 //
347 // Ignore set request if the CPU does not support APIC Base Address MSR
348 //
349 return;
350 }
351
352 CurrentMode = GetApicMode ();
353 if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {
354 switch (ApicMode) {
355 case LOCAL_APIC_MODE_XAPIC:
356 break;
357 case LOCAL_APIC_MODE_X2APIC:
358 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
359 ApicBaseMsr.Bits.Extd = 1;
360 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);
361 break;
362 default:
363 ASSERT (FALSE);
364 }
365 } else {
366 switch (ApicMode) {
367 case LOCAL_APIC_MODE_XAPIC:
368 //
369 // Transition from x2APIC mode to xAPIC mode is a two-step process:
370 // x2APIC -> Local APIC disabled -> xAPIC
371 //
372 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
373 ApicBaseMsr.Bits.Extd = 0;
374 ApicBaseMsr.Bits.En = 0;
375 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);
376 ApicBaseMsr.Bits.En = 1;
377 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);
378 break;
379 case LOCAL_APIC_MODE_X2APIC:
380 break;
381 default:
382 ASSERT (FALSE);
383 }
384 }
385 }
386
387 /**
388 Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
389
390 In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
391 In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
392 the 32-bit local APIC ID is returned as initial APIC ID.
393
394 @return 32-bit initial local APIC ID of the executing processor.
395 **/
396 UINT32
397 EFIAPI
398 GetInitialApicId (
399 VOID
400 )
401 {
402 UINT32 ApicId;
403 UINT32 MaxCpuIdIndex;
404 UINT32 RegEbx;
405
406 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
407 //
408 // Get the max index of basic CPUID
409 //
410 AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
411 //
412 // If CPUID Leaf B is supported,
413 // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
414 // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
415 //
416 if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
417 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, NULL, NULL, &ApicId);
418 return ApicId;
419 }
420 AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
421 return RegEbx >> 24;
422 } else {
423 return GetApicId ();
424 }
425 }
426
427 /**
428 Get the local APIC ID of the executing processor.
429
430 @return 32-bit local APIC ID of the executing processor.
431 **/
432 UINT32
433 EFIAPI
434 GetApicId (
435 VOID
436 )
437 {
438 UINT32 ApicId;
439 UINT32 InitApicId;
440
441 ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
442 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
443 ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;
444 }
445
446 return ApicId;
447 }
448
449 /**
450 Get the value of the local APIC version register.
451
452 @return the value of the local APIC version register.
453 **/
454 UINT32
455 EFIAPI
456 GetApicVersion (
457 VOID
458 )
459 {
460 return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
461 }
462
463 /**
464 Send a Fixed IPI to a specified target processor.
465
466 This function returns after the IPI has been accepted by the target processor.
467
468 @param ApicId The local APIC ID of the target processor.
469 @param Vector The vector number of the interrupt being sent.
470 **/
471 VOID
472 EFIAPI
473 SendFixedIpi (
474 IN UINT32 ApicId,
475 IN UINT8 Vector
476 )
477 {
478 LOCAL_APIC_ICR_LOW IcrLow;
479
480 IcrLow.Uint32 = 0;
481 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
482 IcrLow.Bits.Level = 1;
483 IcrLow.Bits.Vector = Vector;
484 SendIpi (IcrLow.Uint32, ApicId);
485 }
486
487 /**
488 Send a Fixed IPI to all processors excluding self.
489
490 This function returns after the IPI has been accepted by the target processors.
491
492 @param Vector The vector number of the interrupt being sent.
493 **/
494 VOID
495 EFIAPI
496 SendFixedIpiAllExcludingSelf (
497 IN UINT8 Vector
498 )
499 {
500 LOCAL_APIC_ICR_LOW IcrLow;
501
502 IcrLow.Uint32 = 0;
503 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
504 IcrLow.Bits.Level = 1;
505 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
506 IcrLow.Bits.Vector = Vector;
507 SendIpi (IcrLow.Uint32, 0);
508 }
509
510 /**
511 Send a SMI IPI to a specified target processor.
512
513 This function returns after the IPI has been accepted by the target processor.
514
515 @param ApicId Specify the local APIC ID of the target processor.
516 **/
517 VOID
518 EFIAPI
519 SendSmiIpi (
520 IN UINT32 ApicId
521 )
522 {
523 LOCAL_APIC_ICR_LOW IcrLow;
524
525 IcrLow.Uint32 = 0;
526 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
527 IcrLow.Bits.Level = 1;
528 SendIpi (IcrLow.Uint32, ApicId);
529 }
530
531 /**
532 Send a SMI IPI to all processors excluding self.
533
534 This function returns after the IPI has been accepted by the target processors.
535 **/
536 VOID
537 EFIAPI
538 SendSmiIpiAllExcludingSelf (
539 VOID
540 )
541 {
542 LOCAL_APIC_ICR_LOW IcrLow;
543
544 IcrLow.Uint32 = 0;
545 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
546 IcrLow.Bits.Level = 1;
547 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
548 SendIpi (IcrLow.Uint32, 0);
549 }
550
551 /**
552 Send an INIT IPI to a specified target processor.
553
554 This function returns after the IPI has been accepted by the target processor.
555
556 @param ApicId Specify the local APIC ID of the target processor.
557 **/
558 VOID
559 EFIAPI
560 SendInitIpi (
561 IN UINT32 ApicId
562 )
563 {
564 LOCAL_APIC_ICR_LOW IcrLow;
565
566 IcrLow.Uint32 = 0;
567 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
568 IcrLow.Bits.Level = 1;
569 SendIpi (IcrLow.Uint32, ApicId);
570 }
571
572 /**
573 Send an INIT IPI to all processors excluding self.
574
575 This function returns after the IPI has been accepted by the target processors.
576 **/
577 VOID
578 EFIAPI
579 SendInitIpiAllExcludingSelf (
580 VOID
581 )
582 {
583 LOCAL_APIC_ICR_LOW IcrLow;
584
585 IcrLow.Uint32 = 0;
586 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
587 IcrLow.Bits.Level = 1;
588 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
589 SendIpi (IcrLow.Uint32, 0);
590 }
591
592 /**
593 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
594
595 This function returns after the IPI has been accepted by the target processor.
596
597 if StartupRoutine >= 1M, then ASSERT.
598 if StartupRoutine is not multiple of 4K, then ASSERT.
599
600 @param ApicId Specify the local APIC ID of the target processor.
601 @param StartupRoutine Points to a start-up routine which is below 1M physical
602 address and 4K aligned.
603 **/
604 VOID
605 EFIAPI
606 SendInitSipiSipi (
607 IN UINT32 ApicId,
608 IN UINT32 StartupRoutine
609 )
610 {
611 LOCAL_APIC_ICR_LOW IcrLow;
612
613 ASSERT (StartupRoutine < 0x100000);
614 ASSERT ((StartupRoutine & 0xfff) == 0);
615
616 SendInitIpi (ApicId);
617 MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
618 IcrLow.Uint32 = 0;
619 IcrLow.Bits.Vector = (StartupRoutine >> 12);
620 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
621 IcrLow.Bits.Level = 1;
622 SendIpi (IcrLow.Uint32, ApicId);
623 MicroSecondDelay (200);
624 SendIpi (IcrLow.Uint32, ApicId);
625 }
626
627 /**
628 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
629
630 This function returns after the IPI has been accepted by the target processors.
631
632 if StartupRoutine >= 1M, then ASSERT.
633 if StartupRoutine is not multiple of 4K, then ASSERT.
634
635 @param StartupRoutine Points to a start-up routine which is below 1M physical
636 address and 4K aligned.
637 **/
638 VOID
639 EFIAPI
640 SendInitSipiSipiAllExcludingSelf (
641 IN UINT32 StartupRoutine
642 )
643 {
644 LOCAL_APIC_ICR_LOW IcrLow;
645
646 ASSERT (StartupRoutine < 0x100000);
647 ASSERT ((StartupRoutine & 0xfff) == 0);
648
649 SendInitIpiAllExcludingSelf ();
650 MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
651 IcrLow.Uint32 = 0;
652 IcrLow.Bits.Vector = (StartupRoutine >> 12);
653 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
654 IcrLow.Bits.Level = 1;
655 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
656 SendIpi (IcrLow.Uint32, 0);
657 MicroSecondDelay (200);
658 SendIpi (IcrLow.Uint32, 0);
659 }
660
661 /**
662 Programming Virtual Wire Mode.
663
664 This function programs the local APIC for virtual wire mode following
665 the example described in chapter A.3 of the MP 1.4 spec.
666
667 IOxAPIC is not involved in this type of virtual wire mode.
668 **/
669 VOID
670 EFIAPI
671 ProgramVirtualWireMode (
672 VOID
673 )
674 {
675 LOCAL_APIC_SVR Svr;
676 LOCAL_APIC_LVT_LINT Lint;
677
678 //
679 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
680 //
681 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
682 Svr.Bits.SpuriousVector = 0xf;
683 Svr.Bits.SoftwareEnable = 1;
684 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
685
686 //
687 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
688 //
689 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
690 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
691 Lint.Bits.InputPinPolarity = 0;
692 Lint.Bits.TriggerMode = 0;
693 Lint.Bits.Mask = 0;
694 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
695
696 //
697 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
698 //
699 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
700 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
701 Lint.Bits.InputPinPolarity = 0;
702 Lint.Bits.TriggerMode = 0;
703 Lint.Bits.Mask = 0;
704 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
705 }
706
707 /**
708 Disable LINT0 & LINT1 interrupts.
709
710 This function sets the mask flag in the LVT LINT0 & LINT1 registers.
711 **/
712 VOID
713 EFIAPI
714 DisableLvtInterrupts (
715 VOID
716 )
717 {
718 LOCAL_APIC_LVT_LINT LvtLint;
719
720 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
721 LvtLint.Bits.Mask = 1;
722 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
723
724 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
725 LvtLint.Bits.Mask = 1;
726 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
727 }
728
729 /**
730 Read the initial count value from the init-count register.
731
732 @return The initial count value read from the init-count register.
733 **/
734 UINT32
735 EFIAPI
736 GetApicTimerInitCount (
737 VOID
738 )
739 {
740 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
741 }
742
743 /**
744 Read the current count value from the current-count register.
745
746 @return The current count value read from the current-count register.
747 **/
748 UINT32
749 EFIAPI
750 GetApicTimerCurrentCount (
751 VOID
752 )
753 {
754 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
755 }
756
757 /**
758 Initialize the local APIC timer.
759
760 The local APIC timer is initialized and enabled.
761
762 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
763 If it is 0, then use the current divide value in the DCR.
764 @param InitCount The initial count value.
765 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
766 @param Vector The timer interrupt vector number.
767 **/
768 VOID
769 EFIAPI
770 InitializeApicTimer (
771 IN UINTN DivideValue,
772 IN UINT32 InitCount,
773 IN BOOLEAN PeriodicMode,
774 IN UINT8 Vector
775 )
776 {
777 LOCAL_APIC_SVR Svr;
778 LOCAL_APIC_DCR Dcr;
779 LOCAL_APIC_LVT_TIMER LvtTimer;
780 UINT32 Divisor;
781
782 //
783 // Ensure local APIC is in software-enabled state.
784 //
785 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
786 Svr.Bits.SoftwareEnable = 1;
787 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
788
789 //
790 // Program init-count register.
791 //
792 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
793
794 if (DivideValue != 0) {
795 ASSERT (DivideValue <= 128);
796 ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));
797 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
798
799 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
800 Dcr.Bits.DivideValue1 = (Divisor & 0x3);
801 Dcr.Bits.DivideValue2 = (Divisor >> 2);
802 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
803 }
804
805 //
806 // Enable APIC timer interrupt with specified timer mode.
807 //
808 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
809 if (PeriodicMode) {
810 LvtTimer.Bits.TimerMode = 1;
811 } else {
812 LvtTimer.Bits.TimerMode = 0;
813 }
814 LvtTimer.Bits.Mask = 0;
815 LvtTimer.Bits.Vector = Vector;
816 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
817 }
818
819 /**
820 Get the state of the local APIC timer.
821
822 This function will ASSERT if the local APIC is not software enabled.
823
824 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
825 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
826 @param Vector Return the timer interrupt vector number.
827 **/
828 VOID
829 EFIAPI
830 GetApicTimerState (
831 OUT UINTN *DivideValue OPTIONAL,
832 OUT BOOLEAN *PeriodicMode OPTIONAL,
833 OUT UINT8 *Vector OPTIONAL
834 )
835 {
836 UINT32 Divisor;
837 LOCAL_APIC_DCR Dcr;
838 LOCAL_APIC_LVT_TIMER LvtTimer;
839
840 //
841 // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
842 // Vector Register.
843 // This bit will be 1, if local APIC is software enabled.
844 //
845 ASSERT ((ReadLocalApicReg(XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
846
847 if (DivideValue != NULL) {
848 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
849 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
850 Divisor = (Divisor + 1) & 0x7;
851 *DivideValue = ((UINTN)1) << Divisor;
852 }
853
854 if (PeriodicMode != NULL || Vector != NULL) {
855 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
856 if (PeriodicMode != NULL) {
857 if (LvtTimer.Bits.TimerMode == 1) {
858 *PeriodicMode = TRUE;
859 } else {
860 *PeriodicMode = FALSE;
861 }
862 }
863 if (Vector != NULL) {
864 *Vector = (UINT8) LvtTimer.Bits.Vector;
865 }
866 }
867 }
868
869 /**
870 Enable the local APIC timer interrupt.
871 **/
872 VOID
873 EFIAPI
874 EnableApicTimerInterrupt (
875 VOID
876 )
877 {
878 LOCAL_APIC_LVT_TIMER LvtTimer;
879
880 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
881 LvtTimer.Bits.Mask = 0;
882 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
883 }
884
885 /**
886 Disable the local APIC timer interrupt.
887 **/
888 VOID
889 EFIAPI
890 DisableApicTimerInterrupt (
891 VOID
892 )
893 {
894 LOCAL_APIC_LVT_TIMER LvtTimer;
895
896 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
897 LvtTimer.Bits.Mask = 1;
898 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
899 }
900
901 /**
902 Get the local APIC timer interrupt state.
903
904 @retval TRUE The local APIC timer interrupt is enabled.
905 @retval FALSE The local APIC timer interrupt is disabled.
906 **/
907 BOOLEAN
908 EFIAPI
909 GetApicTimerInterruptState (
910 VOID
911 )
912 {
913 LOCAL_APIC_LVT_TIMER LvtTimer;
914
915 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
916 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
917 }
918
919 /**
920 Send EOI to the local APIC.
921 **/
922 VOID
923 EFIAPI
924 SendApicEoi (
925 VOID
926 )
927 {
928 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
929 }
930
931 /**
932 Get the 32-bit address that a device should use to send a Message Signaled
933 Interrupt (MSI) to the Local APIC of the currently executing processor.
934
935 @return 32-bit address used to send an MSI to the Local APIC.
936 **/
937 UINT32
938 EFIAPI
939 GetApicMsiAddress (
940 VOID
941 )
942 {
943 LOCAL_APIC_MSI_ADDRESS MsiAddress;
944
945 //
946 // Return address for an MSI interrupt to be delivered only to the APIC ID
947 // of the currently executing processor.
948 //
949 MsiAddress.Uint32 = 0;
950 MsiAddress.Bits.BaseAddress = 0xFEE;
951 MsiAddress.Bits.DestinationId = GetApicId ();
952 return MsiAddress.Uint32;
953 }
954
955 /**
956 Get the 64-bit data value that a device should use to send a Message Signaled
957 Interrupt (MSI) to the Local APIC of the currently executing processor.
958
959 If Vector is not in range 0x10..0xFE, then ASSERT().
960 If DeliveryMode is not supported, then ASSERT().
961
962 @param Vector The 8-bit interrupt vector associated with the MSI.
963 Must be in the range 0x10..0xFE
964 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
965 is handled. The only supported values are:
966 0: LOCAL_APIC_DELIVERY_MODE_FIXED
967 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
968 2: LOCAL_APIC_DELIVERY_MODE_SMI
969 4: LOCAL_APIC_DELIVERY_MODE_NMI
970 5: LOCAL_APIC_DELIVERY_MODE_INIT
971 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
972
973 @param LevelTriggered TRUE specifies a level triggered interrupt.
974 FALSE specifies an edge triggered interrupt.
975 @param AssertionLevel Ignored if LevelTriggered is FALSE.
976 TRUE specifies a level triggered interrupt that active
977 when the interrupt line is asserted.
978 FALSE specifies a level triggered interrupt that active
979 when the interrupt line is deasserted.
980
981 @return 64-bit data value used to send an MSI to the Local APIC.
982 **/
983 UINT64
984 EFIAPI
985 GetApicMsiValue (
986 IN UINT8 Vector,
987 IN UINTN DeliveryMode,
988 IN BOOLEAN LevelTriggered,
989 IN BOOLEAN AssertionLevel
990 )
991 {
992 LOCAL_APIC_MSI_DATA MsiData;
993
994 ASSERT (Vector >= 0x10 && Vector <= 0xFE);
995 ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
996
997 MsiData.Uint64 = 0;
998 MsiData.Bits.Vector = Vector;
999 MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
1000 if (LevelTriggered) {
1001 MsiData.Bits.TriggerMode = 1;
1002 if (AssertionLevel) {
1003 MsiData.Bits.Level = 1;
1004 }
1005 }
1006 return MsiData.Uint64;
1007 }