]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
2d17177df12b189600a3ebe3102c76d2d2f0804d
[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 - 2019, Intel Corporation. All rights reserved.<BR>
8 Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>
9
10 SPDX-License-Identifier: BSD-2-Clause-Patent
11
12 **/
13
14 #include <Register/Intel/Cpuid.h>
15 #include <Register/Amd/Cpuid.h>
16 #include <Register/Intel/Msr.h>
17 #include <Register/Intel/LocalApic.h>
18
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/LocalApicLib.h>
22 #include <Library/IoLib.h>
23 #include <Library/TimerLib.h>
24 #include <Library/PcdLib.h>
25 #include <Library/UefiCpuLib.h>
26 #include <IndustryStandard/Tdx.h>
27
28 //
29 // Library internal functions
30 //
31
32 /**
33 Some MSRs in TDX are accessed via TdCall.
34 Some are directly read/write from/to CPU.
35
36 @param MsrIndex Index of the MSR
37 @retval TRUE MSR accessed via TdCall.
38 @retval FALSE MSR accessed not via TdCall.
39
40 **/
41 BOOLEAN
42 AccessMsrTdxCall (
43 IN UINT32 MsrIndex
44 )
45 {
46 if (!TdIsEnabled ()) {
47 return FALSE;
48 }
49
50 switch (MsrIndex) {
51 case MSR_IA32_X2APIC_TPR:
52 case MSR_IA32_X2APIC_PPR:
53 case MSR_IA32_X2APIC_EOI:
54 case MSR_IA32_X2APIC_ISR0:
55 case MSR_IA32_X2APIC_ISR1:
56 case MSR_IA32_X2APIC_ISR2:
57 case MSR_IA32_X2APIC_ISR3:
58 case MSR_IA32_X2APIC_ISR4:
59 case MSR_IA32_X2APIC_ISR5:
60 case MSR_IA32_X2APIC_ISR6:
61 case MSR_IA32_X2APIC_ISR7:
62 case MSR_IA32_X2APIC_TMR0:
63 case MSR_IA32_X2APIC_TMR1:
64 case MSR_IA32_X2APIC_TMR2:
65 case MSR_IA32_X2APIC_TMR3:
66 case MSR_IA32_X2APIC_TMR4:
67 case MSR_IA32_X2APIC_TMR5:
68 case MSR_IA32_X2APIC_TMR6:
69 case MSR_IA32_X2APIC_TMR7:
70 case MSR_IA32_X2APIC_IRR0:
71 case MSR_IA32_X2APIC_IRR1:
72 case MSR_IA32_X2APIC_IRR2:
73 case MSR_IA32_X2APIC_IRR3:
74 case MSR_IA32_X2APIC_IRR4:
75 case MSR_IA32_X2APIC_IRR5:
76 case MSR_IA32_X2APIC_IRR6:
77 case MSR_IA32_X2APIC_IRR7:
78 return FALSE;
79 default:
80 break;
81 }
82
83 return TRUE;
84 }
85
86 /**
87 Read MSR value.
88
89 @param MsrIndex Index of the MSR to read
90 @retval 64-bit Value of MSR.
91
92 **/
93 UINT64
94 LocalApicReadMsrReg64 (
95 IN UINT32 MsrIndex
96 )
97 {
98 UINT64 Val;
99 UINT64 Status;
100
101 if (AccessMsrTdxCall (MsrIndex)) {
102 Status = TdVmCall (TDVMCALL_RDMSR, (UINT64)MsrIndex, 0, 0, 0, &Val);
103 if (Status != 0) {
104 TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
105 }
106 } else {
107 Val = AsmReadMsr64 (MsrIndex);
108 }
109
110 return Val;
111 }
112
113 /**
114 Write to MSR.
115
116 @param MsrIndex Index of the MSR to write to
117 @param Value Value to be written to the MSR
118
119 @return Value
120
121 **/
122 UINT64
123 LocalApicWriteMsrReg64 (
124 IN UINT32 MsrIndex,
125 IN UINT64 Value
126 )
127 {
128 UINT64 Status;
129
130 if (AccessMsrTdxCall (MsrIndex)) {
131 Status = TdVmCall (TDVMCALL_WRMSR, (UINT64)MsrIndex, Value, 0, 0, 0);
132 if (Status != 0) {
133 TdVmCall (TDVMCALL_HALT, 0, 0, 0, 0, 0);
134 }
135 } else {
136 AsmWriteMsr64 (MsrIndex, Value);
137 }
138
139 return Value;
140 }
141
142 /**
143 Read MSR value.
144
145 @param MsrIndex Index of the MSR to read
146 @retval 32-bit Value of MSR.
147
148 **/
149 UINT32
150 LocalApicReadMsrReg32 (
151 IN UINT32 MsrIndex
152 )
153 {
154 return (UINT32)LocalApicReadMsrReg64 (MsrIndex);
155 }
156
157 /**
158 Write to MSR.
159
160 @param MsrIndex Index of the MSR to write to
161 @param Value Value to be written to the MSR
162
163 @return Value
164
165 **/
166 UINT32
167 LocalApicWriteMsrReg32 (
168 IN UINT32 MsrIndex,
169 IN UINT32 Value
170 )
171 {
172 return (UINT32)LocalApicWriteMsrReg64 (MsrIndex, Value);
173 }
174
175 /**
176 Determine if the CPU supports the Local APIC Base Address MSR.
177
178 @retval TRUE The CPU supports the Local APIC Base Address MSR.
179 @retval FALSE The CPU does not support the Local APIC Base Address MSR.
180
181 **/
182 BOOLEAN
183 LocalApicBaseAddressMsrSupported (
184 VOID
185 )
186 {
187 UINT32 RegEax;
188 UINTN FamilyId;
189
190 AsmCpuid (1, &RegEax, NULL, NULL, NULL);
191 FamilyId = BitFieldRead32 (RegEax, 8, 11);
192 if ((FamilyId == 0x04) || (FamilyId == 0x05)) {
193 //
194 // CPUs with a FamilyId of 0x04 or 0x05 do not support the
195 // Local APIC Base Address MSR
196 //
197 return FALSE;
198 }
199
200 return TRUE;
201 }
202
203 /**
204 Retrieve the base address of local APIC.
205
206 @return The base address of local APIC.
207
208 **/
209 UINTN
210 EFIAPI
211 GetLocalApicBaseAddress (
212 VOID
213 )
214 {
215 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
216
217 if (!LocalApicBaseAddressMsrSupported ()) {
218 //
219 // If CPU does not support Local APIC Base Address MSR, then retrieve
220 // Local APIC Base Address from PCD
221 //
222 return PcdGet32 (PcdCpuLocalApicBaseAddress);
223 }
224
225 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);
226
227 return (UINTN)(LShiftU64 ((UINT64)ApicBaseMsr.Bits.ApicBaseHi, 32)) +
228 (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
229 }
230
231 /**
232 Set the base address of local APIC.
233
234 If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
235
236 @param[in] BaseAddress Local APIC base address to be set.
237
238 **/
239 VOID
240 EFIAPI
241 SetLocalApicBaseAddress (
242 IN UINTN BaseAddress
243 )
244 {
245 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
246
247 ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
248
249 if (!LocalApicBaseAddressMsrSupported ()) {
250 //
251 // Ignore set request of the CPU does not support APIC Base Address MSR
252 //
253 return;
254 }
255
256 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);
257
258 ApicBaseMsr.Bits.ApicBase = (UINT32)(BaseAddress >> 12);
259 ApicBaseMsr.Bits.ApicBaseHi = (UINT32)(RShiftU64 ((UINT64)BaseAddress, 32));
260
261 LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
262 }
263
264 /**
265 Read from a local APIC register.
266
267 This function reads from a local APIC register either in xAPIC or x2APIC mode.
268 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
269 accessed using multiple 32-bit loads or stores, so this function only performs
270 32-bit read.
271
272 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
273 It must be 16-byte aligned.
274
275 @return 32-bit Value read from the register.
276 **/
277 UINT32
278 EFIAPI
279 ReadLocalApicReg (
280 IN UINTN MmioOffset
281 )
282 {
283 UINT32 MsrIndex;
284
285 ASSERT ((MmioOffset & 0xf) == 0);
286
287 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
288 return MmioRead32 (GetLocalApicBaseAddress () + MmioOffset);
289 } else {
290 //
291 // DFR is not supported in x2APIC mode.
292 //
293 ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
294 //
295 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
296 // is not supported in this function for simplicity.
297 //
298 ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
299
300 MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
301 return LocalApicReadMsrReg32 (MsrIndex);
302 }
303 }
304
305 /**
306 Write to a local APIC register.
307
308 This function writes to a local APIC register either in xAPIC or x2APIC mode.
309 It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
310 accessed using multiple 32-bit loads or stores, so this function only performs
311 32-bit write.
312
313 if the register index is invalid or unsupported in current APIC mode, then ASSERT.
314
315 @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
316 It must be 16-byte aligned.
317 @param Value Value to be written to the register.
318 **/
319 VOID
320 EFIAPI
321 WriteLocalApicReg (
322 IN UINTN MmioOffset,
323 IN UINT32 Value
324 )
325 {
326 UINT32 MsrIndex;
327
328 ASSERT ((MmioOffset & 0xf) == 0);
329
330 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
331 MmioWrite32 (GetLocalApicBaseAddress () + MmioOffset, Value);
332 } else {
333 //
334 // DFR is not supported in x2APIC mode.
335 //
336 ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
337 //
338 // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
339 // is not supported in this function for simplicity.
340 //
341 ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
342 ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET);
343
344 MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
345 //
346 // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.
347 // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
348 //
349 MemoryFence ();
350 LocalApicWriteMsrReg32 (MsrIndex, Value);
351 }
352 }
353
354 /**
355 Send an IPI by writing to ICR.
356
357 This function returns after the IPI has been accepted by the target processor.
358
359 @param IcrLow 32-bit value to be written to the low half of ICR.
360 @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
361 **/
362 VOID
363 SendIpi (
364 IN UINT32 IcrLow,
365 IN UINT32 ApicId
366 )
367 {
368 UINT64 MsrValue;
369 LOCAL_APIC_ICR_LOW IcrLowReg;
370 UINTN LocalApciBaseAddress;
371 UINT32 IcrHigh;
372 BOOLEAN InterruptState;
373
374 //
375 // Legacy APIC or X2APIC?
376 //
377 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
378 ASSERT (ApicId <= 0xff);
379
380 InterruptState = SaveAndDisableInterrupts ();
381
382 //
383 // Get base address of this LAPIC
384 //
385 LocalApciBaseAddress = GetLocalApicBaseAddress ();
386
387 //
388 // Save existing contents of ICR high 32 bits
389 //
390 IcrHigh = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET);
391
392 //
393 // Wait for DeliveryStatus clear in case a previous IPI
394 // is still being sent
395 //
396 do {
397 IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
398 } while (IcrLowReg.Bits.DeliveryStatus != 0);
399
400 //
401 // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
402 //
403 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
404 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);
405
406 //
407 // Wait for DeliveryStatus clear again
408 //
409 do {
410 IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
411 } while (IcrLowReg.Bits.DeliveryStatus != 0);
412
413 //
414 // And restore old contents of ICR high
415 //
416 MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, IcrHigh);
417
418 SetInterruptState (InterruptState);
419 } else {
420 //
421 // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an
422 // interrupt in x2APIC mode.
423 //
424 MsrValue = LShiftU64 ((UINT64)ApicId, 32) | IcrLow;
425 AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);
426 }
427 }
428
429 //
430 // Library API implementation functions
431 //
432
433 /**
434 Get the current local APIC mode.
435
436 If local APIC is disabled, then ASSERT.
437
438 @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.
439 @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
440 **/
441 UINTN
442 EFIAPI
443 GetApicMode (
444 VOID
445 )
446 {
447 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
448
449 if (!LocalApicBaseAddressMsrSupported ()) {
450 //
451 // If CPU does not support APIC Base Address MSR, then return XAPIC mode
452 //
453 return LOCAL_APIC_MODE_XAPIC;
454 }
455
456 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);
457 //
458 // Local APIC should have been enabled
459 //
460 ASSERT (ApicBaseMsr.Bits.EN != 0);
461 if (ApicBaseMsr.Bits.EXTD != 0) {
462 return LOCAL_APIC_MODE_X2APIC;
463 } else {
464 return LOCAL_APIC_MODE_XAPIC;
465 }
466 }
467
468 /**
469 Set the current local APIC mode.
470
471 If the specified local APIC mode is not valid, then ASSERT.
472 If the specified local APIC mode can't be set as current, then ASSERT.
473
474 @param ApicMode APIC mode to be set.
475
476 @note This API must not be called from an interrupt handler or SMI handler.
477 It may result in unpredictable behavior.
478 **/
479 VOID
480 EFIAPI
481 SetApicMode (
482 IN UINTN ApicMode
483 )
484 {
485 UINTN CurrentMode;
486 MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
487
488 if (!LocalApicBaseAddressMsrSupported ()) {
489 //
490 // Ignore set request if the CPU does not support APIC Base Address MSR
491 //
492 return;
493 }
494
495 CurrentMode = GetApicMode ();
496 if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {
497 switch (ApicMode) {
498 case LOCAL_APIC_MODE_XAPIC:
499 break;
500 case LOCAL_APIC_MODE_X2APIC:
501 ApicBaseMsr.Uint64 = LocalApicReadMsrReg64 (MSR_IA32_APIC_BASE);
502 ApicBaseMsr.Bits.EXTD = 1;
503 LocalApicWriteMsrReg64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
504 break;
505 default:
506 ASSERT (FALSE);
507 }
508 } else {
509 switch (ApicMode) {
510 case LOCAL_APIC_MODE_XAPIC:
511 //
512 // Transition from x2APIC mode to xAPIC mode is a two-step process:
513 // x2APIC -> Local APIC disabled -> xAPIC
514 //
515 ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
516 ApicBaseMsr.Bits.EXTD = 0;
517 ApicBaseMsr.Bits.EN = 0;
518 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
519 ApicBaseMsr.Bits.EN = 1;
520 AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
521 break;
522 case LOCAL_APIC_MODE_X2APIC:
523 break;
524 default:
525 ASSERT (FALSE);
526 }
527 }
528 }
529
530 /**
531 Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
532
533 In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
534 In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
535 the 32-bit local APIC ID is returned as initial APIC ID.
536
537 @return 32-bit initial local APIC ID of the executing processor.
538 **/
539 UINT32
540 EFIAPI
541 GetInitialApicId (
542 VOID
543 )
544 {
545 UINT32 ApicId;
546 UINT32 MaxCpuIdIndex;
547 UINT32 RegEbx;
548
549 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
550 //
551 // Get the max index of basic CPUID
552 //
553 AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
554 //
555 // If CPUID Leaf B is supported,
556 // And CPUID.0BH:EBX[15:0] reports a non-zero value,
557 // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
558 // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
559 //
560 if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
561 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);
562 if ((RegEbx & (BIT16 - 1)) != 0) {
563 return ApicId;
564 }
565 }
566
567 AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
568 return RegEbx >> 24;
569 } else {
570 return GetApicId ();
571 }
572 }
573
574 /**
575 Get the local APIC ID of the executing processor.
576
577 @return 32-bit local APIC ID of the executing processor.
578 **/
579 UINT32
580 EFIAPI
581 GetApicId (
582 VOID
583 )
584 {
585 UINT32 ApicId;
586 UINT32 InitApicId;
587
588 ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
589 if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
590 ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;
591 }
592
593 return ApicId;
594 }
595
596 /**
597 Get the value of the local APIC version register.
598
599 @return the value of the local APIC version register.
600 **/
601 UINT32
602 EFIAPI
603 GetApicVersion (
604 VOID
605 )
606 {
607 return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
608 }
609
610 /**
611 Send a Fixed IPI to a specified target processor.
612
613 This function returns after the IPI has been accepted by the target processor.
614
615 @param ApicId The local APIC ID of the target processor.
616 @param Vector The vector number of the interrupt being sent.
617 **/
618 VOID
619 EFIAPI
620 SendFixedIpi (
621 IN UINT32 ApicId,
622 IN UINT8 Vector
623 )
624 {
625 LOCAL_APIC_ICR_LOW IcrLow;
626
627 IcrLow.Uint32 = 0;
628 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
629 IcrLow.Bits.Level = 1;
630 IcrLow.Bits.Vector = Vector;
631 SendIpi (IcrLow.Uint32, ApicId);
632 }
633
634 /**
635 Send a Fixed IPI to all processors excluding self.
636
637 This function returns after the IPI has been accepted by the target processors.
638
639 @param Vector The vector number of the interrupt being sent.
640 **/
641 VOID
642 EFIAPI
643 SendFixedIpiAllExcludingSelf (
644 IN UINT8 Vector
645 )
646 {
647 LOCAL_APIC_ICR_LOW IcrLow;
648
649 IcrLow.Uint32 = 0;
650 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
651 IcrLow.Bits.Level = 1;
652 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
653 IcrLow.Bits.Vector = Vector;
654 SendIpi (IcrLow.Uint32, 0);
655 }
656
657 /**
658 Send a SMI IPI to a specified target processor.
659
660 This function returns after the IPI has been accepted by the target processor.
661
662 @param ApicId Specify the local APIC ID of the target processor.
663 **/
664 VOID
665 EFIAPI
666 SendSmiIpi (
667 IN UINT32 ApicId
668 )
669 {
670 LOCAL_APIC_ICR_LOW IcrLow;
671
672 IcrLow.Uint32 = 0;
673 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
674 IcrLow.Bits.Level = 1;
675 SendIpi (IcrLow.Uint32, ApicId);
676 }
677
678 /**
679 Send a SMI IPI to all processors excluding self.
680
681 This function returns after the IPI has been accepted by the target processors.
682 **/
683 VOID
684 EFIAPI
685 SendSmiIpiAllExcludingSelf (
686 VOID
687 )
688 {
689 LOCAL_APIC_ICR_LOW IcrLow;
690
691 IcrLow.Uint32 = 0;
692 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
693 IcrLow.Bits.Level = 1;
694 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
695 SendIpi (IcrLow.Uint32, 0);
696 }
697
698 /**
699 Send an INIT IPI to a specified target processor.
700
701 This function returns after the IPI has been accepted by the target processor.
702
703 @param ApicId Specify the local APIC ID of the target processor.
704 **/
705 VOID
706 EFIAPI
707 SendInitIpi (
708 IN UINT32 ApicId
709 )
710 {
711 LOCAL_APIC_ICR_LOW IcrLow;
712
713 IcrLow.Uint32 = 0;
714 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
715 IcrLow.Bits.Level = 1;
716 SendIpi (IcrLow.Uint32, ApicId);
717 }
718
719 /**
720 Send an INIT IPI to all processors excluding self.
721
722 This function returns after the IPI has been accepted by the target processors.
723 **/
724 VOID
725 EFIAPI
726 SendInitIpiAllExcludingSelf (
727 VOID
728 )
729 {
730 LOCAL_APIC_ICR_LOW IcrLow;
731
732 IcrLow.Uint32 = 0;
733 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
734 IcrLow.Bits.Level = 1;
735 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
736 SendIpi (IcrLow.Uint32, 0);
737 }
738
739 /**
740 Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
741
742 This function returns after the IPI has been accepted by the target processor.
743
744 if StartupRoutine >= 1M, then ASSERT.
745 if StartupRoutine is not multiple of 4K, then ASSERT.
746
747 @param ApicId Specify the local APIC ID of the target processor.
748 @param StartupRoutine Points to a start-up routine which is below 1M physical
749 address and 4K aligned.
750 **/
751 VOID
752 EFIAPI
753 SendInitSipiSipi (
754 IN UINT32 ApicId,
755 IN UINT32 StartupRoutine
756 )
757 {
758 LOCAL_APIC_ICR_LOW IcrLow;
759
760 ASSERT (StartupRoutine < 0x100000);
761 ASSERT ((StartupRoutine & 0xfff) == 0);
762
763 SendInitIpi (ApicId);
764 MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));
765 IcrLow.Uint32 = 0;
766 IcrLow.Bits.Vector = (StartupRoutine >> 12);
767 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
768 IcrLow.Bits.Level = 1;
769 SendIpi (IcrLow.Uint32, ApicId);
770 if (!StandardSignatureIsAuthenticAMD ()) {
771 MicroSecondDelay (200);
772 SendIpi (IcrLow.Uint32, ApicId);
773 }
774 }
775
776 /**
777 Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
778
779 This function returns after the IPI has been accepted by the target processors.
780
781 if StartupRoutine >= 1M, then ASSERT.
782 if StartupRoutine is not multiple of 4K, then ASSERT.
783
784 @param StartupRoutine Points to a start-up routine which is below 1M physical
785 address and 4K aligned.
786 **/
787 VOID
788 EFIAPI
789 SendInitSipiSipiAllExcludingSelf (
790 IN UINT32 StartupRoutine
791 )
792 {
793 LOCAL_APIC_ICR_LOW IcrLow;
794
795 ASSERT (StartupRoutine < 0x100000);
796 ASSERT ((StartupRoutine & 0xfff) == 0);
797
798 SendInitIpiAllExcludingSelf ();
799 MicroSecondDelay (PcdGet32 (PcdCpuInitIpiDelayInMicroSeconds));
800 IcrLow.Uint32 = 0;
801 IcrLow.Bits.Vector = (StartupRoutine >> 12);
802 IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
803 IcrLow.Bits.Level = 1;
804 IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
805 SendIpi (IcrLow.Uint32, 0);
806 if (!StandardSignatureIsAuthenticAMD ()) {
807 MicroSecondDelay (200);
808 SendIpi (IcrLow.Uint32, 0);
809 }
810 }
811
812 /**
813 Initialize the state of the SoftwareEnable bit in the Local APIC
814 Spurious Interrupt Vector register.
815
816 @param Enable If TRUE, then set SoftwareEnable to 1
817 If FALSE, then set SoftwareEnable to 0.
818
819 **/
820 VOID
821 EFIAPI
822 InitializeLocalApicSoftwareEnable (
823 IN BOOLEAN Enable
824 )
825 {
826 LOCAL_APIC_SVR Svr;
827
828 //
829 // Set local APIC software-enabled bit.
830 //
831 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
832 if (Enable) {
833 if (Svr.Bits.SoftwareEnable == 0) {
834 Svr.Bits.SoftwareEnable = 1;
835 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
836 }
837 } else {
838 if (Svr.Bits.SoftwareEnable == 1) {
839 Svr.Bits.SoftwareEnable = 0;
840 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
841 }
842 }
843 }
844
845 /**
846 Programming Virtual Wire Mode.
847
848 This function programs the local APIC for virtual wire mode following
849 the example described in chapter A.3 of the MP 1.4 spec.
850
851 IOxAPIC is not involved in this type of virtual wire mode.
852 **/
853 VOID
854 EFIAPI
855 ProgramVirtualWireMode (
856 VOID
857 )
858 {
859 LOCAL_APIC_SVR Svr;
860 LOCAL_APIC_LVT_LINT Lint;
861
862 //
863 // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
864 //
865 Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
866 Svr.Bits.SpuriousVector = 0xf;
867 Svr.Bits.SoftwareEnable = 1;
868 WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
869
870 //
871 // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
872 //
873 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
874 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
875 Lint.Bits.InputPinPolarity = 0;
876 Lint.Bits.TriggerMode = 0;
877 Lint.Bits.Mask = 0;
878 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
879
880 //
881 // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
882 //
883 Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
884 Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
885 Lint.Bits.InputPinPolarity = 0;
886 Lint.Bits.TriggerMode = 0;
887 Lint.Bits.Mask = 0;
888 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
889 }
890
891 /**
892 Disable LINT0 & LINT1 interrupts.
893
894 This function sets the mask flag in the LVT LINT0 & LINT1 registers.
895 **/
896 VOID
897 EFIAPI
898 DisableLvtInterrupts (
899 VOID
900 )
901 {
902 LOCAL_APIC_LVT_LINT LvtLint;
903
904 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
905 LvtLint.Bits.Mask = 1;
906 WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
907
908 LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
909 LvtLint.Bits.Mask = 1;
910 WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
911 }
912
913 /**
914 Read the initial count value from the init-count register.
915
916 @return The initial count value read from the init-count register.
917 **/
918 UINT32
919 EFIAPI
920 GetApicTimerInitCount (
921 VOID
922 )
923 {
924 return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
925 }
926
927 /**
928 Read the current count value from the current-count register.
929
930 @return The current count value read from the current-count register.
931 **/
932 UINT32
933 EFIAPI
934 GetApicTimerCurrentCount (
935 VOID
936 )
937 {
938 return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
939 }
940
941 /**
942 Initialize the local APIC timer.
943
944 The local APIC timer is initialized and enabled.
945
946 @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
947 If it is 0, then use the current divide value in the DCR.
948 @param InitCount The initial count value.
949 @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
950 @param Vector The timer interrupt vector number.
951 **/
952 VOID
953 EFIAPI
954 InitializeApicTimer (
955 IN UINTN DivideValue,
956 IN UINT32 InitCount,
957 IN BOOLEAN PeriodicMode,
958 IN UINT8 Vector
959 )
960 {
961 LOCAL_APIC_DCR Dcr;
962 LOCAL_APIC_LVT_TIMER LvtTimer;
963 UINT32 Divisor;
964
965 //
966 // Ensure local APIC is in software-enabled state.
967 //
968 InitializeLocalApicSoftwareEnable (TRUE);
969
970 //
971 // Program init-count register.
972 //
973 WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
974
975 if (DivideValue != 0) {
976 ASSERT (DivideValue <= 128);
977 ASSERT (DivideValue == GetPowerOfTwo32 ((UINT32)DivideValue));
978 Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
979
980 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
981 Dcr.Bits.DivideValue1 = (Divisor & 0x3);
982 Dcr.Bits.DivideValue2 = (Divisor >> 2);
983 WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
984 }
985
986 //
987 // Enable APIC timer interrupt with specified timer mode.
988 //
989 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
990 if (PeriodicMode) {
991 LvtTimer.Bits.TimerMode = 1;
992 } else {
993 LvtTimer.Bits.TimerMode = 0;
994 }
995
996 LvtTimer.Bits.Mask = 0;
997 LvtTimer.Bits.Vector = Vector;
998 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
999 }
1000
1001 /**
1002 Get the state of the local APIC timer.
1003
1004 This function will ASSERT if the local APIC is not software enabled.
1005
1006 @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
1007 @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
1008 @param Vector Return the timer interrupt vector number.
1009 **/
1010 VOID
1011 EFIAPI
1012 GetApicTimerState (
1013 OUT UINTN *DivideValue OPTIONAL,
1014 OUT BOOLEAN *PeriodicMode OPTIONAL,
1015 OUT UINT8 *Vector OPTIONAL
1016 )
1017 {
1018 UINT32 Divisor;
1019 LOCAL_APIC_DCR Dcr;
1020 LOCAL_APIC_LVT_TIMER LvtTimer;
1021
1022 //
1023 // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
1024 // Vector Register.
1025 // This bit will be 1, if local APIC is software enabled.
1026 //
1027 ASSERT ((ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
1028
1029 if (DivideValue != NULL) {
1030 Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
1031 Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
1032 Divisor = (Divisor + 1) & 0x7;
1033 *DivideValue = ((UINTN)1) << Divisor;
1034 }
1035
1036 if ((PeriodicMode != NULL) || (Vector != NULL)) {
1037 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
1038 if (PeriodicMode != NULL) {
1039 if (LvtTimer.Bits.TimerMode == 1) {
1040 *PeriodicMode = TRUE;
1041 } else {
1042 *PeriodicMode = FALSE;
1043 }
1044 }
1045
1046 if (Vector != NULL) {
1047 *Vector = (UINT8)LvtTimer.Bits.Vector;
1048 }
1049 }
1050 }
1051
1052 /**
1053 Enable the local APIC timer interrupt.
1054 **/
1055 VOID
1056 EFIAPI
1057 EnableApicTimerInterrupt (
1058 VOID
1059 )
1060 {
1061 LOCAL_APIC_LVT_TIMER LvtTimer;
1062
1063 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
1064 LvtTimer.Bits.Mask = 0;
1065 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
1066 }
1067
1068 /**
1069 Disable the local APIC timer interrupt.
1070 **/
1071 VOID
1072 EFIAPI
1073 DisableApicTimerInterrupt (
1074 VOID
1075 )
1076 {
1077 LOCAL_APIC_LVT_TIMER LvtTimer;
1078
1079 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
1080 LvtTimer.Bits.Mask = 1;
1081 WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
1082 }
1083
1084 /**
1085 Get the local APIC timer interrupt state.
1086
1087 @retval TRUE The local APIC timer interrupt is enabled.
1088 @retval FALSE The local APIC timer interrupt is disabled.
1089 **/
1090 BOOLEAN
1091 EFIAPI
1092 GetApicTimerInterruptState (
1093 VOID
1094 )
1095 {
1096 LOCAL_APIC_LVT_TIMER LvtTimer;
1097
1098 LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
1099 return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
1100 }
1101
1102 /**
1103 Send EOI to the local APIC.
1104 **/
1105 VOID
1106 EFIAPI
1107 SendApicEoi (
1108 VOID
1109 )
1110 {
1111 WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
1112 }
1113
1114 /**
1115 Get the 32-bit address that a device should use to send a Message Signaled
1116 Interrupt (MSI) to the Local APIC of the currently executing processor.
1117
1118 @return 32-bit address used to send an MSI to the Local APIC.
1119 **/
1120 UINT32
1121 EFIAPI
1122 GetApicMsiAddress (
1123 VOID
1124 )
1125 {
1126 LOCAL_APIC_MSI_ADDRESS MsiAddress;
1127
1128 //
1129 // Return address for an MSI interrupt to be delivered only to the APIC ID
1130 // of the currently executing processor.
1131 //
1132 MsiAddress.Uint32 = 0;
1133 MsiAddress.Bits.BaseAddress = 0xFEE;
1134 MsiAddress.Bits.DestinationId = GetApicId ();
1135 return MsiAddress.Uint32;
1136 }
1137
1138 /**
1139 Get the 64-bit data value that a device should use to send a Message Signaled
1140 Interrupt (MSI) to the Local APIC of the currently executing processor.
1141
1142 If Vector is not in range 0x10..0xFE, then ASSERT().
1143 If DeliveryMode is not supported, then ASSERT().
1144
1145 @param Vector The 8-bit interrupt vector associated with the MSI.
1146 Must be in the range 0x10..0xFE
1147 @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
1148 is handled. The only supported values are:
1149 0: LOCAL_APIC_DELIVERY_MODE_FIXED
1150 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
1151 2: LOCAL_APIC_DELIVERY_MODE_SMI
1152 4: LOCAL_APIC_DELIVERY_MODE_NMI
1153 5: LOCAL_APIC_DELIVERY_MODE_INIT
1154 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
1155
1156 @param LevelTriggered TRUE specifies a level triggered interrupt.
1157 FALSE specifies an edge triggered interrupt.
1158 @param AssertionLevel Ignored if LevelTriggered is FALSE.
1159 TRUE specifies a level triggered interrupt that active
1160 when the interrupt line is asserted.
1161 FALSE specifies a level triggered interrupt that active
1162 when the interrupt line is deasserted.
1163
1164 @return 64-bit data value used to send an MSI to the Local APIC.
1165 **/
1166 UINT64
1167 EFIAPI
1168 GetApicMsiValue (
1169 IN UINT8 Vector,
1170 IN UINTN DeliveryMode,
1171 IN BOOLEAN LevelTriggered,
1172 IN BOOLEAN AssertionLevel
1173 )
1174 {
1175 LOCAL_APIC_MSI_DATA MsiData;
1176
1177 ASSERT (Vector >= 0x10 && Vector <= 0xFE);
1178 ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
1179
1180 MsiData.Uint64 = 0;
1181 MsiData.Bits.Vector = Vector;
1182 MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
1183 if (LevelTriggered) {
1184 MsiData.Bits.TriggerMode = 1;
1185 if (AssertionLevel) {
1186 MsiData.Bits.Level = 1;
1187 }
1188 }
1189
1190 return MsiData.Uint64;
1191 }
1192
1193 /**
1194 Get Package ID/Core ID/Thread ID of a processor.
1195
1196 The algorithm assumes the target system has symmetry across physical
1197 package boundaries with respect to the number of logical processors
1198 per package, number of cores per package.
1199
1200 @param[in] InitialApicId Initial APIC ID of the target logical processor.
1201 @param[out] Package Returns the processor package ID.
1202 @param[out] Core Returns the processor core ID.
1203 @param[out] Thread Returns the processor thread ID.
1204 **/
1205 VOID
1206 EFIAPI
1207 GetProcessorLocationByApicId (
1208 IN UINT32 InitialApicId,
1209 OUT UINT32 *Package OPTIONAL,
1210 OUT UINT32 *Core OPTIONAL,
1211 OUT UINT32 *Thread OPTIONAL
1212 )
1213 {
1214 BOOLEAN TopologyLeafSupported;
1215 CPUID_VERSION_INFO_EBX VersionInfoEbx;
1216 CPUID_VERSION_INFO_EDX VersionInfoEdx;
1217 CPUID_CACHE_PARAMS_EAX CacheParamsEax;
1218 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
1219 CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx;
1220 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
1221 CPUID_AMD_EXTENDED_CPU_SIG_ECX AmdExtendedCpuSigEcx;
1222 CPUID_AMD_PROCESSOR_TOPOLOGY_EBX AmdProcessorTopologyEbx;
1223 CPUID_AMD_VIR_PHY_ADDRESS_SIZE_ECX AmdVirPhyAddressSizeEcx;
1224 UINT32 MaxStandardCpuIdIndex;
1225 UINT32 MaxExtendedCpuIdIndex;
1226 UINT32 SubIndex;
1227 UINTN LevelType;
1228 UINT32 MaxLogicProcessorsPerPackage;
1229 UINT32 MaxCoresPerPackage;
1230 UINTN ThreadBits;
1231 UINTN CoreBits;
1232
1233 //
1234 // Check if the processor is capable of supporting more than one logical processor.
1235 //
1236 AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
1237 if (VersionInfoEdx.Bits.HTT == 0) {
1238 if (Thread != NULL) {
1239 *Thread = 0;
1240 }
1241
1242 if (Core != NULL) {
1243 *Core = 0;
1244 }
1245
1246 if (Package != NULL) {
1247 *Package = 0;
1248 }
1249
1250 return;
1251 }
1252
1253 //
1254 // Assume three-level mapping of APIC ID: Package|Core|Thread.
1255 //
1256 ThreadBits = 0;
1257 CoreBits = 0;
1258
1259 //
1260 // Get max index of CPUID
1261 //
1262 AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
1263 AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedCpuIdIndex, NULL, NULL, NULL);
1264
1265 //
1266 // If the extended topology enumeration leaf is available, it
1267 // is the preferred mechanism for enumerating topology.
1268 //
1269 TopologyLeafSupported = FALSE;
1270 if (MaxStandardCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
1271 AsmCpuidEx (
1272 CPUID_EXTENDED_TOPOLOGY,
1273 0,
1274 &ExtendedTopologyEax.Uint32,
1275 &ExtendedTopologyEbx.Uint32,
1276 &ExtendedTopologyEcx.Uint32,
1277 NULL
1278 );
1279 //
1280 // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
1281 // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
1282 // supported on that processor.
1283 //
1284 if (ExtendedTopologyEbx.Uint32 != 0) {
1285 TopologyLeafSupported = TRUE;
1286
1287 //
1288 // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
1289 // the SMT sub-field of x2APIC ID.
1290 //
1291 LevelType = ExtendedTopologyEcx.Bits.LevelType;
1292 ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
1293 ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
1294
1295 //
1296 // Software must not assume any "level type" encoding
1297 // value to be related to any sub-leaf index, except sub-leaf 0.
1298 //
1299 SubIndex = 1;
1300 do {
1301 AsmCpuidEx (
1302 CPUID_EXTENDED_TOPOLOGY,
1303 SubIndex,
1304 &ExtendedTopologyEax.Uint32,
1305 NULL,
1306 &ExtendedTopologyEcx.Uint32,
1307 NULL
1308 );
1309 LevelType = ExtendedTopologyEcx.Bits.LevelType;
1310 if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
1311 CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
1312 break;
1313 }
1314
1315 SubIndex++;
1316 } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
1317 }
1318 }
1319
1320 if (!TopologyLeafSupported) {
1321 //
1322 // Get logical processor count
1323 //
1324 AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
1325 MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
1326
1327 //
1328 // Assume single-core processor
1329 //
1330 MaxCoresPerPackage = 1;
1331
1332 //
1333 // Check for topology extensions on AMD processor
1334 //
1335 if (StandardSignatureIsAuthenticAMD ()) {
1336 if (MaxExtendedCpuIdIndex >= CPUID_AMD_PROCESSOR_TOPOLOGY) {
1337 AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, &AmdExtendedCpuSigEcx.Uint32, NULL);
1338 if (AmdExtendedCpuSigEcx.Bits.TopologyExtensions != 0) {
1339 //
1340 // Account for max possible thread count to decode ApicId
1341 //
1342 AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, NULL, NULL, &AmdVirPhyAddressSizeEcx.Uint32, NULL);
1343 MaxLogicProcessorsPerPackage = 1 << AmdVirPhyAddressSizeEcx.Bits.ApicIdCoreIdSize;
1344
1345 //
1346 // Get cores per processor package
1347 //
1348 AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY, NULL, &AmdProcessorTopologyEbx.Uint32, NULL, NULL);
1349 MaxCoresPerPackage = MaxLogicProcessorsPerPackage / (AmdProcessorTopologyEbx.Bits.ThreadsPerCore + 1);
1350 }
1351 }
1352 } else {
1353 //
1354 // Extract core count based on CACHE information
1355 //
1356 if (MaxStandardCpuIdIndex >= CPUID_CACHE_PARAMS) {
1357 AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
1358 if (CacheParamsEax.Uint32 != 0) {
1359 MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
1360 }
1361 }
1362 }
1363
1364 ThreadBits = (UINTN)(HighBitSet32 (MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
1365 CoreBits = (UINTN)(HighBitSet32 (MaxCoresPerPackage - 1) + 1);
1366 }
1367
1368 if (Thread != NULL) {
1369 *Thread = InitialApicId & ((1 << ThreadBits) - 1);
1370 }
1371
1372 if (Core != NULL) {
1373 *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
1374 }
1375
1376 if (Package != NULL) {
1377 *Package = (InitialApicId >> (ThreadBits + CoreBits));
1378 }
1379 }
1380
1381 /**
1382 Get Package ID/Die ID/Tile ID/Module ID/Core ID/Thread ID of a processor.
1383
1384 The algorithm assumes the target system has symmetry across physical
1385 package boundaries with respect to the number of threads per core, number of
1386 cores per module, number of modules per tile, number of tiles per die, number
1387 of dies per package.
1388
1389 @param[in] InitialApicId Initial APIC ID of the target logical processor.
1390 @param[out] Package Returns the processor package ID.
1391 @param[out] Die Returns the processor die ID.
1392 @param[out] Tile Returns the processor tile ID.
1393 @param[out] Module Returns the processor module ID.
1394 @param[out] Core Returns the processor core ID.
1395 @param[out] Thread Returns the processor thread ID.
1396 **/
1397 VOID
1398 EFIAPI
1399 GetProcessorLocation2ByApicId (
1400 IN UINT32 InitialApicId,
1401 OUT UINT32 *Package OPTIONAL,
1402 OUT UINT32 *Die OPTIONAL,
1403 OUT UINT32 *Tile OPTIONAL,
1404 OUT UINT32 *Module OPTIONAL,
1405 OUT UINT32 *Core OPTIONAL,
1406 OUT UINT32 *Thread OPTIONAL
1407 )
1408 {
1409 CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
1410 CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
1411 UINT32 MaxStandardCpuIdIndex;
1412 UINT32 Index;
1413 UINTN LevelType;
1414 UINT32 Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
1415 UINT32 *Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
1416
1417 for (LevelType = 0; LevelType < ARRAY_SIZE (Bits); LevelType++) {
1418 Bits[LevelType] = 0;
1419 }
1420
1421 //
1422 // Get max index of CPUID
1423 //
1424 AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
1425 if (MaxStandardCpuIdIndex < CPUID_V2_EXTENDED_TOPOLOGY) {
1426 if (Die != NULL) {
1427 *Die = 0;
1428 }
1429
1430 if (Tile != NULL) {
1431 *Tile = 0;
1432 }
1433
1434 if (Module != NULL) {
1435 *Module = 0;
1436 }
1437
1438 GetProcessorLocationByApicId (InitialApicId, Package, Core, Thread);
1439 return;
1440 }
1441
1442 //
1443 // If the V2 extended topology enumeration leaf is available, it
1444 // is the preferred mechanism for enumerating topology.
1445 //
1446 for (Index = 0; ; Index++) {
1447 AsmCpuidEx (
1448 CPUID_V2_EXTENDED_TOPOLOGY,
1449 Index,
1450 &ExtendedTopologyEax.Uint32,
1451 NULL,
1452 &ExtendedTopologyEcx.Uint32,
1453 NULL
1454 );
1455
1456 LevelType = ExtendedTopologyEcx.Bits.LevelType;
1457
1458 //
1459 // first level reported should be SMT.
1460 //
1461 ASSERT ((Index != 0) || (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT));
1462 if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID) {
1463 break;
1464 }
1465
1466 ASSERT (LevelType < ARRAY_SIZE (Bits));
1467 Bits[LevelType] = ExtendedTopologyEax.Bits.ApicIdShift;
1468 }
1469
1470 for (LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE; LevelType < ARRAY_SIZE (Bits); LevelType++) {
1471 //
1472 // If there are more levels between level-1 (low-level) and level-2 (high-level), the unknown levels will be ignored
1473 // and treated as an extension of the last known level (i.e., level-1 in this case).
1474 //
1475 if (Bits[LevelType] == 0) {
1476 Bits[LevelType] = Bits[LevelType - 1];
1477 }
1478 }
1479
1480 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = Package;
1481 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE] = Die;
1482 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_TILE] = Tile;
1483 Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_MODULE] = Module;
1484 Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE] = Core;
1485 Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT] = Thread;
1486
1487 Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = 32;
1488
1489 for ( LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
1490 ; LevelType <= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1
1491 ; LevelType++
1492 )
1493 {
1494 if (Location[LevelType] != NULL) {
1495 //
1496 // Bits[i] holds the number of bits to shift right on x2APIC ID to get a unique
1497 // topology ID of the next level type.
1498 //
1499 *Location[LevelType] = InitialApicId >> Bits[LevelType - 1];
1500
1501 //
1502 // Bits[i] - Bits[i-1] holds the number of bits for the next ONE level type.
1503 //
1504 *Location[LevelType] &= (1 << (Bits[LevelType] - Bits[LevelType - 1])) - 1;
1505 }
1506 }
1507 }