]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: LoongArch: selftests: Add steal time test case
authorBibo Mao <maobibo@loongson.cn>
Fri, 6 Feb 2026 01:28:01 +0000 (09:28 +0800)
committerHuacai Chen <chenhuacai@loongson.cn>
Fri, 6 Feb 2026 01:28:01 +0000 (09:28 +0800)
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>
tools/testing/selftests/kvm/Makefile.kvm
tools/testing/selftests/kvm/steal_time.c

index ba5c2b643efaa263f90185b72fe59ecb0fcd6dbc..a18c00f1a4fa8106d4cb1cbd890f9eb414b2e159 100644 (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
index 8edc1fca345bae9903d7b8cafda946240739b76a..7be8adfe5dd36ffcbb5e52800e142d73337e5146 100644 (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)