]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
Avoid DxeCore to reclaim PEI stack as IDT may be on it (like 32-bit OVMF).
[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 Read the initial count value from the init-count register.
548
549 @return The initial count value read from the init-count register.
550 **/
551 UINT32
552 EFIAPI
553 GetApicTimerInitCount (
554 VOID
555 )
556 {
557 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
558 }
559
560 /**
561 Read the current count value from the current-count register.
562
563 @return The current count value read from the current-count register.
564 **/
565 UINT32
566 EFIAPI
567 GetApicTimerCurrentCount (
568 VOID
569 )
570 {
571 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
572 }
573
574 /**
575 Initialize the local APIC timer.
576
577 The local APIC timer is initialized and enabled.
578
579 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
580 If it is 0, then use the current divide value in the DCR.
581 @param InitCount The initial count value.
582 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
583 @param Vector The timer interrupt vector number.
584 **/
585 VOID
586 EFIAPI
587 InitializeApicTimer (
588 IN UINTN DivideValue,
589 IN UINT32 InitCount,
590 IN BOOLEAN PeriodicMode,
591 IN UINT8 Vector
592 )
593 {
594 LOCAL_APIC_SVR Svr;
595 LOCAL_APIC_DCR Dcr;
596 LOCAL_APIC_LVT_TIMER LvtTimer;
597 UINT32 Divisor;
598
599 //
600 // Ensure local APIC is in software-enabled state.
601 //
602 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
603 Svr.Bits.SoftwareEnable = 1;
604 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
605
606 //
607 // Program init-count register.
608 //
609 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
610
611 if (DivideValue != 0) {
612 ASSERT (DivideValue <= 128);
613 ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));
614 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
615
616 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
617 Dcr.Bits.DivideValue1 = (Divisor & 0x3);
618 Dcr.Bits.DivideValue2 = (Divisor >> 2);
619 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
620 }
621
622 //
623 // Enable APIC timer interrupt with specified timer mode.
624 //
625 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
626 if (PeriodicMode) {
627 LvtTimer.Bits.TimerMode = 1;
628 } else {
629 LvtTimer.Bits.TimerMode = 0;
630 }
631 LvtTimer.Bits.Mask = 0;
632 LvtTimer.Bits.Vector = Vector;
633 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
634 }
635
636 /**
637 Get the state of the local APIC timer.
638
639 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
640 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
641 @param Vector Return the timer interrupt vector number.
642 **/
643 VOID
644 EFIAPI
645 GetApicTimerState (
646 OUT UINTN *DivideValue OPTIONAL,
647 OUT BOOLEAN *PeriodicMode OPTIONAL,
648 OUT UINT8 *Vector OPTIONAL
649 )
650 {
651 UINT32 Divisor;
652 LOCAL_APIC_DCR Dcr;
653 LOCAL_APIC_LVT_TIMER LvtTimer;
654
655 if (DivideValue != NULL) {
656 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
657 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
658 Divisor = (Divisor + 1) & 0x7;
659 *DivideValue = ((UINTN)1) << Divisor;
660 }
661
662 if (PeriodicMode != NULL || Vector != NULL) {
663 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
664 if (PeriodicMode != NULL) {
665 if (LvtTimer.Bits.TimerMode == 1) {
666 *PeriodicMode = TRUE;
667 } else {
668 *PeriodicMode = FALSE;
669 }
670 }
671 if (Vector != NULL) {
672 *Vector = (UINT8) LvtTimer.Bits.Vector;
673 }
674 }
675 }
676
677 /**
678 Enable the local APIC timer interrupt.
679 **/
680 VOID
681 EFIAPI
682 EnableApicTimerInterrupt (
683 VOID
684 )
685 {
686 LOCAL_APIC_LVT_TIMER LvtTimer;
687
688 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
689 LvtTimer.Bits.Mask = 0;
690 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
691 }
692
693 /**
694 Disable the local APIC timer interrupt.
695 **/
696 VOID
697 EFIAPI
698 DisableApicTimerInterrupt (
699 VOID
700 )
701 {
702 LOCAL_APIC_LVT_TIMER LvtTimer;
703
704 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
705 LvtTimer.Bits.Mask = 1;
706 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
707 }
708
709 /**
710 Get the local APIC timer interrupt state.
711
712 @retval TRUE The local APIC timer interrupt is enabled.
713 @retval FALSE The local APIC timer interrupt is disabled.
714 **/
715 BOOLEAN
716 EFIAPI
717 GetApicTimerInterruptState (
718 VOID
719 )
720 {
721 LOCAL_APIC_LVT_TIMER LvtTimer;
722
723 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
724 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
725 }
726
727 /**
728 Send EOI to the local APIC.
729 **/
730 VOID
731 EFIAPI
732 SendApicEoi (
733 VOID
734 )
735 {
736 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
737 }
738