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