KVM: LoongArch: selftests: Add steal time test case

LoongArch KVM supports steal time accounting now, here add steal time
test case on LoongArch.

Signed-off-by: Bibo Mao <maobibo@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
This commit is contained in:
Bibo Mao 2026-02-06 09:28:01 +08:00 committed by Huacai Chen
parent 872d277a1e
commit 2d94a3f708
2 changed files with 97 additions and 0 deletions

View File

@ -228,6 +228,7 @@ TEST_GEN_PROGS_loongarch += kvm_page_table_test
TEST_GEN_PROGS_loongarch += memslot_modification_stress_test
TEST_GEN_PROGS_loongarch += memslot_perf_test
TEST_GEN_PROGS_loongarch += set_memory_region_test
TEST_GEN_PROGS_loongarch += steal_time
SPLIT_TESTS += arch_timer
SPLIT_TESTS += get-reg-list

View File

@ -301,6 +301,102 @@ static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx)
pr_info("\n");
}
#elif defined(__loongarch__)
/* steal_time must have 64-byte alignment */
#define STEAL_TIME_SIZE ((sizeof(struct kvm_steal_time) + 63) & ~63)
#define KVM_STEAL_PHYS_VALID BIT_ULL(0)
struct kvm_steal_time {
__u64 steal;
__u32 version;
__u32 flags;
__u8 preempted;
__u8 pad[47];
};
static void check_status(struct kvm_steal_time *st)
{
GUEST_ASSERT(!(READ_ONCE(st->version) & 1));
GUEST_ASSERT_EQ(READ_ONCE(st->flags), 0);
GUEST_ASSERT_EQ(READ_ONCE(st->preempted), 0);
}
static void guest_code(int cpu)
{
uint32_t version;
struct kvm_steal_time *st = st_gva[cpu];
memset(st, 0, sizeof(*st));
GUEST_SYNC(0);
check_status(st);
WRITE_ONCE(guest_stolen_time[cpu], st->steal);
version = READ_ONCE(st->version);
check_status(st);
GUEST_SYNC(1);
check_status(st);
GUEST_ASSERT(version < READ_ONCE(st->version));
WRITE_ONCE(guest_stolen_time[cpu], st->steal);
check_status(st);
GUEST_DONE();
}
static bool is_steal_time_supported(struct kvm_vcpu *vcpu)
{
int err;
uint64_t val;
struct kvm_device_attr attr = {
.group = KVM_LOONGARCH_VCPU_CPUCFG,
.attr = CPUCFG_KVM_FEATURE,
.addr = (uint64_t)&val,
};
err = __vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &attr);
if (err)
return false;
err = __vcpu_ioctl(vcpu, KVM_GET_DEVICE_ATTR, &attr);
if (err)
return false;
return val & BIT(KVM_FEATURE_STEAL_TIME);
}
static void steal_time_init(struct kvm_vcpu *vcpu, uint32_t i)
{
int err;
uint64_t st_gpa;
struct kvm_vm *vm = vcpu->vm;
struct kvm_device_attr attr = {
.group = KVM_LOONGARCH_VCPU_PVTIME_CTRL,
.attr = KVM_LOONGARCH_VCPU_PVTIME_GPA,
.addr = (uint64_t)&st_gpa,
};
/* ST_GPA_BASE is identity mapped */
st_gva[i] = (void *)(ST_GPA_BASE + i * STEAL_TIME_SIZE);
sync_global_to_guest(vm, st_gva[i]);
err = __vcpu_ioctl(vcpu, KVM_HAS_DEVICE_ATTR, &attr);
TEST_ASSERT(err == 0, "No PV stealtime Feature");
st_gpa = (unsigned long)st_gva[i] | KVM_STEAL_PHYS_VALID;
err = __vcpu_ioctl(vcpu, KVM_SET_DEVICE_ATTR, &attr);
TEST_ASSERT(err == 0, "Fail to set PV stealtime GPA");
}
static void steal_time_dump(struct kvm_vm *vm, uint32_t vcpu_idx)
{
struct kvm_steal_time *st = addr_gva2hva(vm, (ulong)st_gva[vcpu_idx]);
ksft_print_msg("VCPU%d:\n", vcpu_idx);
ksft_print_msg(" steal: %lld\n", st->steal);
ksft_print_msg(" flags: %d\n", st->flags);
ksft_print_msg(" version: %d\n", st->version);
ksft_print_msg(" preempted: %d\n", st->preempted);
}
#endif
static void *do_steal_time(void *arg)