|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH] x86/hvm: Add x2APIC topology
HVM guests with more than 128 vCPUs require APIC IDs above 255 (since
APIC ID = vcpu_id * 2), which exceeds the 8-bit xAPIC limit. Currently,
CPUID leaf 0xB returns EBX=0, making firmware (OVMF/EDK2) fall back to
CPUID leaf 1 for APIC ID discovery, which is limited to 8 bits and
cannot distinguish vCPUs with APIC IDs greater than 256.
To address this, implement proper CPUID leaf 0xB x2APIC topology
enumeration. Present all vCPUs as cores in a single package with correct
shift values based on the maximum APIC ID, and non-zero EBX so that
firmware uses the 32-bit x2APIC ID from EDX. Moreover, set CPUID leaf 1
EBX[23:16] (max addressable logical processor IDs) to the appropriate
power-of-2 value, but capped at 255.
Signed-off-by: Julian Vetter <julian.vetter@xxxxxxxxxx>
---
xen/arch/x86/cpuid.c | 54 ++++++++++++++++++++++++++++++++++++++++----
1 file changed, 50 insertions(+), 4 deletions(-)
diff --git a/xen/arch/x86/cpuid.c b/xen/arch/x86/cpuid.c
index ceac37b3ae..fb17c71d74 100644
--- a/xen/arch/x86/cpuid.c
+++ b/xen/arch/x86/cpuid.c
@@ -284,10 +284,26 @@ void guest_cpuid(const struct vcpu *v, uint32_t leaf,
const struct cpu_user_regs *regs;
case 0x1:
- /* TODO: Rework topology logic. */
res->b &= 0x00ffffffu;
if ( is_hvm_domain(d) )
- res->b |= (v->vcpu_id * 2) << 24;
+ {
+ unsigned int max_apic_id, max_lp;
+
+ /*
+ * EBX[23:16] = Maximum number of addressable IDs for logical
+ * processors in a physical package. Must be large enough to
+ * accommodate all vCPU APIC IDs. Round up to next power of 2.
+ *
+ * With APIC ID = vcpu_id * 2, max APIC ID = (max_vcpus - 1) * 2.
+ * We need max_lp to be greater than max_apic_id for proper
+ * enumeration.
+ */
+ max_apic_id = (d->max_vcpus - 1) * 2;
+ max_lp = min(1u << fls(max_apic_id), 255u);
+
+ res->b = (res->b & 0xff00ffffu) | (max_lp << 16);
+ res->b |= (uint8_t)(v->vcpu_id * 2) << 24;
+ }
/* TODO: Rework vPMU control in terms of toolstack choices. */
if ( vpmu_available(v) &&
@@ -463,11 +479,41 @@ void guest_cpuid(const struct vcpu *v, uint32_t leaf,
* coupled with x2apic, and we offer an x2apic-capable APIC emulation
* to guests on AMD hardware as well.
*
- * TODO: Rework topology logic.
+ * Provide a simple topology where all vCPUs are cores in a single
+ * package (no SMT). This ensures EBX is non-zero so that software
+ * (like EDK2/OVMF) uses the 32-bit x2APIC ID from EDX.
*/
if ( p->basic.x2apic )
{
- *(uint8_t *)&res->c = subleaf;
+ unsigned int max_vcpus = d->max_vcpus;
+ unsigned int max_apic_id = (max_vcpus - 1) * 2;
+ unsigned int shift;
+
+ /* Calculate shift value for Core level topology. */
+ shift = fls(max_apic_id);
+
+ switch ( subleaf )
+ {
+ /* SMT level - no hyperthreading, 1 thread per core */
+ case 0x0:
+ res->a = 0; /* No shift (1 thread per core) */
+ res->b = 1; /* 1 logical processor at this level */
+ res->c = 0x100 | 0; /* Level type 1 (SMT), level number 0 */
+ break;
+
+ /* Core level - all vCPUs are cores in one package */
+ case 0x1:
+ res->a = shift; /* Bits to shift to get package ID */
+ res->b = max_vcpus; /* Number of logical processors */
+ res->c = 0x200 | 1; /* Level type 2 (Core), level number 1 */
+ break;
+
+ default: /* Invalid level */
+ res->a = 0;
+ res->b = 0;
+ res->c = subleaf; /* Level number only, type 0 (invalid) */
+ break;
+ }
/* Fix the x2APIC identifier. */
res->d = v->vcpu_id * 2;
--
2.51.0
--
Julian Vetter | Vates Hypervisor & Kernel Developer
XCP-ng & Xen Orchestra - Vates solutions
web: https://vates.tech
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |