diff -r 69e5242c35ee sys/dev/nvmm/x86/nvmm_x86.c --- a/sys/dev/nvmm/x86/nvmm_x86.c Sat Jul 11 23:11:22 2026 +0000 +++ b/sys/dev/nvmm/x86/nvmm_x86.c Mon Jul 13 02:45:40 2026 +0000 @@ -470,20 +470,36 @@ nvmm_x86_pat_validate(uint64_t val) uint32_t nvmm_x86_xsave_size(uint64_t xcr0) { - uint32_t size = sizeof(struct xsave_header); + uint32_t totalsize = sizeof(struct xsave_header); unsigned i; - KASSERT((xcr0 & ~__BITS(XSAVE_MAX_COMPONENT, 0)) == 0); + /* + * Caller must not pass bit 63 until the architectural + * extension mechanism it is reserved for has been defined. + */ + KASSERT((xcr0 & ~__BITS(62, 0)) == 0); CTASSERT(sizeof(struct xsave_header) == 512 + 64); - for (i = 0; i < XSAVE_MAX_COMPONENT; i++) { + for (i = 2; i < 63; i++) { + uint32_t descs[4]; + uint32_t size, offset; + if ((xcr0 & __BIT(i)) == 0) continue; - KASSERT(x86_xsave_sizes[i] <= - UINT32_MAX - x86_xsave_offsets[i]); - if (size < x86_xsave_offsets[i] + x86_xsave_sizes[i]) - size = x86_xsave_offsets[i] + x86_xsave_sizes[i]; + /* + * Can't use x86_xsave_offsets[i] + x86_xsave_sizes[i] + * because the NetBSD kernel only queries those for the + * user state components it knows about, but in + * principle this should support any user state + * component the guest wants to use even if NetBSD + * doesn't know how. + */ + x86_cpuid2(0x0d, i, descs); + size = descs[0]; /* CPUID[EAX=0x0d,ECX=i].EAX */ + offset = descs[1]; /* CPUID[EAX=0x0d,ECX=i].EBX */ + KASSERT(size <= UINT32_MAX - offset); + totalsize = MAX(totalsize, offset + size); } - return size; + return totalsize; } diff -r 69e5242c35ee sys/dev/nvmm/x86/nvmm_x86_vmx.c --- a/sys/dev/nvmm/x86/nvmm_x86_vmx.c Sat Jul 11 23:11:22 2026 +0000 +++ b/sys/dev/nvmm/x86/nvmm_x86_vmx.c Mon Jul 13 02:45:40 2026 +0000 @@ -828,7 +828,10 @@ struct vmx_cpudata { struct nvmm_vcpu_conf_tpr tpr; uint64_t xcr0_mask; - /* Guest XSAVE state. */ + /* + * Guest XSAVE state. Must be the last member because it may + * be extended variably by the CPU. + */ struct xsave_header gfpu __aligned(64); }; @@ -3670,9 +3673,11 @@ vmx_init(void) * physical CPU. Hypervisor software can use * nvmm_vcpu_configure(NVMM_VCPU_CONF_XCR0_MASK) to restrict * the available features on a per-vCPU basis, e.g. in order to - * limit guests to compatible features for migration. + * limit guests to compatible features for migration. We mask + * off bit 63 which is reserved for future extension which we + * don't understand. */ - vmx_xcr0_mask = x86_xsave_features; + vmx_xcr0_mask = x86_xsave_features & __BITS(62,0); /* Init the max basic CPUID leaf. */ vmx_cpuid_max_basic = uimin(cpuid_level, VMX_CPUID_MAX_BASIC);