Commit 39ad809d authored by Wu Fei's avatar Wu Fei Committed by Anup Patel
Browse files

KVM: riscv: selftests: Add riscv vm satp modes



Current vm modes cannot represent riscv guest modes precisely, here add
all 9 combinations of P(56,40,41) x V(57,48,39). Also the default vm
mode is detected on runtime instead of hardcoded one, which might not be
supported on specific machine.

Signed-off-by: default avatarWu Fei <wu.fei9@sanechips.com.cn>
Reviewed-by: default avatarAndrew Jones <ajones@ventanamicro.com>
Reviewed-by: default avatarNutty Liu <nutty.liu@hotmail.com>
Reviewed-by: default avatarAnup Patel <anup@brainfault.org>
Link: https://lore.kernel.org/r/20251105151442.28767-1-wu.fei9@sanechips.com.cn


Signed-off-by: default avatarAnup Patel <anup@brainfault.org>
parent ab2a7b7b
Loading
Loading
Loading
Loading
+14 −3
Original line number Diff line number Diff line
@@ -186,6 +186,17 @@ enum vm_guest_mode {
	VM_MODE_P36V48_64K,
	VM_MODE_P47V47_16K,
	VM_MODE_P36V47_16K,

	VM_MODE_P56V57_4K,	/* For riscv64 */
	VM_MODE_P56V48_4K,
	VM_MODE_P56V39_4K,
	VM_MODE_P50V57_4K,
	VM_MODE_P50V48_4K,
	VM_MODE_P50V39_4K,
	VM_MODE_P41V57_4K,
	VM_MODE_P41V48_4K,
	VM_MODE_P41V39_4K,

	NUM_VM_MODES,
};

@@ -210,10 +221,10 @@ kvm_static_assert(sizeof(struct vm_shape) == sizeof(uint64_t));
	shape;					\
})

#if defined(__aarch64__)

extern enum vm_guest_mode vm_mode_default;

#if defined(__aarch64__)

#define VM_MODE_DEFAULT			vm_mode_default
#define MIN_PAGE_SHIFT			12U
#define ptes_per_page(page_size)	((page_size) / 8)
@@ -236,7 +247,7 @@ extern enum vm_guest_mode vm_mode_default;
#error "RISC-V 32-bit kvm selftests not supported"
#endif

#define VM_MODE_DEFAULT			VM_MODE_P40V48_4K
#define VM_MODE_DEFAULT			vm_mode_default
#define MIN_PAGE_SHIFT			12U
#define ptes_per_page(page_size)	((page_size) / 8)

+2 −0
Original line number Diff line number Diff line
@@ -192,4 +192,6 @@ static inline void local_irq_disable(void)
	csr_clear(CSR_SSTATUS, SR_SIE);
}

unsigned long riscv64_get_satp_mode(void);

#endif /* SELFTEST_KVM_PROCESSOR_H */
+34 −7
Original line number Diff line number Diff line
@@ -4,7 +4,7 @@
 */
#include "guest_modes.h"

#ifdef __aarch64__
#if defined(__aarch64__) || defined(__riscv)
#include "processor.h"
enum vm_guest_mode vm_mode_default;
#endif
@@ -13,9 +13,11 @@ struct guest_mode guest_modes[NUM_VM_MODES];

