KVM: arm64: Selftest IPA fixes
Marc Zyngier
maintainercover KVM: arm64: Selftest IPA fixes
Now that the common variety of fruity arm64 systems makes a pretty remarkable KVM host, I have decided to run the collection of selftests on it.
Nothing works. Oh no!
As it turns out, the tests have a notion of "default mode" (36bit PA, 4kB), which cannot work in general on arm64 because there no such thing as an IPA size that would be valid everywhere (apart from the minimal 32bit), nor a guaranteed to be supported page size.
This small series is a first attempt at making these things computed at runtime by making the default something else on systems that do not support it. It also makes the supported page sizes dynamically discovered. The initial patch addresses an issue that has already been addressed separately, and is only there so that I don't get shouted at by some robot.
With that, the selftests do run on the M1, with the exception of the memslot tests that are freaked out by the use of 16kB pages on the host and 4kB in the guest. Maybe I'll implement some form of 16kB support in the future.
Marc Zyngier (5):
KVM: selftests: Fix vm_compute_max_gfn on !x86
KVM: selftests: Initialise default mode in each test
KVM: selftests: arm64: Introduce a variable default IPA size
KVM: selftests: arm64: Check for supported page sizes
KVM: selftests: arm64: Add support for VM_MODE_P36V48_{4K,64K}
.../selftests/kvm/aarch64/arch_timer.c | 3 + .../selftests/kvm/aarch64/debug-exceptions.c | 3 + .../selftests/kvm/aarch64/get-reg-list.c | 3 + .../selftests/kvm/aarch64/psci_cpu_on_test.c | 3 + .../testing/selftests/kvm/aarch64/vgic_init.c | 3 + .../testing/selftests/kvm/include/kvm_util.h | 15 ++-- .../selftests/kvm/kvm_binary_stats_test.c | 3 + .../selftests/kvm/kvm_create_max_vcpus.c | 3 + .../selftests/kvm/lib/aarch64/processor.c | 8 ++ tools/testing/selftests/kvm/lib/guest_modes.c | 77 +++++++++++++++++-- tools/testing/selftests/kvm/lib/kvm_util.c | 6 ++ .../testing/selftests/kvm/memslot_perf_test.c | 4 + tools/testing/selftests/kvm/rseq_test.c | 3 + .../selftests/kvm/set_memory_region_test.c | 4 + tools/testing/selftests/kvm/steal_time.c | 3 + 15 files changed, 131 insertions(+), 10 deletions(-)
Signature · 1 line
2.30.2
Marc Zyngier
maintainerPATCH 1/5 KVM: selftests: Fix vm_compute_max_gfn on !x86
Compiling the selftestts on arm64 leads to this:
gcc -Wall -Wstrict-prototypes -Wuninitialized -O2 -g -std=gnu99 -fno-stack-protector -fno-PIE -I../../../../tools/include -I../../../../tools/arch/arm64/include -I../../../../usr/include/ -Iinclude -Ilib -Iinclude/aarch64 -I.. -c lib/kvm_util.c -o /home/maz/arm-platforms/tools/testing/selftests/kvm/lib/kvm_util.o
In file included from lib/kvm_util.c:10:include/kvm_util.h: In function ‘vm_compute_max_gfn’:include/kvm_util.h:79:21: error: invalid use of undefined type ‘struct kvm_vm’
79 | return ((1ULL << vm->pa_bits) >> vm->page_shift) - 1;
| ^~include/kvm_util.h:79:37: error: invalid use of undefined type ‘struct kvm_vm’
79 | return ((1ULL << vm->pa_bits) >> vm->page_shift) - 1;
| ^~
[...]
This is all because struct kvm_vm is not defined yet (only declared). Sidestep the whole issue by making vm_compute_max_gfn() a macro.
--- tools/testing/selftests/kvm/include/kvm_util.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
tools/testing/selftests/kvm/include/kvm_util.h +5 -4
@@ -74,10 +74,11 @@ enum vm_guest_mode {#if defined(__x86_64__)unsigned long vm_compute_max_gfn (struct kvm_vm *vm);#else -static inline unsigned long vm_compute_max_gfn (struct kvm_vm *vm) -{ -return ((1ULL << vm->pa_bits) >> vm->page_shift) -1 ; -} +#define vm_compute_max_gfn (vm) \ + ({ \ + struct kvm_vm *__vm = vm; \ + ((1ULL << __vm->pa_bits) >> __vm->page_shift) - 1; \ + })#endif #define MIN_PAGE_SIZE (1U << MIN_PAGE_SHIFT)
Signature · 1 line
2.30.2
Marc Zyngier
maintainerPATCH 2/5 KVM: selftests: Initialise default mode in each test
In reply to Marc ZyngierAs we are going to add support for a variable default mode on arm64, let's make sure it is setup first by sprinkling a number of calls to get_modes_append_default() when the test starts.
--- tools/testing/selftests/kvm/aarch64/arch_timer.c | 3 +++ tools/testing/selftests/kvm/aarch64/debug-exceptions.c | 3 +++ tools/testing/selftests/kvm/aarch64/get-reg-list.c | 3 +++ tools/testing/selftests/kvm/aarch64/psci_cpu_on_test.c | 3 +++ tools/testing/selftests/kvm/aarch64/vgic_init.c | 3 +++ tools/testing/selftests/kvm/kvm_binary_stats_test.c | 3 +++ tools/testing/selftests/kvm/kvm_create_max_vcpus.c | 3 +++ tools/testing/selftests/kvm/memslot_perf_test.c | 4 ++++ tools/testing/selftests/kvm/rseq_test.c | 3 +++ tools/testing/selftests/kvm/set_memory_region_test.c | 4 ++++ tools/testing/selftests/kvm/steal_time.c | 3 +++ 11 files changed, 35 insertions(+)
tools/testing/selftests/kvm/aarch64/arch_timer.c +3 -0
@@ -35,6 +35,7 @@#include "arch_timer.h" #include "gic.h" #include "vgic.h" +#include "guest_modes.h" #define NR_VCPUS_DEF 4#define NR_TEST_ITERS_DEF 5
@@ -460,6 +461,8 @@ int main(int argc, char *argv[]) {struct kvm_vm *vm; +guest_modes_append_default (); +/* Tell stdout not to buffer its content */ setbuf (stdout,NULL );
tools/testing/selftests/kvm/aarch64/debug-exceptions.c +3 -0
@@ -2,6 +2,7 @@#include <test_util.h> #include <kvm_util.h> #include <processor.h> +#include <guest_modes.h> #define VCPU_ID 0
@@ -200,6 +201,8 @@ int main(int argc, char *argv[])struct ucall uc;int stage; +guest_modes_append_default (); + vm =vm_create_default (VCPU_ID ,0 , guest_code);ucall_init (vm,NULL );
tools/testing/selftests/kvm/aarch64/get-reg-list.c +3 -0
@@ -33,6 +33,7 @@#include "kvm_util.h" #include "test_util.h" #include "processor.h" +#include "guest_modes.h" static struct kvm_reg_list *reg_list;static __u64 *blessed_reg, blessed_n;
@@ -588,6 +589,8 @@ int main(int ac, char **av)int i, ret =0 ;pid_t pid; +guest_modes_append_default (); +for (i =1 ; i < ac; ++i) {if (strcmp (av[i],"--core-reg-fixup" ) ==0 ) fixup_core_regs = true;
tools/testing/selftests/kvm/aarch64/psci_cpu_on_test.c +3 -0
@@ -16,6 +16,7 @@#include "kvm_util.h" #include "processor.h" #include "test_util.h" +#include "guest_modes.h" #define VCPU_ID_SOURCE 0#define VCPU_ID_TARGET 1
@@ -76,6 +77,8 @@ int main(void)struct kvm_vm *vm;struct ucall uc; +guest_modes_append_default (); + vm =vm_create (VM_MODE_DEFAULT ,DEFAULT_GUEST_PHY_PAGES ,O_RDWR );kvm_vm_elf_load (vm, program_invocation_name);ucall_init (vm,NULL );
tools/testing/selftests/kvm/aarch64/vgic_init.c +3 -0
@@ -14,6 +14,7 @@#include "kvm_util.h" #include "processor.h" #include "vgic.h" +#include "guest_modes.h" #define NR_VCPUS 4
@@ -699,6 +700,8 @@ int main(int ac, char **av)int ret;int pa_bits; +guest_modes_append_default (); + pa_bits = vm_guest_mode_params[VM_MODE_DEFAULT ].pa_bits; max_phys_size =1ULL << pa_bits;
tools/testing/selftests/kvm/kvm_binary_stats_test.c +3 -0
@@ -17,6 +17,7 @@#include "test_util.h" #include "kvm_util.h" +#include "guest_modes.h" #include "asm/kvm.h" #include "linux/kvm.h"
@@ -207,6 +208,8 @@ int main(int argc, char *argv[])int max_vm =DEFAULT_NUM_VM ;int max_vcpu =DEFAULT_NUM_VCPU ; +guest_modes_append_default (); +/* Get the number of VMs and VCPUs that would be created for testing. */ if (argc >1 ) { max_vm =strtol (argv[1 ],NULL ,0 );
tools/testing/selftests/kvm/kvm_create_max_vcpus.c +3 -0
@@ -17,6 +17,7 @@#include "test_util.h" #include "kvm_util.h" +#include "guest_modes.h" #include "asm/kvm.h" #include "linux/kvm.h"
@@ -51,6 +52,8 @@ int main(int argc, char *argv[])pr_info ("KVM_CAP_MAX_VCPU_ID: %d\n" , kvm_max_vcpu_id);pr_info ("KVM_CAP_MAX_VCPUS: %d\n" , kvm_max_vcpus); +guest_modes_append_default (); +/* * Check that we're allowed to open nr_fds_wanted file descriptors and * try raising the limits if needed.
tools/testing/selftests/kvm/memslot_perf_test.c +4 -0
@@ -25,6 +25,8 @@#include <kvm_util.h> #include <processor.h> +#include "guest_modes.h" +#define VCPU_ID 0#define MEM_SIZE ((512U << 20) + 4096)
@@ -1015,6 +1017,8 @@ int main(int argc, char *argv[])if (!parse_args (argc, argv, &targs))return -1 ; +guest_modes_append_default (); + rbestslottime.slottimens =0 ;for (tctr = targs.tfirst; tctr <= targs.tlast; tctr++) {const struct test_data *data = &tests[tctr];
tools/testing/selftests/kvm/rseq_test.c +3 -0
@@ -19,6 +19,7 @@#include "kvm_util.h" #include "processor.h" #include "test_util.h" +#include "guest_modes.h" #define VCPU_ID 0
@@ -223,6 +224,8 @@ int main(int argc, char *argv[])sys_rseq (0 ); +guest_modes_append_default (); +/* * Create and run a dummy VM that immediately exits to userspace via * GUEST_SYNC, while concurrently migrating the process by setting its
tools/testing/selftests/kvm/set_memory_region_test.c +4 -0
@@ -17,6 +17,8 @@#include <kvm_util.h> #include <processor.h> +#include "guest_modes.h" +#define VCPU_ID 0/*
@@ -413,6 +415,8 @@ int main(int argc, char *argv[])int i, loops;#endif +guest_modes_append_default (); +/* Tell stdout not to buffer its content */ setbuf (stdout,NULL );
tools/testing/selftests/kvm/steal_time.c +3 -0
@@ -16,6 +16,7 @@#include "test_util.h" #include "kvm_util.h" #include "processor.h" +#include "guest_modes.h" #define NR_VCPUS 4#define ST_GPA_BASE (1 << 30)
@@ -273,6 +274,8 @@ int main(int ac, char **av)pthread_attr_setaffinity_np (&attr,sizeof (cpu_set_t), &cpuset);pthread_setaffinity_np (pthread_self (),sizeof (cpu_set_t), &cpuset); +guest_modes_append_default (); +/* Create a one VCPU guest and an identity mapped memslot for the steal time structure */ vm =vm_create_default (0 ,0 , guest_code); gpages =vm_calc_num_guest_pages (VM_MODE_DEFAULT ,STEAL_TIME_SIZE *NR_VCPUS );
Signature · 1 line
2.30.2
Re: [PATCH 2/5] KVM: selftests: Initialise default mode in each test
Quoted 5 lines · Marc Zyngier
As we are going to add support for a variable default mode on arm64, let's make sure it is setup first by sprinkling a number of calls to
get_modes_append_default()when the test starts.Signed-off-by Marc Zyngier <[email protected]>
Quoted 12 lines
--- tools/testing/selftests/kvm/aarch64/arch_timer.c | 3 +++ tools/testing/selftests/kvm/aarch64/debug-exceptions.c | 3 +++ tools/testing/selftests/kvm/aarch64/get-reg-list.c | 3 +++ tools/testing/selftests/kvm/aarch64/psci_cpu_on_test.c | 3 +++ tools/testing/selftests/kvm/aarch64/vgic_init.c | 3 +++ tools/testing/selftests/kvm/kvm_binary_stats_test.c | 3 +++ tools/testing/selftests/kvm/kvm_create_max_vcpus.c | 3 +++ tools/testing/selftests/kvm/memslot_perf_test.c | 4 ++++ tools/testing/selftests/kvm/rseq_test.c | 3 +++ tools/testing/selftests/kvm/set_memory_region_test.c | 4 ++++ tools/testing/selftests/kvm/steal_time.c | 3 +++
I wish there was a better way to set the defaults for each test without requiring a function call to be put at the beginning of each test. Maybe we should create a constructor function? I.e.
tools/testing/selftests/kvm/Makefile +1 -1
@@ -148,7 +148,7 @@ LDFLAGS += -pthread $(no-pie-option) $(pgste-option) # $(TEST_GEN_PROGS) starts with $(OUTPUT)/ include ../lib.mk -STATIC_LIBS := $(OUTPUT)/libkvm.a +STATIC_LIBS := lib/init.o $(OUTPUT)/libkvm.a LIBKVM_C := $(filter %.c,$(LIBKVM)) LIBKVM_S := $(filter %.S,$(LIBKVM)) LIBKVM_C_OBJ := $(patsubst %.c, $(OUTPUT)/%.o, $(LIBKVM_C))
tools/testing/selftests/kvm/lib/init.c new file +6 -0
@@ -0,0 +1,6 @@ +#include "guest_modes.h" + +void __attribute__((constructor))main_init (void ) +{ +#ifdef __aarch64__ +guest_modes_set_default ();
+#endif
+}
Thanks,
drew
_______________________________________________
kvmarm mailing list
[email protected]
https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
Marc Zyngier
maintainerPATCH 3/5 KVM: selftests: arm64: Introduce a variable default IPA size
In reply to Marc ZyngierContrary to popular belief, there is no such thing as a default IPA size on arm64. Anything goes, and implementations are the usual Wild West.
The selftest infrastructure default to 40bit IPA, which obviously doesn't work for some systems out there.
Turn VM_MODE_DEFAULT from a constant into a variable, and let guest_modes_append_default() populate it, depending on what the HW can do. In order to preserve the current behaviour, we still pick 40bits IPA as the default if it is available, and the largest supported IPA space otherwise.
--- .../testing/selftests/kvm/include/kvm_util.h | 4 ++- tools/testing/selftests/kvm/lib/guest_modes.c | 28 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-)
tools/testing/selftests/kvm/include/kvm_util.h +3 -1
@@ -53,7 +53,9 @@ enum vm_guest_mode {#if defined(__aarch64__) -#define VM_MODE_DEFAULT VM_MODE_P40V48_4K +extern enum vm_guest_mode vm_mode_default; + +#define VM_MODE_DEFAULT vm_mode_default#define MIN_PAGE_SHIFT 12U#define ptes_per_page (page_size) ((page_size) / 8)
tools/testing/selftests/kvm/lib/guest_modes.c +26 -2
@@ -4,22 +4,46 @@*/ #include "guest_modes.h" +#ifdef __aarch64__ +enum vm_guest_mode vm_mode_default; +#endif +struct guest_mode guest_modes[NUM_VM_MODES ];void guest_modes_append_default (void ) { +#ifndef __aarch64__guest_mode_append (VM_MODE_DEFAULT , true, true); - +#endif #ifdef __aarch64__ -guest_mode_append (VM_MODE_P40V48_64K , true, true); {unsigned int limit =kvm_check_cap (KVM_CAP_ARM_VM_IPA_SIZE ); +int i; + + vm_mode_default =NUM_VM_MODES ; +if (limit >=52 )guest_mode_append (VM_MODE_P52V48_64K , true, true);if (limit >=48 ) {guest_mode_append (VM_MODE_P48V48_4K , true, true);guest_mode_append (VM_MODE_P48V48_64K , true, true); } +if (limit >=40 ) { +guest_mode_append (VM_MODE_P40V48_4K , true, true); +guest_mode_append (VM_MODE_P40V48_64K , true, true); + vm_mode_default =VM_MODE_P40V48_4K ; + } + +/* Pick the largest supported IPA size */ +for (i =0 ; + vm_mode_default ==NUM_VM_MODES && i <NUM_VM_MODES ; + i++) { +if (guest_modes[i].supported) + vm_mode_default = i; + } + +TEST_ASSERT (vm_mode_default !=NUM_VM_MODES , +"No supported mode!" ); }#endif #ifdef __s390x__
Signature · 1 line
2.30.2
Re: [PATCH 3/5] KVM: selftests: arm64: Introduce a variable default IPA size
Quoted 65 lines · Marc Zyngier
Contrary to popular belief, there is no such thing as a default IPA size on arm64. Anything goes, and implementations are the usual Wild West.
The selftest infrastructure default to 40bit IPA, which obviously doesn't work for some systems out there.
Turn
VM_MODE_DEFAULTfrom a constant into a variable, and letguest_modes_append_default()populate it, depending on what the HW can do. In order to preserve the current behaviour, we still pick 40bits IPA as the default if it is available, and the largest supported IPA space otherwise.Signed-off-by Marc Zyngier <[email protected]>--- .../testing/selftests/kvm/include/kvm_util.h | 4 ++- tools/testing/selftests/kvm/lib/guest_modes.c | 28 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-)tools/testing/selftests/kvm/include/kvm_util.h +3
-1@@ -53,7 +53,9 @@ enum vm_guest_mode {#if defined(__aarch64__) -#define VM_MODE_DEFAULT VM_MODE_P40V48_4K +extern enum vm_guest_mode vm_mode_default; + +#define VM_MODE_DEFAULT vm_mode_default#define MIN_PAGE_SHIFT 12U#define ptes_per_page (page_size) ((page_size) / 8)tools/testing/selftests/kvm/lib/guest_modes.c +10
-2@@ -4,22 +4,46 @@*/ #include "guest_modes.h" +#ifdef __aarch64__ +enum vm_guest_mode vm_mode_default; +#endif +struct guest_mode guest_modes[NUM_VM_MODES ];void guest_modes_append_default (void ) { +#ifndef __aarch64__guest_mode_append (VM_MODE_DEFAULT , true, true); - +#endif #ifdef __aarch64__ -guest_mode_append (VM_MODE_P40V48_64K , true, true); {unsigned int limit =kvm_check_cap (KVM_CAP_ARM_VM_IPA_SIZE ); +int i; + + vm_mode_default =NUM_VM_MODES ; +if (limit >=52 )guest_mode_append (VM_MODE_P52V48_64K , true, true);if (limit >=48 ) {
tools/testing/selftests/kvm/lib/guest_modes.c line 37
Quoted 10 lines
tools/testing/selftests/kvm/lib/guest_modes.c +7
-0guest_mode_append (VM_MODE_P48V48_4K , true, true);guest_mode_append (VM_MODE_P48V48_64K , true, true); } +if (limit >=40 ) { +guest_mode_append (VM_MODE_P40V48_4K , true, true); +guest_mode_append (VM_MODE_P40V48_64K , true, true); + vm_mode_default =VM_MODE_P40V48_4K ; + } + +/* Pick the largest supported IPA size */
The guest_modes array isn't sorted from smallest to largest PA addresses, although it could be.
tools/testing/selftests/kvm/lib/guest_modes.c line 40
Quoted 3 lines
tools/testing/selftests/kvm/lib/guest_modes.c +3
-0+for (i =0 ; + vm_mode_default ==NUM_VM_MODES && i <NUM_VM_MODES ; + i++) {
Feel free to put this on one line.
tools/testing/selftests/kvm/lib/guest_modes.c line 41
Quoted 1 line
tools/testing/selftests/kvm/lib/guest_modes.c +1
-0+if (guest_modes[i].supported)
A bit safer would be to check both .supported and .enabled.
Quoted 11 lines
tools/testing/selftests/kvm/lib/guest_modes.c +5
-0+ vm_mode_default = i; + } + +TEST_ASSERT (vm_mode_default !=NUM_VM_MODES , +"No supported mode!" ); }#endif #ifdef __s390x__Signature · 1 line
2.30.2
Thanks,
drew
Marc Zyngier
maintainerPATCH 4/5 KVM: selftests: arm64: Check for supported page sizes
In reply to Marc ZyngierJust 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.
--- tools/testing/selftests/kvm/lib/guest_modes.c | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-)
tools/testing/selftests/kvm/lib/guest_modes.c +45 -6
@@ -5,7 +5,42 @@#include "guest_modes.h" #ifdef __aarch64__ +#include "processor.h" enum vm_guest_mode vm_mode_default; +static void get_supported_psz (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); +}#endif struct guest_mode guest_modes[NUM_VM_MODES ];
@@ -18,20 +53,24 @@ void guest_modes_append_default(void)#ifdef __aarch64__ {unsigned int limit =kvm_check_cap (KVM_CAP_ARM_VM_IPA_SIZE ); +bool ps4k, ps16k, ps64k;int i; +get_supported_psz (limit, &ps4k, &ps16k, &ps64k); + vm_mode_default =NUM_VM_MODES ;if (limit >=52 ) -guest_mode_append (VM_MODE_P52V48_64K , true, true); +guest_mode_append (VM_MODE_P52V48_64K , ps64k, ps64k);if (limit >=48 ) { -guest_mode_append (VM_MODE_P48V48_4K , true, true); -guest_mode_append (VM_MODE_P48V48_64K , true, true); +guest_mode_append (VM_MODE_P48V48_4K , ps4k, ps4k); +guest_mode_append (VM_MODE_P48V48_64K , ps64k, ps64k); }if (limit >=40 ) { -guest_mode_append (VM_MODE_P40V48_4K , true, true); -guest_mode_append (VM_MODE_P40V48_64K , true, true); - vm_mode_default =VM_MODE_P40V48_4K ; +guest_mode_append (VM_MODE_P40V48_4K , ps4k, ps4k); +guest_mode_append (VM_MODE_P40V48_64K , ps64k, ps64k); +if (ps4k) + vm_mode_default =VM_MODE_P40V48_4K ; }/* Pick the largest supported IPA size */
Signature · 1 line
2.30.2
Re: [PATCH 4/5] KVM: selftests: arm64: Check for supported page sizes
Quoted 45 lines · Marc Zyngier
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 <[email protected]>--- tools/testing/selftests/kvm/lib/guest_modes.c | 51 ++++++++++++++++--- 1 file changed, 45 insertions(+), 6 deletions(-)tools/testing/selftests/kvm/lib/guest_modes.c +25
-0@@ -5,7 +5,42 @@#include "guest_modes.h" #ifdef __aarch64__ +#include "processor.h" enum vm_guest_mode vm_mode_default; +static void get_supported_psz (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 , ®);
tools/testing/selftests/kvm/lib/guest_modes.c line 43
Quoted 10 lines
tools/testing/selftests/kvm/lib/guest_modes.c +10
-0+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); +}
I think I'd prefer stashing this function in lib/aarch64/processor.c and naming it aarch64_get_supported_page_sizes.
Quoted 37 lines
tools/testing/selftests/kvm/lib/guest_modes.c +10
-6#endif struct guest_mode guest_modes[NUM_VM_MODES ];@@ -18,20 +53,24 @@ void guest_modes_append_default(void)#ifdef __aarch64__ {unsigned int limit =kvm_check_cap (KVM_CAP_ARM_VM_IPA_SIZE ); +bool ps4k, ps16k, ps64k;int i; +get_supported_psz (limit, &ps4k, &ps16k, &ps64k); + vm_mode_default =NUM_VM_MODES ;if (limit >=52 ) -guest_mode_append (VM_MODE_P52V48_64K , true, true); +guest_mode_append (VM_MODE_P52V48_64K , ps64k, ps64k);if (limit >=48 ) { -guest_mode_append (VM_MODE_P48V48_4K , true, true); -guest_mode_append (VM_MODE_P48V48_64K , true, true); +guest_mode_append (VM_MODE_P48V48_4K , ps4k, ps4k); +guest_mode_append (VM_MODE_P48V48_64K , ps64k, ps64k); }if (limit >=40 ) { -guest_mode_append (VM_MODE_P40V48_4K , true, true); -guest_mode_append (VM_MODE_P40V48_64K , true, true); - vm_mode_default =VM_MODE_P40V48_4K ; +guest_mode_append (VM_MODE_P40V48_4K , ps4k, ps4k); +guest_mode_append (VM_MODE_P40V48_64K , ps64k, ps64k); +if (ps4k) + vm_mode_default =VM_MODE_P40V48_4K ; }/* Pick the largest supported IPA size */ Signature · 1 line
2.30.2
Thanks,
drew
Marc Zyngier
maintainerPATCH 5/5 KVM: selftests: arm64: Add support for VM_MODE_P36V48_{4K,64K}
In reply to Marc ZyngierSome of the arm64 systems out there have an IPA space that is positively tiny. Nonetheless, they make great KVM hosts.
Add support for 36bit IPA support with 4kB pages, which makes some of the fruity machines happy. Whilst we're at it, add support for 64kB pages as well, though these boxes have no support for it.
16kB is left as a exercise for the eager reviewer.
--- tools/testing/selftests/kvm/include/kvm_util.h | 2 ++ tools/testing/selftests/kvm/lib/aarch64/processor.c | 8 ++++++++ tools/testing/selftests/kvm/lib/guest_modes.c | 4 ++++ tools/testing/selftests/kvm/lib/kvm_util.c | 6 ++++++ 4 files changed, 20 insertions(+)
tools/testing/selftests/kvm/include/kvm_util.h +2 -0
@@ -48,6 +48,8 @@ enum vm_guest_mode {VM_MODE_PXXV48_4K ,/* For 48bits VA but ANY bits PA */ VM_MODE_P47V64_4K ,VM_MODE_P44V64_4K , +VM_MODE_P36V48_4K , +VM_MODE_P36V48_64K , NUM_VM_MODES, };
tools/testing/selftests/kvm/lib/aarch64/processor.c +8 -0
@@ -264,6 +264,14 @@ void aarch64_vcpu_setup(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_vcpu_init tcr_el1 |=1ul <<14 ;/* TG0 = 64KB */ tcr_el1 |=2ul <<32 ;/* IPS = 40 bits */ break ; +case VM_MODE_P36V48_4K : + tcr_el1 |=0ul <<14 ;/* TG0 = 4KB */ + tcr_el1 |=1ul <<32 ;/* IPS = 36 bits */ +break ; +case VM_MODE_P36V48_64K : + tcr_el1 |=1ul <<14 ;/* TG0 = 64KB */ + tcr_el1 |=1ul <<32 ;/* IPS = 36 bits */ +break ;default :TEST_FAIL ("Unknown guest mode, mode: 0x%x" , vm->mode); }
tools/testing/selftests/kvm/lib/guest_modes.c +4 -0
@@ -72,6 +72,10 @@ void guest_modes_append_default(void)if (ps4k) vm_mode_default =VM_MODE_P40V48_4K ; } +if (limit >=36 ) { +guest_mode_append (VM_MODE_P36V48_4K , ps4k, ps4k); +guest_mode_append (VM_MODE_P36V48_64K , ps64k, ps64k); + }/* Pick the largest supported IPA size */ for (i = 0;
tools/testing/selftests/kvm/lib/kvm_util.c +6 -0
@@ -172,6 +172,8 @@ const char *vm_guest_mode_string(uint32_t i) [VM_MODE_PXXV48_4K] = "PA-bits:ANY, VA-bits:48, 4K pages", [VM_MODE_P47V64_4K] = "PA-bits:47, VA-bits:64, 4K pages", [VM_MODE_P44V64_4K] = "PA-bits:44, VA-bits:64, 4K pages", + [VM_MODE_P36V48_4K] = "PA-bits:36, VA-bits:48, 4K pages", + [VM_MODE_P36V48_64K ] ="PA-bits:36, VA-bits:48, 64K pages" , };_Static_assert (sizeof (strings)/sizeof (char *) ==NUM_VM_MODES ,"Missing new mode strings?" );
@@ -191,6 +193,8 @@ const struct vm_guest_mode_params vm_guest_mode_params[] = { [VM_MODE_PXXV48_4K] = { 0, 0, 0x1000, 12 }, [VM_MODE_P47V64_4K] = { 47, 64, 0x1000, 12 }, [VM_MODE_P44V64_4K] = { 44, 64, 0x1000, 12 }, + [VM_MODE_P36V48_4K] = { 36, 48, 0x1000, 12 }, + [VM_MODE_P36V48_64K] = { 36, 48, 0x10000, 16 }, };_Static_assert (sizeof (vm_guest_mode_params)/sizeof (struct vm_guest_mode_params ) ==NUM_VM_MODES ,"Missing new mode params?" );
@@ -252,9 +256,11 @@ struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) vm->pgtable_levels =3 ;break ;case VM_MODE_P40V48_4K : +case VM_MODE_P36V48_4K : vm->pgtable_levels =4 ;break ;case VM_MODE_P40V48_64K : +case VM_MODE_P36V48_64K : vm->pgtable_levels =3 ;break ;case VM_MODE_PXXV48_4K :
Signature · 1 line
2.30.2
Re: [PATCH 5/5] KVM: selftests: arm64: Add support for VM_MODE_P36V48_{4K,64K}
Quoted 9 lines · Marc Zyngier
Some of the arm64 systems out there have an IPA space that is positively tiny. Nonetheless, they make great KVM hosts.
Add support for 36bit IPA support with 4kB pages, which makes some of the fruity machines happy. Whilst we're at it, add support for 64kB pages as well, though these boxes have no support for it.
16kB is left as a exercise for the eager reviewer.
Quoted 8 lines
Signed-off-by Marc Zyngier <[email protected]>--- tools/testing/selftests/kvm/include/kvm_util.h | 2 ++ tools/testing/selftests/kvm/lib/aarch64/processor.c | 8 ++++++++ tools/testing/selftests/kvm/lib/guest_modes.c | 4 ++++ tools/testing/selftests/kvm/lib/kvm_util.c | 6 ++++++ 4 files changed, 20 insertions(+)