]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
UefiCpuPkg: Apply uncrustify changes
[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 - 2019, Intel Corporation. All rights reserved.<BR>
7 Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>
8
9 SPDX-License-Identifier: BSD-2-Clause-Patent
10
11 **/
12
13 #include <Register/Intel/Cpuid.h>
14 #include <Register/Amd/Cpuid.h>
15 #include <Register/Intel/Msr.h>
16 #include <Register/Intel/LocalApic.h>
17
18 #include <Library/BaseLib.h>
19 #include <Library/DebugLib.h>
20 #include <Library/LocalApicLib.h>
21 #include <Library/IoLib.h>
22 #include <Library/TimerLib.h>
23 #include <Library/PcdLib.h>
24 #include <Library/UefiCpuLib.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
55 return TRUE;
56 }
57
58 /**
59 Retrieve the base address of local APIC.
60
61 @return The base address of local APIC.
62
63 **/
64 UINTN
65 EFIAPI
66 GetLocalApicBaseAddress (
67 VOID
68 )
69 {
70 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
71
72 if (!LocalApicBaseAddressMsrSupported ()) {
73 //
74 // If CPU does not support Local APIC Base Address MSR, then retrieve
75 // Local APIC Base Address from PCD
76 //
77 return PcdGet32 (PcdCpuLocalApicBaseAddress);
78 }
79
80 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
81
82 return (UINTN)(LShiftU64 ((UINT64)ApicBaseMsr.Bits.ApicBaseHi, 32)) +
83 (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
84 }
85
86 /**
87 Set the base address of local APIC.
88
89 If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
90
91 @param[in] BaseAddress Local APIC base address to be set.
92
93 **/
94 VOID
95 EFIAPI
96 SetLocalApicBaseAddress (
97 IN UINTN BaseAddress
98 )
99 {
100 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
101
102 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
103
104 if (!LocalApicBaseAddressMsrSupported ()) {
105 //
106 // Ignore set request if the CPU does not support APIC Base Address MSR
107 //
108 return;
109 }
110
111 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
112
113 ApicBaseMsr.Bits.ApicBase = (UINT32)(BaseAddress >> 12);
114 ApicBaseMsr.Bits.ApicBaseHi = (UINT32)(RShiftU64 ((UINT64)BaseAddress, 32));
115
116 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
117 }
118
119 /**
120 Read from a local APIC register.
121
122 This function reads from a local APIC register either in xAPIC or x2APIC mode.
123 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
124 accessed using multiple 32-bit loads or stores, so this function only performs
125 32-bit read.
126
127 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
128 It must be 16-byte aligned.
129
130 @return 32-bit Value read from the register.
131 **/
132 UINT32
133 EFIAPI
134 ReadLocalApicReg (
135 IN UINTN MmioOffset
136 )
137 {
138 ASSERT ((MmioOffset & 0xf) == 0);
139 ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
140
141 return MmioRead32 (GetLocalApicBaseAddress () + MmioOffset);
142 }
143
144 /**
145 Write to a local APIC register.
146
147 This function writes to a local APIC register either in xAPIC or x2APIC mode.
148 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
149 accessed using multiple 32-bit loads or stores, so this function only performs
150 32-bit write.
151
152 if the register index is invalid or unsupported in current APIC mode, then ASSERT.
153
154 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
155 It must be 16-byte aligned.
156 @param Value Value to be written to the register.
157 **/
158 VOID
159 EFIAPI
160 WriteLocalApicReg (
161 IN UINTN MmioOffset,
162 IN UINT32 Value
163 )
164 {
165 ASSERT ((MmioOffset & 0xf) == 0);
166 ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
167
168 MmioWrite32 (GetLocalApicBaseAddress () + MmioOffset, Value);
169 }
170
171 /**
172 Send an IPI by writing to ICR.
173
174 This function returns after the IPI has been accepted by the target processor.
175
176 @param IcrLow 32-bit value to be written to the low half of ICR.
177 @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
178 **/
179 VOID
180 SendIpi (
181 IN UINT32 IcrLow,
182 IN UINT32 ApicId
183 )
184 {
185 LOCAL_APIC_ICR_LOW IcrLowReg;
186 UINT32 IcrHigh;
187 BOOLEAN InterruptState;
188
189 ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
190 ASSERT (ApicId <= 0xff);
191
192 InterruptState = SaveAndDisableInterrupts ();
193
194 //
195 // Save existing contents of ICR high 32 bits
196 //
197 IcrHigh = ReadLocalApicReg (XAPIC_ICR_HIGH_OFFSET);
198
199 //
200 // Wait for DeliveryStatus clear in case a previous IPI
201 // is still being sent
202 //
203 do {
204 IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);
205 } while (IcrLowReg.Bits.DeliveryStatus != 0);
206
207 //
208 // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
209 //
210 WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
211 WriteLocalApicReg (XAPIC_ICR_LOW_OFFSET, IcrLow);
212
213 //
214 // Wait for DeliveryStatus clear again
215 //
216 do {
217 IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);
218 } while (IcrLowReg.Bits.DeliveryStatus != 0);
219
220 //
221 // And restore old contents of ICR high
222 //
223 WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, IcrHigh);
224
225 SetInterruptState (InterruptState);
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_BEGIN ();
247 {
248 MSR_IA32_APIC_BASE_REGISTER 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);
255 //
256 // Local APIC should have been enabled
257 //
258 ASSERT (ApicBaseMsr.Bits.EN != 0);
259 ASSERT (ApicBaseMsr.Bits.EXTD == 0);
260 }
261 }
262 DEBUG_CODE_END ();
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 // And CPUID.0BH:EBX[15:0] reports a non-zero value,
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, &RegEbx, NULL, &ApicId);
321 if ((RegEbx & (BIT16 - 1)) != 0) {
322 return ApicId;
323 }
324 }
325
326 AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
327 return RegEbx >> 24;
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
343 ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
344
345 if ((ApicId = GetInitialApicId ()) < 0x100) {
346 //
347 // If the initial local APIC ID is less 0x100, read APIC ID from
348 // XAPIC_ID_OFFSET, otherwise return the initial local APIC ID.
349 //
350 ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
351 ApicId >>= 24;
352 }
353
354 return ApicId;
355 }
356
357 /**
358 Get the value of the local APIC version register.
359
360 @return the value of the local APIC version register.
361 **/
362 UINT32
363 EFIAPI
364 GetApicVersion (
365 VOID
366 )
367 {
368 return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
369 }
370
371 /**
372 Send a Fixed IPI to a specified target processor.
373
374 This function returns after the IPI has been accepted by the target processor.
375
376 @param ApicId The local APIC ID of the target processor.
377 @param Vector The vector number of the interrupt being sent.
378 **/
379 VOID
380 EFIAPI
381 SendFixedIpi (
382 IN UINT32 ApicId,
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.Vector = Vector;
392 SendIpi (IcrLow.Uint32, ApicId);
393 }
394
395 /**
396 Send a Fixed IPI to all processors excluding self.
397
398 This function returns after the IPI has been accepted by the target processors.
399
400 @param Vector The vector number of the interrupt being sent.
401 **/
402 VOID
403 EFIAPI
404 SendFixedIpiAllExcludingSelf (
405 IN UINT8 Vector
406 )
407 {
408 LOCAL_APIC_ICR_LOW IcrLow;
409
410 IcrLow.Uint32 = 0;
411 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
412 IcrLow.Bits.Level = 1;
413 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
414 IcrLow.Bits.Vector = Vector;
415 SendIpi (IcrLow.Uint32, 0);
416 }
417
418 /**
419 Send a SMI IPI to a specified target processor.
420
421 This function returns after the IPI has been accepted by the target processor.
422
423 @param ApicId Specify the local APIC ID of the target processor.
424 **/
425 VOID
426 EFIAPI
427 SendSmiIpi (
428 IN UINT32 ApicId
429 )
430 {
431 LOCAL_APIC_ICR_LOW IcrLow;
432
433 IcrLow.Uint32 = 0;
434 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
435 IcrLow.Bits.Level = 1;
436 SendIpi (IcrLow.Uint32, ApicId);
437 }
438
439 /**
440 Send a SMI IPI to all processors excluding self.
441
442 This function returns after the IPI has been accepted by the target processors.
443 **/
444 VOID
445 EFIAPI
446 SendSmiIpiAllExcludingSelf (
447 VOID
448 )
449 {
450 LOCAL_APIC_ICR_LOW IcrLow;
451
452 IcrLow.Uint32 = 0;
453 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
454 IcrLow.Bits.Level = 1;
455 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
456 SendIpi (IcrLow.Uint32, 0);
457 }
458
459 /**
460 Send an INIT IPI to a specified target processor.
461
462 This function returns after the IPI has been accepted by the target processor.
463
464 @param ApicId Specify the local APIC ID of the target processor.
465 **/
466 VOID
467 EFIAPI
468 SendInitIpi (
469 IN UINT32 ApicId
470 )
471 {
472 LOCAL_APIC_ICR_LOW IcrLow;
473
474 IcrLow.Uint32 = 0;
475 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
476 IcrLow.Bits.Level = 1;
477 SendIpi (IcrLow.Uint32, ApicId);
478 }
479
480 /**
481 Send an INIT IPI to all processors excluding self.
482
483 This function returns after the IPI has been accepted by the target processors.
484 **/
485 VOID
486 EFIAPI
487 SendInitIpiAllExcludingSelf (
488 VOID
489 )
490 {
491 LOCAL_APIC_ICR_LOW IcrLow;
492
493 IcrLow.Uint32 = 0;
494 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
495 IcrLow.Bits.Level = 1;
496 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
497 SendIpi (IcrLow.Uint32, 0);
498 }
499
500 /**
501 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
502
503 This function returns after the IPI has been accepted by the target processor.
504
505 if StartupRoutine >= 1M, then ASSERT.
506 if StartupRoutine is not multiple of 4K, then ASSERT.
507
508 @param ApicId Specify the local APIC ID of the target processor.
509 @param StartupRoutine Points to a start-up routine which is below 1M physical
510 address and 4K aligned.
511 **/
512 VOID
513 EFIAPI
514 SendInitSipiSipi (
515 IN UINT32 ApicId,
516 IN UINT32 StartupRoutine
517 )
518 {
519 LOCAL_APIC_ICR_LOW IcrLow;
520
521 ASSERT (StartupRoutine < 0x100000);
522 ASSERT ((StartupRoutine & 0xfff) == 0);
523
524 SendInitIpi (ApicId);
525 MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));
526 IcrLow.Uint32 = 0;
527 IcrLow.Bits.Vector = (StartupRoutine >> 12);
528 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
529 IcrLow.Bits.Level = 1;
530 SendIpi (IcrLow.Uint32, ApicId);
531 if (!StandardSignatureIsAuthenticAMD ()) {
532 MicroSecondDelay (200);
533 SendIpi (IcrLow.Uint32, ApicId);
534 }
535 }
536
537 /**
538 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
539
540 This function returns after the IPI has been accepted by the target processors.
541
542 if StartupRoutine >= 1M, then ASSERT.
543 if StartupRoutine is not multiple of 4K, then ASSERT.
544
545 @param StartupRoutine Points to a start-up routine which is below 1M physical
546 address and 4K aligned.
547 **/
548 VOID
549 EFIAPI
550 SendInitSipiSipiAllExcludingSelf (
551 IN UINT32 StartupRoutine
552 )
553 {
554 LOCAL_APIC_ICR_LOW IcrLow;
555
556 ASSERT (StartupRoutine < 0x100000);
557 ASSERT ((StartupRoutine & 0xfff) == 0);
558
559 SendInitIpiAllExcludingSelf ();
560 MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));
561 IcrLow.Uint32 = 0;
562 IcrLow.Bits.Vector = (StartupRoutine >> 12);
563 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
564 IcrLow.Bits.Level = 1;
565 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
566 SendIpi (IcrLow.Uint32, 0);
567 if (!StandardSignatureIsAuthenticAMD ()) {
568 MicroSecondDelay (200);
569 SendIpi (IcrLow.Uint32, 0);
570 }
571 }
572
573 /**
574 Initialize the state of the SoftwareEnable bit in the Local APIC
575 Spurious Interrupt Vector register.
576
577 @param Enable If TRUE, then set SoftwareEnable to 1
578 If FALSE, then set SoftwareEnable to 0.
579
580 **/
581 VOID
582 EFIAPI
583 InitializeLocalApicSoftwareEnable (
584 IN BOOLEAN Enable
585 )
586 {
587 LOCAL_APIC_SVR Svr;
588
589 //
590 // Set local APIC software-enabled bit.
591 //
592 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
593 if (Enable) {
594 if (Svr.Bits.SoftwareEnable == 0) {
595 Svr.Bits.SoftwareEnable = 1;
596 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
597 }
598 } else {
599 if (Svr.Bits.SoftwareEnable == 1) {
600 Svr.Bits.SoftwareEnable = 0;
601 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
602 }
603 }
604 }
605
606 /**
607 Programming Virtual Wire Mode.
608
609 This function programs the local APIC for virtual wire mode following
610 the example described in chapter A.3 of the MP 1.4 spec.
611
612 IOxAPIC is not involved in this type of virtual wire mode.
613 **/
614 VOID
615 EFIAPI
616 ProgramVirtualWireMode (
617 VOID
618 )
619 {
620 LOCAL_APIC_SVR Svr;
621 LOCAL_APIC_LVT_LINT Lint;
622
623 //
624 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
625 //
626 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
627 Svr.Bits.SpuriousVector = 0xf;
628 Svr.Bits.SoftwareEnable = 1;
629 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
630
631 //
632 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
633 //
634 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
635 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
636 Lint.Bits.InputPinPolarity = 0;
637 Lint.Bits.TriggerMode = 0;
638 Lint.Bits.Mask = 0;
639 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
640
641 //
642 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
643 //
644 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
645 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
646 Lint.Bits.InputPinPolarity = 0;
647 Lint.Bits.TriggerMode = 0;
648 Lint.Bits.Mask = 0;
649 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
650 }
651
652 /**
653 Disable LINT0 & LINT1 interrupts.
654
655 This function sets the mask flag in the LVT LINT0 & LINT1 registers.
656 **/
657 VOID
658 EFIAPI
659 DisableLvtInterrupts (
660 VOID
661 )
662 {
663 LOCAL_APIC_LVT_LINT LvtLint;
664
665 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
666 LvtLint.Bits.Mask = 1;
667 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
668
669 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
670 LvtLint.Bits.Mask = 1;
671 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
672 }
673
674 /**
675 Read the initial count value from the init-count register.
676
677 @return The initial count value read from the init-count register.
678 **/
679 UINT32
680 EFIAPI
681 GetApicTimerInitCount (
682 VOID
683 )
684 {
685 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
686 }
687
688 /**
689 Read the current count value from the current-count register.
690
691 @return The current count value read from the current-count register.
692 **/
693 UINT32
694 EFIAPI
695 GetApicTimerCurrentCount (
696 VOID
697 )
698 {
699 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
700 }
701
702 /**
703 Initialize the local APIC timer.
704
705 The local APIC timer is initialized and enabled.
706
707 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
708 If it is 0, then use the current divide value in the DCR.
709 @param InitCount The initial count value.
710 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
711 @param Vector The timer interrupt vector number.
712 **/
713 VOID
714 EFIAPI
715 InitializeApicTimer (
716 IN UINTN DivideValue,
717 IN UINT32 InitCount,
718 IN BOOLEAN PeriodicMode,
719 IN UINT8 Vector
720 )
721 {
722 LOCAL_APIC_DCR Dcr;
723 LOCAL_APIC_LVT_TIMER LvtTimer;
724 UINT32 Divisor;
725
726 //
727 // Ensure local APIC is in software-enabled state.
728 //
729 InitializeLocalApicSoftwareEnable (TRUE);
730
731 //
732 // Program init-count register.
733 //
734 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
735
736 if (DivideValue != 0) {
737 ASSERT (DivideValue <= 128);
738 ASSERT (DivideValue == GetPowerOfTwo32 ((UINT32)DivideValue));
739 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
740
741 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
742 Dcr.Bits.DivideValue1 = (Divisor & 0x3);
743 Dcr.Bits.DivideValue2 = (Divisor >> 2);
744 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
745 }
746
747 //
748 // Enable APIC timer interrupt with specified timer mode.
749 //
750 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
751 if (PeriodicMode) {
752 LvtTimer.Bits.TimerMode = 1;
753 } else {
754 LvtTimer.Bits.TimerMode = 0;
755 }
756
757 LvtTimer.Bits.Mask = 0;
758 LvtTimer.Bits.Vector = Vector;
759 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
760 }
761
762 /**
763 Get the state of the local APIC timer.
764
765 This function will ASSERT if the local APIC is not software enabled.
766
767 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
768 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
769 @param Vector Return the timer interrupt vector number.
770 **/
771 VOID
772 EFIAPI
773 GetApicTimerState (
774 OUT UINTN *DivideValue OPTIONAL,
775 OUT BOOLEAN *PeriodicMode OPTIONAL,
776 OUT UINT8 *Vector OPTIONAL
777 )
778 {
779 UINT32 Divisor;
780 LOCAL_APIC_DCR Dcr;
781 LOCAL_APIC_LVT_TIMER LvtTimer;
782
783 //
784 // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
785 // Vector Register.
786 // This bit will be 1, if local APIC is software enabled.
787 //
788 ASSERT ((ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
789
790 if (DivideValue != NULL) {
791 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
792 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
793 Divisor = (Divisor + 1) & 0x7;
794 *DivideValue = ((UINTN)1) << Divisor;
795 }
796
797 if ((PeriodicMode != NULL) || (Vector != NULL)) {
798 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
799 if (PeriodicMode != NULL) {
800 if (LvtTimer.Bits.TimerMode == 1) {
801 *PeriodicMode = TRUE;
802 } else {
803 *PeriodicMode = FALSE;
804 }
805 }
806
807 if (Vector != NULL) {
808 *Vector = (UINT8)LvtTimer.Bits.Vector;
809 }
810 }
811 }
812
813 /**
814 Enable the local APIC timer interrupt.
815 **/
816 VOID
817 EFIAPI
818 EnableApicTimerInterrupt (
819 VOID
820 )
821 {
822 LOCAL_APIC_LVT_TIMER LvtTimer;
823
824 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
825 LvtTimer.Bits.Mask = 0;
826 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
827 }
828
829 /**
830 Disable the local APIC timer interrupt.
831 **/
832 VOID
833 EFIAPI
834 DisableApicTimerInterrupt (
835 VOID
836 )
837 {
838 LOCAL_APIC_LVT_TIMER LvtTimer;
839
840 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
841 LvtTimer.Bits.Mask = 1;
842 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
843 }
844
845 /**
846 Get the local APIC timer interrupt state.
847
848 @retval TRUE The local APIC timer interrupt is enabled.
849 @retval FALSE The local APIC timer interrupt is disabled.
850 **/
851 BOOLEAN
852 EFIAPI
853 GetApicTimerInterruptState (
854 VOID
855 )
856 {
857 LOCAL_APIC_LVT_TIMER LvtTimer;
858
859 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
860 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
861 }
862
863 /**
864 Send EOI to the local APIC.
865 **/
866 VOID
867 EFIAPI
868 SendApicEoi (
869 VOID
870 )
871 {
872 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
873 }
874
875 /**
876 Get the 32-bit address that a device should use to send a Message Signaled
877 Interrupt (MSI) to the Local APIC of the currently executing processor.
878
879 @return 32-bit address used to send an MSI to the Local APIC.
880 **/
881 UINT32
882 EFIAPI
883 GetApicMsiAddress (
884 VOID
885 )
886 {
887 LOCAL_APIC_MSI_ADDRESS MsiAddress;
888
889 //
890 // Return address for an MSI interrupt to be delivered only to the APIC ID
891 // of the currently executing processor.
892 //
893 MsiAddress.Uint32 = 0;
894 MsiAddress.Bits.BaseAddress = 0xFEE;
895 MsiAddress.Bits.DestinationId = GetApicId ();
896 return MsiAddress.Uint32;
897 }
898
899 /**
900 Get the 64-bit data value that a device should use to send a Message Signaled
901 Interrupt (MSI) to the Local APIC of the currently executing processor.
902
903 If Vector is not in range 0x10..0xFE, then ASSERT().
904 If DeliveryMode is not supported, then ASSERT().
905
906 @param Vector The 8-bit interrupt vector associated with the MSI.
907 Must be in the range 0x10..0xFE
908 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
909 is handled. The only supported values are:
910 0: LOCAL_APIC_DELIVERY_MODE_FIXED
911 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
912 2: LOCAL_APIC_DELIVERY_MODE_SMI
913 4: LOCAL_APIC_DELIVERY_MODE_NMI
914 5: LOCAL_APIC_DELIVERY_MODE_INIT
915 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
916
917 @param LevelTriggered TRUE specifies a level triggered interrupt.
918 FALSE specifies an edge triggered interrupt.
919 @param AssertionLevel Ignored if LevelTriggered is FALSE.
920 TRUE specifies a level triggered interrupt that active
921 when the interrupt line is asserted.
922 FALSE specifies a level triggered interrupt that active
923 when the interrupt line is deasserted.
924
925 @return 64-bit data value used to send an MSI to the Local APIC.
926 **/
927 UINT64
928 EFIAPI
929 GetApicMsiValue (
930 IN UINT8 Vector,
931 IN UINTN DeliveryMode,
932 IN BOOLEAN LevelTriggered,
933 IN BOOLEAN AssertionLevel
934 )
935 {
936 LOCAL_APIC_MSI_DATA MsiData;
937
938 ASSERT (Vector >= 0x10 && Vector <= 0xFE);
939 ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
940
941 MsiData.Uint64 = 0;
942 MsiData.Bits.Vector = Vector;
943 MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
944 if (LevelTriggered) {
945 MsiData.Bits.TriggerMode = 1;
946 if (AssertionLevel) {
947 MsiData.Bits.Level = 1;
948 }
949 }
950
951 return MsiData.Uint64;
952 }
953
954 /**
955 Get Package ID/Core ID/Thread ID of a processor.
956
957 The algorithm assumes the target system has symmetry across physical
958 package boundaries with respect to the number of logical processors
959 per package, number of cores per package.
960
961 @param[in] InitialApicId Initial APIC ID of the target logical processor.
962 @param[out] Package Returns the processor package ID.
963 @param[out] Core Returns the processor core ID.
964 @param[out] Thread Returns the processor thread ID.
965 **/
966 VOID
967 EFIAPI
968 GetProcessorLocationByApicId (
969 IN UINT32 InitialApicId,
970 OUT UINT32 *Package OPTIONAL,
971 OUT UINT32 *Core OPTIONAL,
972 OUT UINT32 *Thread OPTIONAL
973 )
974 {
975 BOOLEAN TopologyLeafSupported;
976 CPUID_VERSION_INFO_EBX VersionInfoEbx;
977 CPUID_VERSION_INFO_EDX VersionInfoEdx;
978 CPUID_CACHE_PARAMS_EAX CacheParamsEax;
979 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
980 CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx;
981 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
982 CPUID_AMD_EXTENDED_CPU_SIG_ECX AmdExtendedCpuSigEcx;
983 CPUID_AMD_PROCESSOR_TOPOLOGY_EBX AmdProcessorTopologyEbx;
984 CPUID_AMD_VIR_PHY_ADDRESS_SIZE_ECX AmdVirPhyAddressSizeEcx;
985 UINT32 MaxStandardCpuIdIndex;
986 UINT32 MaxExtendedCpuIdIndex;
987 UINT32 SubIndex;
988 UINTN LevelType;
989 UINT32 MaxLogicProcessorsPerPackage;
990 UINT32 MaxCoresPerPackage;
991 UINTN ThreadBits;
992 UINTN CoreBits;
993
994 //
995 // Check if the processor is capable of supporting more than one logical processor.
996 //
997 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
998 if (VersionInfoEdx.Bits.HTT == 0) {
999 if (Thread != NULL) {
1000 *Thread = 0;
1001 }
1002
1003 if (Core != NULL) {
1004 *Core = 0;
1005 }
1006
1007 if (Package != NULL) {
1008 *Package = 0;
1009 }
1010
1011 return;
1012 }
1013
1014 //
1015 // Assume three-level mapping of APIC ID: Package|Core|Thread.
1016 //
1017 ThreadBits = 0;
1018 CoreBits = 0;
1019
1020 //
1021 // Get max index of CPUID
1022 //
1023 AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
1024 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedCpuIdIndex, NULL, NULL, NULL);
1025
1026 //
1027 // If the extended topology enumeration leaf is available, it
1028 // is the preferred mechanism for enumerating topology.
1029 //
1030 TopologyLeafSupported = FALSE;
1031 if (MaxStandardCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
1032 AsmCpuidEx (
1033 CPUID_EXTENDED_TOPOLOGY,
1034 0,
1035 &ExtendedTopologyEax.Uint32,
1036 &ExtendedTopologyEbx.Uint32,
1037 &ExtendedTopologyEcx.Uint32,
1038 NULL
1039 );
1040 //
1041 // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
1042 // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
1043 // supported on that processor.
1044 //
1045 if (ExtendedTopologyEbx.Uint32 != 0) {
1046 TopologyLeafSupported = TRUE;
1047
1048 //
1049 // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
1050 // the SMT sub-field of x2APIC ID.
1051 //
1052 LevelType = ExtendedTopologyEcx.Bits.LevelType;
1053 ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
1054 ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
1055
1056 //
1057 // Software must not assume any "level type" encoding
1058 // value to be related to any sub-leaf index, except sub-leaf 0.
1059 //
1060 SubIndex = 1;
1061 do {
1062 AsmCpuidEx (
1063 CPUID_EXTENDED_TOPOLOGY,
1064 SubIndex,
1065 &ExtendedTopologyEax.Uint32,
1066 NULL,
1067 &ExtendedTopologyEcx.Uint32,
1068 NULL
1069 );
1070 LevelType = ExtendedTopologyEcx.Bits.LevelType;
1071 if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
1072 CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
1073 break;
1074 }
1075
1076 SubIndex++;
1077 } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
1078 }
1079 }
1080
1081 if (!TopologyLeafSupported) {
1082 //
1083 // Get logical processor count
1084 //
1085 AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
1086 MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
1087
1088 //
1089 // Assume single-core processor
1090 //
1091 MaxCoresPerPackage = 1;
1092
1093 //
1094 // Check for topology extensions on AMD processor
1095 //
1096 if (StandardSignatureIsAuthenticAMD ()) {
1097 if (MaxExtendedCpuIdIndex >= CPUID_AMD_PROCESSOR_TOPOLOGY) {
1098 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, &AmdExtendedCpuSigEcx.Uint32, NULL);
1099 if (AmdExtendedCpuSigEcx.Bits.TopologyExtensions != 0) {
1100 //
1101 // Account for max possible thread count to decode ApicId
1102 //
1103 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, NULL, NULL, &AmdVirPhyAddressSizeEcx.Uint32, NULL);
1104 MaxLogicProcessorsPerPackage = 1 << AmdVirPhyAddressSizeEcx.Bits.ApicIdCoreIdSize;
1105
1106 //
1107 // Get cores per processor package
1108 //
1109 AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY, NULL, &AmdProcessorTopologyEbx.Uint32, NULL, NULL);
1110 MaxCoresPerPackage = MaxLogicProcessorsPerPackage / (AmdProcessorTopologyEbx.Bits.ThreadsPerCore + 1);
1111 }
1112 }
1113 } else {
1114 //
1115 // Extract core count based on CACHE information
1116 //
1117 if (MaxStandardCpuIdIndex >= CPUID_CACHE_PARAMS) {
1118 AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
1119 if (CacheParamsEax.Uint32 != 0) {
1120 MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
1121 }
1122 }
1123 }
1124
1125 ThreadBits = (UINTN)(HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
1126 CoreBits = (UINTN)(HighBitSet32 (MaxCoresPerPackage - 1) + 1);
1127 }
1128
1129 if (Thread != NULL) {
1130 *Thread = InitialApicId & ((1 << ThreadBits) - 1);
1131 }
1132
1133 if (Core != NULL) {
1134 *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
1135 }
1136
1137 if (Package != NULL) {
1138 *Package = (InitialApicId >> (ThreadBits + CoreBits));
1139 }
1140 }
1141
1142 /**
1143 Get Package ID/Die ID/Tile ID/Module ID/Core ID/Thread ID of a processor.
1144
1145 The algorithm assumes the target system has symmetry across physical
1146 package boundaries with respect to the number of threads per core, number of
1147 cores per module, number of modules per tile, number of tiles per die, number
1148 of dies per package.
1149
1150 @param[in] InitialApicId Initial APIC ID of the target logical processor.
1151 @param[out] Package Returns the processor package ID.
1152 @param[out] Die Returns the processor die ID.
1153 @param[out] Tile Returns the processor tile ID.
1154 @param[out] Module Returns the processor module ID.
1155 @param[out] Core Returns the processor core ID.
1156 @param[out] Thread Returns the processor thread ID.
1157 **/
1158 VOID
1159 EFIAPI
1160 GetProcessorLocation2ByApicId (
1161 IN UINT32 InitialApicId,
1162 OUT UINT32 *Package OPTIONAL,
1163 OUT UINT32 *Die OPTIONAL,
1164 OUT UINT32 *Tile OPTIONAL,
1165 OUT UINT32 *Module OPTIONAL,
1166 OUT UINT32 *Core OPTIONAL,
1167 OUT UINT32 *Thread OPTIONAL
1168 )
1169 {
1170 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
1171 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
1172 UINT32 MaxStandardCpuIdIndex;
1173 UINT32 Index;
1174 UINTN LevelType;
1175 UINT32 Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
1176 UINT32 *Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
1177
1178 for (LevelType = 0; LevelType < ARRAY_SIZE (Bits); LevelType++) {
1179 Bits[LevelType] = 0;
1180 }
1181
1182 //
1183 // Get max index of CPUID
1184 //
1185 AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
1186 if (MaxStandardCpuIdIndex < CPUID_V2_EXTENDED_TOPOLOGY) {
1187 if (Die != NULL) {
1188 *Die = 0;
1189 }
1190
1191 if (Tile != NULL) {
1192 *Tile = 0;
1193 }
1194
1195 if (Module != NULL) {
1196 *Module = 0;
1197 }
1198
1199 GetProcessorLocationByApicId (InitialApicId, Package, Core, Thread);
1200 return;
1201 }
1202
1203 //
1204 // If the V2 extended topology enumeration leaf is available, it
1205 // is the preferred mechanism for enumerating topology.
1206 //
1207 for (Index = 0; ; Index++) {
1208 AsmCpuidEx (
1209 CPUID_V2_EXTENDED_TOPOLOGY,
1210 Index,
1211 &ExtendedTopologyEax.Uint32,
1212 NULL,
1213 &ExtendedTopologyEcx.Uint32,
1214 NULL
1215 );
1216
1217 LevelType = ExtendedTopologyEcx.Bits.LevelType;
1218
1219 //
1220 // first level reported should be SMT.
1221 //
1222 ASSERT ((Index != 0) || (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT));
1223 if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID) {
1224 break;
1225 }
1226
1227 ASSERT (LevelType < ARRAY_SIZE (Bits));
1228 Bits[LevelType] = ExtendedTopologyEax.Bits.ApicIdShift;
1229 }
1230
1231 for (LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE; LevelType < ARRAY_SIZE (Bits); LevelType++) {
1232 //
1233 // If there are more levels between level-1 (low-level) and level-2 (high-level), the unknown levels will be ignored
1234 // and treated as an extension of the last known level (i.e., level-1 in this case).
1235 //
1236 if (Bits[LevelType] == 0) {
1237 Bits[LevelType] = Bits[LevelType - 1];
1238 }
1239 }
1240
1241 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = Package;
1242 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE] = Die;
1243 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_TILE] = Tile;
1244 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_MODULE] = Module;
1245 Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE] = Core;
1246 Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT] = Thread;
1247
1248 Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = 32;
1249
1250 for ( LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
1251 ; LevelType <= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1
1252 ; LevelType++
1253 )
1254 {
1255 if (Location[LevelType] != NULL) {
1256 //
1257 // Bits[i] holds the number of bits to shift right on x2APIC ID to get a unique
1258 // topology ID of the next level type.
1259 //
1260 *Location[LevelType] = InitialApicId >> Bits[LevelType - 1];
1261
1262 //
1263 // Bits[i] - Bits[i-1] holds the number of bits for the next ONE level type.
1264 //
1265 *Location[LevelType] &= (1 << (Bits[LevelType] - Bits[LevelType - 1])) - 1;
1266 }
1267 }
1268 }