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