Commit 2d94a3f7 authored by Bibo Mao's avatar Bibo Mao Committed by Huacai Chen
Browse files

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: default avatarBibo Mao <maobibo@loongson.cn>
Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent 872d277a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+96 −0
Original line number Diff line number Diff line
@@ -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)