void guest_modes_append_default(void)
{
#ifndef __aarch64__
#if !defined(__aarch64__) && !defined(__riscv)
	guest_mode_append(VM_MODE_DEFAULT, true);
#else
#endif

#ifdef __aarch64__
	{
		unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE);
		uint32_t ipa4k, ipa16k, ipa64k;
@@ -74,11 +76,36 @@ void guest_modes_append_default(void)
#ifdef __riscv
	{
		unsigned int sz = kvm_check_cap(KVM_CAP_VM_GPA_BITS);
		unsigned long satp_mode = riscv64_get_satp_mode() << SATP_MODE_SHIFT;
		int i;

		if (sz >= 52)
			guest_mode_append(VM_MODE_P52V48_4K, true);
		if (sz >= 48)
			guest_mode_append(VM_MODE_P48V48_4K, true);
		switch (sz) {
		case 59:
			guest_mode_append(VM_MODE_P56V57_4K, satp_mode >= SATP_MODE_57);
			guest_mode_append(VM_MODE_P56V48_4K, satp_mode >= SATP_MODE_48);
			guest_mode_append(VM_MODE_P56V39_4K, satp_mode >= SATP_MODE_39);
			break;
		case 50:
			guest_mode_append(VM_MODE_P50V57_4K, satp_mode >= SATP_MODE_57);
			guest_mode_append(VM_MODE_P50V48_4K, satp_mode >= SATP_MODE_48);
			guest_mode_append(VM_MODE_P50V39_4K, satp_mode >= SATP_MODE_39);
			break;
		case 41:
			guest_mode_append(VM_MODE_P41V57_4K, satp_mode >= SATP_MODE_57);
			guest_mode_append(VM_MODE_P41V48_4K, satp_mode >= SATP_MODE_48);
			guest_mode_append(VM_MODE_P41V39_4K, satp_mode >= SATP_MODE_39);
			break;
		default:
			break;
		}

		/* set the first supported mode as default */
		vm_mode_default = NUM_VM_MODES;
		for (i = 0; vm_mode_default == NUM_VM_MODES && i < NUM_VM_MODES; i++) {
			if (guest_modes[i].supported && guest_modes[i].enabled)
				vm_mode_default = i;
		}
		TEST_ASSERT(vm_mode_default != NUM_VM_MODES, "No supported mode!");
	}
#endif
}
+33 −0
Original line number Diff line number Diff line
@@ -209,6 +209,15 @@ const char *vm_guest_mode_string(uint32_t i)
		[VM_MODE_P36V48_64K]	= "PA-bits:36,  VA-bits:48, 64K pages",
		[VM_MODE_P47V47_16K]	= "PA-bits:47,  VA-bits:47, 16K pages",
		[VM_MODE_P36V47_16K]	= "PA-bits:36,  VA-bits:47, 16K pages",
		[VM_MODE_P56V57_4K]	= "PA-bits:56,  VA-bits:57,  4K pages",
		[VM_MODE_P56V48_4K]	= "PA-bits:56,  VA-bits:48,  4K pages",
		[VM_MODE_P56V39_4K]	= "PA-bits:56,  VA-bits:39,  4K pages",
		[VM_MODE_P50V57_4K]	= "PA-bits:50,  VA-bits:57,  4K pages",
		[VM_MODE_P50V48_4K]	= "PA-bits:50,  VA-bits:48,  4K pages",
		[VM_MODE_P50V39_4K]	= "PA-bits:50,  VA-bits:39,  4K pages",
		[VM_MODE_P41V57_4K]	= "PA-bits:41,  VA-bits:57,  4K pages",
		[VM_MODE_P41V48_4K]	= "PA-bits:41,  VA-bits:48,  4K pages",
		[VM_MODE_P41V39_4K]	= "PA-bits:41,  VA-bits:39,  4K pages",
	};
	_Static_assert(sizeof(strings)/sizeof(char *) == NUM_VM_MODES,
		       "Missing new mode strings?");
@@ -236,6 +245,15 @@ const struct vm_guest_mode_params vm_guest_mode_params[] = {
	[VM_MODE_P36V48_64K]	= { 36, 48, 0x10000, 16 },
	[VM_MODE_P47V47_16K]	= { 47, 47,  0x4000, 14 },
	[VM_MODE_P36V47_16K]	= { 36, 47,  0x4000, 14 },
	[VM_MODE_P56V57_4K]	= { 56, 57,  0x1000, 12 },
	[VM_MODE_P56V48_4K]	= { 56, 48,  0x1000, 12 },
	[VM_MODE_P56V39_4K]	= { 56, 39,  0x1000, 12 },
	[VM_MODE_P50V57_4K]	= { 50, 57,  0x1000, 12 },
	[VM_MODE_P50V48_4K]	= { 50, 48,  0x1000, 12 },
	[VM_MODE_P50V39_4K]	= { 50, 39,  0x1000, 12 },
	[VM_MODE_P41V57_4K]	= { 41, 57,  0x1000, 12 },
	[VM_MODE_P41V48_4K]	= { 41, 48,  0x1000, 12 },
	[VM_MODE_P41V39_4K]	= { 41, 39,  0x1000, 12 },
};
_Static_assert(sizeof(vm_guest_mode_params)/sizeof(struct vm_guest_mode_params) == NUM_VM_MODES,
	       "Missing new mode params?");
