KVM: selftests: Extend memstress to run on nested SVM

Add L1 SVM code and generalize the setup code to work for both VMX and
SVM. This allows running 'dirty_log_perf_test -n' on AMD CPUs.

Signed-off-by: Yosry Ahmed <yosry.ahmed@linux.dev>
Link: https://patch.msgid.link/20251230230150.4150236-20-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
Yosry Ahmed 2025-12-30 15:01:48 -08:00 committed by Sean Christopherson
parent 6794d916f8
commit 59eef1a47b

View File

@ -13,6 +13,7 @@
#include "kvm_util.h"
#include "memstress.h"
#include "processor.h"
#include "svm_util.h"
#include "vmx.h"
void memstress_l2_guest_code(uint64_t vcpu_id)
@ -29,9 +30,10 @@ __asm__(
" ud2;"
);
static void memstress_l1_guest_code(struct vmx_pages *vmx, uint64_t vcpu_id)
{
#define L2_GUEST_STACK_SIZE 64
static void l1_vmx_code(struct vmx_pages *vmx, uint64_t vcpu_id)
{
unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
unsigned long *rsp;
@ -45,10 +47,34 @@ static void memstress_l1_guest_code(struct vmx_pages *vmx, uint64_t vcpu_id)
prepare_vmcs(vmx, memstress_l2_guest_entry, rsp);
GUEST_ASSERT(!vmlaunch());
GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL);
GUEST_ASSERT_EQ(vmreadz(VM_EXIT_REASON), EXIT_REASON_VMCALL);
GUEST_DONE();
}
static void l1_svm_code(struct svm_test_data *svm, uint64_t vcpu_id)
{
unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE];
unsigned long *rsp;
rsp = &l2_guest_stack[L2_GUEST_STACK_SIZE - 1];
*rsp = vcpu_id;
generic_svm_setup(svm, memstress_l2_guest_entry, rsp);
run_guest(svm->vmcb, svm->vmcb_gpa);
GUEST_ASSERT_EQ(svm->vmcb->control.exit_code, SVM_EXIT_VMMCALL);
GUEST_DONE();
}
static void memstress_l1_guest_code(void *data, uint64_t vcpu_id)
{
if (this_cpu_has(X86_FEATURE_VMX))
l1_vmx_code(data, vcpu_id);
else
l1_svm_code(data, vcpu_id);
}
uint64_t memstress_nested_pages(int nr_vcpus)
{
/*
@ -78,15 +104,17 @@ static void memstress_setup_ept_mappings(struct kvm_vm *vm)
void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vcpus[])
{
struct kvm_regs regs;
vm_vaddr_t vmx_gva;
vm_vaddr_t nested_gva;
int vcpu_id;
TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
TEST_REQUIRE(kvm_cpu_has_tdp());
vm_enable_tdp(vm);
for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) {
vcpu_alloc_vmx(vm, &vmx_gva);
if (kvm_cpu_has(X86_FEATURE_VMX))
vcpu_alloc_vmx(vm, &nested_gva);
else
vcpu_alloc_svm(vm, &nested_gva);
/* The EPTs are shared across vCPUs, setup the mappings once */
if (vcpu_id == 0)
@ -99,6 +127,6 @@ void memstress_setup_nested(struct kvm_vm *vm, int nr_vcpus, struct kvm_vcpu *vc
vcpu_regs_get(vcpus[vcpu_id], &regs);
regs.rip = (unsigned long) memstress_l1_guest_code;
vcpu_regs_set(vcpus[vcpu_id], &regs);
vcpu_args_set(vcpus[vcpu_id], 2, vmx_gva, vcpu_id);
vcpu_args_set(vcpus[vcpu_id], 2, nested_gva, vcpu_id);
}
}