]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
1. Read 32bit CPU Init APIC ID from CPUID leaf B in XAPIC mode.
[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 - 2013, 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 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 ApicId;
306 UINT32 MaxCpuIdIndex;
307 UINT32 RegEbx;
308
309 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
310 //
311 // Get the max index of basic CPUID
312 //
313 AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
314 //
315 // If CPUID Leaf B is supported,
316 // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
317 // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
318 //
319 if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
320 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, NULL, NULL, &ApicId);
321 return ApicId;
322 }
323 AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
324 return RegEbx >> 24;
325 } else {
326 return GetApicId ();
327 }
328 }
329
330 /**
331 Get the local APIC ID of the executing processor.
332
333 @return 32-bit local APIC ID of the executing processor.
334 **/
335 UINT32
336 EFIAPI
337 GetApicId (
338 VOID
339 )
340 {
341 UINT32 ApicId;
342 UINT32 InitApicId;
343
344 ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
345 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
346 ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;
347 }
348
349 return ApicId;
350 }
351
352 /**
353 Get the value of the local APIC version register.
354
355 @return the value of the local APIC version register.
356 **/
357 UINT32
358 EFIAPI
359 GetApicVersion (
360 VOID
361 )
362 {
363 return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
364 }
365
366 /**
367 Send a Fixed IPI to a specified target processor.
368
369 This function returns after the IPI has been accepted by the target processor.
370
371 @param ApicId The local APIC ID of the target processor.
372 @param Vector The vector number of the interrupt being sent.
373 **/
374 VOID
375 EFIAPI
376 SendFixedIpi (
377 IN UINT32 ApicId,
378 IN UINT8 Vector
379 )
380 {
381 LOCAL_APIC_ICR_LOW IcrLow;
382
383 IcrLow.Uint32 = 0;
384 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
385 IcrLow.Bits.Level = 1;
386 IcrLow.Bits.Vector = Vector;
387 SendIpi (IcrLow.Uint32, ApicId);
388 }
389
390 /**
391 Send a Fixed IPI to all processors excluding self.
392
393 This function returns after the IPI has been accepted by the target processors.
394
395 @param Vector The vector number of the interrupt being sent.
396 **/
397 VOID
398 EFIAPI
399 SendFixedIpiAllExcludingSelf (
400 IN UINT8 Vector
401 )
402 {
403 LOCAL_APIC_ICR_LOW IcrLow;
404
405 IcrLow.Uint32 = 0;
406 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
407 IcrLow.Bits.Level = 1;
408 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
409 IcrLow.Bits.Vector = Vector;
410 SendIpi (IcrLow.Uint32, 0);
411 }
412
413 /**
414 Send a SMI IPI to a specified target processor.
415
416 This function returns after the IPI has been accepted by the target processor.
417
418 @param ApicId Specify the local APIC ID of the target processor.
419 **/
420 VOID
421 EFIAPI
422 SendSmiIpi (
423 IN UINT32 ApicId
424 )
425 {
426 LOCAL_APIC_ICR_LOW IcrLow;
427
428 IcrLow.Uint32 = 0;
429 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
430 IcrLow.Bits.Level = 1;
431 SendIpi (IcrLow.Uint32, ApicId);
432 }
433
434 /**
435 Send a SMI IPI to all processors excluding self.
436
437 This function returns after the IPI has been accepted by the target processors.
438 **/
439 VOID
440 EFIAPI
441 SendSmiIpiAllExcludingSelf (
442 VOID
443 )
444 {
445 LOCAL_APIC_ICR_LOW IcrLow;
446
447 IcrLow.Uint32 = 0;
448 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
449 IcrLow.Bits.Level = 1;
450 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
451 SendIpi (IcrLow.Uint32, 0);
452 }
453
454 /**
455 Send an INIT IPI to a specified target processor.
456
457 This function returns after the IPI has been accepted by the target processor.
458
459 @param ApicId Specify the local APIC ID of the target processor.
460 **/
461 VOID
462 EFIAPI
463 SendInitIpi (
464 IN UINT32 ApicId
465 )
466 {
467 LOCAL_APIC_ICR_LOW IcrLow;
468
469 IcrLow.Uint32 = 0;
470 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
471 IcrLow.Bits.Level = 1;
472 SendIpi (IcrLow.Uint32, ApicId);
473 }
474
475 /**
476 Send an INIT IPI to all processors excluding self.
477
478 This function returns after the IPI has been accepted by the target processors.
479 **/
480 VOID
481 EFIAPI
482 SendInitIpiAllExcludingSelf (
483 VOID
484 )
485 {
486 LOCAL_APIC_ICR_LOW IcrLow;
487
488 IcrLow.Uint32 = 0;
489 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
490 IcrLow.Bits.Level = 1;
491 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
492 SendIpi (IcrLow.Uint32, 0);
493 }
494
495 /**
496 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
497
498 This function returns after the IPI has been accepted by the target processor.
499
500 if StartupRoutine >= 1M, then ASSERT.
501 if StartupRoutine is not multiple of 4K, then ASSERT.
502
503 @param ApicId Specify the local APIC ID of the target processor.
504 @param StartupRoutine Points to a start-up routine which is below 1M physical
505 address and 4K aligned.
506 **/
507 VOID
508 EFIAPI
509 SendInitSipiSipi (
510 IN UINT32 ApicId,
511 IN UINT32 StartupRoutine
512 )
513 {
514 LOCAL_APIC_ICR_LOW IcrLow;
515
516 ASSERT (StartupRoutine < 0x100000);
517 ASSERT ((StartupRoutine & 0xfff) == 0);
518
519 SendInitIpi (ApicId);
520 MicroSecondDelay (10);
521 IcrLow.Uint32 = 0;
522 IcrLow.Bits.Vector = (StartupRoutine >> 12);
523 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
524 IcrLow.Bits.Level = 1;
525 SendIpi (IcrLow.Uint32, ApicId);
526 MicroSecondDelay (200);
527 SendIpi (IcrLow.Uint32, ApicId);
528 }
529
530 /**
531 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
532
533 This function returns after the IPI has been accepted by the target processors.
534
535 if StartupRoutine >= 1M, then ASSERT.
536 if StartupRoutine is not multiple of 4K, then ASSERT.
537
538 @param StartupRoutine Points to a start-up routine which is below 1M physical
539 address and 4K aligned.
540 **/
541 VOID
542 EFIAPI
543 SendInitSipiSipiAllExcludingSelf (
544 IN UINT32 StartupRoutine
545 )
546 {
547 LOCAL_APIC_ICR_LOW IcrLow;
548
549 ASSERT (StartupRoutine < 0x100000);
550 ASSERT ((StartupRoutine & 0xfff) == 0);
551
552 SendInitIpiAllExcludingSelf ();
553 MicroSecondDelay (10);
554 IcrLow.Uint32 = 0;
555 IcrLow.Bits.Vector = (StartupRoutine >> 12);
556 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
557 IcrLow.Bits.Level = 1;
558 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
559 SendIpi (IcrLow.Uint32, 0);
560 MicroSecondDelay (200);
561 SendIpi (IcrLow.Uint32, 0);
562 }
563
564 /**
565 Programming Virtual Wire Mode.
566
567 This function programs the local APIC for virtual wire mode following
568 the example described in chapter A.3 of the MP 1.4 spec.
569
570 IOxAPIC is not involved in this type of virtual wire mode.
571 **/
572 VOID
573 EFIAPI
574 ProgramVirtualWireMode (
575 VOID
576 )
577 {
578 LOCAL_APIC_SVR Svr;
579 LOCAL_APIC_LVT_LINT Lint;
580
581 //
582 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
583 //
584 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
585 Svr.Bits.SpuriousVector = 0xf;
586 Svr.Bits.SoftwareEnable = 1;
587 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
588
589 //
590 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
591 //
592 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
593 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
594 Lint.Bits.InputPinPolarity = 0;
595 Lint.Bits.TriggerMode = 0;
596 Lint.Bits.Mask = 0;
597 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
598
599 //
600 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
601 //
602 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
603 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
604 Lint.Bits.InputPinPolarity = 0;
605 Lint.Bits.TriggerMode = 0;
606 Lint.Bits.Mask = 0;
607 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
608 }
609
610 /**
611 Disable LINT0 & LINT1 interrupts.
612
613 This function sets the mask flag in the LVT LINT0 & LINT1 registers.
614 **/
615 VOID
616 EFIAPI
617 DisableLvtInterrupts (
618 VOID
619 )
620 {
621 LOCAL_APIC_LVT_LINT LvtLint;
622
623 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
624 LvtLint.Bits.Mask = 1;
625 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
626
627 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
628 LvtLint.Bits.Mask = 1;
629 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
630 }
631
632 /**
633 Read the initial count value from the init-count register.
634
635 @return The initial count value read from the init-count register.
636 **/
637 UINT32
638 EFIAPI
639 GetApicTimerInitCount (
640 VOID
641 )
642 {
643 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
644 }
645
646 /**
647 Read the current count value from the current-count register.
648
649 @return The current count value read from the current-count register.
650 **/
651 UINT32
652 EFIAPI
653 GetApicTimerCurrentCount (
654 VOID
655 )
656 {
657 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
658 }
659
660 /**
661 Initialize the local APIC timer.
662
663 The local APIC timer is initialized and enabled.
664
665 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
666 If it is 0, then use the current divide value in the DCR.
667 @param InitCount The initial count value.
668 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
669 @param Vector The timer interrupt vector number.
670 **/
671 VOID
672 EFIAPI
673 InitializeApicTimer (
674 IN UINTN DivideValue,
675 IN UINT32 InitCount,
676 IN BOOLEAN PeriodicMode,
677 IN UINT8 Vector
678 )
679 {
680 LOCAL_APIC_SVR Svr;
681 LOCAL_APIC_DCR Dcr;
682 LOCAL_APIC_LVT_TIMER LvtTimer;
683 UINT32 Divisor;
684
685 //
686 // Ensure local APIC is in software-enabled state.
687 //
688 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
689 Svr.Bits.SoftwareEnable = 1;
690 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
691
692 //
693 // Program init-count register.
694 //
695 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
696
697 if (DivideValue != 0) {
698 ASSERT (DivideValue <= 128);
699 ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));
700 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
701
702 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
703 Dcr.Bits.DivideValue1 = (Divisor & 0x3);
704 Dcr.Bits.DivideValue2 = (Divisor >> 2);
705 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
706 }
707
708 //
709 // Enable APIC timer interrupt with specified timer mode.
710 //
711 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
712 if (PeriodicMode) {
713 LvtTimer.Bits.TimerMode = 1;
714 } else {
715 LvtTimer.Bits.TimerMode = 0;
716 }
717 LvtTimer.Bits.Mask = 0;
718 LvtTimer.Bits.Vector = Vector;
719 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
720 }
721
722 /**
723 Get the state of the local APIC timer.
724
725 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
726 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
727 @param Vector Return the timer interrupt vector number.
728 **/
729 VOID
730 EFIAPI
731 GetApicTimerState (
732 OUT UINTN *DivideValue OPTIONAL,
733 OUT BOOLEAN *PeriodicMode OPTIONAL,
734 OUT UINT8 *Vector OPTIONAL
735 )
736 {
737 UINT32 Divisor;
738 LOCAL_APIC_DCR Dcr;
739 LOCAL_APIC_LVT_TIMER LvtTimer;
740
741 if (DivideValue != NULL) {
742 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
743 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
744 Divisor = (Divisor + 1) & 0x7;
745 *DivideValue = ((UINTN)1) << Divisor;
746 }
747
748 if (PeriodicMode != NULL || Vector != NULL) {
749 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
750 if (PeriodicMode != NULL) {
751 if (LvtTimer.Bits.TimerMode == 1) {
752 *PeriodicMode = TRUE;
753 } else {
754 *PeriodicMode = FALSE;
755 }
756 }
757 if (Vector != NULL) {
758 *Vector = (UINT8) LvtTimer.Bits.Vector;
759 }
760 }
761 }
762
763 /**
764 Enable the local APIC timer interrupt.
765 **/
766 VOID
767 EFIAPI
768 EnableApicTimerInterrupt (
769 VOID
770 )
771 {
772 LOCAL_APIC_LVT_TIMER LvtTimer;
773
774 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
775 LvtTimer.Bits.Mask = 0;
776 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
777 }
778
779 /**
780 Disable the local APIC timer interrupt.
781 **/
782 VOID
783 EFIAPI
784 DisableApicTimerInterrupt (
785 VOID
786 )
787 {
788 LOCAL_APIC_LVT_TIMER LvtTimer;
789
790 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
791 LvtTimer.Bits.Mask = 1;
792 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
793 }
794
795 /**
796 Get the local APIC timer interrupt state.
797
798 @retval TRUE The local APIC timer interrupt is enabled.
799 @retval FALSE The local APIC timer interrupt is disabled.
800 **/
801 BOOLEAN
802 EFIAPI
803 GetApicTimerInterruptState (
804 VOID
805 )
806 {
807 LOCAL_APIC_LVT_TIMER LvtTimer;
808
809 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
810 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
811 }
812
813 /**
814 Send EOI to the local APIC.
815 **/
816 VOID
817 EFIAPI
818 SendApicEoi (
819 VOID
820 )
821 {
822 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
823 }
824
825 /**
826 Get the 32-bit address that a device should use to send a Message Signaled
827 Interrupt (MSI) to the Local APIC of the currently executing processor.
828
829 @return 32-bit address used to send an MSI to the Local APIC.
830 **/
831 UINT32
832 EFIAPI
833 GetApicMsiAddress (
834 VOID
835 )
836 {
837 LOCAL_APIC_MSI_ADDRESS MsiAddress;
838
839 //
840 // Return address for an MSI interrupt to be delivered only to the APIC ID
841 // of the currently executing processor.
842 //
843 MsiAddress.Uint32 = 0;
844 MsiAddress.Bits.BaseAddress = 0xFEE;
845 MsiAddress.Bits.DestinationId = GetApicId ();
846 return MsiAddress.Uint32;
847 }
848
849 /**
850 Get the 64-bit data value that a device should use to send a Message Signaled
851 Interrupt (MSI) to the Local APIC of the currently executing processor.
852
853 If Vector is not in range 0x10..0xFE, then ASSERT().
854 If DeliveryMode is not supported, then ASSERT().
855
856 @param Vector The 8-bit interrupt vector associated with the MSI.
857 Must be in the range 0x10..0xFE
858 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
859 is handled. The only supported values are:
860 0: LOCAL_APIC_DELIVERY_MODE_FIXED
861 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
862 2: LOCAL_APIC_DELIVERY_MODE_SMI
863 4: LOCAL_APIC_DELIVERY_MODE_NMI
864 5: LOCAL_APIC_DELIVERY_MODE_INIT
865 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
866
867 @param LevelTriggered TRUE specifies a level triggered interrupt.
868 FALSE specifies an edge triggered interrupt.
869 @param AssertionLevel Ignored if LevelTriggered is FALSE.
870 TRUE specifies a level triggered interrupt that active
871 when the interrupt line is asserted.
872 FALSE specifies a level triggered interrupt that active
873 when the interrupt line is deasserted.
874
875 @return 64-bit data value used to send an MSI to the Local APIC.
876 **/
877 UINT64
878 EFIAPI
879 GetApicMsiValue (
880 IN UINT8 Vector,
881 IN UINTN DeliveryMode,
882 IN BOOLEAN LevelTriggered,
883 IN BOOLEAN AssertionLevel
884 )
885 {
886 LOCAL_APIC_MSI_DATA MsiData;
887
888 ASSERT (Vector >= 0x10 && Vector <= 0xFE);
889 ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
890
891 MsiData.Uint64 = 0;
892 MsiData.Bits.Vector = Vector;
893 MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
894 if (LevelTriggered) {
895 MsiData.Bits.TriggerMode = 1;
896 if (AssertionLevel) {
897 MsiData.Bits.Level = 1;
898 }
899 }
900 return MsiData.Uint64;
901 }