Exercise reads and writes through low and high guest virtual addresses in the 52-bit VA modes with 4K, 16K and 64K pages. Verify that mappings to the same GPA share data and mappings to distinct GPAs remain independent.
Signed-off-by: Itaru Kitayama <[email protected]> --- tools/testing/selftests/kvm/Makefile.kvm | 1 + tools/testing/selftests/kvm/arm64/lpa_test.c | 124 +++++++++++++++++++++++++++ 2 files changed, 125 insertions(+) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 96bab7002d39..1e9d059ffb24 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -179,6 +179,7 @@ TEST_GEN_PROGS_arm64 += arm64/hello_el2 TEST_GEN_PROGS_arm64 += arm64/host_sve TEST_GEN_PROGS_arm64 += arm64/hypercalls TEST_GEN_PROGS_arm64 += arm64/external_aborts +TEST_GEN_PROGS_arm64 += arm64/lpa_test TEST_GEN_PROGS_arm64 += arm64/mmio_sign_ext TEST_GEN_PROGS_arm64 += arm64/page_fault_test TEST_GEN_PROGS_arm64 += arm64/psci_test diff --git a/tools/testing/selftests/kvm/arm64/lpa_test.c b/tools/testing/selftests/kvm/arm64/lpa_test.c new file mode 100644 index 000000000000..8fe6f254db28 --- /dev/null +++ b/tools/testing/selftests/kvm/arm64/lpa_test.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Higher virtual addresses read/write test + */ +#include <test_util.h> + +#include "kvm_syscalls.h" +#include "kvm_util.h" +#include "ucall_common.h" +#include "guest_modes.h" +#include "processor.h" + +#define LOW_GVA 0xc0000000 +#define HIGH_GVA (LOW_GVA | BIT(48)) + +static void guest_code(void) +{ + u64 *low = (u64 *)LOW_GVA; + u64 *high = (u64 *)HIGH_GVA; + + WRITE_ONCE(*low, 1); + GUEST_ASSERT_EQ(READ_ONCE(*high), 1); + WRITE_ONCE(*high, 2); + GUEST_ASSERT_EQ(READ_ONCE(*low), 2); + + GUEST_SYNC(0); + + asm volatile("dsb sy\n\t" + "tlbi vmalle1is\n\t" + "dsb sy\n\t" + "isb" + : : : "memory"); + + GUEST_SYNC(1); /* Host installs HIGH_GVA -> gpa_b. */ + + asm volatile("dsb sy\n\t" + "isb\n\t" + : : : "memory"); + + /* low and high map to different GPAs. */ + WRITE_ONCE(*low, 1); + WRITE_ONCE(*high, 2); + + /* Check both after both writes to detect accidental aliasing. */ + GUEST_ASSERT_EQ(READ_ONCE(*low), 1); + GUEST_ASSERT_EQ(READ_ONCE(*high), 2); + + /* Updating the low mapping must not change the high mapping. */ + WRITE_ONCE(*low, 3); + + GUEST_ASSERT_EQ(READ_ONCE(*low), 3); + GUEST_ASSERT_EQ(READ_ONCE(*high), 2); + + GUEST_DONE(); +} + +static void run_test(enum vm_guest_mode mode, void *arg) +{ + unsigned int *nr_tests = arg; + struct kvm_vcpu_init init; + struct kvm_vm *vm; + struct kvm_vcpu *vcpu; + struct ucall uc; + + if (mode != VM_MODE_P52V52_4K && + mode != VM_MODE_P52V52_16K && + mode != VM_MODE_P52V52_64K) + return; + + vm = __vm_create(VM_SHAPE(mode), 1, 0); + kvm_get_default_vcpu_target(vm, &init); + vcpu = aarch64_vcpu_add(vm, 0, &init, guest_code); + kvm_arch_vm_finalize_vcpus(vm); + + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(vcpu); + + u64 gpa_a = vm_phy_pages_alloc(vm, 1, 0, 0); + u64 gpa_b = vm_phy_pages_alloc(vm, 1, 0, 0); + + virt_pg_map(vm, LOW_GVA, gpa_a); + virt_pg_map(vm, HIGH_GVA, gpa_a); + + for (;;) { + vcpu_run(vcpu); + switch (get_ucall(vcpu, &uc)) { + case UCALL_DONE: + goto done; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + case UCALL_SYNC: + switch (uc.args[1]) { + case 0: + WRITE_ONCE(*virt_get_pte_hva(vm, HIGH_GVA), 0); + break; + case 1: + virt_pg_map(vm, HIGH_GVA, gpa_b); + break; + default: + TEST_FAIL("Unexpected sync stage: %lu\n", uc.args[1]); + } + /* Complete the host's PTE store before resuming the guest. */ + asm volatile("dsb sy" : : : "memory"); + break; + default: + TEST_FAIL("Unhandled ucall: %ld\n", uc.cmd); + } + } + +done: + kvm_vm_free(vm); + (*nr_tests)++; +} + +int main(int argc, char **argv) +{ + unsigned int nr_tests = 0; + + for_each_guest_mode(run_test, &nr_tests); + if (!nr_tests) + ksft_exit_skip("No supported 52-bit VA guest mode; skipping test\n"); + return 0; +} -- 2.43.0