@@ -338,6 +356,21 @@ struct kvm_vm *____vm_create(struct vm_shape shape)
	case VM_MODE_P44V64_4K:
		vm->pgtable_levels = 5;
		break;
	case VM_MODE_P56V57_4K:
	case VM_MODE_P50V57_4K:
	case VM_MODE_P41V57_4K:
		vm->pgtable_levels = 5;
		break;
	case VM_MODE_P56V48_4K:
	case VM_MODE_P50V48_4K:
	case VM_MODE_P41V48_4K:
		vm->pgtable_levels = 4;
		break;
	case VM_MODE_P56V39_4K:
	case VM_MODE_P50V39_4K:
	case VM_MODE_P41V39_4K:
		vm->pgtable_levels = 3;
		break;
	default:
		TEST_FAIL("Unknown guest mode: 0x%x", vm->mode);
	}
+59 −4
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/compiler.h>
#include <assert.h>

#include "guest_modes.h"
#include "kvm_util.h"
#include "processor.h"
#include "ucall_common.h"
@@ -197,22 +198,41 @@ void riscv_vcpu_mmu_setup(struct kvm_vcpu *vcpu)
{
	struct kvm_vm *vm = vcpu->vm;
	unsigned long satp;
	unsigned long satp_mode;
	unsigned long max_satp_mode;

	/*
	 * The RISC-V Sv48 MMU mode supports 56-bit physical address
	 * for 48-bit virtual address with 4KB last level page size.
	 */
	switch (vm->mode) {
	case VM_MODE_P52V48_4K:
	case VM_MODE_P48V48_4K:
	case VM_MODE_P40V48_4K:
	case VM_MODE_P56V57_4K:
	case VM_MODE_P50V57_4K:
	case VM_MODE_P41V57_4K:
		satp_mode = SATP_MODE_57;
		break;
	case VM_MODE_P56V48_4K:
	case VM_MODE_P50V48_4K:
	case VM_MODE_P41V48_4K:
		satp_mode = SATP_MODE_48;
		break;
	case VM_MODE_P56V39_4K:
	case VM_MODE_P50V39_4K:
	case VM_MODE_P41V39_4K:
		satp_mode = SATP_MODE_39;
		break;
	default:
		TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode);
	}

	max_satp_mode = vcpu_get_reg(vcpu, RISCV_CONFIG_REG(satp_mode));

	if ((satp_mode >> SATP_MODE_SHIFT) > max_satp_mode)
		TEST_FAIL("Unable to set satp mode 0x%lx, max mode 0x%lx\n",
			  satp_mode >> SATP_MODE_SHIFT, max_satp_mode);

	satp = (vm->pgd >> PGTBL_PAGE_SIZE_SHIFT) & SATP_PPN;
	satp |= SATP_MODE_48;
	satp |= satp_mode;

	vcpu_set_reg(vcpu, RISCV_GENERAL_CSR_REG(satp), satp);
}
@@ -515,3 +535,38 @@ unsigned long get_host_sbi_spec_version(void)

	return ret.value;
}

void kvm_selftest_arch_init(void)
{
	/*
	 * riscv64 doesn't have a true default mode, so start by detecting the
	 * supported vm mode.
	 */
	guest_modes_append_default();
}

unsigned long riscv64_get_satp_mode(void)
{
	int kvm_fd, vm_fd, vcpu_fd, err;
	uint64_t val;
	struct kvm_one_reg reg = {
		.id     = RISCV_CONFIG_REG(satp_mode),
		.addr   = (uint64_t)&val,
	};

	kvm_fd = open_kvm_dev_path_or_exit();
	vm_fd = __kvm_ioctl(kvm_fd, KVM_CREATE_VM, NULL);
	TEST_ASSERT(vm_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VM, vm_fd));

	vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0);
	TEST_ASSERT(vcpu_fd >= 0, KVM_IOCTL_ERROR(KVM_CREATE_VCPU, vcpu_fd));

	err = ioctl(vcpu_fd, KVM_GET_ONE_REG, &reg);
	TEST_ASSERT(err == 0, KVM_IOCTL_ERROR(KVM_GET_ONE_REG, vcpu_fd));

	close(vcpu_fd);
	close(vm_fd);
	close(kvm_fd);

	return val;
}