From patchwork Fri Apr 8 00:41:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805959 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 03C34C4332F for ; Fri, 8 Apr 2022 00:41:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233057AbiDHAnf (ORCPT ); Thu, 7 Apr 2022 20:43:35 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38188 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233055AbiDHAna (ORCPT ); Thu, 7 Apr 2022 20:43:30 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6A9791777E4 for ; Thu, 7 Apr 2022 17:41:25 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id l2-20020a17090ad10200b001ca56de815aso4705994pju.0 for ; Thu, 07 Apr 2022 17:41:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=6LDLEOPE/B2F1uvwHczV2kc6SFAwnoNWC1JTMWdq4NQ=; b=WFscQfWierF989JFuuAXeoyw/hgIphIrzYaWPRS65U53hp45shQ6/4B17lbD1Vc0oN ZzJcp0ebA2PdnBU0m1KxOksFigKd2OD6KMw9gC2W9bNLn7z4afOv0C6OGO59eKIe6c4p DEAffen/bitZ5KBd5KFCGIKQ85UdLxa274TYwemdCFVQ4f4IauyhQlzLfcFeQhQ/UAlA PZ/KxXPTLeem07D4QwI12oC63w3sjwN/eKPR25jYwMcT500kjMCqsuy8jzF9LqWPjT+b yFrVrVxb6N5NOeNuFMgfgxduBSFnob/Xrki2/6+vVJBV/zh7NQchaJzNmeUhs73ZB49r Sb4Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=6LDLEOPE/B2F1uvwHczV2kc6SFAwnoNWC1JTMWdq4NQ=; b=no9XfbRDBRGDQ7D8S/7zTobWD9ASsS7qbYUrd7RrjG1UCIohRF+ALf4VXSnxRlsQk+ uBth8r7QEbxL9/UcUDF++WFYhwatYgna7Lsq9i4CQdYE2vsHwKdHfv2GiW18LrKWqkwT 6SJ/xgO8vd17aRBaWhleMQhi0iR29ykqY0f4FXcbiDJfagTwm2JcHCYy1lw6PprRSAsC GDlGAMVjLZ0IPQHtco5chaEyVZSjurSMGHenrvog9isGYC9viROvUVKd+rHK3hXEc2HE YeIzTA1cUHl98K65A9AcJmDXG2zDgqWhE4yo+W5euxOpKkI+DN8TBGsrrM7BXaDo1S0R oDhQ== X-Gm-Message-State: AOAM5325KkQmVj5KHYf2XmL3T8uXDQATwYRWf5AJjRsDRDHtryURbaPg v9slqIW7bR28PL33uwC2afCznv7sjQYIQNhx7eK+e9O9lMMJDqxQ7HlwVhNI26yss4Bu58dQQ0u zDlURgyW0Gq+KKk4OUMn2H5NEMzi23owlm9BMc6OXY7pP/i77srsDD5g0SsH1L8E= X-Google-Smtp-Source: ABdhPJzeWTKhqo4Sz1btkgubw7/GYmUZdt2lP9SiB1XYjqv+31xkjK0YLVTfB4Fjlt7M2MqDOcgfF9BFImu7dg== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a05:6a00:1a06:b0:4fc:d6c5:f3d7 with SMTP id g6-20020a056a001a0600b004fcd6c5f3d7mr16948145pfv.53.1649378484603; Thu, 07 Apr 2022 17:41:24 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:08 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-2-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 01/13] KVM: selftests: Add a userfaultfd library From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Move the generic userfaultfd code out of demand_paging_test.c into a common library, userfaultfd_util. This library consists of a setup and a stop function. The setup function starts a thread for handling page faults using the handler callback function. This setup returns a uffd_desc object which is then used in the stop function (to wait and destroy the threads). Reviewed-by: Ben Gardon Signed-off-by: Ricardo Koller --- tools/testing/selftests/kvm/Makefile | 2 +- .../selftests/kvm/demand_paging_test.c | 227 +++--------------- .../selftests/kvm/include/userfaultfd_util.h | 47 ++++ .../selftests/kvm/lib/userfaultfd_util.c | 187 +++++++++++++++ 4 files changed, 264 insertions(+), 199 deletions(-) create mode 100644 tools/testing/selftests/kvm/include/userfaultfd_util.h create mode 100644 tools/testing/selftests/kvm/lib/userfaultfd_util.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 0e4926bc9a58..bc5f89b3700e 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -37,7 +37,7 @@ ifeq ($(ARCH),riscv) UNAME_M := riscv endif -LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/rbtree.c lib/sparsebit.c lib/test_util.c lib/guest_modes.c lib/perf_test_util.c +LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/rbtree.c lib/sparsebit.c lib/test_util.c lib/guest_modes.c lib/perf_test_util.c lib/userfaultfd_util.c LIBKVM_x86_64 = lib/x86_64/apic.c lib/x86_64/processor.c lib/x86_64/vmx.c lib/x86_64/svm.c lib/x86_64/ucall.c lib/x86_64/handlers.S LIBKVM_aarch64 = lib/aarch64/processor.c lib/aarch64/ucall.c lib/aarch64/handlers.S lib/aarch64/spinlock.c lib/aarch64/gic.c lib/aarch64/gic_v3.c lib/aarch64/vgic.c LIBKVM_s390x = lib/s390x/processor.c lib/s390x/ucall.c lib/s390x/diag318_test_handler.c diff --git a/tools/testing/selftests/kvm/demand_paging_test.c b/tools/testing/selftests/kvm/demand_paging_test.c index 6a719d065599..b3d457cecd68 100644 --- a/tools/testing/selftests/kvm/demand_paging_test.c +++ b/tools/testing/selftests/kvm/demand_paging_test.c @@ -22,23 +22,13 @@ #include "test_util.h" #include "perf_test_util.h" #include "guest_modes.h" +#include "userfaultfd_util.h" #ifdef __NR_userfaultfd -#ifdef PRINT_PER_PAGE_UPDATES -#define PER_PAGE_DEBUG(...) printf(__VA_ARGS__) -#else -#define PER_PAGE_DEBUG(...) _no_printf(__VA_ARGS__) -#endif - -#ifdef PRINT_PER_VCPU_UPDATES -#define PER_VCPU_DEBUG(...) printf(__VA_ARGS__) -#else -#define PER_VCPU_DEBUG(...) _no_printf(__VA_ARGS__) -#endif - static int nr_vcpus = 1; static uint64_t guest_percpu_mem_size = DEFAULT_PER_VCPU_MEM_SIZE; + static size_t demand_paging_size; static char *guest_data_prototype; @@ -69,9 +59,11 @@ static void vcpu_worker(struct perf_test_vcpu_args *vcpu_args) ts_diff.tv_sec, ts_diff.tv_nsec); } -static int handle_uffd_page_request(int uffd_mode, int uffd, uint64_t addr) +static int handle_uffd_page_request(int uffd_mode, int uffd, + struct uffd_msg *msg) { pid_t tid = syscall(__NR_gettid); + uint64_t addr = msg->arg.pagefault.address; struct timespec start; struct timespec ts_diff; int r; @@ -118,175 +110,32 @@ static int handle_uffd_page_request(int uffd_mode, int uffd, uint64_t addr) return 0; } -bool quit_uffd_thread; - -struct uffd_handler_args { +struct test_params { int uffd_mode; - int uffd; - int pipefd; - useconds_t delay; + useconds_t uffd_delay; + enum vm_mem_backing_src_type src_type; + bool partition_vcpu_memory_access; }; -static void *uffd_handler_thread_fn(void *arg) +static void prefault_mem(void *alias, uint64_t len) { - struct uffd_handler_args *uffd_args = (struct uffd_handler_args *)arg; - int uffd = uffd_args->uffd; - int pipefd = uffd_args->pipefd; - useconds_t delay = uffd_args->delay; - int64_t pages = 0; - struct timespec start; - struct timespec ts_diff; - - clock_gettime(CLOCK_MONOTONIC, &start); - while (!quit_uffd_thread) { - struct uffd_msg msg; - struct pollfd pollfd[2]; - char tmp_chr; - int r; - uint64_t addr; - - pollfd[0].fd = uffd; - pollfd[0].events = POLLIN; - pollfd[1].fd = pipefd; - pollfd[1].events = POLLIN; - - r = poll(pollfd, 2, -1); - switch (r) { - case -1: - pr_info("poll err"); - continue; - case 0: - continue; - case 1: - break; - default: - pr_info("Polling uffd returned %d", r); - return NULL; - } - - if (pollfd[0].revents & POLLERR) { - pr_info("uffd revents has POLLERR"); - return NULL; - } - - if (pollfd[1].revents & POLLIN) { - r = read(pollfd[1].fd, &tmp_chr, 1); - TEST_ASSERT(r == 1, - "Error reading pipefd in UFFD thread\n"); - return NULL; - } - - if (!(pollfd[0].revents & POLLIN)) - continue; - - r = read(uffd, &msg, sizeof(msg)); - if (r == -1) { - if (errno == EAGAIN) - continue; - pr_info("Read of uffd got errno %d\n", errno); - return NULL; - } - - if (r != sizeof(msg)) { - pr_info("Read on uffd returned unexpected size: %d bytes", r); - return NULL; - } - - if (!(msg.event & UFFD_EVENT_PAGEFAULT)) - continue; + size_t p; - if (delay) - usleep(delay); - addr = msg.arg.pagefault.address; - r = handle_uffd_page_request(uffd_args->uffd_mode, uffd, addr); - if (r < 0) - return NULL; - pages++; + TEST_ASSERT(alias != NULL, "Alias required for minor faults"); + for (p = 0; p < (len / demand_paging_size); ++p) { + memcpy(alias + (p * demand_paging_size), + guest_data_prototype, demand_paging_size); } - - ts_diff = timespec_elapsed(start); - PER_VCPU_DEBUG("userfaulted %ld pages over %ld.%.9lds. (%f/sec)\n", - pages, ts_diff.tv_sec, ts_diff.tv_nsec, - pages / ((double)ts_diff.tv_sec + (double)ts_diff.tv_nsec / 100000000.0)); - - return NULL; } -static void setup_demand_paging(struct kvm_vm *vm, - pthread_t *uffd_handler_thread, int pipefd, - int uffd_mode, useconds_t uffd_delay, - struct uffd_handler_args *uffd_args, - void *hva, void *alias, uint64_t len) -{ - bool is_minor = (uffd_mode == UFFDIO_REGISTER_MODE_MINOR); - int uffd; - struct uffdio_api uffdio_api; - struct uffdio_register uffdio_register; - uint64_t expected_ioctls = ((uint64_t) 1) << _UFFDIO_COPY; - - PER_PAGE_DEBUG("Userfaultfd %s mode, faults resolved with %s\n", - is_minor ? "MINOR" : "MISSING", - is_minor ? "UFFDIO_CONINUE" : "UFFDIO_COPY"); - - /* In order to get minor faults, prefault via the alias. */ - if (is_minor) { - size_t p; - - expected_ioctls = ((uint64_t) 1) << _UFFDIO_CONTINUE; - - TEST_ASSERT(alias != NULL, "Alias required for minor faults"); - for (p = 0; p < (len / demand_paging_size); ++p) { - memcpy(alias + (p * demand_paging_size), - guest_data_prototype, demand_paging_size); - } - } - - uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); - TEST_ASSERT(uffd >= 0, "uffd creation failed, errno: %d", errno); - - uffdio_api.api = UFFD_API; - uffdio_api.features = 0; - TEST_ASSERT(ioctl(uffd, UFFDIO_API, &uffdio_api) != -1, - "ioctl UFFDIO_API failed: %" PRIu64, - (uint64_t)uffdio_api.api); - - uffdio_register.range.start = (uint64_t)hva; - uffdio_register.range.len = len; - uffdio_register.mode = uffd_mode; - TEST_ASSERT(ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) != -1, - "ioctl UFFDIO_REGISTER failed"); - TEST_ASSERT((uffdio_register.ioctls & expected_ioctls) == - expected_ioctls, "missing userfaultfd ioctls"); - - uffd_args->uffd_mode = uffd_mode; - uffd_args->uffd = uffd; - uffd_args->pipefd = pipefd; - uffd_args->delay = uffd_delay; - pthread_create(uffd_handler_thread, NULL, uffd_handler_thread_fn, - uffd_args); - - PER_VCPU_DEBUG("Created uffd thread for HVA range [%p, %p)\n", - hva, hva + len); -} - -struct test_params { - int uffd_mode; - useconds_t uffd_delay; - enum vm_mem_backing_src_type src_type; - bool partition_vcpu_memory_access; -}; - static void run_test(enum vm_guest_mode mode, void *arg) { struct test_params *p = arg; - pthread_t *uffd_handler_threads = NULL; - struct uffd_handler_args *uffd_args = NULL; + struct uffd_desc **uffd_descs = NULL; struct timespec start; struct timespec ts_diff; - int *pipefds = NULL; struct kvm_vm *vm; int vcpu_id; - int r; vm = perf_test_create_vm(mode, nr_vcpus, guest_percpu_mem_size, 1, p->src_type, p->partition_vcpu_memory_access); @@ -299,15 +148,8 @@ static void run_test(enum vm_guest_mode mode, void *arg) memset(guest_data_prototype, 0xAB, demand_paging_size); if (p->uffd_mode) { - uffd_handler_threads = - malloc(nr_vcpus * sizeof(*uffd_handler_threads)); - TEST_ASSERT(uffd_handler_threads, "Memory allocation failed"); - - uffd_args = malloc(nr_vcpus * sizeof(*uffd_args)); - TEST_ASSERT(uffd_args, "Memory allocation failed"); - - pipefds = malloc(sizeof(int) * nr_vcpus * 2); - TEST_ASSERT(pipefds, "Unable to allocate memory for pipefd"); + uffd_descs = malloc(nr_vcpus * sizeof(struct uffd_desc *)); + TEST_ASSERT(uffd_descs, "Memory allocation failed"); for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) { struct perf_test_vcpu_args *vcpu_args; @@ -320,19 +162,17 @@ static void run_test(enum vm_guest_mode mode, void *arg) vcpu_hva = addr_gpa2hva(vm, vcpu_args->gpa); vcpu_alias = addr_gpa2alias(vm, vcpu_args->gpa); + prefault_mem(vcpu_alias, + vcpu_args->pages * perf_test_args.guest_page_size); + /* * Set up user fault fd to handle demand paging * requests. */ - r = pipe2(&pipefds[vcpu_id * 2], - O_CLOEXEC | O_NONBLOCK); - TEST_ASSERT(!r, "Failed to set up pipefd"); - - setup_demand_paging(vm, &uffd_handler_threads[vcpu_id], - pipefds[vcpu_id * 2], p->uffd_mode, - p->uffd_delay, &uffd_args[vcpu_id], - vcpu_hva, vcpu_alias, - vcpu_args->pages * perf_test_args.guest_page_size); + uffd_descs[vcpu_id] = uffd_setup_demand_paging( + p->uffd_mode, p->uffd_delay, vcpu_hva, + vcpu_args->pages * perf_test_args.guest_page_size, + &handle_uffd_page_request); } } @@ -347,15 +187,9 @@ static void run_test(enum vm_guest_mode mode, void *arg) pr_info("All vCPU threads joined\n"); if (p->uffd_mode) { - char c; - /* Tell the user fault fd handler threads to quit */ - for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) { - r = write(pipefds[vcpu_id * 2 + 1], &c, 1); - TEST_ASSERT(r == 1, "Unable to write to pipefd"); - - pthread_join(uffd_handler_threads[vcpu_id], NULL); - } + for (vcpu_id = 0; vcpu_id < nr_vcpus; vcpu_id++) + uffd_stop_demand_paging(uffd_descs[vcpu_id]); } pr_info("Total guest execution time: %ld.%.9lds\n", @@ -367,11 +201,8 @@ static void run_test(enum vm_guest_mode mode, void *arg) perf_test_destroy_vm(vm); free(guest_data_prototype); - if (p->uffd_mode) { - free(uffd_handler_threads); - free(uffd_args); - free(pipefds); - } + if (p->uffd_mode) + free(uffd_descs); } static void help(char *name) diff --git a/tools/testing/selftests/kvm/include/userfaultfd_util.h b/tools/testing/selftests/kvm/include/userfaultfd_util.h new file mode 100644 index 000000000000..dffb4e768d56 --- /dev/null +++ b/tools/testing/selftests/kvm/include/userfaultfd_util.h @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KVM userfaultfd util + * Adapted from demand_paging_test.c + * + * Copyright (C) 2018, Red Hat, Inc. + * Copyright (C) 2019, Google, Inc. + * Copyright (C) 2022, Google, Inc. + */ + +#define _GNU_SOURCE /* for pipe2 */ + +#include +#include +#include +#include + +#include "test_util.h" + +typedef int (*uffd_handler_t)(int uffd_mode, int uffd, struct uffd_msg *msg); + +struct uffd_desc { + int uffd_mode; + int uffd; + int pipefds[2]; + useconds_t delay; + uffd_handler_t handler; + pthread_t thread; +}; + +struct uffd_desc *uffd_setup_demand_paging(int uffd_mode, + useconds_t uffd_delay, void *hva, uint64_t len, + uffd_handler_t handler); + +void uffd_stop_demand_paging(struct uffd_desc *uffd); + +#ifdef PRINT_PER_PAGE_UPDATES +#define PER_PAGE_DEBUG(...) printf(__VA_ARGS__) +#else +#define PER_PAGE_DEBUG(...) _no_printf(__VA_ARGS__) +#endif + +#ifdef PRINT_PER_VCPU_UPDATES +#define PER_VCPU_DEBUG(...) printf(__VA_ARGS__) +#else +#define PER_VCPU_DEBUG(...) _no_printf(__VA_ARGS__) +#endif diff --git a/tools/testing/selftests/kvm/lib/userfaultfd_util.c b/tools/testing/selftests/kvm/lib/userfaultfd_util.c new file mode 100644 index 000000000000..4395032ccbe4 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/userfaultfd_util.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KVM userfaultfd util + * Adapted from demand_paging_test.c + * + * Copyright (C) 2018, Red Hat, Inc. + * Copyright (C) 2019, Google, Inc. + * Copyright (C) 2022, Google, Inc. + */ + +#define _GNU_SOURCE /* for pipe2 */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "kvm_util.h" +#include "test_util.h" +#include "perf_test_util.h" +#include "userfaultfd_util.h" + +#ifdef __NR_userfaultfd + +static void *uffd_handler_thread_fn(void *arg) +{ + struct uffd_desc *uffd_desc = (struct uffd_desc *)arg; + int uffd = uffd_desc->uffd; + int pipefd = uffd_desc->pipefds[0]; + useconds_t delay = uffd_desc->delay; + int64_t pages = 0; + struct timespec start; + struct timespec ts_diff; + + clock_gettime(CLOCK_MONOTONIC, &start); + while (1) { + struct uffd_msg msg; + struct pollfd pollfd[2]; + char tmp_chr; + int r; + + pollfd[0].fd = uffd; + pollfd[0].events = POLLIN; + pollfd[1].fd = pipefd; + pollfd[1].events = POLLIN; + + r = poll(pollfd, 2, -1); + switch (r) { + case -1: + pr_info("poll err"); + continue; + case 0: + continue; + case 1: + break; + default: + pr_info("Polling uffd returned %d", r); + return NULL; + } + + if (pollfd[0].revents & POLLERR) { + pr_info("uffd revents has POLLERR"); + return NULL; + } + + if (pollfd[1].revents & POLLIN) { + r = read(pollfd[1].fd, &tmp_chr, 1); + TEST_ASSERT(r == 1, + "Error reading pipefd in UFFD thread\n"); + return NULL; + } + + if (!(pollfd[0].revents & POLLIN)) + continue; + + r = read(uffd, &msg, sizeof(msg)); + if (r == -1) { + if (errno == EAGAIN) + continue; + pr_info("Read of uffd got errno %d\n", errno); + return NULL; + } + + if (r != sizeof(msg)) { + pr_info("Read on uffd returned unexpected size: %d bytes", r); + return NULL; + } + + if (!(msg.event & UFFD_EVENT_PAGEFAULT)) + continue; + + if (delay) + usleep(delay); + r = uffd_desc->handler(uffd_desc->uffd_mode, uffd, &msg); + if (r < 0) + return NULL; + pages++; + } + + ts_diff = timespec_elapsed(start); + PER_VCPU_DEBUG("userfaulted %ld pages over %ld.%.9lds. (%f/sec)\n", + pages, ts_diff.tv_sec, ts_diff.tv_nsec, + pages / ((double)ts_diff.tv_sec + (double)ts_diff.tv_nsec / 100000000.0)); + + return NULL; +} + +struct uffd_desc *uffd_setup_demand_paging(int uffd_mode, + useconds_t uffd_delay, void *hva, uint64_t len, + uffd_handler_t handler) +{ + struct uffd_desc *uffd_desc; + bool is_minor = (uffd_mode == UFFDIO_REGISTER_MODE_MINOR); + int uffd; + struct uffdio_api uffdio_api; + struct uffdio_register uffdio_register; + uint64_t expected_ioctls = ((uint64_t) 1) << _UFFDIO_COPY; + int ret; + + PER_PAGE_DEBUG("Userfaultfd %s mode, faults resolved with %s\n", + is_minor ? "MINOR" : "MISSING", + is_minor ? "UFFDIO_CONINUE" : "UFFDIO_COPY"); + + uffd_desc = malloc(sizeof(struct uffd_desc)); + TEST_ASSERT(uffd_desc, "malloc failed"); + + /* In order to get minor faults, prefault via the alias. */ + if (is_minor) + expected_ioctls = ((uint64_t) 1) << _UFFDIO_CONTINUE; + + uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); + TEST_ASSERT(uffd >= 0, "uffd creation failed, errno: %d", errno); + + uffdio_api.api = UFFD_API; + uffdio_api.features = 0; + TEST_ASSERT(ioctl(uffd, UFFDIO_API, &uffdio_api) != -1, + "ioctl UFFDIO_API failed: %" PRIu64, + (uint64_t)uffdio_api.api); + + uffdio_register.range.start = (uint64_t)hva; + uffdio_register.range.len = len; + uffdio_register.mode = uffd_mode; + TEST_ASSERT(ioctl(uffd, UFFDIO_REGISTER, &uffdio_register) != -1, + "ioctl UFFDIO_REGISTER failed"); + TEST_ASSERT((uffdio_register.ioctls & expected_ioctls) == + expected_ioctls, "missing userfaultfd ioctls"); + + ret = pipe2(uffd_desc->pipefds, O_CLOEXEC | O_NONBLOCK); + TEST_ASSERT(!ret, "Failed to set up pipefd"); + + uffd_desc->uffd_mode = uffd_mode; + uffd_desc->uffd = uffd; + uffd_desc->delay = uffd_delay; + uffd_desc->handler = handler; + pthread_create(&uffd_desc->thread, NULL, uffd_handler_thread_fn, + uffd_desc); + + PER_VCPU_DEBUG("Created uffd thread for HVA range [%p, %p)\n", + hva, hva + len); + + return uffd_desc; +} + +void uffd_stop_demand_paging(struct uffd_desc *uffd) +{ + char c = 0; + int ret; + + ret = write(uffd->pipefds[1], &c, 1); + TEST_ASSERT(ret == 1, "Unable to write to pipefd"); + + ret = pthread_join(uffd->thread, NULL); + TEST_ASSERT(ret == 0, "Pthread_join failed."); + + close(uffd->uffd); + + close(uffd->pipefds[1]); + close(uffd->pipefds[0]); + + free(uffd); +} + +#endif /* __NR_userfaultfd */ From patchwork Fri Apr 8 00:41:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805961 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C2AB9C433FE for ; Fri, 8 Apr 2022 00:41:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233060AbiDHAnh (ORCPT ); Thu, 7 Apr 2022 20:43:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38168 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233049AbiDHAnb (ORCPT ); Thu, 7 Apr 2022 20:43:31 -0400 Received: from mail-pg1-x549.google.com (mail-pg1-x549.google.com [IPv6:2607:f8b0:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 829FF17869F for ; Thu, 7 Apr 2022 17:41:27 -0700 (PDT) Received: by mail-pg1-x549.google.com with SMTP id t204-20020a635fd5000000b0039ba3f42ba0so3879225pgb.13 for ; Thu, 07 Apr 2022 17:41:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=HeX9SVaeN+dOlq3215hdXIGo/ycBIAgWX4h+cW+bQa4=; b=A2NZj+FpVZNDGJQWNXDrB2BNEOaaJfiikxNwLSYWGz6Zg9PxPsi/PfA69cXgtQpKBW cS4Xc3Zw68rXwZDzMOUQePv5n9Q1jW6twdRYmGzcWfLz505eZNzAaNqoVjfDNoJNzs5t kkhDrFclG6AMRs/8DvYiF49WBSiWkeb//ayHr/Dywek4pLEUSiko1nFj0N0ZPWqmAeLo iaQpWW/D5UoCcVTmeT1tuu3HwxFwI3ucBk51EU8HRTPTV1ShDoiT/LFnU/x4UE3uGEeO YSNa9Hbp2I8ZNdqwlqVFXkCeNvu4ZBd9JR89XsorHdFFbn6LYPNSqmNiHiTacj1NxRN6 Alow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=HeX9SVaeN+dOlq3215hdXIGo/ycBIAgWX4h+cW+bQa4=; b=Fmw9b+Dk04P6bhRn0k5QWucUtrVsgZOqb8pKC7BWYyaXvYwuO9Y5i/NPKZ1kIQVJsv /fa3GzumJx3bdjsOQfJBDSHkp5LG7QOeBXY9Lp4QsOU8M/3DwoXN4dCOyZlKL3HOxgLu w5CulfURMR4kzymYdO2Lpegc4ILNY3Bt8ibz4vFEPiowYcdrt/egGU9kBAwibxSQVXuC C79Q5X2KTXVTZC6Ww96OOtzUp8wJ/ltvu5fNAx2JrYgeSgurJMxeBsNGv8ZQbrOoV6wk XMxbmEZXtwCJ+fiEyxi4qGvXFasxPXR4y3wlvgITqgJ2OScIL2CB+FVGVk5LXXZsxLWJ H4lg== X-Gm-Message-State: AOAM533nxMFX5bonI7MkU4X/nUXGqCc7cY5LILNd9MtTJA8Wv7ZTLlIn Qj9bhGH7gzBMbuw7eRI8UtvgN47w/RtXfGY+10wvGjGHYDAURU60jrW6ppLfrMOhdwzMj8qimuZ 8FGcMotaLy4Smju0K/SkKAbhuLD19GMFKNiHvVjz/D2b44voogDuAQFNNX83Zd8M= X-Google-Smtp-Source: ABdhPJyKVr37Yo71iEW4bLnBVyE3YskZbsr0cqGngvrD9/wXPN9pxPB1vdwn2+eYR04wMeSf5UMtQue/ILXUyA== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a63:6c8a:0:b0:398:5208:220a with SMTP id h132-20020a636c8a000000b003985208220amr13391414pgc.176.1649378486405; Thu, 07 Apr 2022 17:41:26 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:09 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-3-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 02/13] KVM: selftests: aarch64: Add vm_get_pte_gpa library function From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add a library function (in-guest) to get the GPA of the PTE of a particular GVA. This will be used in a future commit by a test to clear and check the AF (access flag) of a particular page. Signed-off-by: Ricardo Koller --- .../selftests/kvm/include/aarch64/processor.h | 2 ++ .../selftests/kvm/lib/aarch64/processor.c | 24 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index 8f9f46979a00..caa572d83062 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -125,6 +125,8 @@ void vm_install_exception_handler(struct kvm_vm *vm, void vm_install_sync_handler(struct kvm_vm *vm, int vector, int ec, handler_fn handler); +vm_paddr_t vm_get_pte_gpa(struct kvm_vm *vm, vm_vaddr_t gva); + static inline void cpu_relax(void) { asm volatile("yield" ::: "memory"); diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 9343d82519b4..ee006d354b79 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -139,7 +139,7 @@ void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) _virt_pg_map(vm, vaddr, paddr, attr_idx); } -vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) +vm_paddr_t vm_get_pte_gpa(struct kvm_vm *vm, vm_vaddr_t gva) { uint64_t *ptep; @@ -162,7 +162,7 @@ vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) goto unmapped_gva; /* fall through */ case 2: - ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, gva) * 8; + ptep = (uint64_t *)(pte_addr(vm, *ptep) + pte_index(vm, gva) * 8); if (!ptep) goto unmapped_gva; break; @@ -170,6 +170,26 @@ vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) TEST_FAIL("Page table levels must be 2, 3, or 4"); } + return (vm_paddr_t)ptep; + +unmapped_gva: + TEST_FAIL("No mapping for vm virtual address, gva: 0x%lx", gva); + exit(1); +} + +vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) +{ + uint64_t *ptep; + vm_paddr_t ptep_gpa; + + ptep_gpa = vm_get_pte_gpa(vm, gva); + if (!ptep_gpa) + goto unmapped_gva; + + ptep = addr_gpa2hva(vm, ptep_gpa); + if (!ptep) + goto unmapped_gva; + return pte_addr(vm, *ptep) + (gva & (vm->page_size - 1)); unmapped_gva: From patchwork Fri Apr 8 00:41:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805960 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CD96BC433EF for ; Fri, 8 Apr 2022 00:41:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233069AbiDHAng (ORCPT ); Thu, 7 Apr 2022 20:43:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38166 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233060AbiDHAnb (ORCPT ); Thu, 7 Apr 2022 20:43:31 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA5B81770A7 for ; Thu, 7 Apr 2022 17:41:28 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id n22-20020a056a00213600b005056a13e1c1so1562203pfj.20 for ; Thu, 07 Apr 2022 17:41:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=4i8vkVYTpMI8sgCODcyEo+cLvfdtqAncn9Gw8372e+k=; b=SEvnDyhP5Eaj73KDVpVzZJA7xQaM+5EXBgQvOedS4v7Sp4iwcAtMpm93TDhBlUx8HC p39VVoh0d54k+2oHuWizmDPlEUIFVJGOf2bLgWJvv96kgnpWowBMqrggmwcfdF8MTKer NUZ7VnB7Yt0BmOkmTtcHh8WAbsM/yjLXYLBWE7z0BdCWtYSRQGGXnlkuv0G3L+o9V5WU FCy+CpQWbmjc21VjuGBCu/rEKBOK27LcV8IeX+CXJ23rGfPbQbAAbNNfXNlNaC3zfaOX ekanpHOBpTRaYjdr+V4KkNkIKwtsq+cjeDEKdZZczw39vp7vIg1DhPn27SokxJs9rKMQ g6nQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=4i8vkVYTpMI8sgCODcyEo+cLvfdtqAncn9Gw8372e+k=; b=hLhRiMTraLvgEf1iDVlBCtvaRrhh363VUhgu8R9ZyXJ/yVMo2ZrAA9rt776Mye4a9R jOtC0vxUk7MQooBsi/CLbv2s8mNXtbD8P/GFYbh+r5AHyphVZHMcIi/XcjuiCEcpRNEP Ch4cq4J4k9ByUyVYk7KjLMRbwnyDgOGeq7VvBiQbMW5rc2WRCr1Jdhmd0FdGQsS6ARQn bVIK2tE0RZCi1uo43nyChkI7cO57GP3vbIm93fiBRgBfuPkBxdQ6wkHSIOr/KCsuLdtO 07r83UNQhbJNUy446ZKjGjqXJ76RsZXp6lF/cxxN/WMOlg2LVp8ufGP0TsEGitKOxB9E bx5Q== X-Gm-Message-State: AOAM532YswDMwO9GCfJM+aS0YcspMNrNN49BluzmGhpYAy48nCLtP0ee NZmyEZmStgBQmT1YazkyagZu37W3efX8mWpX8Hv2F/wUxfhdNc7h2L5IhN1/JM0m2Ik8tHkJoaf 4PhK8Vjw21uHnTaZDtnXxYB+FKVZdQA/qM/XZo2wOfv7Lmzn5da9IXcCjlvaCX2s= X-Google-Smtp-Source: ABdhPJzen0F2bMdEJMcNp95xTNKQXKaQ6OIyor32CpS2Lnwc27cP2WP3RwfdBMdsdRt73fT1Uhd/kZ6oQLYhlA== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a17:902:8b88:b0:156:2b14:cb6e with SMTP id ay8-20020a1709028b8800b001562b14cb6emr16819381plb.14.1649378488058; Thu, 07 Apr 2022 17:41:28 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:10 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-4-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 03/13] KVM: selftests: Add vm_alloc_page_table_in_memslot library function From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add a library function to allocate a page-table physical page in a particular memslot. The default behavior is to create new page-table pages in memslot 0. Reviewed-by: Ben Gardon Signed-off-by: Ricardo Koller Reviewed-by: Oliver Upton --- tools/testing/selftests/kvm/include/kvm_util_base.h | 1 + tools/testing/selftests/kvm/lib/kvm_util.c | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 4ed6aa049a91..3a69b35e37cc 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -306,6 +306,7 @@ vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, vm_paddr_t vm_phy_pages_alloc(struct kvm_vm *vm, size_t num, vm_paddr_t paddr_min, uint32_t memslot); vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm); +vm_paddr_t vm_alloc_page_table_in_memslot(struct kvm_vm *vm, uint32_t pt_memslot); /* * Create a VM with reasonable defaults diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index d8cf851ab119..e18f1c93e4b4 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -2386,9 +2386,15 @@ vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, vm_paddr_t paddr_min, /* Arbitrary minimum physical address used for virtual translation tables. */ #define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 +vm_paddr_t vm_alloc_page_table_in_memslot(struct kvm_vm *vm, uint32_t pt_memslot) +{ + return vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, + pt_memslot); +} + vm_paddr_t vm_alloc_page_table(struct kvm_vm *vm) { - return vm_phy_page_alloc(vm, KVM_GUEST_PAGE_TABLE_MIN_PADDR, 0); + return vm_alloc_page_table_in_memslot(vm, 0); } /* From patchwork Fri Apr 8 00:41:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805962 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 85E4BC43219 for ; Fri, 8 Apr 2022 00:41:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233072AbiDHAni (ORCPT ); Thu, 7 Apr 2022 20:43:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38410 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233041AbiDHAnd (ORCPT ); Thu, 7 Apr 2022 20:43:33 -0400 Received: from mail-pj1-x104a.google.com (mail-pj1-x104a.google.com [IPv6:2607:f8b0:4864:20::104a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8DBE81777D4 for ; Thu, 7 Apr 2022 17:41:30 -0700 (PDT) Received: by mail-pj1-x104a.google.com with SMTP id oj16-20020a17090b4d9000b001c7552b7546so6707559pjb.8 for ; Thu, 07 Apr 2022 17:41:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=KAfe53pKWAZL68142x6k33xnrCZ2swQcXff2G57c/kw=; b=R7x2A1GHqSEUwbp3RyEZpy1haZz0x79bvMaIOyfgCDQjCzYtjJBgyUTzal/pX7on/z pyi+d3XfXQiXrrUH9EtOHmzz4Lj9WemphCJpjRgJIuCcB6Qk543dE+WBFSuwerNwh0HL 1x90qVj9xfHsU3R6sQ8eFwqUCog0QN8DcHfE9ICiWjtHOeFHivmS/zONvZLw+LFcgVCU obkRjvA7ovoH4Bb480a+XRvrCjmdPrBL2edRp3yHcykJ/8W8lebdYqbfD8X2cLsWGX3l mk1rR0AQiWtVLT+8rAT+xWNYoQqGUAD63H7j6zyn4wGEuI49gkgwVgArIgEFnRpYXqJP 1jxw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=KAfe53pKWAZL68142x6k33xnrCZ2swQcXff2G57c/kw=; b=lkOMWV1Dq75PX6zTlrpanemD3Gb7wnc0Nk9OqkACgp8Ae5+KWr3K5qldu+rZujNPKg 3K+ee32Jxsj29gd0QGbsSDh8+dtQwSaEpDS5qMkDNiXQAGUtviZhtzMzTLAM8pHde77Q wGxhcRbs6M1ewtm9cX5C+0abAL2y9FBIlIeZaFS065BMJ5VVi0i9LNz+m1c9+nBuhXqJ tdNwYCkDkxVffPMJ5+NqQ7hi1Kq9D6uF2hhAu35LMJP3ROqzQFYtbu1R8NeGWqd98n7C 2Shc9ZZoDYNEgo701QakWFzdX1BDUUTlX2rGQusejOAIYGtefvebVjieopXH8dtKKWBq Eadw== X-Gm-Message-State: AOAM531M4VJdN/QzSbhJeCo77Nx7c4KKmMiLSohnOqdN0XuTaPd5FwjL TmDriZmEFZJ0oitURLDBKpud3eUHxE/8qA4NrdnbnjHidhEqB7H9N0SjXHoIMMfg+I/iib7Exxd FL+kDN7Y8WZ4kw/xMq+lfH8JkK9bCvNVGYERUYzlgxB6uVHeqXhwEj5cuHxXrlO8= X-Google-Smtp-Source: ABdhPJy+JrHZpB861uw6fPE5ZifQvEmj2r2MrxGNq54LBdPo29NP4IZe9IfCDi7uv13BtKsv1tHqwXGSCGD1Iw== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a17:90a:558a:b0:1ca:a819:d2d1 with SMTP id c10-20020a17090a558a00b001caa819d2d1mr19006855pji.126.1649378489720; Thu, 07 Apr 2022 17:41:29 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:11 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-5-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 04/13] KVM: selftests: aarch64: Export _virt_pg_map with a pt_memslot arg From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add an argument, pt_memslot, into _virt_pg_map in order to use a specific memslot for the page-table allocations performed when creating a new map. This will be used in a future commit to test having PTEs stored on memslots with different setups (e.g., hugetlb with a hole). Signed-off-by: Ricardo Koller Reviewed-by: Oliver Upton --- .../selftests/kvm/include/aarch64/processor.h | 3 +++ tools/testing/selftests/kvm/lib/aarch64/processor.c | 12 ++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index caa572d83062..3965a5ac778e 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -125,6 +125,9 @@ void vm_install_exception_handler(struct kvm_vm *vm, void vm_install_sync_handler(struct kvm_vm *vm, int vector, int ec, handler_fn handler); +void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, + uint64_t flags, uint32_t pt_memslot); + vm_paddr_t vm_get_pte_gpa(struct kvm_vm *vm, vm_vaddr_t gva); static inline void cpu_relax(void) diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index ee006d354b79..8f4ec1be4364 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -86,8 +86,8 @@ void virt_pgd_alloc(struct kvm_vm *vm) } } -static void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, - uint64_t flags) +void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, + uint64_t flags, uint32_t pt_memslot) { uint8_t attr_idx = flags & 7; uint64_t *ptep; @@ -108,18 +108,18 @@ static void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, ptep = addr_gpa2hva(vm, vm->pgd) + pgd_index(vm, vaddr) * 8; if (!*ptep) - *ptep = vm_alloc_page_table(vm) | 3; + *ptep = vm_alloc_page_table_in_memslot(vm, pt_memslot) | 3; switch (vm->pgtable_levels) { case 4: ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pud_index(vm, vaddr) * 8; if (!*ptep) - *ptep = vm_alloc_page_table(vm) | 3; + *ptep = vm_alloc_page_table_in_memslot(vm, pt_memslot) | 3; /* fall through */ case 3: ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pmd_index(vm, vaddr) * 8; if (!*ptep) - *ptep = vm_alloc_page_table(vm) | 3; + *ptep = vm_alloc_page_table_in_memslot(vm, pt_memslot) | 3; /* fall through */ case 2: ptep = addr_gpa2hva(vm, pte_addr(vm, *ptep)) + pte_index(vm, vaddr) * 8; @@ -136,7 +136,7 @@ void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) { uint64_t attr_idx = 4; /* NORMAL (See DEFAULT_MAIR_EL1) */ - _virt_pg_map(vm, vaddr, paddr, attr_idx); + _virt_pg_map(vm, vaddr, paddr, attr_idx, 0); } vm_paddr_t vm_get_pte_gpa(struct kvm_vm *vm, vm_vaddr_t gva) From patchwork Fri Apr 8 00:41:12 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805963 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 356D1C433EF for ; Fri, 8 Apr 2022 00:41:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233074AbiDHAnj (ORCPT ); Thu, 7 Apr 2022 20:43:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38504 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233053AbiDHAne (ORCPT ); Thu, 7 Apr 2022 20:43:34 -0400 Received: from mail-pg1-x549.google.com (mail-pg1-x549.google.com [IPv6:2607:f8b0:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9F23E176D06 for ; Thu, 7 Apr 2022 17:41:32 -0700 (PDT) Received: by mail-pg1-x549.google.com with SMTP id m3-20020a633f03000000b00385d8711757so3873827pga.14 for ; Thu, 07 Apr 2022 17:41:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=gARM1z8TWPcLta8zngl9X4Eb51iL3uDEv2L7Sujnzmc=; b=fw0w/2HTVE3GHwYT1kKkJB7GGiQbxbK9jPoy5eWfwEScRi0F0XDRRYUhcnPlZ/PSoi WY+2sNSJC2ulW6fEg9q4lijTezcdTH0uVN9GxUZxP9rhLf2LFJl8tw4nAV/fN/0tHoiP ghyC34QypLmnPRiEVcckksMmnDFrzt19JZjE566PTMCPd6IbrTXCAhN9pSH4/d7ncPnL zEU6m1GWInfU1cMZ/EN056sjlcONS2cKuviDNJ3kzwZib5Mtu9aaXVoL5jaHFNjAIR+v Oiju7dlEh2c+CJRn/LmPNijfh7XJ8R+FSxj/LMoFbteb9iFeJE66Jo7O3NsR2uxRCEXd ESIQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=gARM1z8TWPcLta8zngl9X4Eb51iL3uDEv2L7Sujnzmc=; b=Nsvrkcq5AQ77lb8olVX3xxkTPVPCeL9hNJlQQ19ZCuNeCGsheDN/YLfnVYciTRwCRH 67hFFCFihWmsWXfkPe9q6PY3GaaNyabCcFIqvFlrMWjtOUSuGEKkNR6WmeK56czWJp8l BZ0mNjcZ0TJNByGmxhyT+OoW3JbUIEr/W+KG9B2+NTaMQSgtFbb8kdgw8iCnsycLZgzf FZwpeSl8YylKzQG9n2yM8oExOsv4TbMueIdNUJuixldGIUO9hK5p4ff6kmh3GPtxDXT7 6NKuS1I9ESSHA6F9fChyRSe+0iQjABShn/YQx+/fwSY0keiLP0pRzVv6YZ2XZYs23U5z NRYA== X-Gm-Message-State: AOAM533dkwknWc183ejUYUT/vyFYN+p8FSi3FgFyIROj5f8vYXjL/8py wi7rovB/lmfALG32VxQqYKuRLq3YRZNkN3TZdSohTZOlCfpbghrP2487QWZm2z8CfSMSEtChZAM 56E/4WLHcBslBJkz62CsiX25hs0RQIbQkFvUuR03XXBUQ7AHCIAO/VS/9CcHqCyk= X-Google-Smtp-Source: ABdhPJzRgN+sMT9MhT0Mu86l71agS8/aGmuvBBJg8sMMx2/UHmcc2ZsWJo6jNZwn4d6Nf44QLSwyUyjz26442A== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a17:90a:db48:b0:1ca:ab67:d75 with SMTP id u8-20020a17090adb4800b001caab670d75mr36135pjx.1.1649378491209; Thu, 07 Apr 2022 17:41:31 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:12 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-6-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 05/13] KVM: selftests: Add missing close and munmap in __vm_mem_region_delete From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Deleting a memslot (when freeing a VM) is not closing the backing fd, nor it's unmapping the alias mapping. Fix by adding the missing close and munmap. Reviewed-by: Ben Gardon Signed-off-by: Ricardo Koller Reviewed-by: Oliver Upton --- tools/testing/selftests/kvm/lib/kvm_util.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index e18f1c93e4b4..268ad3d75fe2 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -679,6 +679,12 @@ static void __vm_mem_region_delete(struct kvm_vm *vm, sparsebit_free(®ion->unused_phy_pages); ret = munmap(region->mmap_start, region->mmap_size); TEST_ASSERT(ret == 0, "munmap failed, rc: %i errno: %i", ret, errno); + if (region->fd >= 0) { + /* There's an extra map shen using shared memory. */ + ret = munmap(region->mmap_alias, region->mmap_size); + TEST_ASSERT(ret == 0, "munmap failed, rc: %i errno: %i", ret, errno); + close(region->fd); + } free(region); } From patchwork Fri Apr 8 00:41:13 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805964 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 21B07C433FE for ; Fri, 8 Apr 2022 00:41:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233080AbiDHAnk (ORCPT ); Thu, 7 Apr 2022 20:43:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38614 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233058AbiDHAng (ORCPT ); Thu, 7 Apr 2022 20:43:36 -0400 Received: from mail-pj1-x1049.google.com (mail-pj1-x1049.google.com [IPv6:2607:f8b0:4864:20::1049]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AA55C17869F for ; Thu, 7 Apr 2022 17:41:33 -0700 (PDT) Received: by mail-pj1-x1049.google.com with SMTP id d11-20020a17090a628b00b001ca8fc92b9eso3785737pjj.9 for ; Thu, 07 Apr 2022 17:41:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=ma205ge9BDOVMj7gZDxqTm6bY+KHnPOCZruDDJTsiDQ=; b=XdNNOy+Xf42B56zBTOagqhnkIL2gXF35sWD5D7P7s7jff+QGphla7l3EukkPSCLOin y57ixsuzrAl5CZiH4/eM6+jb6VFmpuz7ijMdbG82+JFA98iXGDE+0nabN/AdBig7OyzM FwttxRmdVs+dk2sBGidoWMyRKJX/6B+84LQpzH1Sdj0KDpzB2IdXX1LWXnnHlCc2rp5Q qTN1IWY7L3kXbPiMNb4wYaaUR3tXU7OWTrVtGTumt60ZVQcqcaQobGp+hYjPriXhciZ6 HIkKnfTwtETqk1UYPo0Zk82c+mLcr6IMof2gV+2x/9G+1Yt/20zk2YI6LsEeKO+7+YjZ V5XQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=ma205ge9BDOVMj7gZDxqTm6bY+KHnPOCZruDDJTsiDQ=; b=aNZwOh3CYhufw2vNsIRu7sRJcFTkw14ZHUBrk/EP+dKUIBshV35dFn5RaFY3w7M36w VvHc7493LO1h0OedjMO7zm/jbVDE+jnlQU77G3IjSOM35Bybv4YeUh3Hj4wZlVUjV5Sf pE+VcIwSdO8asLMBDPM//Om7KohlPw+VempM2Bz5RGAnGh8atAFWjJM+Iac7xxNN0Mjt Pm2XI8u8QOlkSqEIe0RkwZBZeN5WUKIoIZkVrtsWadDcgJOFvYeHOo8Aj+MzNyUg0GhU mfzycMXcyo/skC5oxqDLAlV0kyajER6EKRBbVJ/kkhBhxPqr+zQ4VlouttPlIjgZcHNq ta5g== X-Gm-Message-State: AOAM533L94Gl1TJloc6+DEFAcu78mQK++1fgKHTyclamLvuiGJmMUYEe fQpHy9X/OAZXhpvowFtfP5AU5RKJVrXWvXCsLeaZpuS+dftwojwxszZyytWq1/avJVnK+/nSzco 7IPsagJBAeG4TlVCfAEDhMBjhEnSasva+NFxBPRG6Xwtmu+sSsbEdTC3I2KI8Oa8= X-Google-Smtp-Source: ABdhPJx/x/5ymStBVtSGKj7Xfm/crzv8lUGNkVJDDDCjk2nW2zm+u3BK3CB1mCfuw7JBEbiV1LYqYuZQsLSIEw== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a17:903:20c:b0:154:b58:d424 with SMTP id r12-20020a170903020c00b001540b58d424mr16087633plh.45.1649378492864; Thu, 07 Apr 2022 17:41:32 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:13 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-7-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 06/13] KVM: selftests: Add vm_mem_region_get_src_fd library function From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add a library function to get the backing source FD of a memslot. Signed-off-by: Ricardo Koller Reviewed-by: Oliver Upton --- .../selftests/kvm/include/kvm_util_base.h | 1 + tools/testing/selftests/kvm/lib/kvm_util.c | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/tools/testing/selftests/kvm/include/kvm_util_base.h b/tools/testing/selftests/kvm/include/kvm_util_base.h index 3a69b35e37cc..c8dce12a9a52 100644 --- a/tools/testing/selftests/kvm/include/kvm_util_base.h +++ b/tools/testing/selftests/kvm/include/kvm_util_base.h @@ -163,6 +163,7 @@ int _kvm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); void vm_mem_region_move(struct kvm_vm *vm, uint32_t slot, uint64_t new_gpa); void vm_mem_region_delete(struct kvm_vm *vm, uint32_t slot); +int vm_mem_region_get_src_fd(struct kvm_vm *vm, uint32_t memslot); void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid); vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min); vm_vaddr_t vm_vaddr_alloc_pages(struct kvm_vm *vm, int nr_pages); diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 268ad3d75fe2..a0a9cd575fac 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -580,6 +580,29 @@ kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, return ®ion->region; } +/* + * KVM Userspace Memory Get Backing Source FD + * + * Input Args: + * vm - Virtual Machine + * memslot - KVM memory slot ID + * + * Output Args: None + * + * Return: + * Backing source file descriptor, -1 if the memslot is an anonymous region. + * + * Returns the backing source fd of a memslot, so tests can use it to punch + * holes, or to setup permissions. + */ +int vm_mem_region_get_src_fd(struct kvm_vm *vm, uint32_t memslot) +{ + struct userspace_mem_region *region; + + region = memslot2region(vm, memslot); + return region->fd; +} + /* * VCPU Find * From patchwork Fri Apr 8 00:41:14 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805965 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 57160C433F5 for ; Fri, 8 Apr 2022 00:41:42 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233086AbiDHAnl (ORCPT ); Thu, 7 Apr 2022 20:43:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38696 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233070AbiDHAng (ORCPT ); Thu, 7 Apr 2022 20:43:36 -0400 Received: from mail-pl1-x649.google.com (mail-pl1-x649.google.com [IPv6:2607:f8b0:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D53971786B3 for ; Thu, 7 Apr 2022 17:41:34 -0700 (PDT) Received: by mail-pl1-x649.google.com with SMTP id n11-20020a170902d2cb00b00156c1fd01c2so3611509plc.12 for ; Thu, 07 Apr 2022 17:41:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=tRGVvoht62Wm0zdeImIalZjSLMP6mzAfCTWi8BhGbl8=; b=n4CEYM1D4z3Giyg+eCtkiEPPA3r+PIMHJVXRYwvPp7clxkEoLN6B6kqft8A7MJji+k iU8SOTNYfL4+d2PP5p2Vr0VZawQI+r6N14yhgAMXQ3z1V2Tx7DV1g3/ubk+U3oeTt7zh WDKha5AI4T8BUlhzIeEEfcfEBk1YhYRvuxgQe76KY2LtnMsAtLdhV8kYGXiLQBg3MwY2 DDInFL5IOU7mjynjxSSCwyfUY4YRd3xJblLcvRLp2Rm2llgnV8j4Adpq+hBh9U23S35b 1da6uAkxawWDJQVvptnrSvI5refAD77/Yit/Wzu3iA2UXDrZSnGXfnI025QofF+Z83/B e7cg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=tRGVvoht62Wm0zdeImIalZjSLMP6mzAfCTWi8BhGbl8=; b=Ssz3fuwLeFjsTzQkK7Su839YC0lUrAnBE5BRRUfftQUsqi+rhlQYl0YZKlgwZa1y7F wrNaNrVktzOzBFJklgAPQ5MrRLX9MfOZSXAhO00rYHy46F6p2L/HRpXVV8zVIBtwj9RJ 8MilwWS371HCL/9cB4KtrOodUmczbFFQgbMv1s+5o4h68XTrcXhF7s64l8auTo/BRfyJ a8z95RQEFbVcJWeQgIbm62+zDkdP9GBCK13Cj8u6A5aDiKaBbXvbOy9/6ST0kZAFg6ZG g43UipzV1B68Kl8TGLY5eOE+36HBL1Z4mL0WAdA9Gey10MDnm/QDB8sfv2Ohhx7t+cES s9SQ== X-Gm-Message-State: AOAM531g1RktrBGHx0CoxAziGGs73kKydQPgxeXX/MKnYCnutCgwhVsv WP5QocUm41g2cKeQohsuec7SgzqGC5XhWjo+TBq/yFb39pNNCvwXCUhzdGYO8KAGHWOlF5Cqu7c Taz9rjXz1WJspdBwYjSdSvMjzvM/JCoPEFlqEpT8mTJsECmXNutyuBKB+lTf0Dyk= X-Google-Smtp-Source: ABdhPJz6ca9o7Zb2UxcHfmiWYOMgxfK+ATlfbD5jLUnRA5ipNhqqxQmJEMTBA9bnY7kk9pmVoibA7Pf0fmkrug== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a17:902:6901:b0:156:4aad:fad7 with SMTP id j1-20020a170902690100b001564aadfad7mr16809280plk.33.1649378494200; Thu, 07 Apr 2022 17:41:34 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:14 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-8-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 07/13] KVM: selftests: aarch64: Construct DEFAULT_MAIR_EL1 using sysreg.h macros From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Define macros for memory type indexes and construct DEFAULT_MAIR_EL1 with macros from asm/sysreg.h. The index macros can then be used when constructing PTEs (instead of using raw numbers). Signed-off-by: Ricardo Koller Reviewed-by: Oliver Upton --- .../selftests/kvm/include/aarch64/processor.h | 24 ++++++++++++++----- .../selftests/kvm/lib/aarch64/processor.c | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index 3965a5ac778e..16753a1f28e3 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -38,12 +38,24 @@ * NORMAL 4 1111:1111 * NORMAL_WT 5 1011:1011 */ -#define DEFAULT_MAIR_EL1 ((0x00ul << (0 * 8)) | \ - (0x04ul << (1 * 8)) | \ - (0x0cul << (2 * 8)) | \ - (0x44ul << (3 * 8)) | \ - (0xfful << (4 * 8)) | \ - (0xbbul << (5 * 8))) + +/* Linux doesn't use these memory types, so let's define them. */ +#define MAIR_ATTR_DEVICE_GRE UL(0x0c) +#define MAIR_NORMAL_WT UL(0xbb) + +#define MT_DEVICE_nGnRnE 0 +#define MT_DEVICE_nGnRE 1 +#define MT_DEVICE_GRE 2 +#define MT_NORMAL_NC 3 +#define MT_NORMAL 4 +#define MT_NORMAL_WT 5 + +#define DEFAULT_MAIR_EL1 \ + (MAIR_ATTRIDX(MAIR_ATTR_DEVICE_nGnRE, MT_DEVICE_nGnRE) | \ + MAIR_ATTRIDX(MAIR_ATTR_DEVICE_GRE, MT_DEVICE_GRE) | \ + MAIR_ATTRIDX(MAIR_ATTR_NORMAL_NC, MT_NORMAL_NC) | \ + MAIR_ATTRIDX(MAIR_ATTR_NORMAL, MT_NORMAL) | \ + MAIR_ATTRIDX(MAIR_NORMAL_WT, MT_NORMAL_WT)) #define MPIDR_HWID_BITMASK (0xff00fffffful) diff --git a/tools/testing/selftests/kvm/lib/aarch64/processor.c b/tools/testing/selftests/kvm/lib/aarch64/processor.c index 8f4ec1be4364..c7b899ba3e38 100644 --- a/tools/testing/selftests/kvm/lib/aarch64/processor.c +++ b/tools/testing/selftests/kvm/lib/aarch64/processor.c @@ -134,7 +134,7 @@ void _virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) { - uint64_t attr_idx = 4; /* NORMAL (See DEFAULT_MAIR_EL1) */ + uint64_t attr_idx = MT_NORMAL; _virt_pg_map(vm, vaddr, paddr, attr_idx, 0); } From patchwork Fri Apr 8 00:41:15 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805966 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 15338C4332F for ; Fri, 8 Apr 2022 00:41:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233093AbiDHAnm (ORCPT ); Thu, 7 Apr 2022 20:43:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38940 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233076AbiDHAnj (ORCPT ); Thu, 7 Apr 2022 20:43:39 -0400 Received: from mail-pj1-x104a.google.com (mail-pj1-x104a.google.com [IPv6:2607:f8b0:4864:20::104a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9AEF7177D2A for ; Thu, 7 Apr 2022 17:41:36 -0700 (PDT) Received: by mail-pj1-x104a.google.com with SMTP id d11-20020a17090a628b00b001ca8fc92b9eso3785805pjj.9 for ; Thu, 07 Apr 2022 17:41:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=ccbYNHwG829rw3c/9epbQKzTVhiKefqcuAuLRUDVGRg=; b=FEYPip5Cnc+Sh8U3lQEP/pXhqZJQfyj//s6OKdU/AEmt+VDAfTpQYAblIDbaTAfO5k f8jdd5dbH6GZFZI0oH+xoFFi9zM/tf/XoETfB5R1ItKtOftF3BMSSyQTr6HDqM6TFBM7 u4V414xm9TIwHmWX0ZNjG4QxmsDh7Q56k2KJ9zVuKVD2NBMTLp3YF0a/1m3hIjT2wohT 7Kgw6xZNFiiVyLNCrQL0WjJSIDlWZZc9epouaW65g/2z1BfZT0LMeHSVUC6e4XbCl75p a6Gau1lTjaAxrD3bo+HvG62jb1QigX/TnLaqMHluWpqazcXaZLeAc3wzF8fnt8XkWdUD 5ySg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=ccbYNHwG829rw3c/9epbQKzTVhiKefqcuAuLRUDVGRg=; b=inSJyRPSmUh8fVwPang7VhOJdCN+oUrYHpjpvFJwUvW2/fsvB1T6jj1UitNGGAjHwM uQUrtET9i2FPzYm4UdJ00q8ZSzGasXNrq+viHf64MVfyidOvvcBOpa7SrUuF/eN5eoE3 7QqF//BuQHpr/6aoeSnhfHADUHI3yrMHSsMokP/MOwFzyWPTe/Y11aS91SzUzWlTbaar krho/ocv8oBdzac1ONUGxAFa3rBGM5A4+JN3J1e6WXFlfhibFfJmgtoMVksaJObV8lMp CRD8THMKdeiVfJJp5ClFvC7xQJR8q+BlvSLaBilB/YCuCy0zjfIWswuxSdzL9LHM1Sl2 1NIg== X-Gm-Message-State: AOAM530wZbKFe0cubmWRUS4g0pueIUQJsbFdJ6MhNLqOOB6e8Si1kX9G Jy37nsDAVvPKGiIx3geXsxc6rVSdoUvjZCKF9Ew8ukXPkgsn+w4/HgTb4Vi0njZKoAGXKQvO7kr 8XOWGH91GVtW23gU76tf4jZnWYMom6MkJFMGSNK4IZ8ypg3gyKsBQm0XQWEfqqU0= X-Google-Smtp-Source: ABdhPJwIIlRWyZn8e5aPDSHkNsKORn7LgmK3yWl1ZIZK+Ds0SMHtRJyFyWdvr9BmVfFmFAEhcykMuCjjt1m2nQ== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a17:903:1210:b0:14f:973e:188d with SMTP id l16-20020a170903121000b0014f973e188dmr16591734plh.61.1649378495896; Thu, 07 Apr 2022 17:41:35 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:15 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-9-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 08/13] tools: Copy bitfield.h from the kernel sources From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller , Jakub Kicinski , Arnaldo Carvalho de Melo Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Copy bitfield.h from include/linux/bitfield.h. It defines some FIELD_{GET,PREP} macros that will be needed in the next patch in the series. The header was copied as-is, no changes needed. Cc: Jakub Kicinski Cc: Arnaldo Carvalho de Melo Signed-off-by: Ricardo Koller Reviewed-by: Oliver Upton --- tools/include/linux/bitfield.h | 176 +++++++++++++++++++++++++++++++++ 1 file changed, 176 insertions(+) create mode 100644 tools/include/linux/bitfield.h diff --git a/tools/include/linux/bitfield.h b/tools/include/linux/bitfield.h new file mode 100644 index 000000000000..6093fa6db260 --- /dev/null +++ b/tools/include/linux/bitfield.h @@ -0,0 +1,176 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2014 Felix Fietkau + * Copyright (C) 2004 - 2009 Ivo van Doorn + */ + +#ifndef _LINUX_BITFIELD_H +#define _LINUX_BITFIELD_H + +#include +#include + +/* + * Bitfield access macros + * + * FIELD_{GET,PREP} macros take as first parameter shifted mask + * from which they extract the base mask and shift amount. + * Mask must be a compilation time constant. + * + * Example: + * + * #define REG_FIELD_A GENMASK(6, 0) + * #define REG_FIELD_B BIT(7) + * #define REG_FIELD_C GENMASK(15, 8) + * #define REG_FIELD_D GENMASK(31, 16) + * + * Get: + * a = FIELD_GET(REG_FIELD_A, reg); + * b = FIELD_GET(REG_FIELD_B, reg); + * + * Set: + * reg = FIELD_PREP(REG_FIELD_A, 1) | + * FIELD_PREP(REG_FIELD_B, 0) | + * FIELD_PREP(REG_FIELD_C, c) | + * FIELD_PREP(REG_FIELD_D, 0x40); + * + * Modify: + * reg &= ~REG_FIELD_C; + * reg |= FIELD_PREP(REG_FIELD_C, c); + */ + +#define __bf_shf(x) (__builtin_ffsll(x) - 1) + +#define __scalar_type_to_unsigned_cases(type) \ + unsigned type: (unsigned type)0, \ + signed type: (unsigned type)0 + +#define __unsigned_scalar_typeof(x) typeof( \ + _Generic((x), \ + char: (unsigned char)0, \ + __scalar_type_to_unsigned_cases(char), \ + __scalar_type_to_unsigned_cases(short), \ + __scalar_type_to_unsigned_cases(int), \ + __scalar_type_to_unsigned_cases(long), \ + __scalar_type_to_unsigned_cases(long long), \ + default: (x))) + +#define __bf_cast_unsigned(type, x) ((__unsigned_scalar_typeof(type))(x)) + +#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \ + ({ \ + BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \ + _pfx "mask is not constant"); \ + BUILD_BUG_ON_MSG((_mask) == 0, _pfx "mask is zero"); \ + BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \ + ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \ + _pfx "value too large for the field"); \ + BUILD_BUG_ON_MSG(__bf_cast_unsigned(_mask, _mask) > \ + __bf_cast_unsigned(_reg, ~0ull), \ + _pfx "type of reg too small for mask"); \ + __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ + (1ULL << __bf_shf(_mask))); \ + }) + +/** + * FIELD_MAX() - produce the maximum value representable by a field + * @_mask: shifted mask defining the field's length and position + * + * FIELD_MAX() returns the maximum value that can be held in the field + * specified by @_mask. + */ +#define FIELD_MAX(_mask) \ + ({ \ + __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_MAX: "); \ + (typeof(_mask))((_mask) >> __bf_shf(_mask)); \ + }) + +/** + * FIELD_FIT() - check if value fits in the field + * @_mask: shifted mask defining the field's length and position + * @_val: value to test against the field + * + * Return: true if @_val can fit inside @_mask, false if @_val is too big. + */ +#define FIELD_FIT(_mask, _val) \ + ({ \ + __BF_FIELD_CHECK(_mask, 0ULL, 0ULL, "FIELD_FIT: "); \ + !((((typeof(_mask))_val) << __bf_shf(_mask)) & ~(_mask)); \ + }) + +/** + * FIELD_PREP() - prepare a bitfield element + * @_mask: shifted mask defining the field's length and position + * @_val: value to put in the field + * + * FIELD_PREP() masks and shifts up the value. The result should + * be combined with other fields of the bitfield using logical OR. + */ +#define FIELD_PREP(_mask, _val) \ + ({ \ + __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \ + ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ + }) + +/** + * FIELD_GET() - extract a bitfield element + * @_mask: shifted mask defining the field's length and position + * @_reg: value of entire bitfield + * + * FIELD_GET() extracts the field specified by @_mask from the + * bitfield passed in as @_reg by masking and shifting it down. + */ +#define FIELD_GET(_mask, _reg) \ + ({ \ + __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ + (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ + }) + +extern void __compiletime_error("value doesn't fit into mask") +__field_overflow(void); +extern void __compiletime_error("bad bitfield mask") +__bad_mask(void); +static __always_inline u64 field_multiplier(u64 field) +{ + if ((field | (field - 1)) & ((field | (field - 1)) + 1)) + __bad_mask(); + return field & -field; +} +static __always_inline u64 field_mask(u64 field) +{ + return field / field_multiplier(field); +} +#define field_max(field) ((typeof(field))field_mask(field)) +#define ____MAKE_OP(type,base,to,from) \ +static __always_inline __##type type##_encode_bits(base v, base field) \ +{ \ + if (__builtin_constant_p(v) && (v & ~field_mask(field))) \ + __field_overflow(); \ + return to((v & field_mask(field)) * field_multiplier(field)); \ +} \ +static __always_inline __##type type##_replace_bits(__##type old, \ + base val, base field) \ +{ \ + return (old & ~to(field)) | type##_encode_bits(val, field); \ +} \ +static __always_inline void type##p_replace_bits(__##type *p, \ + base val, base field) \ +{ \ + *p = (*p & ~to(field)) | type##_encode_bits(val, field); \ +} \ +static __always_inline base type##_get_bits(__##type v, base field) \ +{ \ + return (from(v) & field)/field_multiplier(field); \ +} +#define __MAKE_OP(size) \ + ____MAKE_OP(le##size,u##size,cpu_to_le##size,le##size##_to_cpu) \ + ____MAKE_OP(be##size,u##size,cpu_to_be##size,be##size##_to_cpu) \ + ____MAKE_OP(u##size,u##size,,) +____MAKE_OP(u8,u8,,) +__MAKE_OP(16) +__MAKE_OP(32) +__MAKE_OP(64) +#undef __MAKE_OP +#undef ____MAKE_OP + +#endif From patchwork Fri Apr 8 00:41:16 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805967 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B40EEC433FE for ; Fri, 8 Apr 2022 00:41:43 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233099AbiDHAnn (ORCPT ); Thu, 7 Apr 2022 20:43:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39054 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233081AbiDHAnl (ORCPT ); Thu, 7 Apr 2022 20:43:41 -0400 Received: from mail-pj1-x104a.google.com (mail-pj1-x104a.google.com [IPv6:2607:f8b0:4864:20::104a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1139E1788FD for ; Thu, 7 Apr 2022 17:41:38 -0700 (PDT) Received: by mail-pj1-x104a.google.com with SMTP id gq2-20020a17090b104200b001ca93cdc0f2so3790889pjb.7 for ; Thu, 07 Apr 2022 17:41:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc:content-transfer-encoding; bh=TgEc+cFjoJ+MQanxTOwuuuuuiKuUixk1wIZGdO5gL+c=; b=k0lBM31u2rQk35EjnvC6UvbDbIALQB8S5NP+en85JjJrkeTQZGGPRqA2rA8BGtMzLg qxicck5hpHNmlyZIiOcFkUnLum80jeD1sXSqF0bjtMZGTLDp7/oXk2M4fbRJvbQW7Cnq payEu34VFKlpyk3/aynW5V5DfIKMn6nVgBx46nuqFUfB6K0FnZ60Bd3EOhI6NQpkC/xg IS6FHbNj/43vBpS6HxBGXWpaL4E/6oGMVJrmK1DFtC43ay1ZoIChKTIQhaO0nWHz71tS hs86RQDdssOu3Zq389tMledezSc1eT42jn2T5GBjFcQCHO10QM5scRhVGvPfkIoNPKUn YBrQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc:content-transfer-encoding; bh=TgEc+cFjoJ+MQanxTOwuuuuuiKuUixk1wIZGdO5gL+c=; b=wsZC4vO/t/i0QgdtmAU+x+aJJlUXWWEbat6qIjeoh6j/MY4LQNO/FRJcqIzHEumpa9 G5pOltvLYKUymKsC3gPGBiKQ93e48LFB9sbCMBLXSqTaLQkD+xpJQi+5UVYOHl4Hksrj fnYMRVozRf1Ux4aOqwWuHxvuWPo7bkf4bAknCl/bZym0yendksAL62c0zbZI2B1FONc8 Lp+qbryOCaqnV5F/sH6LrTujpZ74W3+s4DoSwMPfZK8EDv2y3y9U90AksRRGLzsrWNiH vHabb0M/n/dj1G5Q8upVGHuN3rjWN8fvdUELq7x31fKQH7uxuJg1nxELHD4NTaw9FXTE JYgA== X-Gm-Message-State: AOAM533Gsu/5pgiumAQhnC6CVfqGuieaBTEubSodUAHoh1dwsKw6PRe2 /eqqd5N4qjK7w8SGdfb1O3NEk1uQ0XfRpvSYwgPHtfYW8pUsf1R/yWBvAMnBAnWqt/rSpZPmpyG AYZgECj6oV+McRUHh0yeFR/d1qfpleaLm2sKxlPSUqAaS2T/dIx7CwOQx6YxKjeo= X-Google-Smtp-Source: ABdhPJzmJjo5z2lFM4bRy34RCI5eDN4WupCLrB5DhDHrwjMoJvggNs/FPlo8vdAj3Cka+0I9tk1hNL0Rxk5a1Q== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a63:5560:0:b0:399:4e32:42 with SMTP id f32-20020a635560000000b003994e320042mr13366852pgm.164.1649378497427; Thu, 07 Apr 2022 17:41:37 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:16 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-10-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 09/13] KVM: selftests: aarch64: Add aarch64/page_fault_test From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add a new test for stage 2 faults when using different combinations of guest accesses (e.g., write, S1PTW), backing source type (e.g., anon) and types of faults (e.g., read on hugetlbfs with a hole). The next commits will add different handling methods and more faults (e.g., uffd and dirty logging). This first commit starts by adding two sanity checks for all types of accesses: AF setting by the hw, and accessing memslots with holes. Signed-off-by: Ricardo Koller --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/aarch64/page_fault_test.c | 691 ++++++++++++++++++ .../selftests/kvm/include/aarch64/processor.h | 6 + 3 files changed, 698 insertions(+) create mode 100644 tools/testing/selftests/kvm/aarch64/page_fault_test.c diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index bc5f89b3700e..6a192798b217 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -103,6 +103,7 @@ TEST_GEN_PROGS_x86_64 += system_counter_offset_test TEST_GEN_PROGS_aarch64 += aarch64/arch_timer TEST_GEN_PROGS_aarch64 += aarch64/debug-exceptions TEST_GEN_PROGS_aarch64 += aarch64/get-reg-list +TEST_GEN_PROGS_aarch64 += aarch64/page_fault_test TEST_GEN_PROGS_aarch64 += aarch64/psci_cpu_on_test TEST_GEN_PROGS_aarch64 += aarch64/vgic_init TEST_GEN_PROGS_aarch64 += aarch64/vgic_irq diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c new file mode 100644 index 000000000000..04fc6007f630 --- /dev/null +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -0,0 +1,691 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * page_fault_test.c - Test stage 2 faults. + * + * This test tries different combinations of guest accesses (e.g., write, + * S1PTW), backing source type (e.g., anon) and types of faults (e.g., read on + * hugetlbfs with a hole). It checks that the expected handling method is + * called (e.g., uffd faults with the right address and write/read flag). + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include "guest_modes.h" +#include "userfaultfd_util.h" + +#define VCPU_ID 0 + +#define TEST_MEM_SLOT_INDEX 1 +#define TEST_PT_SLOT_INDEX 2 + +/* Max number of backing pages per guest page */ +#define BACKING_PG_PER_GUEST_PG (64 / 4) + +/* Test memslot in backing source pages */ +#define TEST_MEMSLOT_BACKING_SRC_NPAGES (1 * BACKING_PG_PER_GUEST_PG) + +/* PT memslot size in backing source pages */ +#define PT_MEMSLOT_BACKING_SRC_NPAGES (4 * BACKING_PG_PER_GUEST_PG) + +/* Guest virtual addresses that point to the test page and its PTE. */ +#define TEST_GVA 0xc0000000 +#define TEST_EXEC_GVA 0xc0000008 +#define TEST_PTE_GVA 0xd0000000 +#define TEST_DATA 0x0123456789ABCDEF + +#define CMD_NONE (0) +#define CMD_SKIP_TEST (1ULL << 1) +#define CMD_HOLE_PT (1ULL << 2) +#define CMD_HOLE_TEST (1ULL << 3) + +#define PREPARE_FN_NR 10 +#define CHECK_FN_NR 10 + +uint64_t pte_gpa; + +enum { PT, TEST, NR_MEMSLOTS}; + +struct memslot_desc { + void *hva; + uint64_t gpa; + uint64_t size; + uint64_t guest_pages; + uint64_t backing_pages; + enum vm_mem_backing_src_type src_type; + uint32_t idx; +} memslot[NR_MEMSLOTS] = { + { + .idx = TEST_PT_SLOT_INDEX, + .backing_pages = PT_MEMSLOT_BACKING_SRC_NPAGES, + }, + { + .idx = TEST_MEM_SLOT_INDEX, + .backing_pages = TEST_MEMSLOT_BACKING_SRC_NPAGES, + }, +}; + +static struct event_cnt { + int aborts; + int fail_vcpu_runs; +} events; + +struct test_desc { + const char *name; + uint64_t mem_mark_cmd; + /* Skip the test if any prepare function returns false */ + bool (*guest_prepare[PREPARE_FN_NR])(void); + void (*guest_test)(void); + void (*guest_test_check[CHECK_FN_NR])(void); + void (*dabt_handler)(struct ex_regs *regs); + void (*iabt_handler)(struct ex_regs *regs); + uint32_t pt_memslot_flags; + uint32_t test_memslot_flags; + bool skip; + struct event_cnt expected_events; +}; + +struct test_params { + enum vm_mem_backing_src_type src_type; + struct test_desc *test_desc; +}; + + +static inline void flush_tlb_page(uint64_t vaddr) +{ + uint64_t page = vaddr >> 12; + + dsb(ishst); + asm volatile("tlbi vaae1is, %0" :: "r" (page)); + dsb(ish); + isb(); +} + +static void guest_nop(void) +{} + +static bool guest_prepare_nop(void) +{ + return true; +} + +static void guest_check_nop(void) +{} + +static void guest_write64(void) +{ + uint64_t val; + + WRITE_ONCE(*((uint64_t *)TEST_GVA), TEST_DATA); + val = READ_ONCE(*(uint64_t *)TEST_GVA); + GUEST_ASSERT_EQ(val, TEST_DATA); +} + +/* Check the system for atomic instructions. */ +static bool guest_check_lse(void) +{ + uint64_t isar0 = read_sysreg(id_aa64isar0_el1); + uint64_t atomic; + + atomic = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64ISAR0_ATOMICS), isar0); + return atomic >= 2; +} + +static bool guest_check_dc_zva(void) +{ + uint64_t dczid = read_sysreg(dczid_el0); + uint64_t dzp = FIELD_GET(ARM64_FEATURE_MASK(DCZID_DZP), dczid); + + return dzp == 0; +} + +/* Compare and swap instruction. */ +static void guest_cas(void) +{ + uint64_t val; + uint64_t addr = TEST_GVA; + + GUEST_ASSERT_EQ(guest_check_lse(), 1); + asm volatile(".arch_extension lse\n" + "casal %0, %1, [%2]\n" + :: "r" (0), "r" (TEST_DATA), "r" (addr)); + val = READ_ONCE(*(uint64_t *)(addr)); + GUEST_ASSERT_EQ(val, TEST_DATA); +} + +static void guest_read64(void) +{ + uint64_t val; + + val = READ_ONCE(*(uint64_t *)TEST_GVA); + GUEST_ASSERT_EQ(val, 0); +} + +/* Address translation instruction */ +static void guest_at(void) +{ + uint64_t par; + uint64_t addr = 0; + + asm volatile("at s1e1r, %0" :: "r" (TEST_GVA)); + par = read_sysreg(par_el1); + + /* Bit 1 indicates whether the AT was successful */ + GUEST_ASSERT_EQ(par & 1, 0); + /* The PA in bits [51:12] */ + addr = par & (((1ULL << 40) - 1) << 12); + GUEST_ASSERT_EQ(addr, memslot[TEST].gpa); +} + +/* + * The size of the block written by "dc zva" is guaranteed to be between (2 << + * 0) and (2 << 9), which is safe in our case as we need the write to happen + * for at least a word, and not more than a page. + */ +static void guest_dc_zva(void) +{ + uint16_t val; + + asm volatile("dc zva, %0\n" + "dsb ish\n" + :: "r" (TEST_GVA)); + val = READ_ONCE(*(uint16_t *)TEST_GVA); + GUEST_ASSERT_EQ(val, 0); +} + +/* + * Pre-indexing loads and stores don't have a valid syndrome (ESR_EL2.ISV==0). + * And that's special because KVM must take special care with those: they + * should still count as accesses for dirty logging or user-faulting, but + * should be handled differently on mmio. + */ +static void guest_ld_preidx(void) +{ + uint64_t val; + uint64_t addr = TEST_GVA - 8; + + /* + * This ends up accessing "TEST_GVA + 8 - 8", where "TEST_GVA - 8" is + * in a gap between memslots not backing by anything. + */ + asm volatile("ldr %0, [%1, #8]!" + : "=r" (val), "+r" (addr)); + GUEST_ASSERT_EQ(val, 0); + GUEST_ASSERT_EQ(addr, TEST_GVA); +} + +static void guest_st_preidx(void) +{ + uint64_t val = TEST_DATA; + uint64_t addr = TEST_GVA - 8; + + asm volatile("str %0, [%1, #8]!" + : "+r" (val), "+r" (addr)); + + GUEST_ASSERT_EQ(addr, TEST_GVA); + val = READ_ONCE(*(uint64_t *)TEST_GVA); +} + +static bool guest_set_ha(void) +{ + uint64_t mmfr1 = read_sysreg(id_aa64mmfr1_el1); + uint64_t hadbs, tcr; + + /* Skip if HA is not supported. */ + hadbs = FIELD_GET(ARM64_FEATURE_MASK(ID_AA64MMFR1_HADBS), mmfr1); + if (hadbs == 0) + return false; + + tcr = read_sysreg(tcr_el1) | TCR_EL1_HA; + write_sysreg(tcr, tcr_el1); + isb(); + + return true; +} + +static bool guest_clear_pte_af(void) +{ + *((uint64_t *)TEST_PTE_GVA) &= ~PTE_AF; + flush_tlb_page(TEST_PTE_GVA); + + return true; +} + +static void guest_check_pte_af(void) +{ + flush_tlb_page(TEST_PTE_GVA); + GUEST_ASSERT_EQ(*((uint64_t *)TEST_PTE_GVA) & PTE_AF, PTE_AF); +} + +static void guest_exec(void) +{ + int (*code)(void) = (int (*)(void))TEST_EXEC_GVA; + int ret; + + ret = code(); + GUEST_ASSERT_EQ(ret, 0x77); +} + +static bool guest_prepare(struct test_desc *test) +{ + bool (*prepare_fn)(void); + int i; + + for (i = 0; i < PREPARE_FN_NR; i++) { + prepare_fn = test->guest_prepare[i]; + if (prepare_fn && !prepare_fn()) + return false; + } + + return true; +} + +static void guest_test_check(struct test_desc *test) +{ + void (*check_fn)(void); + int i; + + for (i = 0; i < CHECK_FN_NR; i++) { + check_fn = test->guest_test_check[i]; + if (!check_fn) + continue; + check_fn(); + } +} + +static void guest_code(struct test_desc *test) +{ + if (!test->guest_test) + test->guest_test = guest_nop; + + if (!guest_prepare(test)) + GUEST_SYNC(CMD_SKIP_TEST); + + GUEST_SYNC(test->mem_mark_cmd); + test->guest_test(); + + guest_test_check(test); + GUEST_DONE(); +} + +static void no_dabt_handler(struct ex_regs *regs) +{ + GUEST_ASSERT_1(false, read_sysreg(far_el1)); +} + +static void no_iabt_handler(struct ex_regs *regs) +{ + GUEST_ASSERT_1(false, regs->pc); +} + +static void punch_hole_in_memslot(struct kvm_vm *vm, + struct memslot_desc *memslot) +{ + int ret, fd; + void *hva; + + fd = vm_mem_region_get_src_fd(vm, memslot->idx); + if (fd != -1) { + ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + 0, memslot->size); + TEST_ASSERT(ret == 0, "fallocate failed, errno: %d\n", errno); + } else { + hva = addr_gpa2hva(vm, memslot->gpa); + ret = madvise(hva, memslot->size, MADV_DONTNEED); + TEST_ASSERT(ret == 0, "madvise failed, errno: %d\n", errno); + } +} + +/* Returns false when the test was skipped. */ +static bool handle_cmd(struct kvm_vm *vm, int cmd) +{ + if (cmd == CMD_SKIP_TEST) + return false; + + if (cmd & CMD_HOLE_PT) + punch_hole_in_memslot(vm, &memslot[PT]); + if (cmd & CMD_HOLE_TEST) + punch_hole_in_memslot(vm, &memslot[TEST]); + + return true; +} + +static void sync_stats_from_guest(struct kvm_vm *vm) +{ + struct event_cnt *ec = addr_gva2hva(vm, (uint64_t)&events); + + events.aborts += ec->aborts; +} + +void fail_vcpu_run_no_handler(int ret) +{ + TEST_FAIL("Unexpected vcpu run failure\n"); +} + +static uint64_t get_total_guest_pages(enum vm_guest_mode mode, + struct test_params *p) +{ + uint64_t backing_page_size = get_backing_src_pagesz(p->src_type); + uint64_t guest_page_size = vm_guest_mode_params[mode].page_size; + uint64_t size; + + size = PT_MEMSLOT_BACKING_SRC_NPAGES * backing_page_size; + size += TEST_MEMSLOT_BACKING_SRC_NPAGES * backing_page_size; + + return size / guest_page_size; +} + +extern unsigned char __exec_test; + +void noinline __return_0x77(void) +{ + asm volatile("__exec_test: mov x0, #0x77\n" + "ret\n"); +} + +static void load_exec_code_for_test(void) +{ + uint64_t *code, *c; + + assert(TEST_EXEC_GVA - TEST_GVA); + code = memslot[TEST].hva + 8; + + /* + * We need the cast to be separate in order for the compiler to not + * complain with: "‘memcpy’ forming offset [1, 7] is out of the bounds + * [0, 1] of object ‘__exec_test’ with type ‘unsigned char’" + */ + c = (uint64_t *)&__exec_test; + memcpy(code, c, 8); +} + +static void setup_abort_handlers(struct kvm_vm *vm, struct test_desc *test) +{ + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(vm, VCPU_ID); + if (!test->dabt_handler) + test->dabt_handler = no_dabt_handler; + if (!test->iabt_handler) + test->iabt_handler = no_iabt_handler; + vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT, + 0x25, test->dabt_handler); + vm_install_sync_handler(vm, VECTOR_SYNC_CURRENT, + 0x21, test->iabt_handler); +} + +static void setup_memslots(struct kvm_vm *vm, enum vm_guest_mode mode, + struct test_params *p) +{ + uint64_t backing_page_size = get_backing_src_pagesz(p->src_type); + uint64_t guest_page_size = vm_guest_mode_params[mode].page_size; + struct test_desc *test = p->test_desc; + uint64_t hole_gpa; + uint64_t alignment; + int i; + + /* Calculate the test and PT memslot sizes */ + for (i = 0; i < NR_MEMSLOTS; i++) { + memslot[i].size = backing_page_size * memslot[i].backing_pages; + memslot[i].guest_pages = memslot[i].size / guest_page_size; + memslot[i].src_type = p->src_type; + } + + TEST_ASSERT(memslot[TEST].size >= guest_page_size, + "The test memslot should have space one guest page.\n"); + TEST_ASSERT(memslot[PT].size >= (4 * guest_page_size), + "The PT memslot sould have space for 4 guest pages.\n"); + + /* Place the memslots GPAs at the end of physical memory */ + alignment = max(backing_page_size, guest_page_size); + memslot[TEST].gpa = (vm_get_max_gfn(vm) - memslot[TEST].guest_pages) * + guest_page_size; + memslot[TEST].gpa = align_down(memslot[TEST].gpa, alignment); + + /* Add a 1-guest_page gap between the two memslots */ + hole_gpa = memslot[TEST].gpa - guest_page_size; + virt_pg_map(vm, TEST_GVA - guest_page_size, hole_gpa); + + memslot[PT].gpa = hole_gpa - (memslot[PT].guest_pages * + guest_page_size); + memslot[PT].gpa = align_down(memslot[PT].gpa, alignment); + + /* Create memslots for the test data and a PTE. */ + vm_userspace_mem_region_add(vm, p->src_type, memslot[PT].gpa, + memslot[PT].idx, memslot[PT].guest_pages, + test->pt_memslot_flags); + vm_userspace_mem_region_add(vm, p->src_type, memslot[TEST].gpa, + memslot[TEST].idx, memslot[TEST].guest_pages, + test->test_memslot_flags); + + for (i = 0; i < NR_MEMSLOTS; i++) + memslot[i].hva = addr_gpa2hva(vm, memslot[i].gpa); + + /* Map the test TEST_GVA using the PT memslot. */ + _virt_pg_map(vm, TEST_GVA, memslot[TEST].gpa, MT_NORMAL, + TEST_PT_SLOT_INDEX); + + /* + * Find the PTE of the test page and map it in the guest so it can + * clear the AF. + */ + pte_gpa = vm_get_pte_gpa(vm, TEST_GVA); + TEST_ASSERT(memslot[PT].gpa <= pte_gpa && + pte_gpa < (memslot[PT].gpa + memslot[PT].size), + "The EPT should be in the PT memslot."); + /* This is an artibrary requirement just to make things simpler. */ + TEST_ASSERT(pte_gpa % guest_page_size == 0, + "The pte_gpa (%p) should be aligned to the guest page (%lx).", + (void *)pte_gpa, guest_page_size); + virt_pg_map(vm, TEST_PTE_GVA, pte_gpa); +} + +static void check_event_counts(struct test_desc *test) +{ + ASSERT_EQ(test->expected_events.aborts, events.aborts); +} + +static void print_test_banner(enum vm_guest_mode mode, struct test_params *p) +{ + struct test_desc *test = p->test_desc; + + pr_debug("Test: %s\n", test->name); + pr_debug("Testing guest mode: %s\n", vm_guest_mode_string(mode)); + pr_debug("Testing memory backing src type: %s\n", + vm_mem_backing_src_alias(p->src_type)->name); +} + +static void reset_event_counts(void) +{ + memset(&events, 0, sizeof(events)); +} + +static bool vcpu_run_loop(struct kvm_vm *vm, struct test_desc *test) +{ + bool skip_test = false; + struct ucall uc; + int stage; + + for (stage = 0; ; stage++) { + vcpu_run(vm, VCPU_ID); + + switch (get_ucall(vm, VCPU_ID, &uc)) { + case UCALL_SYNC: + if (!handle_cmd(vm, uc.args[1])) { + pr_debug("Skipped.\n"); + skip_test = true; + goto done; + } + break; + case UCALL_ABORT: + TEST_FAIL("%s at %s:%ld\n\tvalues: %#lx, %#lx", + (const char *)uc.args[0], + __FILE__, uc.args[1], uc.args[2], uc.args[3]); + break; + case UCALL_DONE: + pr_debug("Done.\n"); + goto done; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + } + } + +done: + return skip_test; +} + +static void run_test(enum vm_guest_mode mode, void *arg) +{ + struct test_params *p = (struct test_params *)arg; + struct test_desc *test = p->test_desc; + struct kvm_vm *vm; + bool skip_test = false; + + print_test_banner(mode, p); + + vm = vm_create_with_vcpus(mode, 1, DEFAULT_GUEST_PHY_PAGES, + get_total_guest_pages(mode, p), 0, guest_code, NULL); + ucall_init(vm, NULL); + + reset_event_counts(); + setup_memslots(vm, mode, p); + + load_exec_code_for_test(); + setup_abort_handlers(vm, test); + vcpu_args_set(vm, 0, 1, test); + + sync_global_to_guest(vm, memslot); + + skip_test = vcpu_run_loop(vm, test); + + sync_stats_from_guest(vm); + ucall_uninit(vm); + kvm_vm_free(vm); + + if (!skip_test) + check_event_counts(test); +} + +static void for_each_test_and_guest_mode(void (*func)(enum vm_guest_mode, void *), + enum vm_mem_backing_src_type src_type); + +static void help(char *name) +{ + puts(""); + printf("usage: %s [-h] [-s mem-type]\n", name); + puts(""); + guest_modes_help(); + backing_src_help("-s"); + puts(""); +} + +int main(int argc, char *argv[]) +{ + enum vm_mem_backing_src_type src_type; + int opt; + + setbuf(stdout, NULL); + + src_type = DEFAULT_VM_MEM_SRC; + + guest_modes_append_default(); + + while ((opt = getopt(argc, argv, "hm:s:")) != -1) { + switch (opt) { + case 'm': + guest_modes_cmdline(optarg); + break; + case 's': + src_type = parse_backing_src_type(optarg); + break; + case 'h': + default: + help(argv[0]); + exit(0); + } + } + + for_each_test_and_guest_mode(run_test, src_type); + return 0; +} + +#define SNAME(s) #s +#define SCAT2(a, b) SNAME(a ## _ ## b) +#define SCAT3(a, b, c) SCAT2(a, SCAT2(b, c)) + +#define _CHECK(_test) _CHECK_##_test +#define _PREPARE(_test) _PREPARE_##_test +#define _PREPARE_guest_read64 guest_prepare_nop +#define _PREPARE_guest_ld_preidx guest_prepare_nop +#define _PREPARE_guest_write64 guest_prepare_nop +#define _PREPARE_guest_st_preidx guest_prepare_nop +#define _PREPARE_guest_exec guest_prepare_nop +#define _PREPARE_guest_at guest_prepare_nop +#define _PREPARE_guest_dc_zva guest_check_dc_zva +#define _PREPARE_guest_cas guest_check_lse + +/* With or without access flag checks */ +#define _PREPARE_with_af guest_set_ha, guest_clear_pte_af +#define _PREPARE_no_af guest_prepare_nop +#define _CHECK_with_af guest_check_pte_af +#define _CHECK_no_af guest_check_nop + +/* Performs an access and checks that no faults (no events) were triggered. */ +#define TEST_ACCESS(_access, _with_af, _mark_cmd) \ +{ \ + .name = SCAT3(_access, _with_af, #_mark_cmd), \ + .guest_prepare = { _PREPARE(_with_af), \ + _PREPARE(_access) }, \ + .mem_mark_cmd = _mark_cmd, \ + .guest_test = _access, \ + .guest_test_check = { _CHECK(_with_af) }, \ + .expected_events = { 0 }, \ +} + +static struct test_desc tests[] = { + /* Check that HW is setting the Access Flag (AF) (sanity checks). */ + TEST_ACCESS(guest_read64, with_af, CMD_NONE), + TEST_ACCESS(guest_ld_preidx, with_af, CMD_NONE), + TEST_ACCESS(guest_cas, with_af, CMD_NONE), + TEST_ACCESS(guest_write64, with_af, CMD_NONE), + TEST_ACCESS(guest_st_preidx, with_af, CMD_NONE), + TEST_ACCESS(guest_dc_zva, with_af, CMD_NONE), + TEST_ACCESS(guest_exec, with_af, CMD_NONE), + + /* + * Accessing a hole in the test memslot (punched with fallocate or + * madvise) shouldn't fault (more sanity checks). + */ + TEST_ACCESS(guest_read64, no_af, CMD_HOLE_TEST), + TEST_ACCESS(guest_cas, no_af, CMD_HOLE_TEST), + TEST_ACCESS(guest_ld_preidx, no_af, CMD_HOLE_TEST), + TEST_ACCESS(guest_write64, no_af, CMD_HOLE_TEST), + TEST_ACCESS(guest_st_preidx, no_af, CMD_HOLE_TEST), + TEST_ACCESS(guest_at, no_af, CMD_HOLE_TEST), + TEST_ACCESS(guest_dc_zva, no_af, CMD_HOLE_TEST), + + { 0 }, +}; + +static void for_each_test_and_guest_mode( + void (*func)(enum vm_guest_mode m, void *a), + enum vm_mem_backing_src_type src_type) +{ + struct test_desc *t; + + for (t = &tests[0]; t->name; t++) { + if (t->skip) + continue; + + struct test_params p = { + .src_type = src_type, + .test_desc = t, + }; + + for_each_guest_mode(run_test, &p); + } +} diff --git a/tools/testing/selftests/kvm/include/aarch64/processor.h b/tools/testing/selftests/kvm/include/aarch64/processor.h index 16753a1f28e3..cb5849fd8fd1 100644 --- a/tools/testing/selftests/kvm/include/aarch64/processor.h +++ b/tools/testing/selftests/kvm/include/aarch64/processor.h @@ -125,6 +125,12 @@ enum { #define ESR_EC_WP_CURRENT 0x35 #define ESR_EC_BRK_INS 0x3c +/* Access flag */ +#define PTE_AF (1ULL << 10) + +/* Acces flag update enable/disable */ +#define TCR_EL1_HA (1ULL << 39) + void aarch64_get_supported_page_sizes(uint32_t ipa, bool *ps4k, bool *ps16k, bool *ps64k); From patchwork Fri Apr 8 00:41:17 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805968 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B641EC433EF for ; Fri, 8 Apr 2022 00:41:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233101AbiDHAno (ORCPT ); Thu, 7 Apr 2022 20:43:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39172 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233085AbiDHAnl (ORCPT ); Thu, 7 Apr 2022 20:43:41 -0400 Received: from mail-pg1-x549.google.com (mail-pg1-x549.google.com [IPv6:2607:f8b0:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B262E4163E for ; Thu, 7 Apr 2022 17:41:39 -0700 (PDT) Received: by mail-pg1-x549.google.com with SMTP id d1-20020a631d41000000b0039cbc6d6499so2614008pgm.7 for ; Thu, 07 Apr 2022 17:41:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=vmPxi8tlqNKxZd05a1XP/jao3E82fBv+i/4x7pnaLsI=; b=tMIuX0yqrclqYGkpTzh/qLhiF10GNnRXa1Nk//WTzhHNhjuHwW7Zf/y4gV3vufmaGE w++9eq0eqfz10dQi1xFQVIdPDQ43/yc/sekFfKgBswkq8c+hPL5pwzcRYKutblQCWat/ l/ak6XVuFefGxfFueLCZUmfiSiK/WaHdVbd92YGcTcamLQXg1/RPZvJ1wpT5PZGtJk3p JFpZXMm3hSffNSyojcXWGEhDrF/OhPR5rQFz5HSrBDiO8dDlNY32lXA9ZGy1h11FgaSk RCygPZtzuKBb9b62pXLZ1EiuoqhaWyUp06ZFAE4+nvIDcxrHGiruQpk996MEYuYGTSxD w/7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=vmPxi8tlqNKxZd05a1XP/jao3E82fBv+i/4x7pnaLsI=; b=Xnh4ZKYRydIBeaMvIhWEdCBcDCrph8d2rA4eGpBF4X0ZdFrkAI92ISUYceTBLdSBPI oInG3pC8ZyaFkKkURosfct4UYE6Pu45dRhaNLeiQCOPZDDq8zgBBZI/4AlTCj+UysjXY 87sJq1dO4bpKFono5361T08r3uHCwDXRnFe7/nZrF5/o/lSre4xRSr7Mv1mJdwjJRwD9 Xr8FLG4mSWx6089mHAqd6IvrW15zufx2fJ8Rh2Sy2jcGTKfdmHhZoaA3GmdOFs4pnWTy Dm2uozIsb7s8/j2GmL+dtQCexiozFL5qjFWyAh8el9ocAxN5/wRd1rzjvzQ28bjhjLbH 8Lqg== X-Gm-Message-State: AOAM533DNciu+6/s9KHDx7yK7+d0821WwCLcBzQYsoomnBjhx6vsWFmY z3f7VESabe1np9YGSXmgFLgvTKuC/zrKtelQdO7cobZnFFqblYPLPlePG9rw55M7HoLVYRPlWjV bUPSj/NBww0ictvRdiSnOV44iw2A2/caZirxzM5g9NGnslA6D2YWVuWW/gIP20JI= X-Google-Smtp-Source: ABdhPJw2ii8+mstoIuvp0zydoE6c6ec/E5e3hrWq9R0OHBslT05bVGeSTfjavLWiiOJfCDLrMZTaTtXLvKUpgw== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a05:6a00:182a:b0:4fd:dee2:6371 with SMTP id y42-20020a056a00182a00b004fddee26371mr16982089pfa.8.1649378499100; Thu, 07 Apr 2022 17:41:39 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:17 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-11-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 10/13] KVM: selftests: aarch64: Add userfaultfd tests into page_fault_test From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add some userfaultfd tests into page_fault_test. Punch holes into the data and/or page-table memslots, perform some accesses, and check that the faults are taken (or not taken) when expected. Signed-off-by: Ricardo Koller --- .../selftests/kvm/aarch64/page_fault_test.c | 171 +++++++++++++++++- 1 file changed, 169 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c index 04fc6007f630..bee525625956 100644 --- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -52,6 +52,8 @@ uint64_t pte_gpa; enum { PT, TEST, NR_MEMSLOTS}; struct memslot_desc { + size_t paging_size; + char *data_copy; void *hva; uint64_t gpa; uint64_t size; @@ -73,6 +75,9 @@ struct memslot_desc { static struct event_cnt { int aborts; int fail_vcpu_runs; + int uffd_faults; + /* uffd_faults is incremented from multiple threads. */ + pthread_mutex_t uffd_faults_mutex; } events; struct test_desc { @@ -82,6 +87,8 @@ struct test_desc { bool (*guest_prepare[PREPARE_FN_NR])(void); void (*guest_test)(void); void (*guest_test_check[CHECK_FN_NR])(void); + int (*uffd_pt_handler)(int mode, int uffd, struct uffd_msg *msg); + int (*uffd_test_handler)(int mode, int uffd, struct uffd_msg *msg); void (*dabt_handler)(struct ex_regs *regs); void (*iabt_handler)(struct ex_regs *regs); uint32_t pt_memslot_flags; @@ -306,6 +313,7 @@ static void guest_code(struct test_desc *test) if (!guest_prepare(test)) GUEST_SYNC(CMD_SKIP_TEST); + flush_tlb_page(TEST_GVA); GUEST_SYNC(test->mem_mark_cmd); test->guest_test(); @@ -323,6 +331,56 @@ static void no_iabt_handler(struct ex_regs *regs) GUEST_ASSERT_1(false, regs->pc); } +static int uffd_generic_handler(int uffd_mode, int uffd, + struct uffd_msg *msg, struct memslot_desc *memslot, + bool expect_write) +{ + uint64_t addr = msg->arg.pagefault.address; + uint64_t flags = msg->arg.pagefault.flags; + struct uffdio_copy copy; + int ret; + + TEST_ASSERT(uffd_mode == UFFDIO_REGISTER_MODE_MISSING, + "The only expected UFFD mode is MISSING"); + ASSERT_EQ(!!(flags & UFFD_PAGEFAULT_FLAG_WRITE), expect_write); + ASSERT_EQ(addr, (uint64_t)memslot->hva); + + pr_debug("uffd fault: addr=%p write=%d\n", + (void *)addr, !!(flags & UFFD_PAGEFAULT_FLAG_WRITE)); + + copy.src = (uint64_t)memslot->data_copy; + copy.dst = addr; + copy.len = memslot->paging_size; + copy.mode = 0; + + ret = ioctl(uffd, UFFDIO_COPY, ©); + if (ret == -1) { + pr_info("Failed UFFDIO_COPY in 0x%lx with errno: %d\n", + addr, errno); + return ret; + } + + pthread_mutex_lock(&events.uffd_faults_mutex); + events.uffd_faults += 1; + pthread_mutex_unlock(&events.uffd_faults_mutex); + return 0; +} + +static int uffd_pt_write_handler(int mode, int uffd, struct uffd_msg *msg) +{ + return uffd_generic_handler(mode, uffd, msg, &memslot[PT], true); +} + +static int uffd_test_write_handler(int mode, int uffd, struct uffd_msg *msg) +{ + return uffd_generic_handler(mode, uffd, msg, &memslot[TEST], true); +} + +static int uffd_test_read_handler(int mode, int uffd, struct uffd_msg *msg) +{ + return uffd_generic_handler(mode, uffd, msg, &memslot[TEST], false); +} + static void punch_hole_in_memslot(struct kvm_vm *vm, struct memslot_desc *memslot) { @@ -332,11 +390,11 @@ static void punch_hole_in_memslot(struct kvm_vm *vm, fd = vm_mem_region_get_src_fd(vm, memslot->idx); if (fd != -1) { ret = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, - 0, memslot->size); + 0, memslot->paging_size); TEST_ASSERT(ret == 0, "fallocate failed, errno: %d\n", errno); } else { hva = addr_gpa2hva(vm, memslot->gpa); - ret = madvise(hva, memslot->size, MADV_DONTNEED); + ret = madvise(hva, memslot->paging_size, MADV_DONTNEED); TEST_ASSERT(ret == 0, "madvise failed, errno: %d\n", errno); } } @@ -484,9 +542,60 @@ static void setup_memslots(struct kvm_vm *vm, enum vm_guest_mode mode, virt_pg_map(vm, TEST_PTE_GVA, pte_gpa); } +static void setup_uffd(enum vm_guest_mode mode, struct test_params *p, + struct uffd_desc **uffd) +{ + struct test_desc *test = p->test_desc; + uint64_t large_page_size = get_backing_src_pagesz(p->src_type); + int i; + + /* + * When creating the map, we might not only have created a pte page, + * but also an intermediate level (pte_gpa != gpa[PT]). So, we + * might need to demand page both. + */ + memslot[PT].paging_size = align_up(pte_gpa - memslot[PT].gpa, + large_page_size) + large_page_size; + memslot[TEST].paging_size = large_page_size; + + for (i = 0; i < NR_MEMSLOTS; i++) { + memslot[i].data_copy = malloc(memslot[i].paging_size); + TEST_ASSERT(memslot[i].data_copy, "Failed malloc."); + memcpy(memslot[i].data_copy, memslot[i].hva, + memslot[i].paging_size); + } + + uffd[PT] = NULL; + if (test->uffd_pt_handler) + uffd[PT] = uffd_setup_demand_paging( + UFFDIO_REGISTER_MODE_MISSING, 0, + memslot[PT].hva, memslot[PT].paging_size, + test->uffd_pt_handler); + + uffd[TEST] = NULL; + if (test->uffd_test_handler) + uffd[TEST] = uffd_setup_demand_paging( + UFFDIO_REGISTER_MODE_MISSING, 0, + memslot[TEST].hva, memslot[TEST].paging_size, + test->uffd_test_handler); +} + static void check_event_counts(struct test_desc *test) { ASSERT_EQ(test->expected_events.aborts, events.aborts); + ASSERT_EQ(test->expected_events.uffd_faults, events.uffd_faults); +} + +static void free_uffd(struct test_desc *test, struct uffd_desc **uffd) +{ + int i; + + if (test->uffd_pt_handler) + uffd_stop_demand_paging(uffd[PT]); + if (test->uffd_test_handler) + uffd_stop_demand_paging(uffd[TEST]); + for (i = 0; i < NR_MEMSLOTS; i++) + free(memslot[i].data_copy); } static void print_test_banner(enum vm_guest_mode mode, struct test_params *p) @@ -543,6 +652,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) struct test_params *p = (struct test_params *)arg; struct test_desc *test = p->test_desc; struct kvm_vm *vm; + struct uffd_desc *uffd[NR_MEMSLOTS]; bool skip_test = false; print_test_banner(mode, p); @@ -554,7 +664,14 @@ static void run_test(enum vm_guest_mode mode, void *arg) reset_event_counts(); setup_memslots(vm, mode, p); + /* + * Set some code at memslot[TEST].hva for the guest to execute (only + * applicable to the EXEC tests). This has to be done before + * setup_uffd() as that function copies the memslot data for the uffd + * handler. + */ load_exec_code_for_test(); + setup_uffd(mode, p, uffd); setup_abort_handlers(vm, test); vcpu_args_set(vm, 0, 1, test); @@ -565,7 +682,12 @@ static void run_test(enum vm_guest_mode mode, void *arg) sync_stats_from_guest(vm); ucall_uninit(vm); kvm_vm_free(vm); + free_uffd(test, uffd); + /* + * Make sure this is called after the uffd threads have exited (and + * updated their respective event counters). + */ if (!skip_test) check_event_counts(test); } @@ -616,6 +738,7 @@ int main(int argc, char *argv[]) #define SNAME(s) #s #define SCAT2(a, b) SNAME(a ## _ ## b) #define SCAT3(a, b, c) SCAT2(a, SCAT2(b, c)) +#define SCAT4(a, b, c, d) SCAT2(a, SCAT3(b, c, d)) #define _CHECK(_test) _CHECK_##_test #define _PREPARE(_test) _PREPARE_##_test @@ -646,6 +769,20 @@ int main(int argc, char *argv[]) .expected_events = { 0 }, \ } +#define TEST_UFFD(_access, _with_af, _mark_cmd, \ + _uffd_test_handler, _uffd_pt_handler, _uffd_faults) \ +{ \ + .name = SCAT4(uffd, _access, _with_af, #_mark_cmd), \ + .guest_prepare = { _PREPARE(_with_af), \ + _PREPARE(_access) }, \ + .guest_test = _access, \ + .mem_mark_cmd = _mark_cmd, \ + .guest_test_check = { _CHECK(_with_af) }, \ + .uffd_test_handler = _uffd_test_handler, \ + .uffd_pt_handler = _uffd_pt_handler, \ + .expected_events = { .uffd_faults = _uffd_faults, }, \ +} + static struct test_desc tests[] = { /* Check that HW is setting the Access Flag (AF) (sanity checks). */ TEST_ACCESS(guest_read64, with_af, CMD_NONE), @@ -668,6 +805,36 @@ static struct test_desc tests[] = { TEST_ACCESS(guest_at, no_af, CMD_HOLE_TEST), TEST_ACCESS(guest_dc_zva, no_af, CMD_HOLE_TEST), + /* + * Punch holes in the test and PT memslots and mark them for + * userfaultfd handling. This should result in 2 faults: the test + * access and its respective S1 page table walk (S1PTW). + */ + TEST_UFFD(guest_read64, with_af, CMD_HOLE_TEST | CMD_HOLE_PT, + uffd_test_read_handler, uffd_pt_write_handler, 2), + /* no_af should also lead to a PT write. */ + TEST_UFFD(guest_read64, no_af, CMD_HOLE_TEST | CMD_HOLE_PT, + uffd_test_read_handler, uffd_pt_write_handler, 2), + /* Note how that cas invokes the read handler. */ + TEST_UFFD(guest_cas, with_af, CMD_HOLE_TEST | CMD_HOLE_PT, + uffd_test_read_handler, uffd_pt_write_handler, 2), + /* + * Can't test guest_at with_af as it's IMPDEF whether the AF is set. + * The S1PTW fault should still be marked as a write. + */ + TEST_UFFD(guest_at, no_af, CMD_HOLE_TEST | CMD_HOLE_PT, + uffd_test_read_handler, uffd_pt_write_handler, 1), + TEST_UFFD(guest_ld_preidx, with_af, CMD_HOLE_TEST | CMD_HOLE_PT, + uffd_test_read_handler, uffd_pt_write_handler, 2), + TEST_UFFD(guest_write64, with_af, CMD_HOLE_TEST | CMD_HOLE_PT, + uffd_test_write_handler, uffd_pt_write_handler, 2), + TEST_UFFD(guest_dc_zva, with_af, CMD_HOLE_TEST | CMD_HOLE_PT, + uffd_test_write_handler, uffd_pt_write_handler, 2), + TEST_UFFD(guest_st_preidx, with_af, CMD_HOLE_TEST | CMD_HOLE_PT, + uffd_test_write_handler, uffd_pt_write_handler, 2), + TEST_UFFD(guest_exec, with_af, CMD_HOLE_TEST | CMD_HOLE_PT, + uffd_test_read_handler, uffd_pt_write_handler, 2), + { 0 }, }; From patchwork Fri Apr 8 00:41:18 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805969 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 97D4DC43217 for ; Fri, 8 Apr 2022 00:41:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233104AbiDHAnp (ORCPT ); Thu, 7 Apr 2022 20:43:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39290 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233089AbiDHAnm (ORCPT ); Thu, 7 Apr 2022 20:43:42 -0400 Received: from mail-pj1-x104a.google.com (mail-pj1-x104a.google.com [IPv6:2607:f8b0:4864:20::104a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 697E6176D35 for ; Thu, 7 Apr 2022 17:41:41 -0700 (PDT) Received: by mail-pj1-x104a.google.com with SMTP id mn10-20020a17090b188a00b001cab9c0bc4dso6730457pjb.1 for ; Thu, 07 Apr 2022 17:41:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=aoevi1/32QaVDCl+0szzfKHcofBdzbe9olbkExGouDU=; b=Q3W9yM2TaUg82+PVHhJ8mGGjamC+M7ubH5r5aVeen2pcp/xncjpRLX2bxSAbh9u0wU 2Mjoo9kni1Ftlar5xEf8tT50lHbRkf9ITovBMge+y+LDBUh83qjcXIgPTyk1h+Y7oVL2 MlYJl0OgTPZWfmtD5UDrY2A2/UoiYOnwS08NHJ3lcr0dlRYIR5HZI5Mc+Gb8oF89HKF4 vzZLgAJ345U7wtQqHIcumU6JIntk952u6HHQIQbU57ZaBxo5/FPA7rjyle3ICFdRbcN4 cxT/FwFLPehjYXC3tVmLfQe7xPcBL+4JP3IUzG3JBMxTYGdUYokEGfl+OqgpqPinssEH zVQQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=aoevi1/32QaVDCl+0szzfKHcofBdzbe9olbkExGouDU=; b=EJ71PyocEqBvGUKPzkV/8ntM83YYUXP5RbI7cOytllFdctXDRAJ8k9BSSAOAX9L1c5 KFe1VJR+dzEiLBnsm6ljxM+MxKg6NAIu6hm5WYXQ+e5uS91hEg4JdgV7U+OSbRZr1lGo bFPGH62DvPky+ItMa+2rQCvHqzepsDSQYx0mAGqWB8uz38DCEtgAR4cFmqHQy0R065/1 uYyYSjW+L/VerXPm3NbT4M70KZbOyNG8sCjTu//knXoY40NF+jfV+2INndyJwIdDJSTG 36cwho/fKIPMkkBI7bLG1XU/Ox3oubK0dr6qZtlhUewrvznLMPhJ8ZQksIImPp5GzZ6q j24g== X-Gm-Message-State: AOAM533qJrkKXvEHjE5cNsSdmR9wWjBRfsZ8mfnEdJz2DRdItR2RY+6K jq7FWyqaUIkmlbu0aHNTkqyHOyndXmg8nozjOIN5bNGI6B2auwhEdRUJ4A7qtyKR3/DZkcDp+8R +nOalddbmNrtE+VmWkzKcTGcR2j6FDgWNm5lNDhB1ZvLIqvdDjDNnD1/oATlaMQ8= X-Google-Smtp-Source: ABdhPJwiQGNa+4qbobcoTIwwKQaBhvMBS+dfIPSyzmuIf4+XOeYr9E/iSLYO1Q0ddo5TGg+q+oAsMD5PGSBGuA== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a17:902:bcca:b0:153:88c7:a02 with SMTP id o10-20020a170902bcca00b0015388c70a02mr16810370pls.112.1649378500718; Thu, 07 Apr 2022 17:41:40 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:18 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-12-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 11/13] KVM: selftests: aarch64: Add dirty logging tests into page_fault_test From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add some dirty logging tests into page_fault_test. Mark the data and/or page-table memslots for dirty logging, perform some accesses, and check that the dirty log bits are set or clean when expected. Signed-off-by: Ricardo Koller --- .../selftests/kvm/aarch64/page_fault_test.c | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c index bee525625956..342170e207b0 100644 --- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -43,6 +43,12 @@ #define CMD_SKIP_TEST (1ULL << 1) #define CMD_HOLE_PT (1ULL << 2) #define CMD_HOLE_TEST (1ULL << 3) +#define CMD_RECREATE_PT_MEMSLOT_WR (1ULL << 4) +#define CMD_CHECK_WRITE_IN_DIRTY_LOG (1ULL << 5) +#define CMD_CHECK_S1PTW_WR_IN_DIRTY_LOG (1ULL << 6) +#define CMD_CHECK_NO_WRITE_IN_DIRTY_LOG (1ULL << 7) +#define CMD_CHECK_NO_S1PTW_WR_IN_DIRTY_LOG (1ULL << 8) +#define CMD_SET_PTE_AF (1ULL << 9) #define PREPARE_FN_NR 10 #define CHECK_FN_NR 10 @@ -269,6 +275,21 @@ static void guest_check_pte_af(void) GUEST_ASSERT_EQ(*((uint64_t *)TEST_PTE_GVA) & PTE_AF, PTE_AF); } +static void guest_check_write_in_dirty_log(void) +{ + GUEST_SYNC(CMD_CHECK_WRITE_IN_DIRTY_LOG); +} + +static void guest_check_no_write_in_dirty_log(void) +{ + GUEST_SYNC(CMD_CHECK_NO_WRITE_IN_DIRTY_LOG); +} + +static void guest_check_s1ptw_wr_in_dirty_log(void) +{ + GUEST_SYNC(CMD_CHECK_S1PTW_WR_IN_DIRTY_LOG); +} + static void guest_exec(void) { int (*code)(void) = (int (*)(void))TEST_EXEC_GVA; @@ -399,6 +420,19 @@ static void punch_hole_in_memslot(struct kvm_vm *vm, } } +static bool check_write_in_dirty_log(struct kvm_vm *vm, + struct memslot_desc *ms, uint64_t host_pg_nr) +{ + unsigned long *bmap; + bool first_page_dirty; + + bmap = bitmap_zalloc(ms->size / getpagesize()); + kvm_vm_get_dirty_log(vm, ms->idx, bmap); + first_page_dirty = test_bit(host_pg_nr, bmap); + free(bmap); + return first_page_dirty; +} + /* Returns false when the test was skipped. */ static bool handle_cmd(struct kvm_vm *vm, int cmd) { @@ -409,6 +443,18 @@ static bool handle_cmd(struct kvm_vm *vm, int cmd) punch_hole_in_memslot(vm, &memslot[PT]); if (cmd & CMD_HOLE_TEST) punch_hole_in_memslot(vm, &memslot[TEST]); + if (cmd & CMD_CHECK_WRITE_IN_DIRTY_LOG) + TEST_ASSERT(check_write_in_dirty_log(vm, &memslot[TEST], 0), + "Missing write in dirty log"); + if (cmd & CMD_CHECK_S1PTW_WR_IN_DIRTY_LOG) + TEST_ASSERT(check_write_in_dirty_log(vm, &memslot[PT], 0), + "Missing s1ptw write in dirty log"); + if (cmd & CMD_CHECK_NO_WRITE_IN_DIRTY_LOG) + TEST_ASSERT(!check_write_in_dirty_log(vm, &memslot[TEST], 0), + "Unexpected write in dirty log"); + if (cmd & CMD_CHECK_NO_S1PTW_WR_IN_DIRTY_LOG) + TEST_ASSERT(!check_write_in_dirty_log(vm, &memslot[PT], 0), + "Unexpected s1ptw write in dirty log"); return true; } @@ -783,6 +829,19 @@ int main(int argc, char *argv[]) .expected_events = { .uffd_faults = _uffd_faults, }, \ } +#define TEST_DIRTY_LOG(_access, _with_af, _test_check) \ +{ \ + .name = SCAT3(dirty_log, _access, _with_af), \ + .test_memslot_flags = KVM_MEM_LOG_DIRTY_PAGES, \ + .pt_memslot_flags = KVM_MEM_LOG_DIRTY_PAGES, \ + .guest_prepare = { _PREPARE(_with_af), \ + _PREPARE(_access) }, \ + .guest_test = _access, \ + .guest_test_check = { _CHECK(_with_af), _test_check, \ + guest_check_s1ptw_wr_in_dirty_log}, \ + .expected_events = { 0 }, \ +} + static struct test_desc tests[] = { /* Check that HW is setting the Access Flag (AF) (sanity checks). */ TEST_ACCESS(guest_read64, with_af, CMD_NONE), @@ -835,6 +894,21 @@ static struct test_desc tests[] = { TEST_UFFD(guest_exec, with_af, CMD_HOLE_TEST | CMD_HOLE_PT, uffd_test_read_handler, uffd_pt_write_handler, 2), + /* + * Try accesses when the test and PT memslots are both tracked for + * dirty logging. + */ + TEST_DIRTY_LOG(guest_read64, with_af, guest_check_no_write_in_dirty_log), + /* no_af should also lead to a PT write. */ + TEST_DIRTY_LOG(guest_read64, no_af, guest_check_no_write_in_dirty_log), + TEST_DIRTY_LOG(guest_ld_preidx, with_af, guest_check_no_write_in_dirty_log), + TEST_DIRTY_LOG(guest_at, no_af, guest_check_no_write_in_dirty_log), + TEST_DIRTY_LOG(guest_exec, with_af, guest_check_no_write_in_dirty_log), + TEST_DIRTY_LOG(guest_write64, with_af, guest_check_write_in_dirty_log), + TEST_DIRTY_LOG(guest_cas, with_af, guest_check_write_in_dirty_log), + TEST_DIRTY_LOG(guest_dc_zva, with_af, guest_check_write_in_dirty_log), + TEST_DIRTY_LOG(guest_st_preidx, with_af, guest_check_write_in_dirty_log), + { 0 }, }; From patchwork Fri Apr 8 00:41:19 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id ADFD9C433FE for ; Fri, 8 Apr 2022 00:41:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233110AbiDHAnr (ORCPT ); Thu, 7 Apr 2022 20:43:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39562 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233102AbiDHAnp (ORCPT ); Thu, 7 Apr 2022 20:43:45 -0400 Received: from mail-pj1-x104a.google.com (mail-pj1-x104a.google.com [IPv6:2607:f8b0:4864:20::104a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 37F1F1786B3 for ; Thu, 7 Apr 2022 17:41:43 -0700 (PDT) Received: by mail-pj1-x104a.google.com with SMTP id mm2-20020a17090b358200b001bf529127dfso4420629pjb.6 for ; Thu, 07 Apr 2022 17:41:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=0JC27tzxF0DH2/IqsaHt7sMZZrQrpnDQEZxqc8XX/us=; b=G8cwN5MoapOTNKzP7bxMWmyQDpbB6oJ8uyQjQawFuIOxhSTvb9FcJ6bOOdm/rtajz0 TkOn+Yupdz1XAeb8rv+sILLr5Z1UZUXvIclhWIziQ6oUjeCwBgTAYdRdLfD7LnMelCmp qvn6+i0ysj+dwQJ/6un4AcGYhePAurijQ7HgZFJyDI34u8OioMKs0fxgyJslGuWCXP7/ myEAMb2qv7KFnejkoBLXIiILR2vku0bDl1X0yw6tz2/QFehlvJSZUy1BLO6pOywBR/I0 juV+RCwGUIivYJOTMZzofiZsM/ORi2CGlE0CuYh8M9h63yoaa5YYctnGyuU6qrGgk8pU kOGg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=0JC27tzxF0DH2/IqsaHt7sMZZrQrpnDQEZxqc8XX/us=; b=IcUTf14rPHyVzT1Y5PqUu+IYdvKMXvV+w91x5HRtnnC80IBOyB2ZzTrFIEGxlSivjI VvjDnlENyZgJFKwkOzbxceMf3UyzbK01mG0zsKbnxG3X0JEkfsAYmgdksYENIrQ4WcKa 1Vtsz/Eas+Tbiv0uGg7SILFu5pA6g8CvzaEEn12gclGtzAoe2N0l2O9bSBPapGnev7ic Txiu0fKVfT/3WR5mMmmlKlNEddsJ/PHAXoqE9GFgDGm3Uxz+i555uCY8Y+S5VZNWDPr3 HOBXANjaWT4l6KSTKDVlC7ZraSong2x6SjTct7zQl6FzYg0Qv6V8bQiTVXzyI0I3Lz/g dTsQ== X-Gm-Message-State: AOAM531zcth2w4jzq0UBBmXHbWcCNRc4KeqFbP0jqo45r8gY6TLovJ9Q MxdWcS3fsGYZlYgF8yR0DPPNIrFxPuv98UevNAd88secoyZX41p5zlXtLvQQ3EHnTxKLYKj/xT7 dZNpTtDH7KmxIoy4Q0QQdGM82LL98z0D8qCdL8CFSQbx72myBMnFwM7OMr9m1Zzg= X-Google-Smtp-Source: ABdhPJyZAQXUaQMTLgHlY/W0lQueq3rPlOYdS7IEJFB8N1AQsrUeB83cPkXxOQkOSlNvRY6V2z0bn4HWEilgMQ== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:a17:903:248:b0:155:e8c6:8770 with SMTP id j8-20020a170903024800b00155e8c68770mr16082508plh.129.1649378502460; Thu, 07 Apr 2022 17:41:42 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:19 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-13-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 12/13] KVM: selftests: aarch64: Add readonly memslot tests into page_fault_test From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add some readonly memslot tests into page_fault_test. Mark the data and/or page-table memslots as readonly, perform some accesses, and check that the right fault is triggered when expected (e.g., a store with no write-back should lead to an mmio exit). Signed-off-by: Ricardo Koller --- .../selftests/kvm/aarch64/page_fault_test.c | 151 +++++++++++++++++- 1 file changed, 148 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c index 342170e207b0..70085db873d3 100644 --- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -80,6 +80,7 @@ struct memslot_desc { static struct event_cnt { int aborts; + int mmio_exits; int fail_vcpu_runs; int uffd_faults; /* uffd_faults is incremented from multiple threads. */ @@ -97,6 +98,8 @@ struct test_desc { int (*uffd_test_handler)(int mode, int uffd, struct uffd_msg *msg); void (*dabt_handler)(struct ex_regs *regs); void (*iabt_handler)(struct ex_regs *regs); + void (*mmio_handler)(struct kvm_run *run); + void (*fail_vcpu_run_handler)(int ret); uint32_t pt_memslot_flags; uint32_t test_memslot_flags; bool skip; @@ -342,6 +345,20 @@ static void guest_code(struct test_desc *test) GUEST_DONE(); } +static void dabt_s1ptw_on_ro_memslot_handler(struct ex_regs *regs) +{ + GUEST_ASSERT_EQ(read_sysreg(far_el1), TEST_GVA); + events.aborts += 1; + GUEST_SYNC(CMD_RECREATE_PT_MEMSLOT_WR); +} + +static void iabt_s1ptw_on_ro_memslot_handler(struct ex_regs *regs) +{ + GUEST_ASSERT_EQ(regs->pc, TEST_EXEC_GVA); + events.aborts += 1; + GUEST_SYNC(CMD_RECREATE_PT_MEMSLOT_WR); +} + static void no_dabt_handler(struct ex_regs *regs) { GUEST_ASSERT_1(false, read_sysreg(far_el1)); @@ -420,6 +437,49 @@ static void punch_hole_in_memslot(struct kvm_vm *vm, } } +static int __memory_region_add(struct kvm_vm *vm, void *mem, uint32_t slot, + uint32_t size, uint64_t guest_addr, + uint32_t flags) +{ + struct kvm_userspace_memory_region region; + int ret; + + region.slot = slot; + region.flags = flags; + region.guest_phys_addr = guest_addr; + region.memory_size = size; + region.userspace_addr = (uintptr_t) mem; + ret = ioctl(vm_get_fd(vm), KVM_SET_USER_MEMORY_REGION, ®ion); + + return ret; +} + +static void recreate_memslot(struct kvm_vm *vm, struct memslot_desc *ms, + uint32_t flags) +{ + __memory_region_add(vm, ms->hva, ms->idx, 0, ms->gpa, 0); + __memory_region_add(vm, ms->hva, ms->idx, ms->size, ms->gpa, flags); +} + +static void mmio_on_test_gpa_handler(struct kvm_run *run) +{ + ASSERT_EQ(run->mmio.phys_addr, memslot[TEST].gpa); + + memcpy(memslot[TEST].hva, run->mmio.data, run->mmio.len); + events.mmio_exits += 1; +} + +static void mmio_no_handler(struct kvm_run *run) +{ + uint64_t data; + + memcpy(&data, run->mmio.data, sizeof(data)); + pr_debug("addr=%lld len=%d w=%d data=%lx\n", + run->mmio.phys_addr, run->mmio.len, + run->mmio.is_write, data); + TEST_FAIL("There was no MMIO exit expected."); +} + static bool check_write_in_dirty_log(struct kvm_vm *vm, struct memslot_desc *ms, uint64_t host_pg_nr) { @@ -443,6 +503,8 @@ static bool handle_cmd(struct kvm_vm *vm, int cmd) punch_hole_in_memslot(vm, &memslot[PT]); if (cmd & CMD_HOLE_TEST) punch_hole_in_memslot(vm, &memslot[TEST]); + if (cmd & CMD_RECREATE_PT_MEMSLOT_WR) + recreate_memslot(vm, &memslot[PT], 0); if (cmd & CMD_CHECK_WRITE_IN_DIRTY_LOG) TEST_ASSERT(check_write_in_dirty_log(vm, &memslot[TEST], 0), "Missing write in dirty log"); @@ -471,6 +533,13 @@ void fail_vcpu_run_no_handler(int ret) TEST_FAIL("Unexpected vcpu run failure\n"); } +void fail_vcpu_run_mmio_no_syndrome_handler(int ret) +{ + TEST_ASSERT(errno == ENOSYS, "The mmio handler in the kernel" + " should have returned not implemented."); + events.fail_vcpu_runs += 1; +} + static uint64_t get_total_guest_pages(enum vm_guest_mode mode, struct test_params *p) { @@ -626,10 +695,21 @@ static void setup_uffd(enum vm_guest_mode mode, struct test_params *p, test->uffd_test_handler); } +static void setup_default_handlers(struct test_desc *test) +{ + if (!test->mmio_handler) + test->mmio_handler = mmio_no_handler; + + if (!test->fail_vcpu_run_handler) + test->fail_vcpu_run_handler = fail_vcpu_run_no_handler; +} + static void check_event_counts(struct test_desc *test) { ASSERT_EQ(test->expected_events.aborts, events.aborts); ASSERT_EQ(test->expected_events.uffd_faults, events.uffd_faults); + ASSERT_EQ(test->expected_events.mmio_exits, events.mmio_exits); + ASSERT_EQ(test->expected_events.fail_vcpu_runs, events.fail_vcpu_runs); } static void free_uffd(struct test_desc *test, struct uffd_desc **uffd) @@ -661,12 +741,20 @@ static void reset_event_counts(void) static bool vcpu_run_loop(struct kvm_vm *vm, struct test_desc *test) { + struct kvm_run *run; bool skip_test = false; struct ucall uc; - int stage; + int stage, ret; + + run = vcpu_state(vm, VCPU_ID); for (stage = 0; ; stage++) { - vcpu_run(vm, VCPU_ID); + ret = _vcpu_run(vm, VCPU_ID); + if (ret) { + test->fail_vcpu_run_handler(ret); + pr_debug("Done.\n"); + goto done; + } switch (get_ucall(vm, VCPU_ID, &uc)) { case UCALL_SYNC: @@ -684,6 +772,10 @@ static bool vcpu_run_loop(struct kvm_vm *vm, struct test_desc *test) case UCALL_DONE: pr_debug("Done.\n"); goto done; + case UCALL_NONE: + if (run->exit_reason == KVM_EXIT_MMIO) + test->mmio_handler(run); + break; default: TEST_FAIL("Unknown ucall %lu", uc.cmd); } @@ -708,6 +800,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) ucall_init(vm, NULL); reset_event_counts(); + setup_abort_handlers(vm, test); setup_memslots(vm, mode, p); /* @@ -718,7 +811,7 @@ static void run_test(enum vm_guest_mode mode, void *arg) */ load_exec_code_for_test(); setup_uffd(mode, p, uffd); - setup_abort_handlers(vm, test); + setup_default_handlers(test); vcpu_args_set(vm, 0, 1, test); sync_global_to_guest(vm, memslot); @@ -842,6 +935,32 @@ int main(int argc, char *argv[]) .expected_events = { 0 }, \ } +#define TEST_RO_MEMSLOT(_access, _mmio_handler, _mmio_exits, \ + _iabt_handler, _dabt_handler, _aborts) \ +{ \ + .name = SCAT3(ro_memslot, _access, _with_af), \ + .test_memslot_flags = KVM_MEM_READONLY, \ + .pt_memslot_flags = KVM_MEM_READONLY, \ + .guest_prepare = { _PREPARE(_access) }, \ + .guest_test = _access, \ + .mmio_handler = _mmio_handler, \ + .iabt_handler = _iabt_handler, \ + .dabt_handler = _dabt_handler, \ + .expected_events = { .mmio_exits = _mmio_exits, \ + .aborts = _aborts}, \ +} + +#define TEST_RO_MEMSLOT_NO_SYNDROME(_access) \ +{ \ + .name = SCAT2(ro_memslot_no_syndrome, _access), \ + .test_memslot_flags = KVM_MEM_READONLY, \ + .pt_memslot_flags = KVM_MEM_READONLY, \ + .guest_test = _access, \ + .dabt_handler = dabt_s1ptw_on_ro_memslot_handler, \ + .fail_vcpu_run_handler = fail_vcpu_run_mmio_no_syndrome_handler, \ + .expected_events = { .aborts = 1, .fail_vcpu_runs = 1 }, \ +} + static struct test_desc tests[] = { /* Check that HW is setting the Access Flag (AF) (sanity checks). */ TEST_ACCESS(guest_read64, with_af, CMD_NONE), @@ -909,6 +1028,32 @@ static struct test_desc tests[] = { TEST_DIRTY_LOG(guest_dc_zva, with_af, guest_check_write_in_dirty_log), TEST_DIRTY_LOG(guest_st_preidx, with_af, guest_check_write_in_dirty_log), + /* + * Try accesses when both the test and PT memslots are marked read-only + * (with KVM_MEM_READONLY). The S1PTW results in an guest abort, whose + * handler asks the host to recreate the memslot as writable. Note that + * guests would typically panic as there's no way of asking the VMM to + * perform the write for the guest (or make the memslot writable). The + * instruction then is executed: writes with a syndrome result in an + * MMIO exit, writes with no syndrome (e.g., CAS) result in a failed + * vcpu run, and reads/execs with and without syndroms do not fault. + * Check that the expected aborts, failed vcpu runs, mmio exits + * actually happen. + */ + TEST_RO_MEMSLOT(guest_read64, 0, 0, 0, + dabt_s1ptw_on_ro_memslot_handler, 1), + TEST_RO_MEMSLOT(guest_ld_preidx, 0, 0, 0, + dabt_s1ptw_on_ro_memslot_handler, 1), + TEST_RO_MEMSLOT(guest_at, 0, 0, 0, + dabt_s1ptw_on_ro_memslot_handler, 1), + TEST_RO_MEMSLOT(guest_exec, 0, 0, iabt_s1ptw_on_ro_memslot_handler, + 0, 1), + TEST_RO_MEMSLOT(guest_write64, mmio_on_test_gpa_handler, 1, 0, + dabt_s1ptw_on_ro_memslot_handler, 1), + TEST_RO_MEMSLOT_NO_SYNDROME(guest_dc_zva), + TEST_RO_MEMSLOT_NO_SYNDROME(guest_cas), + TEST_RO_MEMSLOT_NO_SYNDROME(guest_st_preidx), + { 0 }, }; From patchwork Fri Apr 8 00:41:20 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ricardo Koller X-Patchwork-Id: 12805971 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 721ADC433F5 for ; Fri, 8 Apr 2022 00:41:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233122AbiDHAnt (ORCPT ); Thu, 7 Apr 2022 20:43:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39704 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233109AbiDHAnr (ORCPT ); Thu, 7 Apr 2022 20:43:47 -0400 Received: from mail-pf1-x449.google.com (mail-pf1-x449.google.com [IPv6:2607:f8b0:4864:20::449]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AF5411770A3 for ; Thu, 7 Apr 2022 17:41:44 -0700 (PDT) Received: by mail-pf1-x449.google.com with SMTP id n22-20020a056a00213600b005056a13e1c1so1562605pfj.20 for ; Thu, 07 Apr 2022 17:41:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=rkJVDUmk9B8/NrjotnCUiZyGZn+HhyJh8bavuSxqe7Q=; b=WlIRLidhHhOdmQkTKNMvcKUC89C0kIToiVd+e5owpY2xeNryaNVhF1TFPdiN8FB9dd 9vwfFyh7JU0Rf8ae14/kZGx4rDhICsLQbODoJTteLUI39T9iqAwZNtdw2I4WZ2n1QpIb iFGb085E3kFSXx2+f3I2j9iT9/qCnxCkuAqjpvZFYdNxEpRB9lXV1paUDHn7V2Vx1Rqx 5sGTabHLK5od1QNdYQDa8HNgZvXZjD7mtyzGewnr3cCGs5j2DPBcGcMY/R/WRh2HpYfa RfP5jOw8O/P1+SX9/+R6OP5tsjeDgHK/4BT9cF6xCwQIQsmZBaUrHrJdxxPPGZ6Zpk5F Jlaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=rkJVDUmk9B8/NrjotnCUiZyGZn+HhyJh8bavuSxqe7Q=; b=IGC9tWm19qybsHta3OzwgtLTiywtO9RBPC/2Nsn2qZQBWUt98qlJ4mJV+c0wKj/GGv +a4HzqPXg1bW7SUFlTyKde8hE19sAkDbBqmPcmSB8ew0sLnktjJgoC4Mi6YWhzFVitz2 905DxZIcOlPP0nBKcvh+VxPmF3qhwm3QTcIRjaAPkLsAhebeBdWo7o0tRUoKfBO8z52Y 63ZTDett8CWRNcpxpvXQCSSr29ewkenjcXMtL4No5QSpL7dpItW4TX0wZZ4P1bWQHedb RQNOol9d0uYXGiywH15WGDxyygf3xsqPGVMaYwZ9XO9qa6NOHxdKkN8ew/evd3aZqT86 aBeA== X-Gm-Message-State: AOAM532GZNhpeSjuYcp8DKp1jklYqlHnmV5OBXUMkgrn1ebqCm/QznLV OSKTSr+OPnYqHGuJmgbagqRV9/nrnI2LlmsjLhgaAw/CgWMaoBpNbxKYWxdPJhQozzm/Tpx14zx WHyo42i1/wJx7GFBdCEAeOeXX/DGx/Vn0/ktE8oEAwq8rNhR17irDO998pGknILg= X-Google-Smtp-Source: ABdhPJzzMftRgV9ggpc7b8MdVAiO90/RVlExwbOxM3uYNmuezPVXHzXCAv9n4tVSfSGh+0AjAau6Yf/4QFXXHQ== X-Received: from ricarkol2.c.googlers.com ([fda3:e722:ac3:cc00:24:72f4:c0a8:62fe]) (user=ricarkol job=sendgmr) by 2002:aa7:88d4:0:b0:4fd:ad26:c52f with SMTP id k20-20020aa788d4000000b004fdad26c52fmr16700591pff.25.1649378504066; Thu, 07 Apr 2022 17:41:44 -0700 (PDT) Date: Thu, 7 Apr 2022 17:41:20 -0700 In-Reply-To: <20220408004120.1969099-1-ricarkol@google.com> Message-Id: <20220408004120.1969099-14-ricarkol@google.com> Mime-Version: 1.0 References: <20220408004120.1969099-1-ricarkol@google.com> X-Mailer: git-send-email 2.35.1.1178.g4f1659d476-goog Subject: [PATCH v3 13/13] KVM: selftests: aarch64: Add mix of tests into page_fault_test From: Ricardo Koller To: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, drjones@redhat.com Cc: pbonzini@redhat.com, maz@kernel.org, alexandru.elisei@arm.com, eric.auger@redhat.com, oupton@google.com, reijiw@google.com, rananta@google.com, bgardon@google.com, axelrasmussen@google.com, Ricardo Koller Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Add some mix of tests into page_fault_test: memslots with all the pairwise combinations of read-only, userfaultfd, and dirty-logging. For example, writing into a read-only memslot which has a hole handled with userfaultfd. Signed-off-by: Ricardo Koller --- .../selftests/kvm/aarch64/page_fault_test.c | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/tools/testing/selftests/kvm/aarch64/page_fault_test.c b/tools/testing/selftests/kvm/aarch64/page_fault_test.c index 70085db873d3..fd83f0adc17f 100644 --- a/tools/testing/selftests/kvm/aarch64/page_fault_test.c +++ b/tools/testing/selftests/kvm/aarch64/page_fault_test.c @@ -419,6 +419,12 @@ static int uffd_test_read_handler(int mode, int uffd, struct uffd_msg *msg) return uffd_generic_handler(mode, uffd, msg, &memslot[TEST], false); } +static int uffd_no_handler(int mode, int uffd, struct uffd_msg *msg) +{ + TEST_FAIL("There was no UFFD fault expected."); + return -1; +} + static void punch_hole_in_memslot(struct kvm_vm *vm, struct memslot_desc *memslot) { @@ -935,6 +941,22 @@ int main(int argc, char *argv[]) .expected_events = { 0 }, \ } +#define TEST_UFFD_AND_DIRTY_LOG(_access, _with_af, _uffd_test_handler, \ + _uffd_faults, _test_check) \ +{ \ + .name = SCAT3(uffd_and_dirty_log, _access, _with_af), \ + .test_memslot_flags = KVM_MEM_LOG_DIRTY_PAGES, \ + .pt_memslot_flags = KVM_MEM_LOG_DIRTY_PAGES, \ + .guest_prepare = { _PREPARE(_with_af), \ + _PREPARE(_access) }, \ + .guest_test = _access, \ + .mem_mark_cmd = CMD_HOLE_TEST | CMD_HOLE_PT, \ + .guest_test_check = { _CHECK(_with_af), _test_check }, \ + .uffd_test_handler = _uffd_test_handler, \ + .uffd_pt_handler = uffd_pt_write_handler, \ + .expected_events = { .uffd_faults = _uffd_faults, }, \ +} + #define TEST_RO_MEMSLOT(_access, _mmio_handler, _mmio_exits, \ _iabt_handler, _dabt_handler, _aborts) \ { \ @@ -961,6 +983,71 @@ int main(int argc, char *argv[]) .expected_events = { .aborts = 1, .fail_vcpu_runs = 1 }, \ } +#define TEST_RO_MEMSLOT_AND_DIRTY_LOG(_access, _mmio_handler, _mmio_exits, \ + _iabt_handler, _dabt_handler, _aborts, \ + _test_check) \ +{ \ + .name = SCAT3(ro_memslot, _access, _with_af), \ + .test_memslot_flags = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES, \ + .pt_memslot_flags = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES, \ + .guest_prepare = { _PREPARE(_access) }, \ + .guest_test = _access, \ + .guest_test_check = { _test_check }, \ + .mmio_handler = _mmio_handler, \ + .iabt_handler = _iabt_handler, \ + .dabt_handler = _dabt_handler, \ + .expected_events = { .mmio_exits = _mmio_exits, \ + .aborts = _aborts}, \ +} + +#define TEST_RO_MEMSLOT_NO_SYNDROME_AND_DIRTY_LOG(_access, _test_check) \ +{ \ + .name = SCAT2(ro_memslot_no_syn_and_dlog, _access), \ + .test_memslot_flags = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES, \ + .pt_memslot_flags = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES, \ + .guest_test = _access, \ + .guest_test_check = { _test_check }, \ + .dabt_handler = dabt_s1ptw_on_ro_memslot_handler, \ + .fail_vcpu_run_handler = fail_vcpu_run_mmio_no_syndrome_handler, \ + .expected_events = { .aborts = 1, .fail_vcpu_runs = 1 }, \ +} + +#define TEST_RO_MEMSLOT_AND_UFFD(_access, _mmio_handler, _mmio_exits, \ + _iabt_handler, _dabt_handler, _aborts, \ + _uffd_test_handler, _uffd_faults) \ +{ \ + .name = SCAT2(ro_memslot_uffd, _access), \ + .test_memslot_flags = KVM_MEM_READONLY, \ + .pt_memslot_flags = KVM_MEM_READONLY, \ + .mem_mark_cmd = CMD_HOLE_TEST | CMD_HOLE_PT, \ + .guest_prepare = { _PREPARE(_access) }, \ + .guest_test = _access, \ + .uffd_test_handler = _uffd_test_handler, \ + .uffd_pt_handler = uffd_pt_write_handler, \ + .mmio_handler = _mmio_handler, \ + .iabt_handler = _iabt_handler, \ + .dabt_handler = _dabt_handler, \ + .expected_events = { .mmio_exits = _mmio_exits, \ + .aborts = _aborts, \ + .uffd_faults = _uffd_faults }, \ +} + +#define TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(_access, _uffd_test_handler, \ + _uffd_faults) \ +{ \ + .name = SCAT2(ro_memslot_no_syndrome, _access), \ + .test_memslot_flags = KVM_MEM_READONLY, \ + .pt_memslot_flags = KVM_MEM_READONLY, \ + .mem_mark_cmd = CMD_HOLE_TEST | CMD_HOLE_PT, \ + .guest_test = _access, \ + .uffd_test_handler = _uffd_test_handler, \ + .uffd_pt_handler = uffd_pt_write_handler, \ + .dabt_handler = dabt_s1ptw_on_ro_memslot_handler, \ + .fail_vcpu_run_handler = fail_vcpu_run_mmio_no_syndrome_handler, \ + .expected_events = { .aborts = 1, .fail_vcpu_runs = 1, \ + .uffd_faults = _uffd_faults }, \ +} + static struct test_desc tests[] = { /* Check that HW is setting the Access Flag (AF) (sanity checks). */ TEST_ACCESS(guest_read64, with_af, CMD_NONE), @@ -1028,6 +1115,35 @@ static struct test_desc tests[] = { TEST_DIRTY_LOG(guest_dc_zva, with_af, guest_check_write_in_dirty_log), TEST_DIRTY_LOG(guest_st_preidx, with_af, guest_check_write_in_dirty_log), + /* + * Access when the test and PT memslots are both marked for dirty + * logging and UFFD at the same time. The expected result is that + * writes should mark the dirty log and trigger a userfaultfd write + * fault. Reads/execs should result in a read userfaultfd fault, and + * nothing in the dirty log. The S1PTW in all cases should result in a + * write in the dirty log and a userfaultfd write. + */ + TEST_UFFD_AND_DIRTY_LOG(guest_read64, with_af, uffd_test_read_handler, 2, + guest_check_no_write_in_dirty_log), + /* no_af should also lead to a PT write. */ + TEST_UFFD_AND_DIRTY_LOG(guest_read64, no_af, uffd_test_read_handler, 2, + guest_check_no_write_in_dirty_log), + TEST_UFFD_AND_DIRTY_LOG(guest_ld_preidx, with_af, uffd_test_read_handler, + 2, guest_check_no_write_in_dirty_log), + TEST_UFFD_AND_DIRTY_LOG(guest_at, with_af, 0, 1, + guest_check_no_write_in_dirty_log), + TEST_UFFD_AND_DIRTY_LOG(guest_exec, with_af, uffd_test_read_handler, 2, + guest_check_no_write_in_dirty_log), + TEST_UFFD_AND_DIRTY_LOG(guest_write64, with_af, uffd_test_write_handler, + 2, guest_check_write_in_dirty_log), + TEST_UFFD_AND_DIRTY_LOG(guest_cas, with_af, uffd_test_read_handler, 2, + guest_check_write_in_dirty_log), + TEST_UFFD_AND_DIRTY_LOG(guest_dc_zva, with_af, uffd_test_write_handler, + 2, guest_check_write_in_dirty_log), + TEST_UFFD_AND_DIRTY_LOG(guest_st_preidx, with_af, + uffd_test_write_handler, 2, + guest_check_write_in_dirty_log), + /* * Try accesses when both the test and PT memslots are marked read-only * (with KVM_MEM_READONLY). The S1PTW results in an guest abort, whose @@ -1054,6 +1170,68 @@ static struct test_desc tests[] = { TEST_RO_MEMSLOT_NO_SYNDROME(guest_cas), TEST_RO_MEMSLOT_NO_SYNDROME(guest_st_preidx), + /* + * Access when both the test and PT memslots are read-only and marked + * for dirty logging at the same time. The expected result is that + * there should be no write in the dirty log. The S1PTW results in an + * abort which is handled by asking the host to recreate the memslot as + * writable. The readonly handling are the same as if the memslots were + * not marked for dirty logging: writes with a syndrome result in an + * MMIO exit, and writes with no syndrome result in a failed vcpu run. + */ + TEST_RO_MEMSLOT_AND_DIRTY_LOG(guest_read64, 0, 0, 0, + dabt_s1ptw_on_ro_memslot_handler, 1, + guest_check_no_write_in_dirty_log), + TEST_RO_MEMSLOT_AND_DIRTY_LOG(guest_ld_preidx, 0, 0, 0, + dabt_s1ptw_on_ro_memslot_handler, 1, + guest_check_no_write_in_dirty_log), + TEST_RO_MEMSLOT_AND_DIRTY_LOG(guest_at, 0, 0, 0, + dabt_s1ptw_on_ro_memslot_handler, 1, + guest_check_no_write_in_dirty_log), + TEST_RO_MEMSLOT_AND_DIRTY_LOG(guest_exec, 0, 0, + iabt_s1ptw_on_ro_memslot_handler, 0, 1, + guest_check_no_write_in_dirty_log), + TEST_RO_MEMSLOT_AND_DIRTY_LOG(guest_write64, mmio_on_test_gpa_handler, + 1, 0, dabt_s1ptw_on_ro_memslot_handler, 1, + guest_check_no_write_in_dirty_log), + TEST_RO_MEMSLOT_NO_SYNDROME_AND_DIRTY_LOG(guest_dc_zva, + guest_check_no_write_in_dirty_log), + TEST_RO_MEMSLOT_NO_SYNDROME_AND_DIRTY_LOG(guest_cas, + guest_check_no_write_in_dirty_log), + TEST_RO_MEMSLOT_NO_SYNDROME_AND_DIRTY_LOG(guest_st_preidx, + guest_check_no_write_in_dirty_log), + + /* + * Access when both the test and PT memslots are read-only, and punched + * with holes tracked with userfaultfd. The expected result is the + * union of both userfaultfd and read-only behaviors. For example, + * write accesses result in a userfaultfd write fault and an MMIO exit. + * Writes with no syndrome result in a failed vcpu run and no + * userfaultfd write fault. Reads only result in userfaultfd getting + * triggered. + */ + TEST_RO_MEMSLOT_AND_UFFD(guest_read64, 0, 0, 0, + dabt_s1ptw_on_ro_memslot_handler, 1, + uffd_test_read_handler, 2), + TEST_RO_MEMSLOT_AND_UFFD(guest_ld_preidx, 0, 0, 0, + dabt_s1ptw_on_ro_memslot_handler, 1, + uffd_test_read_handler, 2), + TEST_RO_MEMSLOT_AND_UFFD(guest_at, 0, 0, 0, + dabt_s1ptw_on_ro_memslot_handler, 1, + uffd_no_handler, 1), + TEST_RO_MEMSLOT_AND_UFFD(guest_exec, 0, 0, + iabt_s1ptw_on_ro_memslot_handler, 0, 1, + uffd_test_read_handler, 2), + TEST_RO_MEMSLOT_AND_UFFD(guest_write64, mmio_on_test_gpa_handler, 1, 0, + dabt_s1ptw_on_ro_memslot_handler, 1, + uffd_test_write_handler, 2), + TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_cas, + uffd_test_read_handler, 2), + TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_dc_zva, + uffd_no_handler, 1), + TEST_RO_MEMSLOT_NO_SYNDROME_AND_UFFD(guest_st_preidx, + uffd_no_handler, 1), + { 0 }, };