@samitouri / QOSamiQemu / commits / 9c961adc87

target/i386/mshv: use hv-provided [0xD,1+2].EBX

We cannot statically set the responses for CPUID[0xD,{1,2}].EBX, b/c those are dynamic, dependent on which features the guest enables. Hence we mask EBX when registering answers for those subleaves at the hypervisor, which will result in the hypervisor providing us answers, considering XCR0 and XSS. The reported size now reflects the field masks properly (without the mask they were 576 and 10728, which is wrong): $ cpuid -l 0xd -s 0 CPU 0: XSAVE features (0xd/0): XCR0 valid bit field mask = 0x00000000000600e7 ... bytes required by fields in XCR0 = 0x00002b00 (11008) bytes required by XSAVE/XRSTOR area = 0x00002b00 (11008) $ cpuid -l 0xd -s 1 CPU 0: XSAVE features (0xd/1): ... SAVE area size in bytes = 0x000029c0 (10688) IA32_XSS lower 32 bits valid bit field mask = 0x00001800 IA32_XSS upper 32 bits valid bit field mask = 0x00000000 Signed-off-by: Magnus Kulke <magnuskulke@linux.microsoft.com> Reviewed-by: Doru Blânzeanu <dblanzeanu@linux.microsoft.com> Link: https://lore.kernel.org/r/20260416121116.527927-9-magnuskulke@linux.microsoft.com Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

Magnus Kulke committed Apr 16, 2026 at 14:11 UTC 9c961adc879aae3430094ca2e2bf7025083ba027
1 file changed +21 -2
target/i386/mshv/mshv-cpu.c
+21 -2
@@ -528,6 +528,7 @@ static void collect_cpuid_entries(const CPUState *cpu, GList **cpuid_entries)
528 static int register_intercept_result_cpuid_entry(const CPUState *cpu,
529 uint8_t subleaf_specific,
530 uint8_t always_override,
531 + uint32_t ebx_mask,
532 struct hv_cpuid_entry *entry)
533 {
534 int ret;
@@ -543,11 +544,12 @@ static int register_intercept_result_cpuid_entry(const CPUState *cpu,
544 /*
545 * Masks specify which bits to override. Set to 0xFFFFFFFF to
546 * override all bits with the values from the QEMU CPU model.
547 + * A mask of 0 lets the hypervisor supply its own value.
548 */
549 .result.eax = entry->eax,
550 .result.eax_mask = 0xFFFFFFFF,
551 .result.ebx = entry->ebx,
550 - .result.ebx_mask = 0xFFFFFFFF,
552 + .result.ebx_mask = ebx_mask,
553 .result.ecx = entry->ecx,
554 .result.ecx_mask = 0xFFFFFFFF,
555 .result.edx = entry->edx,
@@ -582,6 +584,7 @@ static int register_intercept_result_cpuid(const CPUState *cpu,
584 int ret = 0, entry_ret;
585 struct hv_cpuid_entry *entry;
586 uint8_t subleaf_specific, always_override;
587 + uint32_t ebx_mask;
588
589 for (size_t i = 0; i < cpuid->nent; i++) {
590 entry = &cpuid->entries[i];
@@ -589,6 +592,7 @@ static int register_intercept_result_cpuid(const CPUState *cpu,
592 /* set defaults */
593 subleaf_specific = 0;
594 always_override = 1;
595 + ebx_mask = 0xFFFFFFFF;
596
597 /*
598 * Intel
@@ -628,8 +632,22 @@ static int register_intercept_result_cpuid(const CPUState *cpu,
632 always_override = 1;
633 }
634
631 - entry_ret = register_intercept_result_cpuid_entry(cpu, subleaf_specific,
635 + /*
636 + * CPUID[0xD,0].EBX and CPUID[0xD,1].EBX report the XSAVE area
637 + * size based on features currently enabled in XCR0/XSS. These
638 + * values are dynamic and must not be overridden with static
639 + * results from the QEMU CPU model. Setting ebx_mask to 0 lets
640 + * the hypervisor supply EBX based on the guest's actual state.
641 + */
642 + if (entry->function == 0x0d &&
643 + (entry->index == 0 || entry->index == 1)) {
644 + ebx_mask = 0;
645 + }
646 +
647 + entry_ret = register_intercept_result_cpuid_entry(cpu,
648 + subleaf_specific,
649 always_override,
650 + ebx_mask,
651 entry);
652 if ((entry_ret < 0) && (ret == 0)) {
653 ret = entry_ret;
@@ -1688,6 +1706,7 @@ uint32_t mshv_get_supported_cpuid(uint32_t func, uint32_t idx, int reg)
1706 if (func == 0x01 && reg == R_ECX) {
1707 ret &= ~CPUID_EXT_VMX;
1708 }
1709 +
1710 return ret;
1711 }
1712