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