@samitouri / QOSamiQemu / commits / c851e0da56

target/i386/mshv: fix various cpuid traversal bugs

- Hardcoded max_leaf was not accurate. We query leaf 0x0 and 0x80000000 to get the actual max leaves - On all 0 zeroes on leaf 0x0d, we register 0-63 subleaves with zeros indicating XSAVE is disabled - Subleaf 0 was hardcoded, so the Hypervisor returned defaults for other subleaves - Subleaf 0 was hardcoded, so we were passing 0 instead of actual subleaf when adding entries. We now pass the correct subleaf value to add_cpuid_entry() - Leaves 0x04,0x07,0d,0f,10 weren't marked as subleaf-specific Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com> Acked-by: Wei Liu <wei.liu@kernel.org> Reviewed-by: Doru Blânzeanu <dblanzeanu@linux.microsoft.com> Link: https://lore.kernel.org/r/20260416121116.527927-4-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Magnus Kulke committed Apr 16, 2026 at 14:11 UTC c851e0da56d2d892c906fffc4a9780403855caec
1 file changed +61 -27
target/i386/mshv/mshv-cpu.c
+61 -27
@@ -465,14 +465,17 @@ static void collect_cpuid_entries(const CPUState *cpu, GList **cpuid_entries)
465 CPUX86State *env = &x86_cpu->env;
466 uint32_t eax, ebx, ecx, edx;
467 uint32_t leaf, subleaf;
468 - size_t max_leaf = 0x1F;
469 - size_t max_subleaf = 0x20;
470 -
471 - uint32_t leaves_with_subleaves[] = {0x4, 0x7, 0xD, 0xF, 0x10};
468 + uint32_t max_basic_leaf, max_extended_leaf;
469 + uint32_t max_subleaf = 0x20;
470 + uint32_t leaves_with_subleaves[] = {0x04, 0x07, 0x0d, 0x0f, 0x10};
471 int n_subleaf_leaves = ARRAY_SIZE(leaves_with_subleaves);
472
474 - /* Regular leaves without subleaves */
475 - for (leaf = 0; leaf <= max_leaf; leaf++) {
473 + /* Get maximum basic and and extended CPUID leaves */
474 + cpu_x86_cpuid(env, 0, 0, &max_basic_leaf, &ebx, &ecx, &edx);
475 + cpu_x86_cpuid(env, 0x80000000, 0, &max_extended_leaf, &ebx, &ecx, &edx);
476 +
477 + /* Collect basic leaves (0x0 to max_basic_leaf) */
478 + for (leaf = 0; leaf <= max_basic_leaf; leaf++) {
479 bool has_subleaves = false;
480 for (int i = 0; i < n_subleaf_leaves; i++) {
481 if (leaf == leaves_with_subleaves[i]) {
@@ -483,27 +486,40 @@ static void collect_cpuid_entries(const CPUState *cpu, GList **cpuid_entries)
486
487 if (!has_subleaves) {
488 cpu_x86_cpuid(env, leaf, 0, &eax, &ebx, &ecx, &edx);
486 - if (eax == 0 && ebx == 0 && ecx == 0 && edx == 0) {
487 - /* all zeroes indicates no more leaves */
488 - continue;
489 - }
490 -
489 add_cpuid_entry(cpuid_entries, leaf, 0, eax, ebx, ecx, edx);
490 continue;
491 }
492
493 + /*
494 + * Valid XSAVE components can exist at a higher index se we need to set
495 + * all subleaves for leaf 0x0d, even if we encounter an empty one.
496 + */
497 + if (leaf == 0x0d) {
498 + for (subleaf = 0; subleaf <= 63; subleaf++) {
499 + cpu_x86_cpuid(env, leaf, subleaf, &eax, &ebx, &ecx, &edx);
500 + add_cpuid_entry(cpuid_entries, leaf, subleaf,
501 + eax, ebx, ecx, edx);
502 + }
503 + continue;
504 + }
505 +
506 subleaf = 0;
507 while (subleaf < max_subleaf) {
508 cpu_x86_cpuid(env, leaf, subleaf, &eax, &ebx, &ecx, &edx);
509
510 if (eax == 0 && ebx == 0 && ecx == 0 && edx == 0) {
500 - /* all zeroes indicates no more leaves */
511 break;
512 }
503 - add_cpuid_entry(cpuid_entries, leaf, 0, eax, ebx, ecx, edx);
513 + add_cpuid_entry(cpuid_entries, leaf, subleaf, eax, ebx, ecx, edx);
514 subleaf++;
515 }
516 }
517 +
518 + /* Collect extended leaves (0x80000000 to max_extended_leaf) */
519 + for (leaf = 0x80000000; leaf <= max_extended_leaf; leaf++) {
520 + cpu_x86_cpuid(env, leaf, 0, &eax, &ebx, &ecx, &edx);
521 + add_cpuid_entry(cpuid_entries, leaf, 0, eax, ebx, ecx, edx);
522 + }
523 }
524
525 static int register_intercept_result_cpuid_entry(const CPUState *cpu,
@@ -576,22 +592,40 @@ static int register_intercept_result_cpuid(const CPUState *cpu,
592 subleaf_specific = 0;
593 always_override = 1;
594
579 - /* Intel */
580 - /* 0xb - Extended Topology Enumeration Leaf */
581 - /* 0x1f - V2 Extended Topology Enumeration Leaf */
582 - /* AMD */
583 - /* 0x8000_001e - Processor Topology Information */
584 - /* 0x8000_0026 - Extended CPU Topology */
585 - if (entry->function == 0xb
586 - || entry->function == 0x1f
587 - || entry->function == 0x8000001e
588 - || entry->function == 0x80000026) {
595 + /*
596 + * Intel
597 + * 0xb - Extended Topology Enumeration Leaf
598 + * 0x1f - V2 Extended Topology Enumeration Leaf
599 + * AMD
600 + * 0x8000_001e - Processor Topology Information
601 + * 0x8000_0026 - Extended CPU Topology
602 + */
603 + if (entry->function == 0xb ||
604 + entry->function == 0x1f ||
605 + entry->function == 0x8000001e ||
606 + entry->function == 0x80000026) {
607 + subleaf_specific = 1;
608 + always_override = 1;
609 + /*
610 + * Feature enumeration leaves (subleaf-specific)
611 + * 0x04: Deterministic Cache Parameters
612 + * 0x07: Structured Extended Feature Flags
613 + * 0x0D: Processor Extended State Enumeration
614 + * 0x0F: Platform QoS Monitoring
615 + * 0x10: Platform QoS Enforcement
616 + */
617 + } else if (entry->function == 0x04 ||
618 + entry->function == 0x07 ||
619 + entry->function == 0x0d ||
620 + entry->function == 0x0f ||
621 + entry->function == 0x10) {
622 subleaf_specific = 1;
623 always_override = 1;
591 - } else if (entry->function == 0x00000001
592 - || entry->function == 0x80000000
593 - || entry->function == 0x80000001
594 - || entry->function == 0x80000008) {
624 + /* Basic feature leaves (no subleaves) */
625 + } else if (entry->function == 0x00000001 ||
626 + entry->function == 0x80000000 ||
627 + entry->function == 0x80000001 ||
628 + entry->function == 0x80000008) {
629 subleaf_specific = 0;
630 always_override = 1;
631 }