VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c

最後變更 在這個檔案是 105670,由 vboxsync 提交於 8 月 前

Devices/EFI/FirmwareNew: Merge edk2-stable-202405 and make it build on aarch64, bugref:4643

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

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