Skip to content

Commit 8b14c4d

Browse files
committed
KVM: selftests: Configure XCR0 to max supported value by default
To play nice with compilers generating AVX instructions, set CR4.OSXSAVE and configure XCR0 by default when creating selftests vCPUs. Some distros have switched gcc to '-march=x86-64-v3' by default, and while it's hard to find a CPU which doesn't support AVX today, many KVM selftests fail with ==== Test Assertion Failure ==== lib/x86_64/processor.c:570: Unhandled exception in guest pid=72747 tid=72747 errno=4 - Interrupted system call Unhandled exception '0x6' at guest RIP '0x4104f7' due to selftests not enabling AVX by default for the guest. The failure is easy to reproduce elsewhere with: $ make clean && CFLAGS='-march=x86-64-v3' make -j && ./x86_64/kvm_pv_test E.g. gcc-13 with -march=x86-64-v3 compiles this chunk from selftests' kvm_fixup_exception(): regs->rip = regs->r11; regs->r9 = regs->vector; regs->r10 = regs->error_code; into this monstronsity (which is clever, but oof): 405313: c4 e1 f9 6e c8 vmovq %rax,%xmm1 405318: 48 89 68 08 mov %rbp,0x8(%rax) 40531c: 48 89 e8 mov %rbp,%rax 40531f: c4 c3 f1 22 c4 01 vpinsrq $0x1,%r12,%xmm1,%xmm0 405325: 49 89 6d 38 mov %rbp,0x38(%r13) 405329: c5 fa 7f 45 00 vmovdqu %xmm0,0x0(%rbp) Alternatively, KVM selftests could explicitly restrict the compiler to -march=x86-64-v2, but odds are very good that punting on AVX enabling will simply result in tests that "need" AVX doing their own thing, e.g. there are already three or so additional cleanups that can be done on top. Reported-by: Vitaly Kuznetsov <vkuznets@redhat.com> Closes: https://lore.kernel.org/all/20240920154422.2890096-1-vkuznets@redhat.com Reviewed-and-tested-by: Vitaly Kuznetsov <vkuznets@redhat.com> Link: https://lore.kernel.org/r/20241003234337.273364-6-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 2b9a126 commit 8b14c4d

File tree

3 files changed

+32
-3
lines changed

3 files changed

+32
-3
lines changed

tools/testing/selftests/kvm/include/x86_64/processor.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,6 +1049,11 @@ static inline void vcpu_set_cpuid(struct kvm_vcpu *vcpu)
10491049
vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid);
10501050
}
10511051

1052+
static inline void vcpu_get_cpuid(struct kvm_vcpu *vcpu)
1053+
{
1054+
vcpu_ioctl(vcpu, KVM_GET_CPUID2, vcpu->cpuid);
1055+
}
1056+
10521057
void vcpu_set_cpuid_property(struct kvm_vcpu *vcpu,
10531058
struct kvm_x86_cpu_property property,
10541059
uint32_t value);

tools/testing/selftests/kvm/lib/x86_64/processor.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,8 @@ static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
506506

507507
sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG;
508508
sregs.cr4 |= X86_CR4_PAE | X86_CR4_OSFXSR;
509+
if (kvm_cpu_has(X86_FEATURE_XSAVE))
510+
sregs.cr4 |= X86_CR4_OSXSAVE;
509511
sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX);
510512

511513
kvm_seg_set_unusable(&sregs.ldt);
@@ -519,6 +521,20 @@ static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
519521
vcpu_sregs_set(vcpu, &sregs);
520522
}
521523

524+
static void vcpu_init_xcrs(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
525+
{
526+
struct kvm_xcrs xcrs = {
527+
.nr_xcrs = 1,
528+
.xcrs[0].xcr = 0,
529+
.xcrs[0].value = kvm_cpu_supported_xcr0(),
530+
};
531+
532+
if (!kvm_cpu_has(X86_FEATURE_XSAVE))
533+
return;
534+
535+
vcpu_xcrs_set(vcpu, &xcrs);
536+
}
537+
522538
static void set_idt_entry(struct kvm_vm *vm, int vector, unsigned long addr,
523539
int dpl, unsigned short selector)
524540
{
@@ -675,6 +691,7 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
675691
vcpu = __vm_vcpu_add(vm, vcpu_id);
676692
vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
677693
vcpu_init_sregs(vm, vcpu);
694+
vcpu_init_xcrs(vm, vcpu);
678695

679696
/* Setup guest general purpose registers */
680697
vcpu_regs_get(vcpu, &regs);
@@ -686,6 +703,13 @@ struct kvm_vcpu *vm_arch_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)
686703
mp_state.mp_state = 0;
687704
vcpu_mp_state_set(vcpu, &mp_state);
688705

706+
/*
707+
* Refresh CPUID after setting SREGS and XCR0, so that KVM's "runtime"
708+
* updates to guest CPUID, e.g. for OSXSAVE and XSAVE state size, are
709+
* reflected into selftests' vCPU CPUID cache, i.e. so that the cache
710+
* is consistent with vCPU state.
711+
*/
712+
vcpu_get_cpuid(vcpu);
689713
return vcpu;
690714
}
691715

tools/testing/selftests/kvm/x86_64/xcr0_cpuid_test.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,16 +48,16 @@ do { \
4848

4949
static void guest_code(void)
5050
{
51-
uint64_t xcr0_reset;
51+
uint64_t initial_xcr0;
5252
uint64_t supported_xcr0;
5353
int i, vector;
5454

5555
set_cr4(get_cr4() | X86_CR4_OSXSAVE);
5656

57-
xcr0_reset = xgetbv(0);
57+
initial_xcr0 = xgetbv(0);
5858
supported_xcr0 = this_cpu_supported_xcr0();
5959

60-
GUEST_ASSERT(xcr0_reset == XFEATURE_MASK_FP);
60+
GUEST_ASSERT(initial_xcr0 == supported_xcr0);
6161

6262
/* Check AVX */
6363
ASSERT_XFEATURE_DEPENDENCIES(supported_xcr0,

0 commit comments

Comments
 (0)