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