]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
1. Save/restore ICR high 32bit value and check Delivery Status before sending IPI...
[mirror_edk2.git] / UefiCpuPkg / Library / BaseXApicLib / BaseXApicLib.c
1 /** @file
2 Local APIC Library.
3
4 This local APIC library instance supports xAPIC mode only.
5
6 Copyright (c) 2010 - 2014, 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/LocalApic.h>
18
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/LocalApicLib.h>
22 #include <Library/IoLib.h>
23 #include <Library/TimerLib.h>
24
25 //
26 // Library internal functions
27 //
28
29 /**
30 Retrieve the base address of local APIC.
31
32 @return The base address of local APIC.
33
34 **/
35 UINTN
36 EFIAPI
37 GetLocalApicBaseAddress (
38 VOID
39 )
40 {
41 MSR_IA32_APIC_BASE ApicBaseMsr;
42
43 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
44
45 return (UINTN)(LShiftU64 ((UINT64) ApicBaseMsr.Bits.ApicBaseHigh, 32)) +
46 (((UINTN)ApicBaseMsr.Bits.ApicBaseLow) << 12);
47 }
48
49 /**
50 Set the base address of local APIC.
51
52 If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
53
54 @param[in] BaseAddress Local APIC base address to be set.
55
56 **/
57 VOID
58 EFIAPI
59 SetLocalApicBaseAddress (
60 IN UINTN BaseAddress
61 )
62 {
63 MSR_IA32_APIC_BASE ApicBaseMsr;
64
65 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
66
67 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
68
69 ApicBaseMsr.Bits.ApicBaseLow = (UINT32) (BaseAddress >> 12);
70 ApicBaseMsr.Bits.ApicBaseHigh = (UINT32) (RShiftU64((UINT64) BaseAddress, 32));
71
72 AsmWriteMsr64 (MSR_IA32_APIC_BASE_ADDRESS, ApicBaseMsr.Uint64);
73 }
74
75 /**
76 Read from a local APIC register.
77
78 This function reads from a local APIC register either in xAPIC or x2APIC mode.
79 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
80 accessed using multiple 32-bit loads or stores, so this function only performs
81 32-bit read.
82
83 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
84 It must be 16-byte aligned.
85
86 @return 32-bit Value read from the register.
87 **/
88 UINT32
89 EFIAPI
90 ReadLocalApicReg (
91 IN UINTN MmioOffset
92 )
93 {
94 ASSERT ((MmioOffset & 0xf) == 0);
95 ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
96
97 return MmioRead32 (GetLocalApicBaseAddress() + MmioOffset);
98 }
99
100 /**
101 Write to a local APIC register.
102
103 This function writes to a local APIC register either in xAPIC or x2APIC mode.
104 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
105 accessed using multiple 32-bit loads or stores, so this function only performs
106 32-bit write.
107
108 if the register index is invalid or unsupported in current APIC mode, then ASSERT.
109
110 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
111 It must be 16-byte aligned.
112 @param Value Value to be written to the register.
113 **/
114 VOID
115 EFIAPI
116 WriteLocalApicReg (
117 IN UINTN MmioOffset,
118 IN UINT32 Value
119 )
120 {
121 ASSERT ((MmioOffset & 0xf) == 0);
122 ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
123
124 MmioWrite32 (GetLocalApicBaseAddress() + MmioOffset, Value);
125 }
126
127 /**
128 Send an IPI by writing to ICR.
129
130 This function returns after the IPI has been accepted by the target processor.
131
132 @param IcrLow 32-bit value to be written to the low half of ICR.
133 @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
134 **/
135 VOID
136 SendIpi (
137 IN UINT32 IcrLow,
138 IN UINT32 ApicId
139 )
140 {
141 LOCAL_APIC_ICR_LOW IcrLowReg;
142 UINT32 IcrHigh;
143 BOOLEAN InterruptState;
144
145 ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
146 ASSERT (ApicId <= 0xff);
147
148 InterruptState = SaveAndDisableInterrupts ();
149
150 //
151 // Save existing contents of ICR high 32 bits
152 //
153 IcrHigh = ReadLocalApicReg (XAPIC_ICR_HIGH_OFFSET);
154
155 //
156 // Wait for DeliveryStatus clear in case a previous IPI
157 // is still being sent
158 //
159 do {
160 IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);
161 } while (IcrLowReg.Bits.DeliveryStatus != 0);
162
163 //
164 // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
165 //
166 WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
167 WriteLocalApicReg (XAPIC_ICR_LOW_OFFSET, IcrLow);
168
169 //
170 // Wait for DeliveryStatus clear again
171 //
172 do {
173 IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);
174 } while (IcrLowReg.Bits.DeliveryStatus != 0);
175
176 //
177 // And restore old contents of ICR high
178 //
179 WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, IcrHigh);
180
181 SetInterruptState (InterruptState);
182
183 }
184
185 //
186 // Library API implementation functions
187 //
188
189 /**
190 Get the current local APIC mode.
191
192 If local APIC is disabled, then ASSERT.
193
194 @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.
195 @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
196 **/
197 UINTN
198 EFIAPI
199 GetApicMode (
200 VOID
201 )
202 {
203 DEBUG_CODE (
204 {
205 MSR_IA32_APIC_BASE ApicBaseMsr;
206
207 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE_ADDRESS);
208 //
209 // Local APIC should have been enabled
210 //
211 ASSERT (ApicBaseMsr.Bits.En != 0);
212 ASSERT (ApicBaseMsr.Bits.Extd == 0);
213 }
214 );
215 return LOCAL_APIC_MODE_XAPIC;
216 }
217
218 /**
219 Set the current local APIC mode.
220
221 If the specified local APIC mode is not valid, then ASSERT.
222 If the specified local APIC mode can't be set as current, then ASSERT.
223
224 @param ApicMode APIC mode to be set.
225
226 @note This API must not be called from an interrupt handler or SMI handler.
227 It may result in unpredictable behavior.
228 **/
229 VOID
230 EFIAPI
231 SetApicMode (
232 IN UINTN ApicMode
233 )
234 {
235 ASSERT (ApicMode == LOCAL_APIC_MODE_XAPIC);
236 ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
237 }
238
239 /**
240 Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
241
242 In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
243 In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
244 the 32-bit local APIC ID is returned as initial APIC ID.
245
246 @return 32-bit initial local APIC ID of the executing processor.
247 **/
248 UINT32
249 EFIAPI
250 GetInitialApicId (
251 VOID
252 )
253 {
254 UINT32 ApicId;
255 UINT32 MaxCpuIdIndex;
256 UINT32 RegEbx;
257
258 ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
259
260 //
261 // Get the max index of basic CPUID
262 //
263 AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
264
265 //
266 // If CPUID Leaf B is supported,
267 // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
268 // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
269 //
270 if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
271 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, NULL, NULL, &ApicId);
272 return ApicId;
273 }
274
275 AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
276 return RegEbx >> 24;
277 }
278
279 /**
280 Get the local APIC ID of the executing processor.
281
282 @return 32-bit local APIC ID of the executing processor.
283 **/
284 UINT32
285 EFIAPI
286 GetApicId (
287 VOID
288 )
289 {
290 UINT32 ApicId;
291
292 ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
293
294 if ((ApicId = GetInitialApicId ()) < 0x100) {
295 //
296 // If the initial local APIC ID is less 0x100, read APIC ID from
297 // XAPIC_ID_OFFSET, otherwise return the initial local APIC ID.
298 //
299 ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
300 ApicId >>= 24;
301 }
302 return ApicId;
303 }
304
305 /**
306 Get the value of the local APIC version register.
307
308 @return the value of the local APIC version register.
309 **/
310 UINT32
311 EFIAPI
312 GetApicVersion (
313 VOID
314 )
315 {
316 return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
317 }
318
319 /**
320 Send a Fixed IPI to a specified target processor.
321
322 This function returns after the IPI has been accepted by the target processor.
323
324 @param ApicId The local APIC ID of the target processor.
325 @param Vector The vector number of the interrupt being sent.
326 **/
327 VOID
328 EFIAPI
329 SendFixedIpi (
330 IN UINT32 ApicId,
331 IN UINT8 Vector
332 )
333 {
334 LOCAL_APIC_ICR_LOW IcrLow;
335
336 IcrLow.Uint32 = 0;
337 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
338 IcrLow.Bits.Level = 1;
339 IcrLow.Bits.Vector = Vector;
340 SendIpi (IcrLow.Uint32, ApicId);
341 }
342
343 /**
344 Send a Fixed IPI to all processors excluding self.
345
346 This function returns after the IPI has been accepted by the target processors.
347
348 @param Vector The vector number of the interrupt being sent.
349 **/
350 VOID
351 EFIAPI
352 SendFixedIpiAllExcludingSelf (
353 IN UINT8 Vector
354 )
355 {
356 LOCAL_APIC_ICR_LOW IcrLow;
357
358 IcrLow.Uint32 = 0;
359 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
360 IcrLow.Bits.Level = 1;
361 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
362 IcrLow.Bits.Vector = Vector;
363 SendIpi (IcrLow.Uint32, 0);
364 }
365
366 /**
367 Send a SMI IPI to a specified target processor.
368
369 This function returns after the IPI has been accepted by the target processor.
370
371 @param ApicId Specify the local APIC ID of the target processor.
372 **/
373 VOID
374 EFIAPI
375 SendSmiIpi (
376 IN UINT32 ApicId
377 )
378 {
379 LOCAL_APIC_ICR_LOW IcrLow;
380
381 IcrLow.Uint32 = 0;
382 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
383 IcrLow.Bits.Level = 1;
384 SendIpi (IcrLow.Uint32, ApicId);
385 }
386
387 /**
388 Send a SMI IPI to all processors excluding self.
389
390 This function returns after the IPI has been accepted by the target processors.
391 **/
392 VOID
393 EFIAPI
394 SendSmiIpiAllExcludingSelf (
395 VOID
396 )
397 {
398 LOCAL_APIC_ICR_LOW IcrLow;
399
400 IcrLow.Uint32 = 0;
401 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
402 IcrLow.Bits.Level = 1;
403 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
404 SendIpi (IcrLow.Uint32, 0);
405 }
406
407 /**
408 Send an INIT IPI to a specified target processor.
409
410 This function returns after the IPI has been accepted by the target processor.
411
412 @param ApicId Specify the local APIC ID of the target processor.
413 **/
414 VOID
415 EFIAPI
416 SendInitIpi (
417 IN UINT32 ApicId
418 )
419 {
420 LOCAL_APIC_ICR_LOW IcrLow;
421
422 IcrLow.Uint32 = 0;
423 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
424 IcrLow.Bits.Level = 1;
425 SendIpi (IcrLow.Uint32, ApicId);
426 }
427
428 /**
429 Send an INIT IPI to all processors excluding self.
430
431 This function returns after the IPI has been accepted by the target processors.
432 **/
433 VOID
434 EFIAPI
435 SendInitIpiAllExcludingSelf (
436 VOID
437 )
438 {
439 LOCAL_APIC_ICR_LOW IcrLow;
440
441 IcrLow.Uint32 = 0;
442 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
443 IcrLow.Bits.Level = 1;
444 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
445 SendIpi (IcrLow.Uint32, 0);
446 }
447
448 /**
449 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
450
451 This function returns after the IPI has been accepted by the target processor.
452
453 if StartupRoutine >= 1M, then ASSERT.
454 if StartupRoutine is not multiple of 4K, then ASSERT.
455
456 @param ApicId Specify the local APIC ID of the target processor.
457 @param StartupRoutine Points to a start-up routine which is below 1M physical
458 address and 4K aligned.
459 **/
460 VOID
461 EFIAPI
462 SendInitSipiSipi (
463 IN UINT32 ApicId,
464 IN UINT32 StartupRoutine
465 )
466 {
467 LOCAL_APIC_ICR_LOW IcrLow;
468
469 ASSERT (StartupRoutine < 0x100000);
470 ASSERT ((StartupRoutine & 0xfff) == 0);
471
472 SendInitIpi (ApicId);
473 MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
474 IcrLow.Uint32 = 0;
475 IcrLow.Bits.Vector = (StartupRoutine >> 12);
476 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
477 IcrLow.Bits.Level = 1;
478 SendIpi (IcrLow.Uint32, ApicId);
479 MicroSecondDelay (200);
480 SendIpi (IcrLow.Uint32, ApicId);
481 }
482
483 /**
484 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
485
486 This function returns after the IPI has been accepted by the target processors.
487
488 if StartupRoutine >= 1M, then ASSERT.
489 if StartupRoutine is not multiple of 4K, then ASSERT.
490
491 @param StartupRoutine Points to a start-up routine which is below 1M physical
492 address and 4K aligned.
493 **/
494 VOID
495 EFIAPI
496 SendInitSipiSipiAllExcludingSelf (
497 IN UINT32 StartupRoutine
498 )
499 {
500 LOCAL_APIC_ICR_LOW IcrLow;
501
502 ASSERT (StartupRoutine < 0x100000);
503 ASSERT ((StartupRoutine & 0xfff) == 0);
504
505 SendInitIpiAllExcludingSelf ();
506 MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
507 IcrLow.Uint32 = 0;
508 IcrLow.Bits.Vector = (StartupRoutine >> 12);
509 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
510 IcrLow.Bits.Level = 1;
511 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
512 SendIpi (IcrLow.Uint32, 0);
513 MicroSecondDelay (200);
514 SendIpi (IcrLow.Uint32, 0);
515 }
516
517 /**
518 Programming Virtual Wire Mode.
519
520 This function programs the local APIC for virtual wire mode following
521 the example described in chapter A.3 of the MP 1.4 spec.
522
523 IOxAPIC is not involved in this type of virtual wire mode.
524 **/
525 VOID
526 EFIAPI
527 ProgramVirtualWireMode (
528 VOID
529 )
530 {
531 LOCAL_APIC_SVR Svr;
532 LOCAL_APIC_LVT_LINT Lint;
533
534 //
535 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
536 //
537 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
538 Svr.Bits.SpuriousVector = 0xf;
539 Svr.Bits.SoftwareEnable = 1;
540 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
541
542 //
543 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
544 //
545 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
546 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
547 Lint.Bits.InputPinPolarity = 0;
548 Lint.Bits.TriggerMode = 0;
549 Lint.Bits.Mask = 0;
550 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
551
552 //
553 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
554 //
555 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
556 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
557 Lint.Bits.InputPinPolarity = 0;
558 Lint.Bits.TriggerMode = 0;
559 Lint.Bits.Mask = 0;
560 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
561 }
562
563 /**
564 Disable LINT0 & LINT1 interrupts.
565
566 This function sets the mask flag in the LVT LINT0 & LINT1 registers.
567 **/
568 VOID
569 EFIAPI
570 DisableLvtInterrupts (
571 VOID
572 )
573 {
574 LOCAL_APIC_LVT_LINT LvtLint;
575
576 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
577 LvtLint.Bits.Mask = 1;
578 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
579
580 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
581 LvtLint.Bits.Mask = 1;
582 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
583 }
584
585 /**
586 Read the initial count value from the init-count register.
587
588 @return The initial count value read from the init-count register.
589 **/
590 UINT32
591 EFIAPI
592 GetApicTimerInitCount (
593 VOID
594 )
595 {
596 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
597 }
598
599 /**
600 Read the current count value from the current-count register.
601
602 @return The current count value read from the current-count register.
603 **/
604 UINT32
605 EFIAPI
606 GetApicTimerCurrentCount (
607 VOID
608 )
609 {
610 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
611 }
612
613 /**
614 Initialize the local APIC timer.
615
616 The local APIC timer is initialized and enabled.
617
618 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
619 If it is 0, then use the current divide value in the DCR.
620 @param InitCount The initial count value.
621 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
622 @param Vector The timer interrupt vector number.
623 **/
624 VOID
625 EFIAPI
626 InitializeApicTimer (
627 IN UINTN DivideValue,
628 IN UINT32 InitCount,
629 IN BOOLEAN PeriodicMode,
630 IN UINT8 Vector
631 )
632 {
633 LOCAL_APIC_SVR Svr;
634 LOCAL_APIC_DCR Dcr;
635 LOCAL_APIC_LVT_TIMER LvtTimer;
636 UINT32 Divisor;
637
638 //
639 // Ensure local APIC is in software-enabled state.
640 //
641 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
642 Svr.Bits.SoftwareEnable = 1;
643 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
644
645 //
646 // Program init-count register.
647 //
648 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
649
650 if (DivideValue != 0) {
651 ASSERT (DivideValue <= 128);
652 ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));
653 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
654
655 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
656 Dcr.Bits.DivideValue1 = (Divisor & 0x3);
657 Dcr.Bits.DivideValue2 = (Divisor >> 2);
658 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
659 }
660
661 //
662 // Enable APIC timer interrupt with specified timer mode.
663 //
664 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
665 if (PeriodicMode) {
666 LvtTimer.Bits.TimerMode = 1;
667 } else {
668 LvtTimer.Bits.TimerMode = 0;
669 }
670 LvtTimer.Bits.Mask = 0;
671 LvtTimer.Bits.Vector = Vector;
672 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
673 }
674
675 /**
676 Get the state of the local APIC timer.
677
678 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
679 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
680 @param Vector Return the timer interrupt vector number.
681 **/
682 VOID
683 EFIAPI
684 GetApicTimerState (
685 OUT UINTN *DivideValue OPTIONAL,
686 OUT BOOLEAN *PeriodicMode OPTIONAL,
687 OUT UINT8 *Vector OPTIONAL
688 )
689 {
690 UINT32 Divisor;
691 LOCAL_APIC_DCR Dcr;
692 LOCAL_APIC_LVT_TIMER LvtTimer;
693
694 if (DivideValue != NULL) {
695 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
696 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
697 Divisor = (Divisor + 1) & 0x7;
698 *DivideValue = ((UINTN)1) << Divisor;
699 }
700
701 if (PeriodicMode != NULL || Vector != NULL) {
702 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
703 if (PeriodicMode != NULL) {
704 if (LvtTimer.Bits.TimerMode == 1) {
705 *PeriodicMode = TRUE;
706 } else {
707 *PeriodicMode = FALSE;
708 }
709 }
710 if (Vector != NULL) {
711 *Vector = (UINT8) LvtTimer.Bits.Vector;
712 }
713 }
714 }
715
716 /**
717 Enable the local APIC timer interrupt.
718 **/
719 VOID
720 EFIAPI
721 EnableApicTimerInterrupt (
722 VOID
723 )
724 {
725 LOCAL_APIC_LVT_TIMER LvtTimer;
726
727 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
728 LvtTimer.Bits.Mask = 0;
729 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
730 }
731
732 /**
733 Disable the local APIC timer interrupt.
734 **/
735 VOID
736 EFIAPI
737 DisableApicTimerInterrupt (
738 VOID
739 )
740 {
741 LOCAL_APIC_LVT_TIMER LvtTimer;
742
743 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
744 LvtTimer.Bits.Mask = 1;
745 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
746 }
747
748 /**
749 Get the local APIC timer interrupt state.
750
751 @retval TRUE The local APIC timer interrupt is enabled.
752 @retval FALSE The local APIC timer interrupt is disabled.
753 **/
754 BOOLEAN
755 EFIAPI
756 GetApicTimerInterruptState (
757 VOID
758 )
759 {
760 LOCAL_APIC_LVT_TIMER LvtTimer;
761
762 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
763 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
764 }
765
766 /**
767 Send EOI to the local APIC.
768 **/
769 VOID
770 EFIAPI
771 SendApicEoi (
772 VOID
773 )
774 {
775 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
776 }
777
778 /**
779 Get the 32-bit address that a device should use to send a Message Signaled
780 Interrupt (MSI) to the Local APIC of the currently executing processor.
781
782 @return 32-bit address used to send an MSI to the Local APIC.
783 **/
784 UINT32
785 EFIAPI
786 GetApicMsiAddress (
787 VOID
788 )
789 {
790 LOCAL_APIC_MSI_ADDRESS MsiAddress;
791
792 //
793 // Return address for an MSI interrupt to be delivered only to the APIC ID
794 // of the currently executing processor.
795 //
796 MsiAddress.Uint32 = 0;
797 MsiAddress.Bits.BaseAddress = 0xFEE;
798 MsiAddress.Bits.DestinationId = GetApicId ();
799 return MsiAddress.Uint32;
800 }
801
802 /**
803 Get the 64-bit data value that a device should use to send a Message Signaled
804 Interrupt (MSI) to the Local APIC of the currently executing processor.
805
806 If Vector is not in range 0x10..0xFE, then ASSERT().
807 If DeliveryMode is not supported, then ASSERT().
808
809 @param Vector The 8-bit interrupt vector associated with the MSI.
810 Must be in the range 0x10..0xFE
811 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
812 is handled. The only supported values are:
813 0: LOCAL_APIC_DELIVERY_MODE_FIXED
814 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
815 2: LOCAL_APIC_DELIVERY_MODE_SMI
816 4: LOCAL_APIC_DELIVERY_MODE_NMI
817 5: LOCAL_APIC_DELIVERY_MODE_INIT
818 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
819
820 @param LevelTriggered TRUE specifies a level triggered interrupt.
821 FALSE specifies an edge triggered interrupt.
822 @param AssertionLevel Ignored if LevelTriggered is FALSE.
823 TRUE specifies a level triggered interrupt that active
824 when the interrupt line is asserted.
825 FALSE specifies a level triggered interrupt that active
826 when the interrupt line is deasserted.
827
828 @return 64-bit data value used to send an MSI to the Local APIC.
829 **/
830 UINT64
831 EFIAPI
832 GetApicMsiValue (
833 IN UINT8 Vector,
834 IN UINTN DeliveryMode,
835 IN BOOLEAN LevelTriggered,
836 IN BOOLEAN AssertionLevel
837 )
838 {
839 LOCAL_APIC_MSI_DATA MsiData;
840
841 ASSERT (Vector >= 0x10 && Vector <= 0xFE);
842 ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
843
844 MsiData.Uint64 = 0;
845 MsiData.Bits.Vector = Vector;
846 MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
847 if (LevelTriggered) {
848 MsiData.Bits.TriggerMode = 1;
849 if (AssertionLevel) {
850 MsiData.Bits.Level = 1;
851 }
852 }
853 return MsiData.Uint64;
854 }