KVM: selftests: arm64: Check for supported page sizes
Just as arm64 implemenations don't necessary support all IPA ranges, they don't all support the same page sizes either. Fun. Create a dummy VM to snapshot the page sizes supported by the host, and filter the supported modes. Signed-off-by: Marc Zyngier <maz@kernel.org> Reviewed-by: Andrew Jones <drjones@redhat.com> Link: https://lore.kernel.org/r/20211227124809.1335409-4-maz@kernel.org
This commit is contained in:
@@ -113,6 +113,9 @@ enum {
|
|||||||
#define ESR_EC_WP_CURRENT 0x35
|
#define ESR_EC_WP_CURRENT 0x35
|
||||||
#define ESR_EC_BRK_INS 0x3c
|
#define ESR_EC_BRK_INS 0x3c
|
||||||
|
|
||||||
|
void aarch64_get_supported_page_sizes(uint32_t ipa,
|
||||||
|
bool *ps4k, bool *ps16k, bool *ps64k);
|
||||||
|
|
||||||
void vm_init_descriptor_tables(struct kvm_vm *vm);
|
void vm_init_descriptor_tables(struct kvm_vm *vm);
|
||||||
void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid);
|
void vcpu_init_descriptor_tables(struct kvm_vm *vm, uint32_t vcpuid);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "guest_modes.h"
|
||||||
#include "kvm_util.h"
|
#include "kvm_util.h"
|
||||||
#include "../kvm_util_internal.h"
|
#include "../kvm_util_internal.h"
|
||||||
#include "processor.h"
|
#include "processor.h"
|
||||||
@@ -433,6 +434,41 @@ uint32_t guest_get_vcpuid(void)
|
|||||||
return read_sysreg(tpidr_el1);
|
return read_sysreg(tpidr_el1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void aarch64_get_supported_page_sizes(uint32_t ipa,
|
||||||
|
bool *ps4k, bool *ps16k, bool *ps64k)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu_init preferred_init;
|
||||||
|
int kvm_fd, vm_fd, vcpu_fd, err;
|
||||||
|
uint64_t val;
|
||||||
|
struct kvm_one_reg reg = {
|
||||||
|
.id = KVM_ARM64_SYS_REG(SYS_ID_AA64MMFR0_EL1),
|
||||||
|
.addr = (uint64_t)&val,
|
||||||
|
};
|
||||||
|
|
||||||
|
kvm_fd = open_kvm_dev_path_or_exit();
|
||||||
|
vm_fd = ioctl(kvm_fd, KVM_CREATE_VM, ipa);
|
||||||
|
TEST_ASSERT(vm_fd >= 0, "Can't create VM");
|
||||||
|
|
||||||
|
vcpu_fd = ioctl(vm_fd, KVM_CREATE_VCPU, 0);
|
||||||
|
TEST_ASSERT(vcpu_fd >= 0, "Can't create vcpu");
|
||||||
|
|
||||||
|
err = ioctl(vm_fd, KVM_ARM_PREFERRED_TARGET, &preferred_init);
|
||||||
|
TEST_ASSERT(err == 0, "Can't get target");
|
||||||
|
err = ioctl(vcpu_fd, KVM_ARM_VCPU_INIT, &preferred_init);
|
||||||
|
TEST_ASSERT(err == 0, "Can't get init vcpu");
|
||||||
|
|
||||||
|
err = ioctl(vcpu_fd, KVM_GET_ONE_REG, ®);
|
||||||
|
TEST_ASSERT(err == 0, "Can't get MMFR0");
|
||||||
|
|
||||||
|
*ps4k = ((val >> 28) & 0xf) != 0xf;
|
||||||
|
*ps64k = ((val >> 24) & 0xf) == 0;
|
||||||
|
*ps16k = ((val >> 20) & 0xf) != 0;
|
||||||
|
|
||||||
|
close(vcpu_fd);
|
||||||
|
close(vm_fd);
|
||||||
|
close(kvm_fd);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* arm64 doesn't have a true default mode, so start by computing the
|
* arm64 doesn't have a true default mode, so start by computing the
|
||||||
* available IPA space and page sizes early.
|
* available IPA space and page sizes early.
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include "guest_modes.h"
|
#include "guest_modes.h"
|
||||||
|
|
||||||
#ifdef __aarch64__
|
#ifdef __aarch64__
|
||||||
|
#include "processor.h"
|
||||||
enum vm_guest_mode vm_mode_default;
|
enum vm_guest_mode vm_mode_default;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -17,19 +18,23 @@ void guest_modes_append_default(void)
|
|||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE);
|
unsigned int limit = kvm_check_cap(KVM_CAP_ARM_VM_IPA_SIZE);
|
||||||
|
bool ps4k, ps16k, ps64k;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
aarch64_get_supported_page_sizes(limit, &ps4k, &ps16k, &ps64k);
|
||||||
|
|
||||||
vm_mode_default = NUM_VM_MODES;
|
vm_mode_default = NUM_VM_MODES;
|
||||||
|
|
||||||
if (limit >= 52)
|
if (limit >= 52)
|
||||||
guest_mode_append(VM_MODE_P52V48_64K, true, true);
|
guest_mode_append(VM_MODE_P52V48_64K, ps64k, ps64k);
|
||||||
if (limit >= 48) {
|
if (limit >= 48) {
|
||||||
guest_mode_append(VM_MODE_P48V48_4K, true, true);
|
guest_mode_append(VM_MODE_P48V48_4K, ps4k, ps4k);
|
||||||
guest_mode_append(VM_MODE_P48V48_64K, true, true);
|
guest_mode_append(VM_MODE_P48V48_64K, ps64k, ps64k);
|
||||||
}
|
}
|
||||||
if (limit >= 40) {
|
if (limit >= 40) {
|
||||||
guest_mode_append(VM_MODE_P40V48_4K, true, true);
|
guest_mode_append(VM_MODE_P40V48_4K, ps4k, ps4k);
|
||||||
guest_mode_append(VM_MODE_P40V48_64K, true, true);
|
guest_mode_append(VM_MODE_P40V48_64K, ps64k, ps64k);
|
||||||
|
if (ps4k)
|
||||||
vm_mode_default = VM_MODE_P40V48_4K;
|
vm_mode_default = VM_MODE_P40V48_4K;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user