VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c@ 108794

Last change on this file since 108794 was 108794, checked in by vboxsync, 2 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette