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