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