]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
UefiCpuPkg BaseXApic(X2)Lib: Add ASSERT if local APIC not software enabled
[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 This function will ASSERT if the local APIC is not software enabled.
727
728 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
729 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
730 @param Vector Return the timer interrupt vector number.
731 **/
732 VOID
733 EFIAPI
734 GetApicTimerState (
735 OUT UINTN *DivideValue OPTIONAL,
736 OUT BOOLEAN *PeriodicMode OPTIONAL,
737 OUT UINT8 *Vector OPTIONAL
738 )
739 {
740 UINT32 Divisor;
741 LOCAL_APIC_DCR Dcr;
742 LOCAL_APIC_LVT_TIMER LvtTimer;
743
744 //
745 // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
746 // Vector Register.
747 // This bit will be 1, if local APIC is software enabled.
748 //
749 ASSERT ((ReadLocalApicReg(XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
750
751 if (DivideValue != NULL) {
752 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
753 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
754 Divisor = (Divisor + 1) & 0x7;
755 *DivideValue = ((UINTN)1) << Divisor;
756 }
757
758 if (PeriodicMode != NULL || Vector != NULL) {
759 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
760 if (PeriodicMode != NULL) {
761 if (LvtTimer.Bits.TimerMode == 1) {
762 *PeriodicMode = TRUE;
763 } else {
764 *PeriodicMode = FALSE;
765 }
766 }
767 if (Vector != NULL) {
768 *Vector = (UINT8) LvtTimer.Bits.Vector;
769 }
770 }
771 }
772
773 /**
774 Enable the local APIC timer interrupt.
775 **/
776 VOID
777 EFIAPI
778 EnableApicTimerInterrupt (
779 VOID
780 )
781 {
782 LOCAL_APIC_LVT_TIMER LvtTimer;
783
784 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
785 LvtTimer.Bits.Mask = 0;
786 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
787 }
788
789 /**
790 Disable the local APIC timer interrupt.
791 **/
792 VOID
793 EFIAPI
794 DisableApicTimerInterrupt (
795 VOID
796 )
797 {
798 LOCAL_APIC_LVT_TIMER LvtTimer;
799
800 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
801 LvtTimer.Bits.Mask = 1;
802 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
803 }
804
805 /**
806 Get the local APIC timer interrupt state.
807
808 @retval TRUE The local APIC timer interrupt is enabled.
809 @retval FALSE The local APIC timer interrupt is disabled.
810 **/
811 BOOLEAN
812 EFIAPI
813 GetApicTimerInterruptState (
814 VOID
815 )
816 {
817 LOCAL_APIC_LVT_TIMER LvtTimer;
818
819 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
820 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
821 }
822
823 /**
824 Send EOI to the local APIC.
825 **/
826 VOID
827 EFIAPI
828 SendApicEoi (
829 VOID
830 )
831 {
832 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
833 }
834
835 /**
836 Get the 32-bit address that a device should use to send a Message Signaled
837 Interrupt (MSI) to the Local APIC of the currently executing processor.
838
839 @return 32-bit address used to send an MSI to the Local APIC.
840 **/
841 UINT32
842 EFIAPI
843 GetApicMsiAddress (
844 VOID
845 )
846 {
847 LOCAL_APIC_MSI_ADDRESS MsiAddress;
848
849 //
850 // Return address for an MSI interrupt to be delivered only to the APIC ID
851 // of the currently executing processor.
852 //
853 MsiAddress.Uint32 = 0;
854 MsiAddress.Bits.BaseAddress = 0xFEE;
855 MsiAddress.Bits.DestinationId = GetApicId ();
856 return MsiAddress.Uint32;
857 }
858
859 /**
860 Get the 64-bit data value that a device should use to send a Message Signaled
861 Interrupt (MSI) to the Local APIC of the currently executing processor.
862
863 If Vector is not in range 0x10..0xFE, then ASSERT().
864 If DeliveryMode is not supported, then ASSERT().
865
866 @param Vector The 8-bit interrupt vector associated with the MSI.
867 Must be in the range 0x10..0xFE
868 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
869 is handled. The only supported values are:
870 0: LOCAL_APIC_DELIVERY_MODE_FIXED
871 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
872 2: LOCAL_APIC_DELIVERY_MODE_SMI
873 4: LOCAL_APIC_DELIVERY_MODE_NMI
874 5: LOCAL_APIC_DELIVERY_MODE_INIT
875 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
876
877 @param LevelTriggered TRUE specifies a level triggered interrupt.
878 FALSE specifies an edge triggered interrupt.
879 @param AssertionLevel Ignored if LevelTriggered is FALSE.
880 TRUE specifies a level triggered interrupt that active
881 when the interrupt line is asserted.
882 FALSE specifies a level triggered interrupt that active
883 when the interrupt line is deasserted.
884
885 @return 64-bit data value used to send an MSI to the Local APIC.
886 **/
887 UINT64
888 EFIAPI
889 GetApicMsiValue (
890 IN UINT8 Vector,
891 IN UINTN DeliveryMode,
892 IN BOOLEAN LevelTriggered,
893 IN BOOLEAN AssertionLevel
894 )
895 {
896 LOCAL_APIC_MSI_DATA MsiData;
897
898 ASSERT (Vector >= 0x10 && Vector <= 0xFE);
899 ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
900
901 MsiData.Uint64 = 0;
902 MsiData.Bits.Vector = Vector;
903 MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
904 if (LevelTriggered) {
905 MsiData.Bits.TriggerMode = 1;
906 if (AssertionLevel) {
907 MsiData.Bits.Level = 1;
908 }
909 }
910 return MsiData.Uint64;
911 }