diff options
Diffstat (limited to 'tools/testing')
376 files changed, 5872 insertions, 809 deletions
diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index cfd4378e2129..f87e9f251d13 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -670,6 +670,7 @@ static int nfit_test_search_spa(struct nvdimm_bus *bus, .addr = spa->spa, .region = NULL, }; + struct nfit_mem *nfit_mem; u64 dpa; ret = device_for_each_child(&bus->dev, &ctx, @@ -687,8 +688,12 @@ static int nfit_test_search_spa(struct nvdimm_bus *bus, */ nd_mapping = &nd_region->mapping[nd_region->ndr_mappings - 1]; nvdimm = nd_mapping->nvdimm; + nfit_mem = nvdimm_provider_data(nvdimm); + if (!nfit_mem) + return -EINVAL; - spa->devices[0].nfit_device_handle = handle[nvdimm->id]; + spa->devices[0].nfit_device_handle = + __to_nfit_memdev(nfit_mem)->device_handle; spa->num_nvdimms = 1; spa->devices[0].dpa = dpa; diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index c46ebdb9b8ef..56e44a98d6a5 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -54,6 +54,7 @@ TARGETS += kvm TARGETS += landlock TARGETS += lib TARGETS += livepatch +TARGETS += liveupdate TARGETS += lkdtm TARGETS += lsm TARGETS += membarrier diff --git a/tools/testing/selftests/acct/acct_syscall.c b/tools/testing/selftests/acct/acct_syscall.c index 87c044fb9293..421adbdc299d 100644 --- a/tools/testing/selftests/acct/acct_syscall.c +++ b/tools/testing/selftests/acct/acct_syscall.c @@ -9,7 +9,7 @@ #include <string.h> #include <sys/wait.h> -#include "../kselftest.h" +#include "kselftest.h" int main(void) { diff --git a/tools/testing/selftests/alsa/conf.c b/tools/testing/selftests/alsa/conf.c index dc7f40e68dee..317212078e36 100644 --- a/tools/testing/selftests/alsa/conf.c +++ b/tools/testing/selftests/alsa/conf.c @@ -14,7 +14,7 @@ #include <regex.h> #include <sys/stat.h> -#include "../kselftest.h" +#include "kselftest.h" #include "alsa-local.h" #define SYSFS_ROOT "/sys" diff --git a/tools/testing/selftests/alsa/mixer-test.c b/tools/testing/selftests/alsa/mixer-test.c index e113dafa5c24..d4f845c32804 100644 --- a/tools/testing/selftests/alsa/mixer-test.c +++ b/tools/testing/selftests/alsa/mixer-test.c @@ -25,7 +25,7 @@ #include <poll.h> #include <stdint.h> -#include "../kselftest.h" +#include "kselftest.h" #include "alsa-local.h" #define TESTS_PER_CONTROL 7 diff --git a/tools/testing/selftests/alsa/pcm-test.c b/tools/testing/selftests/alsa/pcm-test.c index ce92548670c8..ee04ccef7d7c 100644 --- a/tools/testing/selftests/alsa/pcm-test.c +++ b/tools/testing/selftests/alsa/pcm-test.c @@ -17,7 +17,7 @@ #include <assert.h> #include <pthread.h> -#include "../kselftest.h" +#include "kselftest.h" #include "alsa-local.h" typedef struct timespec timestamp_t; diff --git a/tools/testing/selftests/alsa/test-pcmtest-driver.c b/tools/testing/selftests/alsa/test-pcmtest-driver.c index ca81afa4ee90..95065ef3b441 100644 --- a/tools/testing/selftests/alsa/test-pcmtest-driver.c +++ b/tools/testing/selftests/alsa/test-pcmtest-driver.c @@ -7,7 +7,7 @@ */ #include <string.h> #include <alsa/asoundlib.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define CH_NUM 4 diff --git a/tools/testing/selftests/alsa/utimer-test.c b/tools/testing/selftests/alsa/utimer-test.c index 37964f311a33..c45cb226bd8f 100644 --- a/tools/testing/selftests/alsa/utimer-test.c +++ b/tools/testing/selftests/alsa/utimer-test.c @@ -6,7 +6,7 @@ * * Author: Ivan Orlov <ivan.orlov0322@gmail.com> */ -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <sound/asound.h> #include <unistd.h> #include <fcntl.h> diff --git a/tools/testing/selftests/arm64/abi/hwcap.c b/tools/testing/selftests/arm64/abi/hwcap.c index 3b96d090c5eb..c41640f18e4e 100644 --- a/tools/testing/selftests/arm64/abi/hwcap.c +++ b/tools/testing/selftests/arm64/abi/hwcap.c @@ -19,7 +19,7 @@ #include <linux/auxvec.h> -#include "../../kselftest.h" +#include "kselftest.h" #define TESTS_PER_HWCAP 3 diff --git a/tools/testing/selftests/arm64/abi/ptrace.c b/tools/testing/selftests/arm64/abi/ptrace.c index b51d21f78cf9..0e46ac21c81d 100644 --- a/tools/testing/selftests/arm64/abi/ptrace.c +++ b/tools/testing/selftests/arm64/abi/ptrace.c @@ -18,7 +18,7 @@ #include <asm/sigcontext.h> #include <asm/ptrace.h> -#include "../../kselftest.h" +#include "kselftest.h" #define EXPECTED_TESTS 11 diff --git a/tools/testing/selftests/arm64/abi/syscall-abi.c b/tools/testing/selftests/arm64/abi/syscall-abi.c index 5ec9a18ec802..b67e3e26fa6d 100644 --- a/tools/testing/selftests/arm64/abi/syscall-abi.c +++ b/tools/testing/selftests/arm64/abi/syscall-abi.c @@ -16,7 +16,7 @@ #include <asm/sigcontext.h> #include <asm/unistd.h> -#include "../../kselftest.h" +#include "kselftest.h" #include "syscall-abi.h" diff --git a/tools/testing/selftests/arm64/fp/fp-ptrace.c b/tools/testing/selftests/arm64/fp/fp-ptrace.c index 0114108ab25f..22c584b78be5 100644 --- a/tools/testing/selftests/arm64/fp/fp-ptrace.c +++ b/tools/testing/selftests/arm64/fp/fp-ptrace.c @@ -27,7 +27,7 @@ #include <asm/sve_context.h> #include <asm/ptrace.h> -#include "../../kselftest.h" +#include "kselftest.h" #include "fp-ptrace.h" diff --git a/tools/testing/selftests/arm64/fp/fp-stress.c b/tools/testing/selftests/arm64/fp/fp-stress.c index 9349aa630c84..65e01aba96ff 100644 --- a/tools/testing/selftests/arm64/fp/fp-stress.c +++ b/tools/testing/selftests/arm64/fp/fp-stress.c @@ -24,7 +24,7 @@ #include <sys/wait.h> #include <asm/hwcap.h> -#include "../../kselftest.h" +#include "kselftest.h" #define MAX_VLS 16 diff --git a/tools/testing/selftests/arm64/fp/sve-probe-vls.c b/tools/testing/selftests/arm64/fp/sve-probe-vls.c index a24eca7a4ecb..df0c1b6eb114 100644 --- a/tools/testing/selftests/arm64/fp/sve-probe-vls.c +++ b/tools/testing/selftests/arm64/fp/sve-probe-vls.c @@ -12,7 +12,7 @@ #include <sys/prctl.h> #include <asm/sigcontext.h> -#include "../../kselftest.h" +#include "kselftest.h" #include "rdvl.h" int main(int argc, char **argv) diff --git a/tools/testing/selftests/arm64/fp/sve-ptrace.c b/tools/testing/selftests/arm64/fp/sve-ptrace.c index f44d44618575..28f6b996c5e2 100644 --- a/tools/testing/selftests/arm64/fp/sve-ptrace.c +++ b/tools/testing/selftests/arm64/fp/sve-ptrace.c @@ -19,7 +19,7 @@ #include <asm/sigcontext.h> #include <asm/ptrace.h> -#include "../../kselftest.h" +#include "kselftest.h" /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */ #ifndef NT_ARM_SVE diff --git a/tools/testing/selftests/arm64/fp/vec-syscfg.c b/tools/testing/selftests/arm64/fp/vec-syscfg.c index 2d75d342eeb9..8dd932fdcdc4 100644 --- a/tools/testing/selftests/arm64/fp/vec-syscfg.c +++ b/tools/testing/selftests/arm64/fp/vec-syscfg.c @@ -19,7 +19,7 @@ #include <asm/sigcontext.h> #include <asm/hwcap.h> -#include "../../kselftest.h" +#include "kselftest.h" #include "rdvl.h" #define ARCH_MIN_VL SVE_VL_MIN diff --git a/tools/testing/selftests/arm64/fp/za-ptrace.c b/tools/testing/selftests/arm64/fp/za-ptrace.c index 08c777f87ea2..787eed22d059 100644 --- a/tools/testing/selftests/arm64/fp/za-ptrace.c +++ b/tools/testing/selftests/arm64/fp/za-ptrace.c @@ -18,7 +18,7 @@ #include <asm/sigcontext.h> #include <asm/ptrace.h> -#include "../../kselftest.h" +#include "kselftest.h" /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */ #ifndef NT_ARM_ZA diff --git a/tools/testing/selftests/arm64/fp/zt-ptrace.c b/tools/testing/selftests/arm64/fp/zt-ptrace.c index a7f34040fbf1..f3fa49fd0fbd 100644 --- a/tools/testing/selftests/arm64/fp/zt-ptrace.c +++ b/tools/testing/selftests/arm64/fp/zt-ptrace.c @@ -18,7 +18,7 @@ #include <asm/sigcontext.h> #include <asm/ptrace.h> -#include "../../kselftest.h" +#include "kselftest.h" /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */ #ifndef NT_ARM_ZA diff --git a/tools/testing/selftests/arm64/gcs/gcs-stress.c b/tools/testing/selftests/arm64/gcs/gcs-stress.c index cf316d78ea97..86d8cd42aee7 100644 --- a/tools/testing/selftests/arm64/gcs/gcs-stress.c +++ b/tools/testing/selftests/arm64/gcs/gcs-stress.c @@ -24,7 +24,7 @@ #include <sys/wait.h> #include <asm/hwcap.h> -#include "../../kselftest.h" +#include "kselftest.h" struct child_data { char *name, *output; diff --git a/tools/testing/selftests/arm64/pauth/pac.c b/tools/testing/selftests/arm64/pauth/pac.c index 6d21b2fc758d..67d138057707 100644 --- a/tools/testing/selftests/arm64/pauth/pac.c +++ b/tools/testing/selftests/arm64/pauth/pac.c @@ -10,7 +10,7 @@ #include <setjmp.h> #include <sched.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #include "helper.h" #define PAC_COLLISION_ATTEMPTS 1000 diff --git a/tools/testing/selftests/arm64/tags/tags_test.c b/tools/testing/selftests/arm64/tags/tags_test.c index 8ae26e496c89..375ab47f0edb 100644 --- a/tools/testing/selftests/arm64/tags/tags_test.c +++ b/tools/testing/selftests/arm64/tags/tags_test.c @@ -6,7 +6,7 @@ #include <stdint.h> #include <sys/prctl.h> #include <sys/utsname.h> -#include "../../kselftest.h" +#include "kselftest.h" #define SHIFT_TAG(tag) ((uint64_t)(tag) << 56) #define SET_TAG(ptr, tag) (((uint64_t)(ptr) & ~SHIFT_TAG(0xff)) | \ diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c index 9234a58b0a97..05b3cebc5ca9 100644 --- a/tools/testing/selftests/bpf/xskxceiver.c +++ b/tools/testing/selftests/bpf/xskxceiver.c @@ -96,7 +96,7 @@ #include "xskxceiver.h" #include <bpf/bpf.h> #include <linux/filter.h> -#include "../kselftest.h" +#include "kselftest.h" #include "xsk_xdp_common.h" #include <network_helpers.h> diff --git a/tools/testing/selftests/breakpoints/breakpoint_test.c b/tools/testing/selftests/breakpoints/breakpoint_test.c index d46962a24724..1159d81890c2 100644 --- a/tools/testing/selftests/breakpoints/breakpoint_test.c +++ b/tools/testing/selftests/breakpoints/breakpoint_test.c @@ -18,7 +18,7 @@ #include <errno.h> #include <string.h> -#include "../kselftest.h" +#include "kselftest.h" #define COUNT_ISN_BPS 4 #define COUNT_WPS 4 diff --git a/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c b/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c index e7041816085a..5fc0f37f3fd4 100644 --- a/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c +++ b/tools/testing/selftests/breakpoints/breakpoint_test_arm64.c @@ -26,7 +26,7 @@ #include <errno.h> #include <signal.h> -#include "../kselftest.h" +#include "kselftest.h" static volatile uint8_t var[96] __attribute__((__aligned__(32))); diff --git a/tools/testing/selftests/breakpoints/step_after_suspend_test.c b/tools/testing/selftests/breakpoints/step_after_suspend_test.c index 8d233ac95696..ca2aaab9e4ca 100644 --- a/tools/testing/selftests/breakpoints/step_after_suspend_test.c +++ b/tools/testing/selftests/breakpoints/step_after_suspend_test.c @@ -19,7 +19,7 @@ #include <sys/types.h> #include <sys/wait.h> -#include "../kselftest.h" +#include "kselftest.h" void child(int cpu) { diff --git a/tools/testing/selftests/cachestat/test_cachestat.c b/tools/testing/selftests/cachestat/test_cachestat.c index ab838bcb9ec5..542cd09cb443 100644 --- a/tools/testing/selftests/cachestat/test_cachestat.c +++ b/tools/testing/selftests/cachestat/test_cachestat.c @@ -16,7 +16,7 @@ #include <fcntl.h> #include <errno.h> -#include "../kselftest.h" +#include "kselftest.h" #define NR_TESTS 9 diff --git a/tools/testing/selftests/capabilities/test_execve.c b/tools/testing/selftests/capabilities/test_execve.c index 47bad7ddc5bc..46fc8d46b6e6 100644 --- a/tools/testing/selftests/capabilities/test_execve.c +++ b/tools/testing/selftests/capabilities/test_execve.c @@ -18,7 +18,7 @@ #include <sys/prctl.h> #include <sys/stat.h> -#include "../kselftest.h" +#include "kselftest.h" static int nerrs; static pid_t mpid; /* main() pid is used to avoid duplicate test counts */ diff --git a/tools/testing/selftests/capabilities/validate_cap.c b/tools/testing/selftests/capabilities/validate_cap.c index 65f2a1c89239..cef1d9937b9f 100644 --- a/tools/testing/selftests/capabilities/validate_cap.c +++ b/tools/testing/selftests/capabilities/validate_cap.c @@ -7,7 +7,7 @@ #include <sys/prctl.h> #include <sys/auxv.h> -#include "../kselftest.h" +#include "kselftest.h" #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 19) # define HAVE_GETAUXVAL diff --git a/tools/testing/selftests/cgroup/test_core.c b/tools/testing/selftests/cgroup/test_core.c index 1d778c8b7764..102262555a59 100644 --- a/tools/testing/selftests/cgroup/test_core.c +++ b/tools/testing/selftests/cgroup/test_core.c @@ -17,7 +17,7 @@ #include <string.h> #include <pthread.h> -#include "../kselftest.h" +#include "kselftest.h" #include "cgroup_util.h" static bool nsdelegate; diff --git a/tools/testing/selftests/cgroup/test_cpu.c b/tools/testing/selftests/cgroup/test_cpu.c index b1b30e82dd7c..c83f05438d7c 100644 --- a/tools/testing/selftests/cgroup/test_cpu.c +++ b/tools/testing/selftests/cgroup/test_cpu.c @@ -11,7 +11,7 @@ #include <time.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #include "cgroup_util.h" enum hog_clock_type { diff --git a/tools/testing/selftests/cgroup/test_cpuset.c b/tools/testing/selftests/cgroup/test_cpuset.c index 8086d2ea394f..c5cf8b56ceb8 100644 --- a/tools/testing/selftests/cgroup/test_cpuset.c +++ b/tools/testing/selftests/cgroup/test_cpuset.c @@ -3,7 +3,7 @@ #include <linux/limits.h> #include <signal.h> -#include "../kselftest.h" +#include "kselftest.h" #include "cgroup_util.h" static int idle_process_fn(const char *cgroup, void *arg) diff --git a/tools/testing/selftests/cgroup/test_freezer.c b/tools/testing/selftests/cgroup/test_freezer.c index 465cdad2bfca..97fae92c8387 100644 --- a/tools/testing/selftests/cgroup/test_freezer.c +++ b/tools/testing/selftests/cgroup/test_freezer.c @@ -11,7 +11,7 @@ #include <string.h> #include <sys/wait.h> -#include "../kselftest.h" +#include "kselftest.h" #include "cgroup_util.h" #define DEBUG diff --git a/tools/testing/selftests/cgroup/test_hugetlb_memcg.c b/tools/testing/selftests/cgroup/test_hugetlb_memcg.c index 856f9508ea56..f451aa449be6 100644 --- a/tools/testing/selftests/cgroup/test_hugetlb_memcg.c +++ b/tools/testing/selftests/cgroup/test_hugetlb_memcg.c @@ -7,7 +7,7 @@ #include <stdlib.h> #include <string.h> #include <fcntl.h> -#include "../kselftest.h" +#include "kselftest.h" #include "cgroup_util.h" #define ADDR ((void *)(0x0UL)) diff --git a/tools/testing/selftests/cgroup/test_kill.c b/tools/testing/selftests/cgroup/test_kill.c index ed590b150a17..c8c9d306925b 100644 --- a/tools/testing/selftests/cgroup/test_kill.c +++ b/tools/testing/selftests/cgroup/test_kill.c @@ -9,7 +9,7 @@ #include <sys/types.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #include "../pidfd/pidfd.h" #include "cgroup_util.h" diff --git a/tools/testing/selftests/cgroup/test_kmem.c b/tools/testing/selftests/cgroup/test_kmem.c index d4c4a514ee43..ca38525484e3 100644 --- a/tools/testing/selftests/cgroup/test_kmem.c +++ b/tools/testing/selftests/cgroup/test_kmem.c @@ -14,7 +14,7 @@ #include <sys/sysinfo.h> #include <pthread.h> -#include "../kselftest.h" +#include "kselftest.h" #include "cgroup_util.h" diff --git a/tools/testing/selftests/cgroup/test_memcontrol.c b/tools/testing/selftests/cgroup/test_memcontrol.c index b117325c0439..4e1647568c5b 100644 --- a/tools/testing/selftests/cgroup/test_memcontrol.c +++ b/tools/testing/selftests/cgroup/test_memcontrol.c @@ -18,7 +18,7 @@ #include <errno.h> #include <sys/mman.h> -#include "../kselftest.h" +#include "kselftest.h" #include "cgroup_util.h" static bool has_localevents; diff --git a/tools/testing/selftests/cgroup/test_pids.c b/tools/testing/selftests/cgroup/test_pids.c index d8a1d1cd5007..9a387c815d2c 100644 --- a/tools/testing/selftests/cgroup/test_pids.c +++ b/tools/testing/selftests/cgroup/test_pids.c @@ -9,7 +9,7 @@ #include <sys/types.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #include "cgroup_util.h" static int run_success(const char *cgroup, void *arg) diff --git a/tools/testing/selftests/cgroup/test_zswap.c b/tools/testing/selftests/cgroup/test_zswap.c index 86a8930b47e3..64ebc3f3f203 100644 --- a/tools/testing/selftests/cgroup/test_zswap.c +++ b/tools/testing/selftests/cgroup/test_zswap.c @@ -10,7 +10,7 @@ #include <sys/wait.h> #include <sys/mman.h> -#include "../kselftest.h" +#include "kselftest.h" #include "cgroup_util.h" static int read_int(const char *path, size_t *value) diff --git a/tools/testing/selftests/clone3/clone3.c b/tools/testing/selftests/clone3/clone3.c index e61f07973ce5..289e0c7c1f09 100644 --- a/tools/testing/selftests/clone3/clone3.c +++ b/tools/testing/selftests/clone3/clone3.c @@ -18,7 +18,7 @@ #include <unistd.h> #include <sched.h> -#include "../kselftest.h" +#include "kselftest.h" #include "clone3_selftests.h" enum test_mode { diff --git a/tools/testing/selftests/clone3/clone3_cap_checkpoint_restore.c b/tools/testing/selftests/clone3/clone3_cap_checkpoint_restore.c index 3c196fa86c99..e82281efa273 100644 --- a/tools/testing/selftests/clone3/clone3_cap_checkpoint_restore.c +++ b/tools/testing/selftests/clone3/clone3_cap_checkpoint_restore.c @@ -24,7 +24,7 @@ #include <unistd.h> #include <sched.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "clone3_selftests.h" static void child_exit(int ret) diff --git a/tools/testing/selftests/clone3/clone3_clear_sighand.c b/tools/testing/selftests/clone3/clone3_clear_sighand.c index ce0426786828..de0c9d62015d 100644 --- a/tools/testing/selftests/clone3/clone3_clear_sighand.c +++ b/tools/testing/selftests/clone3/clone3_clear_sighand.c @@ -13,7 +13,7 @@ #include <sys/syscall.h> #include <sys/wait.h> -#include "../kselftest.h" +#include "kselftest.h" #include "clone3_selftests.h" static void nop_handler(int signo) diff --git a/tools/testing/selftests/clone3/clone3_selftests.h b/tools/testing/selftests/clone3/clone3_selftests.h index eeca8005723f..a0593e8950f0 100644 --- a/tools/testing/selftests/clone3/clone3_selftests.h +++ b/tools/testing/selftests/clone3/clone3_selftests.h @@ -11,7 +11,7 @@ #include <syscall.h> #include <sys/wait.h> -#include "../kselftest.h" +#include "kselftest.h" #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr))) diff --git a/tools/testing/selftests/clone3/clone3_set_tid.c b/tools/testing/selftests/clone3/clone3_set_tid.c index bfb0da2b4fdd..5c944aee6b41 100644 --- a/tools/testing/selftests/clone3/clone3_set_tid.c +++ b/tools/testing/selftests/clone3/clone3_set_tid.c @@ -20,7 +20,7 @@ #include <unistd.h> #include <sched.h> -#include "../kselftest.h" +#include "kselftest.h" #include "clone3_selftests.h" #define MAX_PID_NS_LEVEL 32 diff --git a/tools/testing/selftests/connector/proc_filter.c b/tools/testing/selftests/connector/proc_filter.c index 4a825b997666..36c11467a8f1 100644 --- a/tools/testing/selftests/connector/proc_filter.c +++ b/tools/testing/selftests/connector/proc_filter.c @@ -16,7 +16,7 @@ #include <signal.h> #include <string.h> -#include "../kselftest.h" +#include "kselftest.h" #define NL_MESSAGE_SIZE (sizeof(struct nlmsghdr) + sizeof(struct cn_msg) + \ sizeof(struct proc_input)) diff --git a/tools/testing/selftests/core/close_range_test.c b/tools/testing/selftests/core/close_range_test.c index e0d9851fe1c9..f14eca63f20c 100644 --- a/tools/testing/selftests/core/close_range_test.c +++ b/tools/testing/selftests/core/close_range_test.c @@ -14,7 +14,7 @@ #include <sys/resource.h> #include <linux/close_range.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "../clone3/clone3_selftests.h" diff --git a/tools/testing/selftests/core/unshare_test.c b/tools/testing/selftests/core/unshare_test.c index 7fec9dfb1b0e..ffce75a6c228 100644 --- a/tools/testing/selftests/core/unshare_test.c +++ b/tools/testing/selftests/core/unshare_test.c @@ -14,7 +14,7 @@ #include <sys/resource.h> #include <linux/close_range.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "../clone3/clone3_selftests.h" TEST(unshare_EMFILE) diff --git a/tools/testing/selftests/coredump/stackdump_test.c b/tools/testing/selftests/coredump/stackdump_test.c index c2e895bcc160..1ec88937a1c2 100644 --- a/tools/testing/selftests/coredump/stackdump_test.c +++ b/tools/testing/selftests/coredump/stackdump_test.c @@ -19,7 +19,7 @@ #include <sys/un.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "../filesystems/wrappers.h" #include "../pidfd/pidfd.h" diff --git a/tools/testing/selftests/dma/Makefile b/tools/testing/selftests/dma/Makefile deleted file mode 100644 index cd8c5ece1cba..000000000000 --- a/tools/testing/selftests/dma/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -CFLAGS += -I../../../../usr/include/ -CFLAGS += -I../../../../include/ - -TEST_GEN_PROGS := dma_map_benchmark - -include ../lib.mk diff --git a/tools/testing/selftests/dma/config b/tools/testing/selftests/dma/config deleted file mode 100644 index 6102ee3c43cd..000000000000 --- a/tools/testing/selftests/dma/config +++ /dev/null @@ -1 +0,0 @@ -CONFIG_DMA_MAP_BENCHMARK=y diff --git a/tools/testing/selftests/dma/dma_map_benchmark.c b/tools/testing/selftests/dma/dma_map_benchmark.c deleted file mode 100644 index b925756373ce..000000000000 --- a/tools/testing/selftests/dma/dma_map_benchmark.c +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Copyright (C) 2020 HiSilicon Limited. - */ - -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <linux/types.h> -#include <linux/map_benchmark.h> - -#define NSEC_PER_MSEC 1000000L - -static char *directions[] = { - "BIDIRECTIONAL", - "TO_DEVICE", - "FROM_DEVICE", -}; - -int main(int argc, char **argv) -{ - struct map_benchmark map; - int fd, opt; - /* default single thread, run 20 seconds on NUMA_NO_NODE */ - int threads = 1, seconds = 20, node = -1; - /* default dma mask 32bit, bidirectional DMA */ - int bits = 32, xdelay = 0, dir = DMA_MAP_BIDIRECTIONAL; - /* default granule 1 PAGESIZE */ - int granule = 1; - - int cmd = DMA_MAP_BENCHMARK; - - while ((opt = getopt(argc, argv, "t:s:n:b:d:x:g:")) != -1) { - switch (opt) { - case 't': - threads = atoi(optarg); - break; - case 's': - seconds = atoi(optarg); - break; - case 'n': - node = atoi(optarg); - break; - case 'b': - bits = atoi(optarg); - break; - case 'd': - dir = atoi(optarg); - break; - case 'x': - xdelay = atoi(optarg); - break; - case 'g': - granule = atoi(optarg); - break; - default: - return -1; - } - } - - if (threads <= 0 || threads > DMA_MAP_MAX_THREADS) { - fprintf(stderr, "invalid number of threads, must be in 1-%d\n", - DMA_MAP_MAX_THREADS); - exit(1); - } - - if (seconds <= 0 || seconds > DMA_MAP_MAX_SECONDS) { - fprintf(stderr, "invalid number of seconds, must be in 1-%d\n", - DMA_MAP_MAX_SECONDS); - exit(1); - } - - if (xdelay < 0 || xdelay > DMA_MAP_MAX_TRANS_DELAY) { - fprintf(stderr, "invalid transmit delay, must be in 0-%ld\n", - DMA_MAP_MAX_TRANS_DELAY); - exit(1); - } - - /* suppose the mininum DMA zone is 1MB in the world */ - if (bits < 20 || bits > 64) { - fprintf(stderr, "invalid dma mask bit, must be in 20-64\n"); - exit(1); - } - - if (dir != DMA_MAP_BIDIRECTIONAL && dir != DMA_MAP_TO_DEVICE && - dir != DMA_MAP_FROM_DEVICE) { - fprintf(stderr, "invalid dma direction\n"); - exit(1); - } - - if (granule < 1 || granule > 1024) { - fprintf(stderr, "invalid granule size\n"); - exit(1); - } - - fd = open("/sys/kernel/debug/dma_map_benchmark", O_RDWR); - if (fd == -1) { - perror("open"); - exit(1); - } - - memset(&map, 0, sizeof(map)); - map.seconds = seconds; - map.threads = threads; - map.node = node; - map.dma_bits = bits; - map.dma_dir = dir; - map.dma_trans_ns = xdelay; - map.granule = granule; - - if (ioctl(fd, cmd, &map)) { - perror("ioctl"); - exit(1); - } - - printf("dma mapping benchmark: threads:%d seconds:%d node:%d dir:%s granule: %d\n", - threads, seconds, node, directions[dir], granule); - printf("average map latency(us):%.1f standard deviation:%.1f\n", - map.avg_map_100ns/10.0, map.map_stddev/10.0); - printf("average unmap latency(us):%.1f standard deviation:%.1f\n", - map.avg_unmap_100ns/10.0, map.unmap_stddev/10.0); - - return 0; -} diff --git a/tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c b/tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c index 5d0a809dc2df..fc9694fc4e89 100644 --- a/tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c +++ b/tools/testing/selftests/dmabuf-heaps/dmabuf-heap.c @@ -15,7 +15,7 @@ #include <linux/dma-buf.h> #include <linux/dma-heap.h> #include <drm/drm.h> -#include "../kselftest.h" +#include "kselftest.h" #define DEVPATH "/dev/dma_heap" diff --git a/tools/testing/selftests/drivers/dma-buf/udmabuf.c b/tools/testing/selftests/drivers/dma-buf/udmabuf.c index 77aa2897e79f..d78aec662586 100644 --- a/tools/testing/selftests/drivers/dma-buf/udmabuf.c +++ b/tools/testing/selftests/drivers/dma-buf/udmabuf.c @@ -16,7 +16,7 @@ #include <sys/mman.h> #include <linux/memfd.h> #include <linux/udmabuf.h> -#include "../../kselftest.h" +#include "kselftest.h" #define TEST_PREFIX "drivers/dma-buf/udmabuf" #define NUM_PAGES 4 diff --git a/tools/testing/selftests/drivers/net/gro.c b/tools/testing/selftests/drivers/net/gro.c index 995b492f5bcb..e894037d2e3e 100644 --- a/tools/testing/selftests/drivers/net/gro.c +++ b/tools/testing/selftests/drivers/net/gro.c @@ -57,7 +57,7 @@ #include <string.h> #include <unistd.h> -#include "../../kselftest.h" +#include "kselftest.h" #include "../../net/lib/ksft.h" #define DPORT 8000 diff --git a/tools/testing/selftests/drivers/net/hw/toeplitz.c b/tools/testing/selftests/drivers/net/hw/toeplitz.c index a4d04438c313..d23b3b0c20a3 100644 --- a/tools/testing/selftests/drivers/net/hw/toeplitz.c +++ b/tools/testing/selftests/drivers/net/hw/toeplitz.c @@ -55,7 +55,7 @@ #include <ynl.h> #include "ethtool-user.h" -#include "../../../kselftest.h" +#include "kselftest.h" #include "../../../net/lib/ksft.h" #define TOEPLITZ_KEY_MIN_LEN 40 diff --git a/tools/testing/selftests/drivers/ntsync/ntsync.c b/tools/testing/selftests/drivers/ntsync/ntsync.c index 3aad311574c4..e6a37214aa46 100644 --- a/tools/testing/selftests/drivers/ntsync/ntsync.c +++ b/tools/testing/selftests/drivers/ntsync/ntsync.c @@ -12,7 +12,7 @@ #include <time.h> #include <pthread.h> #include <linux/ntsync.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" static int read_sem_state(int sem, __u32 *count, __u32 *max) { diff --git a/tools/testing/selftests/drivers/s390x/uvdevice/test_uvdevice.c b/tools/testing/selftests/drivers/s390x/uvdevice/test_uvdevice.c index 7ee7492138c6..14df9aa07308 100644 --- a/tools/testing/selftests/drivers/s390x/uvdevice/test_uvdevice.c +++ b/tools/testing/selftests/drivers/s390x/uvdevice/test_uvdevice.c @@ -14,7 +14,7 @@ #include <asm/uvdevice.h> -#include "../../../kselftest_harness.h" +#include "kselftest_harness.h" #define UV_PATH "/dev/uv" #define BUFFER_SIZE 0x200 diff --git a/tools/testing/selftests/exec/check-exec.c b/tools/testing/selftests/exec/check-exec.c index 55bce47e56b7..f2397e75aa7c 100644 --- a/tools/testing/selftests/exec/check-exec.c +++ b/tools/testing/selftests/exec/check-exec.c @@ -30,7 +30,7 @@ #define _ASM_GENERIC_FCNTL_H #include <linux/fcntl.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static int sys_execveat(int dirfd, const char *pathname, char *const argv[], char *const envp[], int flags) diff --git a/tools/testing/selftests/exec/execveat.c b/tools/testing/selftests/exec/execveat.c index 8fb7395fd35b..d37c068ed5fe 100644 --- a/tools/testing/selftests/exec/execveat.c +++ b/tools/testing/selftests/exec/execveat.c @@ -21,7 +21,7 @@ #include <string.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #define TESTS_EXPECTED 54 #define TEST_NAME_LEN (PATH_MAX * 4) diff --git a/tools/testing/selftests/exec/load_address.c b/tools/testing/selftests/exec/load_address.c index 8257fddba8c8..55fd3732f029 100644 --- a/tools/testing/selftests/exec/load_address.c +++ b/tools/testing/selftests/exec/load_address.c @@ -6,7 +6,7 @@ #include <stdio.h> #include <stdlib.h> #include <stdbool.h> -#include "../kselftest.h" +#include "kselftest.h" struct Statistics { unsigned long long load_address; diff --git a/tools/testing/selftests/exec/non-regular.c b/tools/testing/selftests/exec/non-regular.c index cd3a34aca93e..14ac36487df5 100644 --- a/tools/testing/selftests/exec/non-regular.c +++ b/tools/testing/selftests/exec/non-regular.c @@ -9,7 +9,7 @@ #include <sys/sysmacros.h> #include <sys/types.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" /* Remove a file, ignoring the result if it didn't exist. */ void rm(struct __test_metadata *_metadata, const char *pathname, diff --git a/tools/testing/selftests/exec/null-argv.c b/tools/testing/selftests/exec/null-argv.c index c19726e710d1..4940aee5bb38 100644 --- a/tools/testing/selftests/exec/null-argv.c +++ b/tools/testing/selftests/exec/null-argv.c @@ -5,7 +5,7 @@ #include <sys/types.h> #include <sys/wait.h> -#include "../kselftest.h" +#include "kselftest.h" #define FORK(exec) \ do { \ diff --git a/tools/testing/selftests/exec/recursion-depth.c b/tools/testing/selftests/exec/recursion-depth.c index 438c8ff2fd26..7b5c4f6d1928 100644 --- a/tools/testing/selftests/exec/recursion-depth.c +++ b/tools/testing/selftests/exec/recursion-depth.c @@ -23,7 +23,7 @@ #include <fcntl.h> #include <sys/mount.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" int main(void) { diff --git a/tools/testing/selftests/fchmodat2/fchmodat2_test.c b/tools/testing/selftests/fchmodat2/fchmodat2_test.c index e0319417124d..e397339495f6 100644 --- a/tools/testing/selftests/fchmodat2/fchmodat2_test.c +++ b/tools/testing/selftests/fchmodat2/fchmodat2_test.c @@ -7,7 +7,7 @@ #include <syscall.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" int sys_fchmodat2(int dfd, const char *filename, mode_t mode, int flags) { diff --git a/tools/testing/selftests/filelock/ofdlocks.c b/tools/testing/selftests/filelock/ofdlocks.c index a55b79810ab2..ff8d47fc373a 100644 --- a/tools/testing/selftests/filelock/ofdlocks.c +++ b/tools/testing/selftests/filelock/ofdlocks.c @@ -6,7 +6,7 @@ #include <stdio.h> #include <unistd.h> #include <string.h> -#include "../kselftest.h" +#include "kselftest.h" static int lock_set(int fd, struct flock *fl) { diff --git a/tools/testing/selftests/filesystems/anon_inode_test.c b/tools/testing/selftests/filesystems/anon_inode_test.c index 73e0a4d4fb2f..94c6c81c2301 100644 --- a/tools/testing/selftests/filesystems/anon_inode_test.c +++ b/tools/testing/selftests/filesystems/anon_inode_test.c @@ -6,7 +6,7 @@ #include <stdio.h> #include <sys/stat.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "wrappers.h" TEST(anon_inode_no_chown) diff --git a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c index 39a68078a79b..a1a79a6fef17 100644 --- a/tools/testing/selftests/filesystems/binderfs/binderfs_test.c +++ b/tools/testing/selftests/filesystems/binderfs/binderfs_test.c @@ -21,7 +21,7 @@ #include <linux/android/binder.h> #include <linux/android/binderfs.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define DEFAULT_THREADS 4 diff --git a/tools/testing/selftests/filesystems/devpts_pts.c b/tools/testing/selftests/filesystems/devpts_pts.c index b1fc9b916ace..54fea349204e 100644 --- a/tools/testing/selftests/filesystems/devpts_pts.c +++ b/tools/testing/selftests/filesystems/devpts_pts.c @@ -11,7 +11,7 @@ #include <asm/ioctls.h> #include <sys/mount.h> #include <sys/wait.h> -#include "../kselftest.h" +#include "kselftest.h" static bool terminal_dup2(int duplicate, int original) { diff --git a/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c b/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c index 65ede506305c..8bc57a2ef966 100644 --- a/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c +++ b/tools/testing/selftests/filesystems/epoll/epoll_wakeup_test.c @@ -11,7 +11,7 @@ #include <sys/epoll.h> #include <sys/socket.h> #include <sys/eventfd.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" struct epoll_mtcontext { diff --git a/tools/testing/selftests/filesystems/eventfd/eventfd_test.c b/tools/testing/selftests/filesystems/eventfd/eventfd_test.c index 72d51ad0ee0e..1b48f267157d 100644 --- a/tools/testing/selftests/filesystems/eventfd/eventfd_test.c +++ b/tools/testing/selftests/filesystems/eventfd/eventfd_test.c @@ -11,7 +11,7 @@ #include <pthread.h> #include <sys/epoll.h> #include <sys/eventfd.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define EVENTFD_TEST_ITERATIONS 100000UL diff --git a/tools/testing/selftests/filesystems/fclog.c b/tools/testing/selftests/filesystems/fclog.c index 912a8b755c3b..551c4a0f395a 100644 --- a/tools/testing/selftests/filesystems/fclog.c +++ b/tools/testing/selftests/filesystems/fclog.c @@ -13,7 +13,7 @@ #include <unistd.h> #include <sys/mount.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define ASSERT_ERRNO(expected, _t, seen) \ __EXPECT(expected, #expected, \ diff --git a/tools/testing/selftests/filesystems/file_stressor.c b/tools/testing/selftests/filesystems/file_stressor.c index 01dd89f8e52f..141badd671a9 100644 --- a/tools/testing/selftests/filesystems/file_stressor.c +++ b/tools/testing/selftests/filesystems/file_stressor.c @@ -12,7 +12,7 @@ #include <sys/mount.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <linux/types.h> #include <linux/mount.h> diff --git a/tools/testing/selftests/filesystems/fuse/fusectl_test.c b/tools/testing/selftests/filesystems/fuse/fusectl_test.c index 8d124d1cacb2..0d1d012c35ed 100644 --- a/tools/testing/selftests/filesystems/fuse/fusectl_test.c +++ b/tools/testing/selftests/filesystems/fuse/fusectl_test.c @@ -17,7 +17,7 @@ #include <sched.h> #include <linux/limits.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define FUSECTL_MOUNTPOINT "/sys/fs/fuse/connections" #define FUSE_MOUNTPOINT "/tmp/fuse_mnt_XXXXXX" diff --git a/tools/testing/selftests/filesystems/kernfs_test.c b/tools/testing/selftests/filesystems/kernfs_test.c index 16538b3b318e..84c2b910a60d 100644 --- a/tools/testing/selftests/filesystems/kernfs_test.c +++ b/tools/testing/selftests/filesystems/kernfs_test.c @@ -7,7 +7,7 @@ #include <sys/stat.h> #include <sys/xattr.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "wrappers.h" TEST(kernfs_listxattr) diff --git a/tools/testing/selftests/filesystems/mount-notify/mount-notify_test.c b/tools/testing/selftests/filesystems/mount-notify/mount-notify_test.c index e4b7c2b457ee..6381af6a40e3 100644 --- a/tools/testing/selftests/filesystems/mount-notify/mount-notify_test.c +++ b/tools/testing/selftests/filesystems/mount-notify/mount-notify_test.c @@ -19,7 +19,7 @@ typedef struct { #include <sys/syscall.h> #include <sys/fanotify.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #include "../statmount/statmount.h" #include "../utils.h" diff --git a/tools/testing/selftests/filesystems/mount-notify/mount-notify_test_ns.c b/tools/testing/selftests/filesystems/mount-notify/mount-notify_test_ns.c index 9f57ca46e3af..320ee25dc8a5 100644 --- a/tools/testing/selftests/filesystems/mount-notify/mount-notify_test_ns.c +++ b/tools/testing/selftests/filesystems/mount-notify/mount-notify_test_ns.c @@ -19,7 +19,7 @@ typedef struct { #include <sys/syscall.h> #include <sys/fanotify.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #include "../statmount/statmount.h" #include "../utils.h" diff --git a/tools/testing/selftests/filesystems/nsfs/iterate_mntns.c b/tools/testing/selftests/filesystems/nsfs/iterate_mntns.c index a3d8015897e9..61e55dfbf121 100644 --- a/tools/testing/selftests/filesystems/nsfs/iterate_mntns.c +++ b/tools/testing/selftests/filesystems/nsfs/iterate_mntns.c @@ -12,7 +12,7 @@ #include <sys/mount.h> #include <unistd.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define MNT_NS_COUNT 11 #define MNT_NS_LAST_INDEX 10 diff --git a/tools/testing/selftests/filesystems/overlayfs/dev_in_maps.c b/tools/testing/selftests/filesystems/overlayfs/dev_in_maps.c index 31db54b00e64..8924cea6aa4b 100644 --- a/tools/testing/selftests/filesystems/overlayfs/dev_in_maps.c +++ b/tools/testing/selftests/filesystems/overlayfs/dev_in_maps.c @@ -15,7 +15,7 @@ #include <sched.h> #include <fcntl.h> -#include "../../kselftest.h" +#include "kselftest.h" #include "log.h" #include "../wrappers.h" diff --git a/tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c b/tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c index dc0449fa628f..3c0b93183348 100644 --- a/tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c +++ b/tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c @@ -12,7 +12,7 @@ #include <sys/mount.h> #include <unistd.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #include "../../pidfd/pidfd.h" #include "log.h" #include "../utils.h" diff --git a/tools/testing/selftests/filesystems/statmount/listmount_test.c b/tools/testing/selftests/filesystems/statmount/listmount_test.c index 15f0834f7557..8bc82f38c42f 100644 --- a/tools/testing/selftests/filesystems/statmount/listmount_test.c +++ b/tools/testing/selftests/filesystems/statmount/listmount_test.c @@ -11,7 +11,7 @@ #include <unistd.h> #include "statmount.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #ifndef LISTMOUNT_REVERSE #define LISTMOUNT_REVERSE (1 << 0) /* List later mounts first */ diff --git a/tools/testing/selftests/filesystems/statmount/statmount_test.c b/tools/testing/selftests/filesystems/statmount/statmount_test.c index f048042e53e9..6e53430423d2 100644 --- a/tools/testing/selftests/filesystems/statmount/statmount_test.c +++ b/tools/testing/selftests/filesystems/statmount/statmount_test.c @@ -13,7 +13,7 @@ #include <linux/stat.h> #include "statmount.h" -#include "../../kselftest.h" +#include "kselftest.h" static const char *const known_fs[] = { "9p", "adfs", "affs", "afs", "aio", "anon_inodefs", "apparmorfs", diff --git a/tools/testing/selftests/filesystems/statmount/statmount_test_ns.c b/tools/testing/selftests/filesystems/statmount/statmount_test_ns.c index 605a3fa16bf7..d56d4103182f 100644 --- a/tools/testing/selftests/filesystems/statmount/statmount_test_ns.c +++ b/tools/testing/selftests/filesystems/statmount/statmount_test_ns.c @@ -15,7 +15,7 @@ #include "statmount.h" #include "../utils.h" -#include "../../kselftest.h" +#include "kselftest.h" #define NSID_PASS 0 #define NSID_FAIL 1 diff --git a/tools/testing/selftests/filesystems/utils.c b/tools/testing/selftests/filesystems/utils.c index a0c64f415a7f..c9dd5412b37b 100644 --- a/tools/testing/selftests/filesystems/utils.c +++ b/tools/testing/selftests/filesystems/utils.c @@ -20,7 +20,7 @@ #include <sys/xattr.h> #include <sys/mount.h> -#include "../kselftest.h" +#include "kselftest.h" #include "wrappers.h" #include "utils.h" diff --git a/tools/testing/selftests/futex/functional/futex_numa_mpol.c b/tools/testing/selftests/futex/functional/futex_numa_mpol.c index d037a3f10ee8..ab8555752137 100644 --- a/tools/testing/selftests/futex/functional/futex_numa_mpol.c +++ b/tools/testing/selftests/futex/functional/futex_numa_mpol.c @@ -18,7 +18,7 @@ #include "futextest.h" #include "futex2test.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define MAX_THREADS 64 diff --git a/tools/testing/selftests/futex/functional/futex_priv_hash.c b/tools/testing/selftests/futex/functional/futex_priv_hash.c index 3b7b5851f290..e8079d7c65e8 100644 --- a/tools/testing/selftests/futex/functional/futex_priv_hash.c +++ b/tools/testing/selftests/futex/functional/futex_priv_hash.c @@ -14,7 +14,7 @@ #include <linux/prctl.h> #include <sys/prctl.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define MAX_THREADS 64 diff --git a/tools/testing/selftests/futex/functional/futex_requeue.c b/tools/testing/selftests/futex/functional/futex_requeue.c index 69e2555b6039..35d4be23db5d 100644 --- a/tools/testing/selftests/futex/functional/futex_requeue.c +++ b/tools/testing/selftests/futex/functional/futex_requeue.c @@ -9,7 +9,7 @@ #include <limits.h> #include "futextest.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define timeout_ns 30000000 #define WAKE_WAIT_US 10000 diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi.c b/tools/testing/selftests/futex/functional/futex_requeue_pi.c index f299d75848cd..46d2858e15a8 100644 --- a/tools/testing/selftests/futex/functional/futex_requeue_pi.c +++ b/tools/testing/selftests/futex/functional/futex_requeue_pi.c @@ -29,7 +29,7 @@ #include "atomic.h" #include "futextest.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define MAX_WAKE_ITERS 1000 #define THREAD_MAX 10 diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c index 77135a22a583..f686e605359c 100644 --- a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c +++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c @@ -25,7 +25,7 @@ #include <time.h> #include "futextest.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" futex_t f1 = FUTEX_INITIALIZER; futex_t f2 = FUTEX_INITIALIZER; diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c index e34ee0f9ebcc..a18ccae73eb1 100644 --- a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c +++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c @@ -27,7 +27,7 @@ #include "atomic.h" #include "futextest.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define DELAY_US 100 diff --git a/tools/testing/selftests/futex/functional/futex_wait.c b/tools/testing/selftests/futex/functional/futex_wait.c index 152ca4612886..0e69c53524c1 100644 --- a/tools/testing/selftests/futex/functional/futex_wait.c +++ b/tools/testing/selftests/futex/functional/futex_wait.c @@ -11,7 +11,7 @@ #include <fcntl.h> #include "futextest.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define timeout_ns 30000000 #define WAKE_WAIT_US 10000 diff --git a/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c b/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c index 8952ebda14ab..2a749f9b14eb 100644 --- a/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c +++ b/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c @@ -28,7 +28,7 @@ #include <signal.h> #include "futextest.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define PAGE_SZ 4096 diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c index 0c8766aced2e..674dd13af421 100644 --- a/tools/testing/selftests/futex/functional/futex_wait_timeout.c +++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c @@ -19,7 +19,7 @@ #include "futextest.h" #include "futex2test.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" static long timeout_ns = 100000; /* 100us default timeout */ static futex_t futex_pi; diff --git a/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c b/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c index ce2301500d83..b07d68a67f31 100644 --- a/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c +++ b/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c @@ -30,7 +30,7 @@ #include <libgen.h> #include "futextest.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define WAIT_US 5000000 diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c index 36b7a54a4085..9ff936ecf164 100644 --- a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c +++ b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c @@ -24,7 +24,7 @@ #include "futextest.h" #include "futex2test.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define timeout_ns 100000 diff --git a/tools/testing/selftests/futex/functional/futex_waitv.c b/tools/testing/selftests/futex/functional/futex_waitv.c index c684b10eb76e..d60876164d4b 100644 --- a/tools/testing/selftests/futex/functional/futex_waitv.c +++ b/tools/testing/selftests/futex/functional/futex_waitv.c @@ -18,7 +18,7 @@ #include "futextest.h" #include "futex2test.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define WAKE_WAIT_US 10000 #define NR_FUTEXES 30 diff --git a/tools/testing/selftests/hid/hid_common.h b/tools/testing/selftests/hid/hid_common.h index 8085519c47cb..e3b267446fa0 100644 --- a/tools/testing/selftests/hid/hid_common.h +++ b/tools/testing/selftests/hid/hid_common.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* Copyright (c) 2022-2024 Red Hat */ -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <fcntl.h> #include <fnmatch.h> diff --git a/tools/testing/selftests/intel_pstate/aperf.c b/tools/testing/selftests/intel_pstate/aperf.c index a8acf3996973..953b63e5aa6a 100644 --- a/tools/testing/selftests/intel_pstate/aperf.c +++ b/tools/testing/selftests/intel_pstate/aperf.c @@ -11,7 +11,7 @@ #include <errno.h> #include <string.h> #include <time.h> -#include "../kselftest.h" +#include "kselftest.h" #define MSEC_PER_SEC 1000L #define NSEC_PER_MSEC 1000000L diff --git a/tools/testing/selftests/iommu/iommufd_utils.h b/tools/testing/selftests/iommu/iommufd_utils.h index 0a0ff6f7926d..5502751d500c 100644 --- a/tools/testing/selftests/iommu/iommufd_utils.h +++ b/tools/testing/selftests/iommu/iommufd_utils.h @@ -11,7 +11,7 @@ #include <assert.h> #include <poll.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "../../../../drivers/iommu/iommufd/iommufd_test.h" /* Hack to make assertions more readable */ diff --git a/tools/testing/selftests/ipc/msgque.c b/tools/testing/selftests/ipc/msgque.c index 5e36aeeb9901..e107379d185c 100644 --- a/tools/testing/selftests/ipc/msgque.c +++ b/tools/testing/selftests/ipc/msgque.c @@ -7,7 +7,7 @@ #include <sys/msg.h> #include <fcntl.h> -#include "../kselftest.h" +#include "kselftest.h" #define MAX_MSG_SIZE 32 diff --git a/tools/testing/selftests/ir/ir_loopback.c b/tools/testing/selftests/ir/ir_loopback.c index f4a15cbdd5ea..adfcf50b1264 100644 --- a/tools/testing/selftests/ir/ir_loopback.c +++ b/tools/testing/selftests/ir/ir_loopback.c @@ -23,7 +23,7 @@ #include <dirent.h> #include <sys/stat.h> #include <fcntl.h> -#include "../kselftest.h" +#include "kselftest.h" #define TEST_SCANCODES 10 #define SYSFS_PATH_MAX 256 diff --git a/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c index d7a8e321bb16..79aa438b7479 100644 --- a/tools/testing/selftests/kcmp/kcmp_test.c +++ b/tools/testing/selftests/kcmp/kcmp_test.c @@ -18,7 +18,7 @@ #include <sys/wait.h> #include <sys/epoll.h> -#include "../kselftest.h" +#include "kselftest.h" static long sys_kcmp(int pid1, int pid2, int type, unsigned long fd1, unsigned long fd2) { diff --git a/tools/testing/selftests/kho/vmtest.sh b/tools/testing/selftests/kho/vmtest.sh index 3f6c17166846..49fdac8e8b15 100755 --- a/tools/testing/selftests/kho/vmtest.sh +++ b/tools/testing/selftests/kho/vmtest.sh @@ -59,6 +59,7 @@ function build_kernel() { tee "$kconfig" > "$kho_config" <<EOF CONFIG_BLK_DEV_INITRD=y CONFIG_KEXEC_HANDOVER=y +CONFIG_KEXEC_HANDOVER_DEBUGFS=y CONFIG_TEST_KEXEC_HANDOVER=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_VM=y diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index 3f66e862e83e..baae6b7ded41 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -14,7 +14,7 @@ * * .. code-block:: c * - * #include "../kselftest_harness.h" + * #include "kselftest_harness.h" * * TEST(standalone_test) { * do_some_stuff; diff --git a/tools/testing/selftests/kselftest_harness/harness-selftest.c b/tools/testing/selftests/kselftest_harness/harness-selftest.c index b555493bdb4d..7820bb5d0e6d 100644 --- a/tools/testing/selftests/kselftest_harness/harness-selftest.c +++ b/tools/testing/selftests/kselftest_harness/harness-selftest.c @@ -8,7 +8,7 @@ /* Avoid any inconsistencies */ #define TH_LOG_STREAM stdout -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static void test_helper(struct __test_metadata *_metadata) { diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index d9fffe06d3ea..f2b223072b62 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -6,7 +6,7 @@ ARCH ?= $(SUBARCH) ifeq ($(ARCH),$(filter $(ARCH),arm64 s390 riscv x86 x86_64 loongarch)) # Top-level selftests allows ARCH=x86_64 :-( ifeq ($(ARCH),x86_64) - ARCH := x86 + override ARCH := x86 endif include Makefile.kvm else diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 148d427ff24b..ba5c2b643efa 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -88,8 +88,12 @@ TEST_GEN_PROGS_x86 += x86/kvm_pv_test TEST_GEN_PROGS_x86 += x86/kvm_buslock_test TEST_GEN_PROGS_x86 += x86/monitor_mwait_test TEST_GEN_PROGS_x86 += x86/msrs_test +TEST_GEN_PROGS_x86 += x86/nested_close_kvm_test TEST_GEN_PROGS_x86 += x86/nested_emulation_test TEST_GEN_PROGS_x86 += x86/nested_exceptions_test +TEST_GEN_PROGS_x86 += x86/nested_invalid_cr3_test +TEST_GEN_PROGS_x86 += x86/nested_tsc_adjust_test +TEST_GEN_PROGS_x86 += x86/nested_tsc_scaling_test TEST_GEN_PROGS_x86 += x86/platform_info_test TEST_GEN_PROGS_x86 += x86/pmu_counters_test TEST_GEN_PROGS_x86 += x86/pmu_event_filter_test @@ -111,14 +115,12 @@ TEST_GEN_PROGS_x86 += x86/ucna_injection_test TEST_GEN_PROGS_x86 += x86/userspace_io_test TEST_GEN_PROGS_x86 += x86/userspace_msr_exit_test TEST_GEN_PROGS_x86 += x86/vmx_apic_access_test -TEST_GEN_PROGS_x86 += x86/vmx_close_while_nested_test TEST_GEN_PROGS_x86 += x86/vmx_dirty_log_test TEST_GEN_PROGS_x86 += x86/vmx_exception_with_invalid_guest_state TEST_GEN_PROGS_x86 += x86/vmx_msrs_test TEST_GEN_PROGS_x86 += x86/vmx_invalid_nested_guest_state +TEST_GEN_PROGS_x86 += x86/vmx_nested_la57_state_test TEST_GEN_PROGS_x86 += x86/vmx_set_nested_state_test -TEST_GEN_PROGS_x86 += x86/vmx_tsc_adjust_test -TEST_GEN_PROGS_x86 += x86/vmx_nested_tsc_scaling_test TEST_GEN_PROGS_x86 += x86/apic_bus_clock_test TEST_GEN_PROGS_x86 += x86/xapic_ipi_test TEST_GEN_PROGS_x86 += x86/xapic_state_test @@ -156,6 +158,7 @@ TEST_GEN_PROGS_EXTENDED_x86 += x86/nx_huge_pages_test TEST_GEN_PROGS_arm64 = $(TEST_GEN_PROGS_COMMON) TEST_GEN_PROGS_arm64 += arm64/aarch32_id_regs TEST_GEN_PROGS_arm64 += arm64/arch_timer_edge_cases +TEST_GEN_PROGS_arm64 += arm64/at TEST_GEN_PROGS_arm64 += arm64/debug-exceptions TEST_GEN_PROGS_arm64 += arm64/hello_el2 TEST_GEN_PROGS_arm64 += arm64/host_sve @@ -163,6 +166,7 @@ TEST_GEN_PROGS_arm64 += arm64/hypercalls TEST_GEN_PROGS_arm64 += arm64/external_aborts TEST_GEN_PROGS_arm64 += arm64/page_fault_test TEST_GEN_PROGS_arm64 += arm64/psci_test +TEST_GEN_PROGS_arm64 += arm64/sea_to_user TEST_GEN_PROGS_arm64 += arm64/set_id_regs TEST_GEN_PROGS_arm64 += arm64/smccc_filter TEST_GEN_PROGS_arm64 += arm64/vcpu_width_config @@ -194,6 +198,7 @@ TEST_GEN_PROGS_s390 += s390/debug_test TEST_GEN_PROGS_s390 += s390/cpumodel_subfuncs_test TEST_GEN_PROGS_s390 += s390/shared_zeropage_test TEST_GEN_PROGS_s390 += s390/ucontrol_test +TEST_GEN_PROGS_s390 += s390/user_operexec TEST_GEN_PROGS_s390 += rseq_test TEST_GEN_PROGS_riscv = $(TEST_GEN_PROGS_COMMON) @@ -210,6 +215,7 @@ TEST_GEN_PROGS_riscv += mmu_stress_test TEST_GEN_PROGS_riscv += rseq_test TEST_GEN_PROGS_riscv += steal_time +TEST_GEN_PROGS_loongarch = arch_timer TEST_GEN_PROGS_loongarch += coalesced_io_test TEST_GEN_PROGS_loongarch += demand_paging_test TEST_GEN_PROGS_loongarch += dirty_log_perf_test diff --git a/tools/testing/selftests/kvm/arm64/at.c b/tools/testing/selftests/kvm/arm64/at.c new file mode 100644 index 000000000000..c8ee6f520734 --- /dev/null +++ b/tools/testing/selftests/kvm/arm64/at.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * at - Test for KVM's AT emulation in the EL2&0 and EL1&0 translation regimes. + */ +#include "kvm_util.h" +#include "processor.h" +#include "test_util.h" +#include "ucall.h" + +#include <asm/sysreg.h> + +#define TEST_ADDR 0x80000000 + +enum { + CLEAR_ACCESS_FLAG, + TEST_ACCESS_FLAG, +}; + +static u64 *ptep_hva; + +#define copy_el2_to_el1(reg) \ + write_sysreg_s(read_sysreg_s(SYS_##reg##_EL1), SYS_##reg##_EL12) + +/* Yes, this is an ugly hack */ +#define __at(op, addr) write_sysreg_s(addr, op) + +#define test_at_insn(op, expect_fault) \ +do { \ + u64 par, fsc; \ + bool fault; \ + \ + GUEST_SYNC(CLEAR_ACCESS_FLAG); \ + \ + __at(OP_AT_##op, TEST_ADDR); \ + isb(); \ + par = read_sysreg(par_el1); \ + \ + fault = par & SYS_PAR_EL1_F; \ + fsc = FIELD_GET(SYS_PAR_EL1_FST, par); \ + \ + __GUEST_ASSERT((expect_fault) == fault, \ + "AT "#op": %sexpected fault (par: %lx)1", \ + (expect_fault) ? "" : "un", par); \ + if ((expect_fault)) { \ + __GUEST_ASSERT(fsc == ESR_ELx_FSC_ACCESS_L(3), \ + "AT "#op": expected access flag fault (par: %lx)", \ + par); \ + } else { \ + GUEST_ASSERT_EQ(FIELD_GET(SYS_PAR_EL1_ATTR, par), MAIR_ATTR_NORMAL); \ + GUEST_ASSERT_EQ(FIELD_GET(SYS_PAR_EL1_SH, par), PTE_SHARED >> 8); \ + GUEST_ASSERT_EQ(par & SYS_PAR_EL1_PA, TEST_ADDR); \ + GUEST_SYNC(TEST_ACCESS_FLAG); \ + } \ +} while (0) + +static void test_at(bool expect_fault) +{ + test_at_insn(S1E2R, expect_fault); + test_at_insn(S1E2W, expect_fault); + + /* Reuse the stage-1 MMU context from EL2 at EL1 */ + copy_el2_to_el1(SCTLR); + copy_el2_to_el1(MAIR); + copy_el2_to_el1(TCR); + copy_el2_to_el1(TTBR0); + copy_el2_to_el1(TTBR1); + + /* Disable stage-2 translation and enter a non-host context */ + write_sysreg(0, vtcr_el2); + write_sysreg(0, vttbr_el2); + sysreg_clear_set(hcr_el2, HCR_EL2_TGE | HCR_EL2_VM, 0); + isb(); + + test_at_insn(S1E1R, expect_fault); + test_at_insn(S1E1W, expect_fault); +} + +static void guest_code(void) +{ + sysreg_clear_set(tcr_el1, TCR_HA, 0); + isb(); + + test_at(true); + + if (!SYS_FIELD_GET(ID_AA64MMFR1_EL1, HAFDBS, read_sysreg(id_aa64mmfr1_el1))) + GUEST_DONE(); + + /* + * KVM's software PTW makes the implementation choice that the AT + * instruction sets the access flag. + */ + sysreg_clear_set(tcr_el1, 0, TCR_HA); + isb(); + test_at(false); + + GUEST_DONE(); +} + +static void handle_sync(struct kvm_vcpu *vcpu, struct ucall *uc) +{ + switch (uc->args[1]) { + case CLEAR_ACCESS_FLAG: + /* + * Delete + reinstall the memslot to invalidate stage-2 + * mappings of the stage-1 page tables, forcing KVM to + * use the 'slow' AT emulation path. + * + * This and clearing the access flag from host userspace + * ensures that the access flag cannot be set speculatively + * and is reliably cleared at the time of the AT instruction. + */ + clear_bit(__ffs(PTE_AF), ptep_hva); + vm_mem_region_reload(vcpu->vm, vcpu->vm->memslots[MEM_REGION_PT]); + break; + case TEST_ACCESS_FLAG: + TEST_ASSERT(test_bit(__ffs(PTE_AF), ptep_hva), + "Expected access flag to be set (desc: %lu)", *ptep_hva); + break; + default: + TEST_FAIL("Unexpected SYNC arg: %lu", uc->args[1]); + } +} + +static void run_test(struct kvm_vcpu *vcpu) +{ + struct ucall uc; + + while (true) { + vcpu_run(vcpu); + switch (get_ucall(vcpu, &uc)) { + case UCALL_DONE: + return; + case UCALL_SYNC: + handle_sync(vcpu, &uc); + continue; + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + return; + default: + TEST_FAIL("Unexpected ucall: %lu", uc.cmd); + } + } +} + +int main(void) +{ + struct kvm_vcpu_init init; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + TEST_REQUIRE(kvm_check_cap(KVM_CAP_ARM_EL2)); + + vm = vm_create(1); + + kvm_get_default_vcpu_target(vm, &init); + init.features[0] |= BIT(KVM_ARM_VCPU_HAS_EL2); + vcpu = aarch64_vcpu_add(vm, 0, &init, guest_code); + kvm_arch_vm_finalize_vcpus(vm); + + virt_map(vm, TEST_ADDR, TEST_ADDR, 1); + ptep_hva = virt_get_pte_hva_at_level(vm, TEST_ADDR, 3); + run_test(vcpu); + + kvm_vm_free(vm); + return 0; +} diff --git a/tools/testing/selftests/kvm/arm64/sea_to_user.c b/tools/testing/selftests/kvm/arm64/sea_to_user.c new file mode 100644 index 000000000000..573dd790aeb8 --- /dev/null +++ b/tools/testing/selftests/kvm/arm64/sea_to_user.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Test KVM returns to userspace with KVM_EXIT_ARM_SEA if host APEI fails + * to handle SEA and userspace has opt-ed in KVM_CAP_ARM_SEA_TO_USER. + * + * After reaching userspace with expected arm_sea info, also test userspace + * injecting a synchronous external data abort into the guest. + * + * This test utilizes EINJ to generate a REAL synchronous external data + * abort by consuming a recoverable uncorrectable memory error. Therefore + * the device under test must support EINJ in both firmware and host kernel, + * including the notrigger feature. Otherwise the test will be skipped. + * The under-test platform's APEI should be unable to claim SEA. Otherwise + * the test will also be skipped. + */ + +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" +#include "guest_modes.h" + +#define PAGE_PRESENT (1ULL << 63) +#define PAGE_PHYSICAL 0x007fffffffffffffULL +#define PAGE_ADDR_MASK (~(0xfffULL)) + +/* Group ISV and ISS[23:14]. */ +#define ESR_ELx_INST_SYNDROME ((ESR_ELx_ISV) | (ESR_ELx_SAS) | \ + (ESR_ELx_SSE) | (ESR_ELx_SRT_MASK) | \ + (ESR_ELx_SF) | (ESR_ELx_AR)) + +#define EINJ_ETYPE "/sys/kernel/debug/apei/einj/error_type" +#define EINJ_ADDR "/sys/kernel/debug/apei/einj/param1" +#define EINJ_MASK "/sys/kernel/debug/apei/einj/param2" +#define EINJ_FLAGS "/sys/kernel/debug/apei/einj/flags" +#define EINJ_NOTRIGGER "/sys/kernel/debug/apei/einj/notrigger" +#define EINJ_DOIT "/sys/kernel/debug/apei/einj/error_inject" +/* Memory Uncorrectable non-fatal. */ +#define ERROR_TYPE_MEMORY_UER 0x10 +/* Memory address and mask valid (param1 and param2). */ +#define MASK_MEMORY_UER 0b10 + +/* Guest virtual address region = [2G, 3G). */ +#define START_GVA 0x80000000UL +#define VM_MEM_SIZE 0x40000000UL +/* Note: EINJ_OFFSET must < VM_MEM_SIZE. */ +#define EINJ_OFFSET 0x01234badUL +#define EINJ_GVA ((START_GVA) + (EINJ_OFFSET)) + +static vm_paddr_t einj_gpa; +static void *einj_hva; +static uint64_t einj_hpa; +static bool far_invalid; + +static uint64_t translate_to_host_paddr(unsigned long vaddr) +{ + uint64_t pinfo; + int64_t offset = vaddr / getpagesize() * sizeof(pinfo); + int fd; + uint64_t page_addr; + uint64_t paddr; + + fd = open("/proc/self/pagemap", O_RDONLY); + if (fd < 0) + ksft_exit_fail_perror("Failed to open /proc/self/pagemap"); + if (pread(fd, &pinfo, sizeof(pinfo), offset) != sizeof(pinfo)) { + close(fd); + ksft_exit_fail_perror("Failed to read /proc/self/pagemap"); + } + + close(fd); + + if ((pinfo & PAGE_PRESENT) == 0) + ksft_exit_fail_perror("Page not present"); + + page_addr = (pinfo & PAGE_PHYSICAL) << MIN_PAGE_SHIFT; + paddr = page_addr + (vaddr & (getpagesize() - 1)); + return paddr; +} + +static void write_einj_entry(const char *einj_path, uint64_t val) +{ + char cmd[256] = {0}; + FILE *cmdfile = NULL; + + sprintf(cmd, "echo %#lx > %s", val, einj_path); + cmdfile = popen(cmd, "r"); + + if (pclose(cmdfile) == 0) + ksft_print_msg("echo %#lx > %s - done\n", val, einj_path); + else + ksft_exit_fail_perror("Failed to write EINJ entry"); +} + +static void inject_uer(uint64_t paddr) +{ + if (access("/sys/firmware/acpi/tables/EINJ", R_OK) == -1) + ksft_test_result_skip("EINJ table no available in firmware"); + + if (access(EINJ_ETYPE, R_OK | W_OK) == -1) + ksft_test_result_skip("EINJ module probably not loaded?"); + + write_einj_entry(EINJ_ETYPE, ERROR_TYPE_MEMORY_UER); + write_einj_entry(EINJ_FLAGS, MASK_MEMORY_UER); + write_einj_entry(EINJ_ADDR, paddr); + write_einj_entry(EINJ_MASK, ~0x0UL); + write_einj_entry(EINJ_NOTRIGGER, 1); + write_einj_entry(EINJ_DOIT, 1); +} + +/* + * When host APEI successfully claims the SEA caused by guest_code, kernel + * will send SIGBUS signal with BUS_MCEERR_AR to test thread. + * + * We set up this SIGBUS handler to skip the test for that case. + */ +static void sigbus_signal_handler(int sig, siginfo_t *si, void *v) +{ + ksft_print_msg("SIGBUS (%d) received, dumping siginfo...\n", sig); + ksft_print_msg("si_signo=%d, si_errno=%d, si_code=%d, si_addr=%p\n", + si->si_signo, si->si_errno, si->si_code, si->si_addr); + if (si->si_code == BUS_MCEERR_AR) + ksft_test_result_skip("SEA is claimed by host APEI\n"); + else + ksft_test_result_fail("Exit with signal unhandled\n"); + + exit(0); +} + +static void setup_sigbus_handler(void) +{ + struct sigaction act; + + memset(&act, 0, sizeof(act)); + sigemptyset(&act.sa_mask); + act.sa_sigaction = sigbus_signal_handler; + act.sa_flags = SA_SIGINFO; + TEST_ASSERT(sigaction(SIGBUS, &act, NULL) == 0, + "Failed to setup SIGBUS handler"); +} + +static void guest_code(void) +{ + uint64_t guest_data; + + /* Consumes error will cause a SEA. */ + guest_data = *(uint64_t *)EINJ_GVA; + + GUEST_FAIL("Poison not protected by SEA: gva=%#lx, guest_data=%#lx\n", + EINJ_GVA, guest_data); +} + +static void expect_sea_handler(struct ex_regs *regs) +{ + u64 esr = read_sysreg(esr_el1); + u64 far = read_sysreg(far_el1); + bool expect_far_invalid = far_invalid; + + GUEST_PRINTF("Handling Guest SEA\n"); + GUEST_PRINTF("ESR_EL1=%#lx, FAR_EL1=%#lx\n", esr, far); + + GUEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_CUR); + GUEST_ASSERT_EQ(esr & ESR_ELx_FSC_TYPE, ESR_ELx_FSC_EXTABT); + + if (expect_far_invalid) { + GUEST_ASSERT_EQ(esr & ESR_ELx_FnV, ESR_ELx_FnV); + GUEST_PRINTF("Guest observed garbage value in FAR\n"); + } else { + GUEST_ASSERT_EQ(esr & ESR_ELx_FnV, 0); + GUEST_ASSERT_EQ(far, EINJ_GVA); + } + + GUEST_DONE(); +} + +static void vcpu_inject_sea(struct kvm_vcpu *vcpu) +{ + struct kvm_vcpu_events events = {}; + + events.exception.ext_dabt_pending = true; + vcpu_events_set(vcpu, &events); +} + +static void run_vm(struct kvm_vm *vm, struct kvm_vcpu *vcpu) +{ + struct ucall uc; + bool guest_done = false; + struct kvm_run *run = vcpu->run; + u64 esr; + + /* Resume the vCPU after error injection to consume the error. */ + vcpu_run(vcpu); + + ksft_print_msg("Dump kvm_run info about KVM_EXIT_%s\n", + exit_reason_str(run->exit_reason)); + ksft_print_msg("kvm_run.arm_sea: esr=%#llx, flags=%#llx\n", + run->arm_sea.esr, run->arm_sea.flags); + ksft_print_msg("kvm_run.arm_sea: gva=%#llx, gpa=%#llx\n", + run->arm_sea.gva, run->arm_sea.gpa); + + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_ARM_SEA); + + esr = run->arm_sea.esr; + TEST_ASSERT_EQ(ESR_ELx_EC(esr), ESR_ELx_EC_DABT_LOW); + TEST_ASSERT_EQ(esr & ESR_ELx_FSC_TYPE, ESR_ELx_FSC_EXTABT); + TEST_ASSERT_EQ(ESR_ELx_ISS2(esr), 0); + TEST_ASSERT_EQ((esr & ESR_ELx_INST_SYNDROME), 0); + TEST_ASSERT_EQ(esr & ESR_ELx_VNCR, 0); + + if (!(esr & ESR_ELx_FnV)) { + ksft_print_msg("Expect gva to match given FnV bit is 0\n"); + TEST_ASSERT_EQ(run->arm_sea.gva, EINJ_GVA); + } + + if (run->arm_sea.flags & KVM_EXIT_ARM_SEA_FLAG_GPA_VALID) { + ksft_print_msg("Expect gpa to match given KVM_EXIT_ARM_SEA_FLAG_GPA_VALID is set\n"); + TEST_ASSERT_EQ(run->arm_sea.gpa, einj_gpa & PAGE_ADDR_MASK); + } + + far_invalid = esr & ESR_ELx_FnV; + + /* Inject a SEA into guest and expect handled in SEA handler. */ + vcpu_inject_sea(vcpu); + + /* Expect the guest to reach GUEST_DONE gracefully. */ + do { + vcpu_run(vcpu); + switch (get_ucall(vcpu, &uc)) { + case UCALL_PRINTF: + ksft_print_msg("From guest: %s", uc.buffer); + break; + case UCALL_DONE: + ksft_print_msg("Guest done gracefully!\n"); + guest_done = 1; + break; + case UCALL_ABORT: + ksft_print_msg("Guest aborted!\n"); + guest_done = 1; + REPORT_GUEST_ASSERT(uc); + break; + default: + TEST_FAIL("Unexpected ucall: %lu\n", uc.cmd); + } + } while (!guest_done); +} + +static struct kvm_vm *vm_create_with_sea_handler(struct kvm_vcpu **vcpu) +{ + size_t backing_page_size; + size_t guest_page_size; + size_t alignment; + uint64_t num_guest_pages; + vm_paddr_t start_gpa; + enum vm_mem_backing_src_type src_type = VM_MEM_SRC_ANONYMOUS_HUGETLB_1GB; + struct kvm_vm *vm; + + backing_page_size = get_backing_src_pagesz(src_type); + guest_page_size = vm_guest_mode_params[VM_MODE_DEFAULT].page_size; + alignment = max(backing_page_size, guest_page_size); + num_guest_pages = VM_MEM_SIZE / guest_page_size; + + vm = __vm_create_with_one_vcpu(vcpu, num_guest_pages, guest_code); + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(*vcpu); + + vm_install_sync_handler(vm, + /*vector=*/VECTOR_SYNC_CURRENT, + /*ec=*/ESR_ELx_EC_DABT_CUR, + /*handler=*/expect_sea_handler); + + start_gpa = (vm->max_gfn - num_guest_pages) * guest_page_size; + start_gpa = align_down(start_gpa, alignment); + + vm_userspace_mem_region_add( + /*vm=*/vm, + /*src_type=*/src_type, + /*guest_paddr=*/start_gpa, + /*slot=*/1, + /*npages=*/num_guest_pages, + /*flags=*/0); + + virt_map(vm, START_GVA, start_gpa, num_guest_pages); + + ksft_print_msg("Mapped %#lx pages: gva=%#lx to gpa=%#lx\n", + num_guest_pages, START_GVA, start_gpa); + return vm; +} + +static void vm_inject_memory_uer(struct kvm_vm *vm) +{ + uint64_t guest_data; + + einj_gpa = addr_gva2gpa(vm, EINJ_GVA); + einj_hva = addr_gva2hva(vm, EINJ_GVA); + + /* Populate certain data before injecting UER. */ + *(uint64_t *)einj_hva = 0xBAADCAFE; + guest_data = *(uint64_t *)einj_hva; + ksft_print_msg("Before EINJect: data=%#lx\n", + guest_data); + + einj_hpa = translate_to_host_paddr((unsigned long)einj_hva); + + ksft_print_msg("EINJ_GVA=%#lx, einj_gpa=%#lx, einj_hva=%p, einj_hpa=%#lx\n", + EINJ_GVA, einj_gpa, einj_hva, einj_hpa); + + inject_uer(einj_hpa); + ksft_print_msg("Memory UER EINJected\n"); +} + +int main(int argc, char *argv[]) +{ + struct kvm_vm *vm; + struct kvm_vcpu *vcpu; + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_ARM_SEA_TO_USER)); + + setup_sigbus_handler(); + + vm = vm_create_with_sea_handler(&vcpu); + vm_enable_cap(vm, KVM_CAP_ARM_SEA_TO_USER, 0); + vm_inject_memory_uer(vm); + run_vm(vm, vcpu); + kvm_vm_free(vm); + + return 0; +} diff --git a/tools/testing/selftests/kvm/arm64/vgic_irq.c b/tools/testing/selftests/kvm/arm64/vgic_irq.c index 6338f5bbdb70..2fb2c7939fe9 100644 --- a/tools/testing/selftests/kvm/arm64/vgic_irq.c +++ b/tools/testing/selftests/kvm/arm64/vgic_irq.c @@ -29,6 +29,7 @@ struct test_args { bool level_sensitive; /* 1 is level, 0 is edge */ int kvm_max_routes; /* output of KVM_CAP_IRQ_ROUTING */ bool kvm_supports_irqfd; /* output of KVM_CAP_IRQFD */ + uint32_t shared_data; }; /* @@ -205,7 +206,7 @@ static void kvm_inject_call(kvm_inject_cmd cmd, uint32_t first_intid, do { \ uint32_t _intid; \ _intid = gic_get_and_ack_irq(); \ - GUEST_ASSERT(_intid == 0 || _intid == IAR_SPURIOUS); \ + GUEST_ASSERT(_intid == IAR_SPURIOUS); \ } while (0) #define CAT_HELPER(a, b) a ## b @@ -359,8 +360,9 @@ static uint32_t wait_for_and_activate_irq(void) * interrupts for the whole test. */ static void test_inject_preemption(struct test_args *args, - uint32_t first_intid, int num, - kvm_inject_cmd cmd) + uint32_t first_intid, int num, + const unsigned long *exclude, + kvm_inject_cmd cmd) { uint32_t intid, prio, step = KVM_PRIO_STEPS; int i; @@ -379,6 +381,10 @@ static void test_inject_preemption(struct test_args *args, for (i = 0; i < num; i++) { uint32_t tmp; intid = i + first_intid; + + if (exclude && test_bit(i, exclude)) + continue; + KVM_INJECT(cmd, intid); /* Each successive IRQ will preempt the previous one. */ tmp = wait_for_and_activate_irq(); @@ -390,15 +396,33 @@ static void test_inject_preemption(struct test_args *args, /* finish handling the IRQs starting with the highest priority one. */ for (i = 0; i < num; i++) { intid = num - i - 1 + first_intid; + + if (exclude && test_bit(intid - first_intid, exclude)) + continue; + gic_set_eoi(intid); - if (args->eoi_split) - gic_set_dir(intid); + } + + if (args->eoi_split) { + for (i = 0; i < num; i++) { + intid = i + first_intid; + + if (exclude && test_bit(i, exclude)) + continue; + + if (args->eoi_split) + gic_set_dir(intid); + } } local_irq_enable(); - for (i = 0; i < num; i++) + for (i = 0; i < num; i++) { + if (exclude && test_bit(i, exclude)) + continue; + GUEST_ASSERT(!gic_irq_get_active(i + first_intid)); + } GUEST_ASSERT_EQ(gic_read_ap1r0(), 0); GUEST_ASSERT_IAR_EMPTY(); @@ -436,33 +460,32 @@ static void test_injection_failure(struct test_args *args, static void test_preemption(struct test_args *args, struct kvm_inject_desc *f) { - /* - * Test up to 4 levels of preemption. The reason is that KVM doesn't - * currently implement the ability to have more than the number-of-LRs - * number of concurrently active IRQs. The number of LRs implemented is - * IMPLEMENTATION DEFINED, however, it seems that most implement 4. - */ + /* Timer PPIs cannot be injected from userspace */ + static const unsigned long ppi_exclude = (BIT(27 - MIN_PPI) | + BIT(30 - MIN_PPI) | + BIT(28 - MIN_PPI) | + BIT(26 - MIN_PPI)); + if (f->sgi) - test_inject_preemption(args, MIN_SGI, 4, f->cmd); + test_inject_preemption(args, MIN_SGI, 16, NULL, f->cmd); if (f->ppi) - test_inject_preemption(args, MIN_PPI, 4, f->cmd); + test_inject_preemption(args, MIN_PPI, 16, &ppi_exclude, f->cmd); if (f->spi) - test_inject_preemption(args, MIN_SPI, 4, f->cmd); + test_inject_preemption(args, MIN_SPI, 31, NULL, f->cmd); } static void test_restore_active(struct test_args *args, struct kvm_inject_desc *f) { - /* Test up to 4 active IRQs. Same reason as in test_preemption. */ if (f->sgi) - guest_restore_active(args, MIN_SGI, 4, f->cmd); + guest_restore_active(args, MIN_SGI, 16, f->cmd); if (f->ppi) - guest_restore_active(args, MIN_PPI, 4, f->cmd); + guest_restore_active(args, MIN_PPI, 16, f->cmd); if (f->spi) - guest_restore_active(args, MIN_SPI, 4, f->cmd); + guest_restore_active(args, MIN_SPI, 31, f->cmd); } static void guest_code(struct test_args *args) @@ -473,12 +496,12 @@ static void guest_code(struct test_args *args) gic_init(GIC_V3, 1); - for (i = 0; i < nr_irqs; i++) - gic_irq_enable(i); - for (i = MIN_SPI; i < nr_irqs; i++) gic_irq_set_config(i, !level_sensitive); + for (i = 0; i < nr_irqs; i++) + gic_irq_enable(i); + gic_set_eoi_split(args->eoi_split); reset_priorities(args); @@ -636,7 +659,7 @@ static void kvm_routing_and_irqfd_check(struct kvm_vm *vm, } for (f = 0, i = intid; i < (uint64_t)intid + num; i++, f++) - close(fd[f]); + kvm_close(fd[f]); } /* handles the valid case: intid=0xffffffff num=1 */ @@ -779,6 +802,221 @@ done: kvm_vm_free(vm); } +static void guest_code_asym_dir(struct test_args *args, int cpuid) +{ + gic_init(GIC_V3, 2); + + gic_set_eoi_split(1); + gic_set_priority_mask(CPU_PRIO_MASK); + + if (cpuid == 0) { + uint32_t intid; + + local_irq_disable(); + + gic_set_priority(MIN_PPI, IRQ_DEFAULT_PRIO); + gic_irq_enable(MIN_SPI); + gic_irq_set_pending(MIN_SPI); + + intid = wait_for_and_activate_irq(); + GUEST_ASSERT_EQ(intid, MIN_SPI); + + gic_set_eoi(intid); + isb(); + + WRITE_ONCE(args->shared_data, MIN_SPI); + dsb(ishst); + + do { + dsb(ishld); + } while (READ_ONCE(args->shared_data) == MIN_SPI); + GUEST_ASSERT(!gic_irq_get_active(MIN_SPI)); + } else { + do { + dsb(ishld); + } while (READ_ONCE(args->shared_data) != MIN_SPI); + + gic_set_dir(MIN_SPI); + isb(); + + WRITE_ONCE(args->shared_data, 0); + dsb(ishst); + } + + GUEST_DONE(); +} + +static void guest_code_group_en(struct test_args *args, int cpuid) +{ + uint32_t intid; + + gic_init(GIC_V3, 2); + + gic_set_eoi_split(0); + gic_set_priority_mask(CPU_PRIO_MASK); + /* SGI0 is G0, which is disabled */ + gic_irq_set_group(0, 0); + + /* Configure all SGIs with decreasing priority */ + for (intid = 0; intid < MIN_PPI; intid++) { + gic_set_priority(intid, (intid + 1) * 8); + gic_irq_enable(intid); + gic_irq_set_pending(intid); + } + + /* Ack and EOI all G1 interrupts */ + for (int i = 1; i < MIN_PPI; i++) { + intid = wait_for_and_activate_irq(); + + GUEST_ASSERT(intid < MIN_PPI); + gic_set_eoi(intid); + isb(); + } + + /* + * Check that SGI0 is still pending, inactive, and that we cannot + * ack anything. + */ + GUEST_ASSERT(gic_irq_get_pending(0)); + GUEST_ASSERT(!gic_irq_get_active(0)); + GUEST_ASSERT_IAR_EMPTY(); + GUEST_ASSERT(read_sysreg_s(SYS_ICC_IAR0_EL1) == IAR_SPURIOUS); + + /* Open the G0 gates, and verify we can ack SGI0 */ + write_sysreg_s(1, SYS_ICC_IGRPEN0_EL1); + isb(); + + do { + intid = read_sysreg_s(SYS_ICC_IAR0_EL1); + } while (intid == IAR_SPURIOUS); + + GUEST_ASSERT(intid == 0); + GUEST_DONE(); +} + +static void guest_code_timer_spi(struct test_args *args, int cpuid) +{ + uint32_t intid; + u64 val; + + gic_init(GIC_V3, 2); + + gic_set_eoi_split(1); + gic_set_priority_mask(CPU_PRIO_MASK); + + /* Add a pending SPI so that KVM starts trapping DIR */ + gic_set_priority(MIN_SPI + cpuid, IRQ_DEFAULT_PRIO); + gic_irq_set_pending(MIN_SPI + cpuid); + + /* Configure the timer with a higher priority, make it pending */ + gic_set_priority(27, IRQ_DEFAULT_PRIO - 8); + + isb(); + val = read_sysreg(cntvct_el0); + write_sysreg(val, cntv_cval_el0); + write_sysreg(1, cntv_ctl_el0); + isb(); + + GUEST_ASSERT(gic_irq_get_pending(27)); + + /* Enable both interrupts */ + gic_irq_enable(MIN_SPI + cpuid); + gic_irq_enable(27); + + /* The timer must fire */ + intid = wait_for_and_activate_irq(); + GUEST_ASSERT(intid == 27); + + /* Check that we can deassert it */ + write_sysreg(0, cntv_ctl_el0); + isb(); + + GUEST_ASSERT(!gic_irq_get_pending(27)); + + /* + * Priority drop, deactivation -- we expect that the host + * deactivation will have been effective + */ + gic_set_eoi(27); + gic_set_dir(27); + + GUEST_ASSERT(!gic_irq_get_active(27)); + + /* Do it one more time */ + isb(); + val = read_sysreg(cntvct_el0); + write_sysreg(val, cntv_cval_el0); + write_sysreg(1, cntv_ctl_el0); + isb(); + + GUEST_ASSERT(gic_irq_get_pending(27)); + + /* The timer must fire again */ + intid = wait_for_and_activate_irq(); + GUEST_ASSERT(intid == 27); + + GUEST_DONE(); +} + +static void *test_vcpu_run(void *arg) +{ + struct kvm_vcpu *vcpu = arg; + struct ucall uc; + + while (1) { + vcpu_run(vcpu); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + break; + case UCALL_DONE: + return NULL; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + } + } + + return NULL; +} + +static void test_vgic_two_cpus(void *gcode) +{ + pthread_t thr[2]; + struct kvm_vcpu *vcpus[2]; + struct test_args args = {}; + struct kvm_vm *vm; + vm_vaddr_t args_gva; + int gic_fd, ret; + + vm = vm_create_with_vcpus(2, gcode, vcpus); + + vm_init_descriptor_tables(vm); + vcpu_init_descriptor_tables(vcpus[0]); + vcpu_init_descriptor_tables(vcpus[1]); + + /* Setup the guest args page (so it gets the args). */ + args_gva = vm_vaddr_alloc_page(vm); + memcpy(addr_gva2hva(vm, args_gva), &args, sizeof(args)); + vcpu_args_set(vcpus[0], 2, args_gva, 0); + vcpu_args_set(vcpus[1], 2, args_gva, 1); + + gic_fd = vgic_v3_setup(vm, 2, 64); + + ret = pthread_create(&thr[0], NULL, test_vcpu_run, vcpus[0]); + if (ret) + TEST_FAIL("Can't create thread for vcpu 0 (%d)\n", ret); + ret = pthread_create(&thr[1], NULL, test_vcpu_run, vcpus[1]); + if (ret) + TEST_FAIL("Can't create thread for vcpu 1 (%d)\n", ret); + + pthread_join(thr[0], NULL); + pthread_join(thr[1], NULL); + + close(gic_fd); + kvm_vm_free(vm); +} + static void help(const char *name) { printf( @@ -835,6 +1073,9 @@ int main(int argc, char **argv) test_vgic(nr_irqs, false /* level */, true /* eoi_split */); test_vgic(nr_irqs, true /* level */, false /* eoi_split */); test_vgic(nr_irqs, true /* level */, true /* eoi_split */); + test_vgic_two_cpus(guest_code_asym_dir); + test_vgic_two_cpus(guest_code_group_en); + test_vgic_two_cpus(guest_code_timer_spi); } else { test_vgic(nr_irqs, level_sensitive, eoi_split); } diff --git a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c index 687d04463983..e857a605f577 100644 --- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c +++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c @@ -118,6 +118,10 @@ static void guest_setup_gic(void) guest_setup_its_mappings(); guest_invalidate_all_rdists(); + + /* SYNC to ensure ITS setup is complete */ + for (cpuid = 0; cpuid < test_data.nr_cpus; cpuid++) + its_send_sync_cmd(test_data.cmdq_base_va, cpuid); } static void guest_code(size_t nr_lpis) diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c index e7d9aeb418d3..618c937f3c90 100644 --- a/tools/testing/selftests/kvm/guest_memfd_test.c +++ b/tools/testing/selftests/kvm/guest_memfd_test.c @@ -19,6 +19,7 @@ #include <sys/stat.h> #include "kvm_util.h" +#include "numaif.h" #include "test_util.h" #include "ucall_common.h" @@ -75,6 +76,101 @@ static void test_mmap_supported(int fd, size_t total_size) kvm_munmap(mem, total_size); } +static void test_mbind(int fd, size_t total_size) +{ + const unsigned long nodemask_0 = 1; /* nid: 0 */ + unsigned long nodemask = 0; + unsigned long maxnode = 8; + int policy; + char *mem; + int ret; + + if (!is_multi_numa_node_system()) + return; + + mem = kvm_mmap(total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd); + + /* Test MPOL_INTERLEAVE policy */ + kvm_mbind(mem, page_size * 2, MPOL_INTERLEAVE, &nodemask_0, maxnode, 0); + kvm_get_mempolicy(&policy, &nodemask, maxnode, mem, MPOL_F_ADDR); + TEST_ASSERT(policy == MPOL_INTERLEAVE && nodemask == nodemask_0, + "Wanted MPOL_INTERLEAVE (%u) and nodemask 0x%lx, got %u and 0x%lx", + MPOL_INTERLEAVE, nodemask_0, policy, nodemask); + + /* Test basic MPOL_BIND policy */ + kvm_mbind(mem + page_size * 2, page_size * 2, MPOL_BIND, &nodemask_0, maxnode, 0); + kvm_get_mempolicy(&policy, &nodemask, maxnode, mem + page_size * 2, MPOL_F_ADDR); + TEST_ASSERT(policy == MPOL_BIND && nodemask == nodemask_0, + "Wanted MPOL_BIND (%u) and nodemask 0x%lx, got %u and 0x%lx", + MPOL_BIND, nodemask_0, policy, nodemask); + + /* Test MPOL_DEFAULT policy */ + kvm_mbind(mem, total_size, MPOL_DEFAULT, NULL, 0, 0); + kvm_get_mempolicy(&policy, &nodemask, maxnode, mem, MPOL_F_ADDR); + TEST_ASSERT(policy == MPOL_DEFAULT && !nodemask, + "Wanted MPOL_DEFAULT (%u) and nodemask 0x0, got %u and 0x%lx", + MPOL_DEFAULT, policy, nodemask); + + /* Test with invalid policy */ + ret = mbind(mem, page_size, 999, &nodemask_0, maxnode, 0); + TEST_ASSERT(ret == -1 && errno == EINVAL, + "mbind with invalid policy should fail with EINVAL"); + + kvm_munmap(mem, total_size); +} + +static void test_numa_allocation(int fd, size_t total_size) +{ + unsigned long node0_mask = 1; /* Node 0 */ + unsigned long node1_mask = 2; /* Node 1 */ + unsigned long maxnode = 8; + void *pages[4]; + int status[4]; + char *mem; + int i; + + if (!is_multi_numa_node_system()) + return; + + mem = kvm_mmap(total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd); + + for (i = 0; i < 4; i++) + pages[i] = (char *)mem + page_size * i; + + /* Set NUMA policy after allocation */ + memset(mem, 0xaa, page_size); + kvm_mbind(pages[0], page_size, MPOL_BIND, &node0_mask, maxnode, 0); + kvm_fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, page_size); + + /* Set NUMA policy before allocation */ + kvm_mbind(pages[0], page_size * 2, MPOL_BIND, &node1_mask, maxnode, 0); + kvm_mbind(pages[2], page_size * 2, MPOL_BIND, &node0_mask, maxnode, 0); + memset(mem, 0xaa, total_size); + + /* Validate if pages are allocated on specified NUMA nodes */ + kvm_move_pages(0, 4, pages, NULL, status, 0); + TEST_ASSERT(status[0] == 1, "Expected page 0 on node 1, got it on node %d", status[0]); + TEST_ASSERT(status[1] == 1, "Expected page 1 on node 1, got it on node %d", status[1]); + TEST_ASSERT(status[2] == 0, "Expected page 2 on node 0, got it on node %d", status[2]); + TEST_ASSERT(status[3] == 0, "Expected page 3 on node 0, got it on node %d", status[3]); + + /* Punch hole for all pages */ + kvm_fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, total_size); + + /* Change NUMA policy nodes and reallocate */ + kvm_mbind(pages[0], page_size * 2, MPOL_BIND, &node0_mask, maxnode, 0); + kvm_mbind(pages[2], page_size * 2, MPOL_BIND, &node1_mask, maxnode, 0); + memset(mem, 0xaa, total_size); + + kvm_move_pages(0, 4, pages, NULL, status, 0); + TEST_ASSERT(status[0] == 0, "Expected page 0 on node 0, got it on node %d", status[0]); + TEST_ASSERT(status[1] == 0, "Expected page 1 on node 0, got it on node %d", status[1]); + TEST_ASSERT(status[2] == 1, "Expected page 2 on node 1, got it on node %d", status[2]); + TEST_ASSERT(status[3] == 1, "Expected page 3 on node 1, got it on node %d", status[3]); + + kvm_munmap(mem, total_size); +} + static void test_fault_sigbus(int fd, size_t accessible_size, size_t map_size) { const char val = 0xaa; @@ -273,11 +369,13 @@ static void __test_guest_memfd(struct kvm_vm *vm, uint64_t flags) if (flags & GUEST_MEMFD_FLAG_INIT_SHARED) { gmem_test(mmap_supported, vm, flags); gmem_test(fault_overflow, vm, flags); + gmem_test(numa_allocation, vm, flags); } else { gmem_test(fault_private, vm, flags); } gmem_test(mmap_cow, vm, flags); + gmem_test(mbind, vm, flags); } else { gmem_test(mmap_not_supported, vm, flags); } diff --git a/tools/testing/selftests/kvm/include/arm64/gic.h b/tools/testing/selftests/kvm/include/arm64/gic.h index baeb3c859389..cc7a7f34ed37 100644 --- a/tools/testing/selftests/kvm/include/arm64/gic.h +++ b/tools/testing/selftests/kvm/include/arm64/gic.h @@ -57,6 +57,7 @@ void gic_irq_set_pending(unsigned int intid); void gic_irq_clear_pending(unsigned int intid); bool gic_irq_get_pending(unsigned int intid); void gic_irq_set_config(unsigned int intid, bool is_edge); +void gic_irq_set_group(unsigned int intid, bool group); void gic_rdist_enable_lpis(vm_paddr_t cfg_table, size_t cfg_table_size, vm_paddr_t pend_table); diff --git a/tools/testing/selftests/kvm/include/arm64/gic_v3_its.h b/tools/testing/selftests/kvm/include/arm64/gic_v3_its.h index 3722ed9c8f96..58feef3eb386 100644 --- a/tools/testing/selftests/kvm/include/arm64/gic_v3_its.h +++ b/tools/testing/selftests/kvm/include/arm64/gic_v3_its.h @@ -15,5 +15,6 @@ void its_send_mapc_cmd(void *cmdq_base, u32 vcpu_id, u32 collection_id, bool val void its_send_mapti_cmd(void *cmdq_base, u32 device_id, u32 event_id, u32 collection_id, u32 intid); void its_send_invall_cmd(void *cmdq_base, u32 collection_id); +void its_send_sync_cmd(void *cmdq_base, u32 vcpu_id); #endif // __SELFTESTS_GIC_V3_ITS_H__ diff --git a/tools/testing/selftests/kvm/include/kvm_syscalls.h b/tools/testing/selftests/kvm/include/kvm_syscalls.h new file mode 100644 index 000000000000..d4e613162bba --- /dev/null +++ b/tools/testing/selftests/kvm/include/kvm_syscalls.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_KVM_SYSCALLS_H +#define SELFTEST_KVM_SYSCALLS_H + +#include <sys/syscall.h> + +#define MAP_ARGS0(m,...) +#define MAP_ARGS1(m,t,a,...) m(t,a) +#define MAP_ARGS2(m,t,a,...) m(t,a), MAP_ARGS1(m,__VA_ARGS__) +#define MAP_ARGS3(m,t,a,...) m(t,a), MAP_ARGS2(m,__VA_ARGS__) +#define MAP_ARGS4(m,t,a,...) m(t,a), MAP_ARGS3(m,__VA_ARGS__) +#define MAP_ARGS5(m,t,a,...) m(t,a), MAP_ARGS4(m,__VA_ARGS__) +#define MAP_ARGS6(m,t,a,...) m(t,a), MAP_ARGS5(m,__VA_ARGS__) +#define MAP_ARGS(n,...) MAP_ARGS##n(__VA_ARGS__) + +#define __DECLARE_ARGS(t, a) t a +#define __UNPACK_ARGS(t, a) a + +#define DECLARE_ARGS(nr_args, args...) MAP_ARGS(nr_args, __DECLARE_ARGS, args) +#define UNPACK_ARGS(nr_args, args...) MAP_ARGS(nr_args, __UNPACK_ARGS, args) + +#define __KVM_SYSCALL_ERROR(_name, _ret) \ + "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno) + +/* Define a kvm_<syscall>() API to assert success. */ +#define __KVM_SYSCALL_DEFINE(name, nr_args, args...) \ +static inline void kvm_##name(DECLARE_ARGS(nr_args, args)) \ +{ \ + int r; \ + \ + r = name(UNPACK_ARGS(nr_args, args)); \ + TEST_ASSERT(!r, __KVM_SYSCALL_ERROR(#name, r)); \ +} + +/* + * Macro to define syscall APIs, either because KVM selftests doesn't link to + * the standard library, e.g. libnuma, or because there is no library that yet + * provides the syscall. These + */ +#define KVM_SYSCALL_DEFINE(name, nr_args, args...) \ +static inline long name(DECLARE_ARGS(nr_args, args)) \ +{ \ + return syscall(__NR_##name, UNPACK_ARGS(nr_args, args)); \ +} \ +__KVM_SYSCALL_DEFINE(name, nr_args, args) + +/* + * Special case mmap(), as KVM selftest rarely/never specific an address, + * rarely specify an offset, and because the unique return code requires + * special handling anyways. + */ +static inline void *__kvm_mmap(size_t size, int prot, int flags, int fd, + off_t offset) +{ + void *mem; + + mem = mmap(NULL, size, prot, flags, fd, offset); + TEST_ASSERT(mem != MAP_FAILED, __KVM_SYSCALL_ERROR("mmap()", + (int)(unsigned long)MAP_FAILED)); + return mem; +} + +static inline void *kvm_mmap(size_t size, int prot, int flags, int fd) +{ + return __kvm_mmap(size, prot, flags, fd, 0); +} + +static inline int kvm_dup(int fd) +{ + int new_fd = dup(fd); + + TEST_ASSERT(new_fd >= 0, __KVM_SYSCALL_ERROR("dup()", new_fd)); + return new_fd; +} + +__KVM_SYSCALL_DEFINE(munmap, 2, void *, mem, size_t, size); +__KVM_SYSCALL_DEFINE(close, 1, int, fd); +__KVM_SYSCALL_DEFINE(fallocate, 4, int, fd, int, mode, loff_t, offset, loff_t, len); +__KVM_SYSCALL_DEFINE(ftruncate, 2, unsigned int, fd, off_t, length); + +#endif /* SELFTEST_KVM_SYSCALLS_H */ diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index d3f3e455c031..81f4355ff28a 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -23,6 +23,7 @@ #include <pthread.h> +#include "kvm_syscalls.h" #include "kvm_util_arch.h" #include "kvm_util_types.h" #include "sparsebit.h" @@ -177,7 +178,7 @@ enum vm_guest_mode { VM_MODE_P40V48_4K, VM_MODE_P40V48_16K, VM_MODE_P40V48_64K, - VM_MODE_PXXV48_4K, /* For 48bits VA but ANY bits PA */ + VM_MODE_PXXVYY_4K, /* For 48-bit or 57-bit VA, depending on host support */ VM_MODE_P47V64_4K, VM_MODE_P44V64_4K, VM_MODE_P36V48_4K, @@ -219,7 +220,7 @@ extern enum vm_guest_mode vm_mode_default; #elif defined(__x86_64__) -#define VM_MODE_DEFAULT VM_MODE_PXXV48_4K +#define VM_MODE_DEFAULT VM_MODE_PXXVYY_4K #define MIN_PAGE_SHIFT 12U #define ptes_per_page(page_size) ((page_size) / 8) @@ -283,34 +284,6 @@ static inline bool kvm_has_cap(long cap) return kvm_check_cap(cap); } -#define __KVM_SYSCALL_ERROR(_name, _ret) \ - "%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno) - -static inline void *__kvm_mmap(size_t size, int prot, int flags, int fd, - off_t offset) -{ - void *mem; - - mem = mmap(NULL, size, prot, flags, fd, offset); - TEST_ASSERT(mem != MAP_FAILED, __KVM_SYSCALL_ERROR("mmap()", - (int)(unsigned long)MAP_FAILED)); - - return mem; -} - -static inline void *kvm_mmap(size_t size, int prot, int flags, int fd) -{ - return __kvm_mmap(size, prot, flags, fd, 0); -} - -static inline void kvm_munmap(void *mem, size_t size) -{ - int ret; - - ret = munmap(mem, size); - TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); -} - /* * Use the "inner", double-underscore macro when reporting errors from within * other macros so that the name of ioctl() and not its literal numeric value @@ -700,12 +673,12 @@ int __vm_set_user_memory_region2(struct kvm_vm *vm, uint32_t slot, uint32_t flag uint32_t guest_memfd, uint64_t guest_memfd_offset); void vm_userspace_mem_region_add(struct kvm_vm *vm, - enum vm_mem_backing_src_type src_type, - uint64_t guest_paddr, uint32_t slot, uint64_t npages, - uint32_t flags); + enum vm_mem_backing_src_type src_type, + uint64_t gpa, uint32_t slot, uint64_t npages, + uint32_t flags); void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, - uint64_t guest_paddr, uint32_t slot, uint64_t npages, - uint32_t flags, int guest_memfd_fd, uint64_t guest_memfd_offset); + uint64_t gpa, uint32_t slot, uint64_t npages, uint32_t flags, + int guest_memfd_fd, uint64_t guest_memfd_offset); #ifndef vm_arch_has_protected_memory static inline bool vm_arch_has_protected_memory(struct kvm_vm *vm) @@ -715,6 +688,7 @@ static inline bool vm_arch_has_protected_memory(struct kvm_vm *vm) #endif void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); +void vm_mem_region_reload(struct kvm_vm *vm, uint32_t slot); 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); struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id); @@ -1230,6 +1204,7 @@ void virt_arch_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr); static inline void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr) { virt_arch_pg_map(vm, vaddr, paddr); + sparsebit_set(vm->vpages_mapped, vaddr >> vm->page_shift); } diff --git a/tools/testing/selftests/kvm/include/loongarch/arch_timer.h b/tools/testing/selftests/kvm/include/loongarch/arch_timer.h new file mode 100644 index 000000000000..2ed106b32c81 --- /dev/null +++ b/tools/testing/selftests/kvm/include/loongarch/arch_timer.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * LoongArch Constant Timer specific interface + */ +#ifndef SELFTEST_KVM_ARCH_TIMER_H +#define SELFTEST_KVM_ARCH_TIMER_H + +#include "processor.h" + +/* LoongArch timer frequency is constant 100MHZ */ +#define TIMER_FREQ (100UL << 20) +#define msec_to_cycles(msec) (TIMER_FREQ * (unsigned long)(msec) / 1000) +#define usec_to_cycles(usec) (TIMER_FREQ * (unsigned long)(usec) / 1000000) +#define cycles_to_usec(cycles) ((unsigned long)(cycles) * 1000000 / TIMER_FREQ) + +static inline unsigned long timer_get_cycles(void) +{ + unsigned long val = 0; + + __asm__ __volatile__( + "rdtime.d %0, $zero\n\t" + : "=r"(val) + : + ); + + return val; +} + +static inline unsigned long timer_get_cfg(void) +{ + return csr_read(LOONGARCH_CSR_TCFG); +} + +static inline unsigned long timer_get_val(void) +{ + return csr_read(LOONGARCH_CSR_TVAL); +} + +static inline void disable_timer(void) +{ + csr_write(0, LOONGARCH_CSR_TCFG); +} + +static inline void timer_irq_enable(void) +{ + unsigned long val; + + val = csr_read(LOONGARCH_CSR_ECFG); + val |= ECFGF_TIMER; + csr_write(val, LOONGARCH_CSR_ECFG); +} + +static inline void timer_irq_disable(void) +{ + unsigned long val; + + val = csr_read(LOONGARCH_CSR_ECFG); + val &= ~ECFGF_TIMER; + csr_write(val, LOONGARCH_CSR_ECFG); +} + +static inline void timer_set_next_cmp_ms(unsigned int msec, bool period) +{ + unsigned long val; + + val = msec_to_cycles(msec) & CSR_TCFG_VAL; + val |= CSR_TCFG_EN; + if (period) + val |= CSR_TCFG_PERIOD; + csr_write(val, LOONGARCH_CSR_TCFG); +} + +static inline void __delay(uint64_t cycles) +{ + uint64_t start = timer_get_cycles(); + + while ((timer_get_cycles() - start) < cycles) + cpu_relax(); +} + +static inline void udelay(unsigned long usec) +{ + __delay(usec_to_cycles(usec)); +} +#endif /* SELFTEST_KVM_ARCH_TIMER_H */ diff --git a/tools/testing/selftests/kvm/include/loongarch/processor.h b/tools/testing/selftests/kvm/include/loongarch/processor.h index 6427a3275e6a..76840ddda57d 100644 --- a/tools/testing/selftests/kvm/include/loongarch/processor.h +++ b/tools/testing/selftests/kvm/include/loongarch/processor.h @@ -83,7 +83,14 @@ #define LOONGARCH_CSR_PRMD 0x1 #define LOONGARCH_CSR_EUEN 0x2 #define LOONGARCH_CSR_ECFG 0x4 +#define ECFGB_TIMER 11 +#define ECFGF_TIMER (BIT_ULL(ECFGB_TIMER)) #define LOONGARCH_CSR_ESTAT 0x5 /* Exception status */ +#define CSR_ESTAT_EXC_SHIFT 16 +#define CSR_ESTAT_EXC_WIDTH 6 +#define CSR_ESTAT_EXC (0x3f << CSR_ESTAT_EXC_SHIFT) +#define EXCCODE_INT 0 /* Interrupt */ +#define INT_TI 11 /* Timer interrupt*/ #define LOONGARCH_CSR_ERA 0x6 /* ERA */ #define LOONGARCH_CSR_BADV 0x7 /* Bad virtual address */ #define LOONGARCH_CSR_EENTRY 0xc @@ -106,6 +113,14 @@ #define LOONGARCH_CSR_KS1 0x31 #define LOONGARCH_CSR_TMID 0x40 #define LOONGARCH_CSR_TCFG 0x41 +#define CSR_TCFG_VAL (BIT_ULL(48) - BIT_ULL(2)) +#define CSR_TCFG_PERIOD_SHIFT 1 +#define CSR_TCFG_PERIOD (0x1UL << CSR_TCFG_PERIOD_SHIFT) +#define CSR_TCFG_EN (0x1UL) +#define LOONGARCH_CSR_TVAL 0x42 +#define LOONGARCH_CSR_TINTCLR 0x44 /* Timer interrupt clear */ +#define CSR_TINTCLR_TI_SHIFT 0 +#define CSR_TINTCLR_TI (1 << CSR_TINTCLR_TI_SHIFT) /* TLB refill exception entry */ #define LOONGARCH_CSR_TLBRENTRY 0x88 #define LOONGARCH_CSR_TLBRSAVE 0x8b @@ -113,6 +128,28 @@ #define CSR_TLBREHI_PS_SHIFT 0 #define CSR_TLBREHI_PS (0x3fUL << CSR_TLBREHI_PS_SHIFT) +#define csr_read(csr) \ +({ \ + register unsigned long __v; \ + __asm__ __volatile__( \ + "csrrd %[val], %[reg]\n\t" \ + : [val] "=r" (__v) \ + : [reg] "i" (csr) \ + : "memory"); \ + __v; \ +}) + +#define csr_write(v, csr) \ +({ \ + register unsigned long __v = v; \ + __asm__ __volatile__ ( \ + "csrwr %[val], %[reg]\n\t" \ + : [val] "+r" (__v) \ + : [reg] "i" (csr) \ + : "memory"); \ + __v; \ +}) + #define EXREGS_GPRS (32) #ifndef __ASSEMBLER__ @@ -124,18 +161,60 @@ struct ex_regs { unsigned long pc; unsigned long estat; unsigned long badv; + unsigned long prmd; }; #define PC_OFFSET_EXREGS offsetof(struct ex_regs, pc) #define ESTAT_OFFSET_EXREGS offsetof(struct ex_regs, estat) #define BADV_OFFSET_EXREGS offsetof(struct ex_regs, badv) +#define PRMD_OFFSET_EXREGS offsetof(struct ex_regs, prmd) #define EXREGS_SIZE sizeof(struct ex_regs) +#define VECTOR_NUM 64 + +typedef void(*handler_fn)(struct ex_regs *); + +struct handlers { + handler_fn exception_handlers[VECTOR_NUM]; +}; + +void vm_init_descriptor_tables(struct kvm_vm *vm); +void vm_install_exception_handler(struct kvm_vm *vm, int vector, handler_fn handler); + +static inline void cpu_relax(void) +{ + asm volatile("nop" ::: "memory"); +} + +static inline void local_irq_enable(void) +{ + unsigned int flags = CSR_CRMD_IE; + register unsigned int mask asm("$t0") = CSR_CRMD_IE; + + __asm__ __volatile__( + "csrxchg %[val], %[mask], %[reg]\n\t" + : [val] "+r" (flags) + : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); +} + +static inline void local_irq_disable(void) +{ + unsigned int flags = 0; + register unsigned int mask asm("$t0") = CSR_CRMD_IE; + + __asm__ __volatile__( + "csrxchg %[val], %[mask], %[reg]\n\t" + : [val] "+r" (flags) + : [mask] "r" (mask), [reg] "i" (LOONGARCH_CSR_CRMD) + : "memory"); +} #else #define PC_OFFSET_EXREGS ((EXREGS_GPRS + 0) * 8) #define ESTAT_OFFSET_EXREGS ((EXREGS_GPRS + 1) * 8) #define BADV_OFFSET_EXREGS ((EXREGS_GPRS + 2) * 8) -#define EXREGS_SIZE ((EXREGS_GPRS + 3) * 8) +#define PRMD_OFFSET_EXREGS ((EXREGS_GPRS + 3) * 8) +#define EXREGS_SIZE ((EXREGS_GPRS + 4) * 8) #endif #endif /* SELFTEST_KVM_PROCESSOR_H */ diff --git a/tools/testing/selftests/kvm/include/numaif.h b/tools/testing/selftests/kvm/include/numaif.h index b020547403fd..29572a6d789c 100644 --- a/tools/testing/selftests/kvm/include/numaif.h +++ b/tools/testing/selftests/kvm/include/numaif.h @@ -1,55 +1,83 @@ /* SPDX-License-Identifier: GPL-2.0-only */ -/* - * tools/testing/selftests/kvm/include/numaif.h - * - * Copyright (C) 2020, Google LLC. - * - * This work is licensed under the terms of the GNU GPL, version 2. - * - * Header file that provides access to NUMA API functions not explicitly - * exported to user space. - */ +/* Copyright (C) 2020, Google LLC. */ #ifndef SELFTEST_KVM_NUMAIF_H #define SELFTEST_KVM_NUMAIF_H -#define __NR_get_mempolicy 239 -#define __NR_migrate_pages 256 +#include <dirent.h> -/* System calls */ -long get_mempolicy(int *policy, const unsigned long *nmask, - unsigned long maxnode, void *addr, int flags) +#include <linux/mempolicy.h> + +#include "kvm_syscalls.h" + +KVM_SYSCALL_DEFINE(get_mempolicy, 5, int *, policy, const unsigned long *, nmask, + unsigned long, maxnode, void *, addr, int, flags); + +KVM_SYSCALL_DEFINE(set_mempolicy, 3, int, mode, const unsigned long *, nmask, + unsigned long, maxnode); + +KVM_SYSCALL_DEFINE(set_mempolicy_home_node, 4, unsigned long, start, + unsigned long, len, unsigned long, home_node, + unsigned long, flags); + +KVM_SYSCALL_DEFINE(migrate_pages, 4, int, pid, unsigned long, maxnode, + const unsigned long *, frommask, const unsigned long *, tomask); + +KVM_SYSCALL_DEFINE(move_pages, 6, int, pid, unsigned long, count, void *, pages, + const int *, nodes, int *, status, int, flags); + +KVM_SYSCALL_DEFINE(mbind, 6, void *, addr, unsigned long, size, int, mode, + const unsigned long *, nodemask, unsigned long, maxnode, + unsigned int, flags); + +static inline int get_max_numa_node(void) { - return syscall(__NR_get_mempolicy, policy, nmask, - maxnode, addr, flags); + struct dirent *de; + int max_node = 0; + DIR *d; + + /* + * Assume there's a single node if the kernel doesn't support NUMA, + * or if no nodes are found. + */ + d = opendir("/sys/devices/system/node"); + if (!d) + return 0; + + while ((de = readdir(d)) != NULL) { + int node_id; + char *endptr; + + if (strncmp(de->d_name, "node", 4) != 0) + continue; + + node_id = strtol(de->d_name + 4, &endptr, 10); + if (*endptr != '\0') + continue; + + if (node_id > max_node) + max_node = node_id; + } + closedir(d); + + return max_node; } -long migrate_pages(int pid, unsigned long maxnode, - const unsigned long *frommask, - const unsigned long *tomask) +static bool is_numa_available(void) { - return syscall(__NR_migrate_pages, pid, maxnode, frommask, tomask); + /* + * Probe for NUMA by doing a dummy get_mempolicy(). If the syscall + * fails with ENOSYS, then the kernel was built without NUMA support. + * if the syscall fails with EPERM, then the process/user lacks the + * necessary capabilities (CAP_SYS_NICE). + */ + return !get_mempolicy(NULL, NULL, 0, NULL, 0) || + (errno != ENOSYS && errno != EPERM); } -/* Policies */ -#define MPOL_DEFAULT 0 -#define MPOL_PREFERRED 1 -#define MPOL_BIND 2 -#define MPOL_INTERLEAVE 3 - -#define MPOL_MAX MPOL_INTERLEAVE - -/* Flags for get_mem_policy */ -#define MPOL_F_NODE (1<<0) /* return next il node or node of address */ - /* Warning: MPOL_F_NODE is unsupported and - * subject to change. Don't use. - */ -#define MPOL_F_ADDR (1<<1) /* look up vma using address */ -#define MPOL_F_MEMS_ALLOWED (1<<2) /* query nodes allowed in cpuset */ - -/* Flags for mbind */ -#define MPOL_MF_STRICT (1<<0) /* Verify existing pages in the mapping */ -#define MPOL_MF_MOVE (1<<1) /* Move pages owned by this process to conform to mapping */ -#define MPOL_MF_MOVE_ALL (1<<2) /* Move every page to conform to mapping */ +static inline bool is_multi_numa_node_system(void) +{ + return is_numa_available() && get_max_numa_node() >= 1; +} #endif /* SELFTEST_KVM_NUMAIF_H */ diff --git a/tools/testing/selftests/kvm/include/x86/processor.h b/tools/testing/selftests/kvm/include/x86/processor.h index 51cd84b9ca66..57d62a425109 100644 --- a/tools/testing/selftests/kvm/include/x86/processor.h +++ b/tools/testing/selftests/kvm/include/x86/processor.h @@ -1441,7 +1441,7 @@ enum pg_level { PG_LEVEL_2M, PG_LEVEL_1G, PG_LEVEL_512G, - PG_LEVEL_NUM + PG_LEVEL_256T }; #define PG_LEVEL_SHIFT(_level) ((_level - 1) * 9 + 12) diff --git a/tools/testing/selftests/kvm/include/x86/vmx.h b/tools/testing/selftests/kvm/include/x86/vmx.h index edb3c391b982..96e2b4c630a9 100644 --- a/tools/testing/selftests/kvm/include/x86/vmx.h +++ b/tools/testing/selftests/kvm/include/x86/vmx.h @@ -568,8 +568,7 @@ void nested_map_memslot(struct vmx_pages *vmx, struct kvm_vm *vm, void nested_identity_map_1g(struct vmx_pages *vmx, struct kvm_vm *vm, uint64_t addr, uint64_t size); bool kvm_cpu_has_ept(void); -void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm, - uint32_t eptp_memslot); +void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm); void prepare_virtualize_apic_accesses(struct vmx_pages *vmx, struct kvm_vm *vm); #endif /* SELFTEST_KVM_VMX_H */ diff --git a/tools/testing/selftests/kvm/kvm_binary_stats_test.c b/tools/testing/selftests/kvm/kvm_binary_stats_test.c index f02355c3c4c2..b7dbde9c0843 100644 --- a/tools/testing/selftests/kvm/kvm_binary_stats_test.c +++ b/tools/testing/selftests/kvm/kvm_binary_stats_test.c @@ -239,14 +239,14 @@ int main(int argc, char *argv[]) * single stats file works and doesn't cause explosions. */ vm_stats_fds = vm_get_stats_fd(vms[i]); - stats_test(dup(vm_stats_fds)); + stats_test(kvm_dup(vm_stats_fds)); /* Verify userspace can instantiate multiple stats files. */ stats_test(vm_get_stats_fd(vms[i])); for (j = 0; j < max_vcpu; ++j) { vcpu_stats_fds[j] = vcpu_get_stats_fd(vcpus[i * max_vcpu + j]); - stats_test(dup(vcpu_stats_fds[j])); + stats_test(kvm_dup(vcpu_stats_fds[j])); stats_test(vcpu_get_stats_fd(vcpus[i * max_vcpu + j])); } diff --git a/tools/testing/selftests/kvm/lib/arm64/gic.c b/tools/testing/selftests/kvm/lib/arm64/gic.c index 7abbf8866512..b023868fe0b8 100644 --- a/tools/testing/selftests/kvm/lib/arm64/gic.c +++ b/tools/testing/selftests/kvm/lib/arm64/gic.c @@ -155,3 +155,9 @@ void gic_irq_set_config(unsigned int intid, bool is_edge) GUEST_ASSERT(gic_common_ops); gic_common_ops->gic_irq_set_config(intid, is_edge); } + +void gic_irq_set_group(unsigned int intid, bool group) +{ + GUEST_ASSERT(gic_common_ops); + gic_common_ops->gic_irq_set_group(intid, group); +} diff --git a/tools/testing/selftests/kvm/lib/arm64/gic_private.h b/tools/testing/selftests/kvm/lib/arm64/gic_private.h index d24e9ecc96c6..b6a7e30c3eb1 100644 --- a/tools/testing/selftests/kvm/lib/arm64/gic_private.h +++ b/tools/testing/selftests/kvm/lib/arm64/gic_private.h @@ -25,6 +25,7 @@ struct gic_common_ops { void (*gic_irq_clear_pending)(uint32_t intid); bool (*gic_irq_get_pending)(uint32_t intid); void (*gic_irq_set_config)(uint32_t intid, bool is_edge); + void (*gic_irq_set_group)(uint32_t intid, bool group); }; extern const struct gic_common_ops gicv3_ops; diff --git a/tools/testing/selftests/kvm/lib/arm64/gic_v3.c b/tools/testing/selftests/kvm/lib/arm64/gic_v3.c index 66d05506f78b..50754a27f493 100644 --- a/tools/testing/selftests/kvm/lib/arm64/gic_v3.c +++ b/tools/testing/selftests/kvm/lib/arm64/gic_v3.c @@ -293,17 +293,36 @@ static void gicv3_enable_redist(volatile void *redist_base) } } +static void gicv3_set_group(uint32_t intid, bool grp) +{ + uint32_t cpu_or_dist; + uint32_t val; + + cpu_or_dist = (get_intid_range(intid) == SPI_RANGE) ? DIST_BIT : guest_get_vcpuid(); + val = gicv3_reg_readl(cpu_or_dist, GICD_IGROUPR + (intid / 32) * 4); + if (grp) + val |= BIT(intid % 32); + else + val &= ~BIT(intid % 32); + gicv3_reg_writel(cpu_or_dist, GICD_IGROUPR + (intid / 32) * 4, val); +} + static void gicv3_cpu_init(unsigned int cpu) { volatile void *sgi_base; unsigned int i; volatile void *redist_base_cpu; + u64 typer; GUEST_ASSERT(cpu < gicv3_data.nr_cpus); redist_base_cpu = gicr_base_cpu(cpu); sgi_base = sgi_base_from_redist(redist_base_cpu); + /* Verify assumption that GICR_TYPER.Processor_number == cpu */ + typer = readq_relaxed(redist_base_cpu + GICR_TYPER); + GUEST_ASSERT_EQ(GICR_TYPER_CPU_NUMBER(typer), cpu); + gicv3_enable_redist(redist_base_cpu); /* @@ -328,6 +347,8 @@ static void gicv3_cpu_init(unsigned int cpu) /* Set a default priority threshold */ write_sysreg_s(ICC_PMR_DEF_PRIO, SYS_ICC_PMR_EL1); + /* Disable Group-0 interrupts */ + write_sysreg_s(ICC_IGRPEN0_EL1_MASK, SYS_ICC_IGRPEN1_EL1); /* Enable non-secure Group-1 interrupts */ write_sysreg_s(ICC_IGRPEN1_EL1_MASK, SYS_ICC_IGRPEN1_EL1); } @@ -400,6 +421,7 @@ const struct gic_common_ops gicv3_ops = { .gic_irq_clear_pending = gicv3_irq_clear_pending, .gic_irq_get_pending = gicv3_irq_get_pending, .gic_irq_set_config = gicv3_irq_set_config, + .gic_irq_set_group = gicv3_set_group, }; void gic_rdist_enable_lpis(vm_paddr_t cfg_table, size_t cfg_table_size, diff --git a/tools/testing/selftests/kvm/lib/arm64/gic_v3_its.c b/tools/testing/selftests/kvm/lib/arm64/gic_v3_its.c index 0e2f8ed90f30..7f9fdcf42ae6 100644 --- a/tools/testing/selftests/kvm/lib/arm64/gic_v3_its.c +++ b/tools/testing/selftests/kvm/lib/arm64/gic_v3_its.c @@ -253,3 +253,13 @@ void its_send_invall_cmd(void *cmdq_base, u32 collection_id) its_send_cmd(cmdq_base, &cmd); } + +void its_send_sync_cmd(void *cmdq_base, u32 vcpu_id) +{ + struct its_cmd_block cmd = {}; + + its_encode_cmd(&cmd, GITS_CMD_SYNC); + its_encode_target(&cmd, procnum_to_rdbase(vcpu_id)); + + its_send_cmd(cmdq_base, &cmd); +} diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index 54f6d17c78f7..d46e4b13b92c 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -324,7 +324,7 @@ void aarch64_vcpu_setup(struct kvm_vcpu *vcpu, struct kvm_vcpu_init *init) /* Configure base granule size */ switch (vm->mode) { - case VM_MODE_PXXV48_4K: + case VM_MODE_PXXVYY_4K: TEST_FAIL("AArch64 does not support 4K sized pages " "with ANY-bit physical address ranges"); case VM_MODE_P52V48_64K: diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 1a93d6361671..8279b6ced8d2 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -201,7 +201,7 @@ const char *vm_guest_mode_string(uint32_t i) [VM_MODE_P40V48_4K] = "PA-bits:40, VA-bits:48, 4K pages", [VM_MODE_P40V48_16K] = "PA-bits:40, VA-bits:48, 16K pages", [VM_MODE_P40V48_64K] = "PA-bits:40, VA-bits:48, 64K pages", - [VM_MODE_PXXV48_4K] = "PA-bits:ANY, VA-bits:48, 4K pages", + [VM_MODE_PXXVYY_4K] = "PA-bits:ANY, VA-bits:48 or 57, 4K pages", [VM_MODE_P47V64_4K] = "PA-bits:47, VA-bits:64, 4K pages", [VM_MODE_P44V64_4K] = "PA-bits:44, VA-bits:64, 4K pages", [VM_MODE_P36V48_4K] = "PA-bits:36, VA-bits:48, 4K pages", @@ -228,7 +228,7 @@ const struct vm_guest_mode_params vm_guest_mode_params[] = { [VM_MODE_P40V48_4K] = { 40, 48, 0x1000, 12 }, [VM_MODE_P40V48_16K] = { 40, 48, 0x4000, 14 }, [VM_MODE_P40V48_64K] = { 40, 48, 0x10000, 16 }, - [VM_MODE_PXXV48_4K] = { 0, 0, 0x1000, 12 }, + [VM_MODE_PXXVYY_4K] = { 0, 0, 0x1000, 12 }, [VM_MODE_P47V64_4K] = { 47, 64, 0x1000, 12 }, [VM_MODE_P44V64_4K] = { 44, 64, 0x1000, 12 }, [VM_MODE_P36V48_4K] = { 36, 48, 0x1000, 12 }, @@ -310,24 +310,26 @@ struct kvm_vm *____vm_create(struct vm_shape shape) case VM_MODE_P36V47_16K: vm->pgtable_levels = 3; break; - case VM_MODE_PXXV48_4K: + case VM_MODE_PXXVYY_4K: #ifdef __x86_64__ kvm_get_cpu_address_width(&vm->pa_bits, &vm->va_bits); kvm_init_vm_address_properties(vm); - /* - * Ignore KVM support for 5-level paging (vm->va_bits == 57), - * it doesn't take effect unless a CR4.LA57 is set, which it - * isn't for this mode (48-bit virtual address space). - */ - TEST_ASSERT(vm->va_bits == 48 || vm->va_bits == 57, - "Linear address width (%d bits) not supported", - vm->va_bits); + pr_debug("Guest physical address width detected: %d\n", vm->pa_bits); - vm->pgtable_levels = 4; - vm->va_bits = 48; + pr_debug("Guest virtual address width detected: %d\n", + vm->va_bits); + + if (vm->va_bits == 57) { + vm->pgtable_levels = 5; + } else { + TEST_ASSERT(vm->va_bits == 48, + "Unexpected guest virtual address width: %d", + vm->va_bits); + vm->pgtable_levels = 4; + } #else - TEST_FAIL("VM_MODE_PXXV48_4K not supported on non-x86 platforms"); + TEST_FAIL("VM_MODE_PXXVYY_4K not supported on non-x86 platforms"); #endif break; case VM_MODE_P47V64_4K: @@ -704,8 +706,6 @@ userspace_mem_region_find(struct kvm_vm *vm, uint64_t start, uint64_t end) static void kvm_stats_release(struct kvm_binary_stats *stats) { - int ret; - if (stats->fd < 0) return; @@ -714,8 +714,7 @@ static void kvm_stats_release(struct kvm_binary_stats *stats) stats->desc = NULL; } - ret = close(stats->fd); - TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("close()", ret)); + kvm_close(stats->fd); stats->fd = -1; } @@ -738,8 +737,6 @@ __weak void vcpu_arch_free(struct kvm_vcpu *vcpu) */ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu) { - int ret; - if (vcpu->dirty_gfns) { kvm_munmap(vcpu->dirty_gfns, vm->dirty_ring_size); vcpu->dirty_gfns = NULL; @@ -747,9 +744,7 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu) kvm_munmap(vcpu->run, vcpu_mmap_sz()); - ret = close(vcpu->fd); - TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("close()", ret)); - + kvm_close(vcpu->fd); kvm_stats_release(&vcpu->stats); list_del(&vcpu->list); @@ -761,16 +756,12 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu) void kvm_vm_release(struct kvm_vm *vmp) { struct kvm_vcpu *vcpu, *tmp; - int ret; list_for_each_entry_safe(vcpu, tmp, &vmp->vcpus, list) vm_vcpu_rm(vmp, vcpu); - ret = close(vmp->fd); - TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("close()", ret)); - - ret = close(vmp->kvm_fd); - TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("close()", ret)); + kvm_close(vmp->fd); + kvm_close(vmp->kvm_fd); /* Free cached stats metadata and close FD */ kvm_stats_release(&vmp->stats); @@ -828,7 +819,7 @@ void kvm_vm_free(struct kvm_vm *vmp) int kvm_memfd_alloc(size_t size, bool hugepages) { int memfd_flags = MFD_CLOEXEC; - int fd, r; + int fd; if (hugepages) memfd_flags |= MFD_HUGETLB; @@ -836,11 +827,8 @@ int kvm_memfd_alloc(size_t size, bool hugepages) fd = memfd_create("kvm_selftest", memfd_flags); TEST_ASSERT(fd != -1, __KVM_SYSCALL_ERROR("memfd_create()", fd)); - r = ftruncate(fd, size); - TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("ftruncate()", r)); - - r = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, size); - TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("fallocate()", r)); + kvm_ftruncate(fd, size); + kvm_fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, 0, size); return fd; } @@ -957,8 +945,8 @@ void vm_set_user_memory_region2(struct kvm_vm *vm, uint32_t slot, uint32_t flags /* FIXME: This thing needs to be ripped apart and rewritten. */ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, - uint64_t guest_paddr, uint32_t slot, uint64_t npages, - uint32_t flags, int guest_memfd, uint64_t guest_memfd_offset) + uint64_t gpa, uint32_t slot, uint64_t npages, uint32_t flags, + int guest_memfd, uint64_t guest_memfd_offset) { int ret; struct userspace_mem_region *region; @@ -972,30 +960,29 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, "Number of guest pages is not compatible with the host. " "Try npages=%d", vm_adjust_num_guest_pages(vm->mode, npages)); - TEST_ASSERT((guest_paddr % vm->page_size) == 0, "Guest physical " + TEST_ASSERT((gpa % vm->page_size) == 0, "Guest physical " "address not on a page boundary.\n" - " guest_paddr: 0x%lx vm->page_size: 0x%x", - guest_paddr, vm->page_size); - TEST_ASSERT((((guest_paddr >> vm->page_shift) + npages) - 1) + " gpa: 0x%lx vm->page_size: 0x%x", + gpa, vm->page_size); + TEST_ASSERT((((gpa >> vm->page_shift) + npages) - 1) <= vm->max_gfn, "Physical range beyond maximum " "supported physical address,\n" - " guest_paddr: 0x%lx npages: 0x%lx\n" + " gpa: 0x%lx npages: 0x%lx\n" " vm->max_gfn: 0x%lx vm->page_size: 0x%x", - guest_paddr, npages, vm->max_gfn, vm->page_size); + gpa, npages, vm->max_gfn, vm->page_size); /* * Confirm a mem region with an overlapping address doesn't * already exist. */ region = (struct userspace_mem_region *) userspace_mem_region_find( - vm, guest_paddr, (guest_paddr + npages * vm->page_size) - 1); + vm, gpa, (gpa + npages * vm->page_size) - 1); if (region != NULL) TEST_FAIL("overlapping userspace_mem_region already " "exists\n" - " requested guest_paddr: 0x%lx npages: 0x%lx " - "page_size: 0x%x\n" - " existing guest_paddr: 0x%lx size: 0x%lx", - guest_paddr, npages, vm->page_size, + " requested gpa: 0x%lx npages: 0x%lx page_size: 0x%x\n" + " existing gpa: 0x%lx size: 0x%lx", + gpa, npages, vm->page_size, (uint64_t) region->region.guest_phys_addr, (uint64_t) region->region.memory_size); @@ -1009,8 +996,7 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, "already exists.\n" " requested slot: %u paddr: 0x%lx npages: 0x%lx\n" " existing slot: %u paddr: 0x%lx size: 0x%lx", - slot, guest_paddr, npages, - region->region.slot, + slot, gpa, npages, region->region.slot, (uint64_t) region->region.guest_phys_addr, (uint64_t) region->region.memory_size); } @@ -1036,7 +1022,7 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, if (src_type == VM_MEM_SRC_ANONYMOUS_THP) alignment = max(backing_src_pagesz, alignment); - TEST_ASSERT_EQ(guest_paddr, align_up(guest_paddr, backing_src_pagesz)); + TEST_ASSERT_EQ(gpa, align_up(gpa, backing_src_pagesz)); /* Add enough memory to align up if necessary */ if (alignment > 1) @@ -1084,8 +1070,7 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, * needing to track if the fd is owned by the framework * or by the caller. */ - guest_memfd = dup(guest_memfd); - TEST_ASSERT(guest_memfd >= 0, __KVM_SYSCALL_ERROR("dup()", guest_memfd)); + guest_memfd = kvm_dup(guest_memfd); } region->region.guest_memfd = guest_memfd; @@ -1097,20 +1082,18 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, region->unused_phy_pages = sparsebit_alloc(); if (vm_arch_has_protected_memory(vm)) region->protected_phy_pages = sparsebit_alloc(); - sparsebit_set_num(region->unused_phy_pages, - guest_paddr >> vm->page_shift, npages); + sparsebit_set_num(region->unused_phy_pages, gpa >> vm->page_shift, npages); region->region.slot = slot; region->region.flags = flags; - region->region.guest_phys_addr = guest_paddr; + region->region.guest_phys_addr = gpa; region->region.memory_size = npages * vm->page_size; region->region.userspace_addr = (uintptr_t) region->host_mem; ret = __vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, ®ion->region); TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION2 IOCTL failed,\n" " rc: %i errno: %i\n" " slot: %u flags: 0x%x\n" - " guest_phys_addr: 0x%lx size: 0x%lx guest_memfd: %d", - ret, errno, slot, flags, - guest_paddr, (uint64_t) region->region.memory_size, + " guest_phys_addr: 0x%lx size: 0x%llx guest_memfd: %d", + ret, errno, slot, flags, gpa, region->region.memory_size, region->region.guest_memfd); /* Add to quick lookup data structures */ @@ -1132,10 +1115,10 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, void vm_userspace_mem_region_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type, - uint64_t guest_paddr, uint32_t slot, - uint64_t npages, uint32_t flags) + uint64_t gpa, uint32_t slot, uint64_t npages, + uint32_t flags) { - vm_mem_add(vm, src_type, guest_paddr, slot, npages, flags, -1, 0); + vm_mem_add(vm, src_type, gpa, slot, npages, flags, -1, 0); } /* @@ -1201,6 +1184,16 @@ void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) ret, errno, slot, flags); } +void vm_mem_region_reload(struct kvm_vm *vm, uint32_t slot) +{ + struct userspace_mem_region *region = memslot2region(vm, slot); + struct kvm_userspace_memory_region2 tmp = region->region; + + tmp.memory_size = 0; + vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, &tmp); + vm_ioctl(vm, KVM_SET_USER_MEMORY_REGION2, ®ion->region); +} + /* * VM Memory Region Move * @@ -1456,8 +1449,6 @@ static vm_vaddr_t ____vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, pages--, vaddr += vm->page_size, paddr += vm->page_size) { virt_pg_map(vm, vaddr, paddr); - - sparsebit_set(vm->vpages_mapped, vaddr >> vm->page_shift); } return vaddr_start; @@ -1571,7 +1562,6 @@ void virt_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, while (npages--) { virt_pg_map(vm, vaddr, paddr); - sparsebit_set(vm->vpages_mapped, vaddr >> vm->page_shift); vaddr += page_size; paddr += page_size; @@ -2025,6 +2015,7 @@ static struct exit_reason { KVM_EXIT_STRING(NOTIFY), KVM_EXIT_STRING(LOONGARCH_IOCSR), KVM_EXIT_STRING(MEMORY_FAULT), + KVM_EXIT_STRING(ARM_SEA), }; /* @@ -2305,11 +2296,35 @@ __weak void kvm_selftest_arch_init(void) { } +static void report_unexpected_signal(int signum) +{ +#define KVM_CASE_SIGNUM(sig) \ + case sig: TEST_FAIL("Unexpected " #sig " (%d)\n", signum) + + switch (signum) { + KVM_CASE_SIGNUM(SIGBUS); + KVM_CASE_SIGNUM(SIGSEGV); + KVM_CASE_SIGNUM(SIGILL); + KVM_CASE_SIGNUM(SIGFPE); + default: + TEST_FAIL("Unexpected signal %d\n", signum); + } +} + void __attribute((constructor)) kvm_selftest_init(void) { + struct sigaction sig_sa = { + .sa_handler = report_unexpected_signal, + }; + /* Tell stdout not to buffer its content. */ setbuf(stdout, NULL); + sigaction(SIGBUS, &sig_sa, NULL); + sigaction(SIGSEGV, &sig_sa, NULL); + sigaction(SIGILL, &sig_sa, NULL); + sigaction(SIGFPE, &sig_sa, NULL); + guest_random_seed = last_guest_seed = random(); pr_info("Random seed: 0x%x\n", guest_random_seed); diff --git a/tools/testing/selftests/kvm/lib/loongarch/exception.S b/tools/testing/selftests/kvm/lib/loongarch/exception.S index 88bfa505c6f5..3f1e4b67c5ae 100644 --- a/tools/testing/selftests/kvm/lib/loongarch/exception.S +++ b/tools/testing/selftests/kvm/lib/loongarch/exception.S @@ -51,9 +51,15 @@ handle_exception: st.d t0, sp, ESTAT_OFFSET_EXREGS csrrd t0, LOONGARCH_CSR_BADV st.d t0, sp, BADV_OFFSET_EXREGS + csrrd t0, LOONGARCH_CSR_PRMD + st.d t0, sp, PRMD_OFFSET_EXREGS or a0, sp, zero bl route_exception + ld.d t0, sp, PC_OFFSET_EXREGS + csrwr t0, LOONGARCH_CSR_ERA + ld.d t0, sp, PRMD_OFFSET_EXREGS + csrwr t0, LOONGARCH_CSR_PRMD restore_gprs sp csrrd sp, LOONGARCH_CSR_KS0 ertn diff --git a/tools/testing/selftests/kvm/lib/loongarch/processor.c b/tools/testing/selftests/kvm/lib/loongarch/processor.c index 0ac1abcb71cb..07c103369ddb 100644 --- a/tools/testing/selftests/kvm/lib/loongarch/processor.c +++ b/tools/testing/selftests/kvm/lib/loongarch/processor.c @@ -3,6 +3,7 @@ #include <assert.h> #include <linux/compiler.h> +#include <asm/kvm.h> #include "kvm_util.h" #include "processor.h" #include "ucall_common.h" @@ -11,6 +12,7 @@ #define LOONGARCH_GUEST_STACK_VADDR_MIN 0x200000 static vm_paddr_t invalid_pgtable[4]; +static vm_vaddr_t exception_handlers; static uint64_t virt_pte_index(struct kvm_vm *vm, vm_vaddr_t gva, int level) { @@ -183,7 +185,14 @@ void assert_on_unhandled_exception(struct kvm_vcpu *vcpu) void route_exception(struct ex_regs *regs) { + int vector; unsigned long pc, estat, badv; + struct handlers *handlers; + + handlers = (struct handlers *)exception_handlers; + vector = (regs->estat & CSR_ESTAT_EXC) >> CSR_ESTAT_EXC_SHIFT; + if (handlers && handlers->exception_handlers[vector]) + return handlers->exception_handlers[vector](regs); pc = regs->pc; badv = regs->badv; @@ -192,6 +201,32 @@ void route_exception(struct ex_regs *regs) while (1) ; } +void vm_init_descriptor_tables(struct kvm_vm *vm) +{ + void *addr; + + vm->handlers = __vm_vaddr_alloc(vm, sizeof(struct handlers), + LOONGARCH_GUEST_STACK_VADDR_MIN, MEM_REGION_DATA); + + addr = addr_gva2hva(vm, vm->handlers); + memset(addr, 0, vm->page_size); + exception_handlers = vm->handlers; + sync_global_to_guest(vm, exception_handlers); +} + +void vm_install_exception_handler(struct kvm_vm *vm, int vector, handler_fn handler) +{ + struct handlers *handlers = addr_gva2hva(vm, vm->handlers); + + assert(vector < VECTOR_NUM); + handlers->exception_handlers[vector] = handler; +} + +uint32_t guest_get_vcpuid(void) +{ + return csr_read(LOONGARCH_CSR_CPUID); +} + void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) { int i; @@ -211,6 +246,11 @@ void vcpu_args_set(struct kvm_vcpu *vcpu, unsigned int num, ...) vcpu_regs_set(vcpu, ®s); } +static void loongarch_set_reg(struct kvm_vcpu *vcpu, uint64_t id, uint64_t val) +{ + __vcpu_set_reg(vcpu, id, val); +} + static void loongarch_get_csr(struct kvm_vcpu *vcpu, uint64_t id, void *addr) { uint64_t csrid; @@ -242,8 +282,8 @@ static void loongarch_vcpu_setup(struct kvm_vcpu *vcpu) TEST_FAIL("Unknown guest mode, mode: 0x%x", vm->mode); } - /* user mode and page enable mode */ - val = PLV_USER | CSR_CRMD_PG; + /* kernel mode and page enable mode */ + val = PLV_KERN | CSR_CRMD_PG; loongarch_set_csr(vcpu, LOONGARCH_CSR_CRMD, val); loongarch_set_csr(vcpu, LOONGARCH_CSR_PRMD, val); loongarch_set_csr(vcpu, LOONGARCH_CSR_EUEN, 1); @@ -251,7 +291,10 @@ static void loongarch_vcpu_setup(struct kvm_vcpu *vcpu) loongarch_set_csr(vcpu, LOONGARCH_CSR_TCFG, 0); loongarch_set_csr(vcpu, LOONGARCH_CSR_ASID, 1); + /* time count start from 0 */ val = 0; + loongarch_set_reg(vcpu, KVM_REG_LOONGARCH_COUNTER, val); + width = vm->page_shift - 3; switch (vm->pgtable_levels) { diff --git a/tools/testing/selftests/kvm/lib/x86/memstress.c b/tools/testing/selftests/kvm/lib/x86/memstress.c index 7f5d62a65c68..0b1f288ad556 100644 --- a/tools/testing/selftests/kvm/lib/x86/memstress.c +++ b/tools/testing/selftests/kvm/lib/x86/memstress.c @@ -63,7 +63,7 @@ void memstress_setup_ept(struct vmx_pages *vmx, struct kvm_vm *vm) { uint64_t start, end; - prepare_eptp(vmx, vm, 0); + prepare_eptp(vmx, vm); /* * Identity map the first 4G and the test region with 1G pages so that diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index b418502c5ecc..36104d27f3d9 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -158,10 +158,10 @@ bool kvm_is_tdp_enabled(void) void virt_arch_pgd_alloc(struct kvm_vm *vm) { - TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, "Attempt to use " - "unknown or unsupported guest mode, mode: 0x%x", vm->mode); + TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K, + "Unknown or unsupported guest mode: 0x%x", vm->mode); - /* If needed, create page map l4 table. */ + /* If needed, create the top-level page table. */ if (!vm->pgd_created) { vm->pgd = vm_alloc_page_table(vm); vm->pgd_created = true; @@ -218,11 +218,11 @@ static uint64_t *virt_create_upper_pte(struct kvm_vm *vm, void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level) { const uint64_t pg_size = PG_LEVEL_SIZE(level); - uint64_t *pml4e, *pdpe, *pde; - uint64_t *pte; + uint64_t *pte = &vm->pgd; + int current_level; - TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, - "Unknown or unsupported guest mode, mode: 0x%x", vm->mode); + TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K, + "Unknown or unsupported guest mode: 0x%x", vm->mode); TEST_ASSERT((vaddr % pg_size) == 0, "Virtual address not aligned,\n" @@ -243,20 +243,17 @@ void __virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, int level) * Allocate upper level page tables, if not already present. Return * early if a hugepage was created. */ - pml4e = virt_create_upper_pte(vm, &vm->pgd, vaddr, paddr, PG_LEVEL_512G, level); - if (*pml4e & PTE_LARGE_MASK) - return; - - pdpe = virt_create_upper_pte(vm, pml4e, vaddr, paddr, PG_LEVEL_1G, level); - if (*pdpe & PTE_LARGE_MASK) - return; - - pde = virt_create_upper_pte(vm, pdpe, vaddr, paddr, PG_LEVEL_2M, level); - if (*pde & PTE_LARGE_MASK) - return; + for (current_level = vm->pgtable_levels; + current_level > PG_LEVEL_4K; + current_level--) { + pte = virt_create_upper_pte(vm, pte, vaddr, paddr, + current_level, level); + if (*pte & PTE_LARGE_MASK) + return; + } /* Fill in page table entry. */ - pte = virt_get_pte(vm, pde, vaddr, PG_LEVEL_4K); + pte = virt_get_pte(vm, pte, vaddr, PG_LEVEL_4K); TEST_ASSERT(!(*pte & PTE_PRESENT_MASK), "PTE already present for 4k page at vaddr: 0x%lx", vaddr); *pte = PTE_PRESENT_MASK | PTE_WRITABLE_MASK | (paddr & PHYSICAL_PAGE_MASK); @@ -289,6 +286,8 @@ void virt_map_level(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, for (i = 0; i < nr_pages; i++) { __virt_pg_map(vm, vaddr, paddr, level); + sparsebit_set_num(vm->vpages_mapped, vaddr >> vm->page_shift, + nr_bytes / PAGE_SIZE); vaddr += pg_size; paddr += pg_size; @@ -310,40 +309,38 @@ static bool vm_is_target_pte(uint64_t *pte, int *level, int current_level) uint64_t *__vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr, int *level) { - uint64_t *pml4e, *pdpe, *pde; + int va_width = 12 + (vm->pgtable_levels) * 9; + uint64_t *pte = &vm->pgd; + int current_level; TEST_ASSERT(!vm->arch.is_pt_protected, "Walking page tables of protected guests is impossible"); - TEST_ASSERT(*level >= PG_LEVEL_NONE && *level < PG_LEVEL_NUM, + TEST_ASSERT(*level >= PG_LEVEL_NONE && *level <= vm->pgtable_levels, "Invalid PG_LEVEL_* '%d'", *level); - TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, "Attempt to use " - "unknown or unsupported guest mode, mode: 0x%x", vm->mode); + TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K, + "Unknown or unsupported guest mode: 0x%x", vm->mode); TEST_ASSERT(sparsebit_is_set(vm->vpages_valid, (vaddr >> vm->page_shift)), "Invalid virtual address, vaddr: 0x%lx", vaddr); /* - * Based on the mode check above there are 48 bits in the vaddr, so - * shift 16 to sign extend the last bit (bit-47), + * Check that the vaddr is a sign-extended va_width value. */ - TEST_ASSERT(vaddr == (((int64_t)vaddr << 16) >> 16), - "Canonical check failed. The virtual address is invalid."); - - pml4e = virt_get_pte(vm, &vm->pgd, vaddr, PG_LEVEL_512G); - if (vm_is_target_pte(pml4e, level, PG_LEVEL_512G)) - return pml4e; - - pdpe = virt_get_pte(vm, pml4e, vaddr, PG_LEVEL_1G); - if (vm_is_target_pte(pdpe, level, PG_LEVEL_1G)) - return pdpe; - - pde = virt_get_pte(vm, pdpe, vaddr, PG_LEVEL_2M); - if (vm_is_target_pte(pde, level, PG_LEVEL_2M)) - return pde; + TEST_ASSERT(vaddr == + (((int64_t)vaddr << (64 - va_width) >> (64 - va_width))), + "Canonical check failed. The virtual address is invalid."); + + for (current_level = vm->pgtable_levels; + current_level > PG_LEVEL_4K; + current_level--) { + pte = virt_get_pte(vm, pte, vaddr, current_level); + if (vm_is_target_pte(pte, level, current_level)) + return pte; + } - return virt_get_pte(vm, pde, vaddr, PG_LEVEL_4K); + return virt_get_pte(vm, pte, vaddr, PG_LEVEL_4K); } uint64_t *vm_get_page_table_entry(struct kvm_vm *vm, uint64_t vaddr) @@ -526,7 +523,8 @@ static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu) { struct kvm_sregs sregs; - TEST_ASSERT_EQ(vm->mode, VM_MODE_PXXV48_4K); + TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K, + "Unknown or unsupported guest mode: 0x%x", vm->mode); /* Set mode specific system register values. */ vcpu_sregs_get(vcpu, &sregs); @@ -540,6 +538,8 @@ static void vcpu_init_sregs(struct kvm_vm *vm, struct kvm_vcpu *vcpu) sregs.cr4 |= X86_CR4_PAE | X86_CR4_OSFXSR; if (kvm_cpu_has(X86_FEATURE_XSAVE)) sregs.cr4 |= X86_CR4_OSXSAVE; + if (vm->pgtable_levels == 5) + sregs.cr4 |= X86_CR4_LA57; sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX); kvm_seg_set_unusable(&sregs.ldt); diff --git a/tools/testing/selftests/kvm/lib/x86/vmx.c b/tools/testing/selftests/kvm/lib/x86/vmx.c index d4d1208dd023..29b082a58daa 100644 --- a/tools/testing/selftests/kvm/lib/x86/vmx.c +++ b/tools/testing/selftests/kvm/lib/x86/vmx.c @@ -401,11 +401,11 @@ void __nested_pg_map(struct vmx_pages *vmx, struct kvm_vm *vm, struct eptPageTableEntry *pt = vmx->eptp_hva, *pte; uint16_t index; - TEST_ASSERT(vm->mode == VM_MODE_PXXV48_4K, "Attempt to use " - "unknown or unsupported guest mode, mode: 0x%x", vm->mode); + TEST_ASSERT(vm->mode == VM_MODE_PXXVYY_4K, + "Unknown or unsupported guest mode: 0x%x", vm->mode); TEST_ASSERT((nested_paddr >> 48) == 0, - "Nested physical address 0x%lx requires 5-level paging", + "Nested physical address 0x%lx is > 48-bits and requires 5-level EPT", nested_paddr); TEST_ASSERT((nested_paddr % page_size) == 0, "Nested physical address not on page boundary,\n" @@ -534,8 +534,7 @@ bool kvm_cpu_has_ept(void) return ctrl & SECONDARY_EXEC_ENABLE_EPT; } -void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm, - uint32_t eptp_memslot) +void prepare_eptp(struct vmx_pages *vmx, struct kvm_vm *vm) { TEST_ASSERT(kvm_cpu_has_ept(), "KVM doesn't support nested EPT"); diff --git a/tools/testing/selftests/kvm/loongarch/arch_timer.c b/tools/testing/selftests/kvm/loongarch/arch_timer.c new file mode 100644 index 000000000000..355ecac30954 --- /dev/null +++ b/tools/testing/selftests/kvm/loongarch/arch_timer.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * The test validates periodic/one-shot constant timer IRQ using + * CSR.TCFG and CSR.TVAL registers. + */ +#include "arch_timer.h" +#include "kvm_util.h" +#include "processor.h" +#include "timer_test.h" +#include "ucall_common.h" + +static void do_idle(void) +{ + unsigned int intid; + unsigned long estat; + + __asm__ __volatile__("idle 0" : : : "memory"); + + estat = csr_read(LOONGARCH_CSR_ESTAT); + intid = !!(estat & BIT(INT_TI)); + + /* Make sure pending timer IRQ arrived */ + GUEST_ASSERT_EQ(intid, 1); + csr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR); +} + +static void guest_irq_handler(struct ex_regs *regs) +{ + unsigned int intid; + uint32_t cpu = guest_get_vcpuid(); + uint64_t xcnt, val, cfg, xcnt_diff_us; + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; + + intid = !!(regs->estat & BIT(INT_TI)); + + /* Make sure we are dealing with the correct timer IRQ */ + GUEST_ASSERT_EQ(intid, 1); + + cfg = timer_get_cfg(); + if (cfg & CSR_TCFG_PERIOD) { + WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter - 1); + if (shared_data->nr_iter == 0) + disable_timer(); + csr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR); + return; + } + + /* + * On real machine, value of LOONGARCH_CSR_TVAL is BIT_ULL(48) - 1 + * On virtual machine, its value counts down from BIT_ULL(48) - 1 + */ + val = timer_get_val(); + xcnt = timer_get_cycles(); + xcnt_diff_us = cycles_to_usec(xcnt - shared_data->xcnt); + + /* Basic 'timer condition met' check */ + __GUEST_ASSERT(val > cfg, + "val = 0x%lx, cfg = 0x%lx, xcnt_diff_us = 0x%lx", + val, cfg, xcnt_diff_us); + + csr_write(CSR_TINTCLR_TI, LOONGARCH_CSR_TINTCLR); + WRITE_ONCE(shared_data->nr_iter, shared_data->nr_iter + 1); +} + +static void guest_test_period_timer(uint32_t cpu) +{ + uint32_t irq_iter, config_iter; + uint64_t us; + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; + + shared_data->nr_iter = test_args.nr_iter; + shared_data->xcnt = timer_get_cycles(); + us = msecs_to_usecs(test_args.timer_period_ms) + test_args.timer_err_margin_us; + timer_set_next_cmp_ms(test_args.timer_period_ms, true); + + for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) { + /* Setup a timeout for the interrupt to arrive */ + udelay(us); + } + + irq_iter = READ_ONCE(shared_data->nr_iter); + __GUEST_ASSERT(irq_iter == 0, + "irq_iter = 0x%x.\n" + " Guest period timer interrupt was not triggered within the specified\n" + " interval, try to increase the error margin by [-e] option.\n", + irq_iter); +} + +static void guest_test_oneshot_timer(uint32_t cpu) +{ + uint32_t irq_iter, config_iter; + uint64_t us; + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; + + shared_data->nr_iter = 0; + shared_data->guest_stage = 0; + us = msecs_to_usecs(test_args.timer_period_ms) + test_args.timer_err_margin_us; + for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) { + shared_data->xcnt = timer_get_cycles(); + + /* Setup the next interrupt */ + timer_set_next_cmp_ms(test_args.timer_period_ms, false); + /* Setup a timeout for the interrupt to arrive */ + udelay(us); + + irq_iter = READ_ONCE(shared_data->nr_iter); + __GUEST_ASSERT(config_iter + 1 == irq_iter, + "config_iter + 1 = 0x%x, irq_iter = 0x%x.\n" + " Guest timer interrupt was not triggered within the specified\n" + " interval, try to increase the error margin by [-e] option.\n", + config_iter + 1, irq_iter); + } +} + +static void guest_test_emulate_timer(uint32_t cpu) +{ + uint32_t config_iter; + uint64_t xcnt_diff_us, us; + struct test_vcpu_shared_data *shared_data = &vcpu_shared_data[cpu]; + + local_irq_disable(); + shared_data->nr_iter = 0; + us = msecs_to_usecs(test_args.timer_period_ms); + for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) { + shared_data->xcnt = timer_get_cycles(); + + /* Setup the next interrupt */ + timer_set_next_cmp_ms(test_args.timer_period_ms, false); + do_idle(); + + xcnt_diff_us = cycles_to_usec(timer_get_cycles() - shared_data->xcnt); + __GUEST_ASSERT(xcnt_diff_us >= us, + "xcnt_diff_us = 0x%lx, us = 0x%lx.\n", + xcnt_diff_us, us); + } + local_irq_enable(); +} + +static void guest_time_count_test(uint32_t cpu) +{ + uint32_t config_iter; + unsigned long start, end, prev, us; + + /* Assuming that test case starts to run in 1 second */ + start = timer_get_cycles(); + us = msec_to_cycles(1000); + __GUEST_ASSERT(start <= us, + "start = 0x%lx, us = 0x%lx.\n", + start, us); + + us = msec_to_cycles(test_args.timer_period_ms); + for (config_iter = 0; config_iter < test_args.nr_iter; config_iter++) { + start = timer_get_cycles(); + end = start + us; + /* test time count growing up always */ + while (start < end) { + prev = start; + start = timer_get_cycles(); + __GUEST_ASSERT(prev <= start, + "prev = 0x%lx, start = 0x%lx.\n", + prev, start); + } + } +} + +static void guest_code(void) +{ + uint32_t cpu = guest_get_vcpuid(); + + /* must run at first */ + guest_time_count_test(cpu); + + timer_irq_enable(); + local_irq_enable(); + guest_test_period_timer(cpu); + guest_test_oneshot_timer(cpu); + guest_test_emulate_timer(cpu); + + GUEST_DONE(); +} + +struct kvm_vm *test_vm_create(void) +{ + struct kvm_vm *vm; + int nr_vcpus = test_args.nr_vcpus; + + vm = vm_create_with_vcpus(nr_vcpus, guest_code, vcpus); + vm_init_descriptor_tables(vm); + vm_install_exception_handler(vm, EXCCODE_INT, guest_irq_handler); + + /* Make all the test's cmdline args visible to the guest */ + sync_global_to_guest(vm, test_args); + + return vm; +} + +void test_vm_cleanup(struct kvm_vm *vm) +{ + kvm_vm_free(vm); +} diff --git a/tools/testing/selftests/kvm/mmu_stress_test.c b/tools/testing/selftests/kvm/mmu_stress_test.c index 37b7e6524533..51c070556f3e 100644 --- a/tools/testing/selftests/kvm/mmu_stress_test.c +++ b/tools/testing/selftests/kvm/mmu_stress_test.c @@ -263,8 +263,10 @@ static void calc_default_nr_vcpus(void) TEST_ASSERT(!r, "sched_getaffinity failed, errno = %d (%s)", errno, strerror(errno)); - nr_vcpus = CPU_COUNT(&possible_mask) * 3/4; + nr_vcpus = CPU_COUNT(&possible_mask); TEST_ASSERT(nr_vcpus > 0, "Uh, no CPUs?"); + if (nr_vcpus >= 2) + nr_vcpus = nr_vcpus * 3/4; } int main(int argc, char *argv[]) @@ -360,11 +362,9 @@ int main(int argc, char *argv[]) #ifdef __x86_64__ /* Identity map memory in the guest using 1gb pages. */ - for (i = 0; i < slot_size; i += SZ_1G) - __virt_pg_map(vm, gpa + i, gpa + i, PG_LEVEL_1G); + virt_map_level(vm, gpa, gpa, slot_size, PG_LEVEL_1G); #else - for (i = 0; i < slot_size; i += vm->page_size) - virt_pg_map(vm, gpa + i, gpa + i); + virt_map(vm, gpa, gpa, slot_size >> vm->page_shift); #endif } diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c index f04768c1d2e4..93e603d91311 100644 --- a/tools/testing/selftests/kvm/pre_fault_memory_test.c +++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c @@ -17,13 +17,13 @@ #define TEST_NPAGES (TEST_SIZE / PAGE_SIZE) #define TEST_SLOT 10 -static void guest_code(uint64_t base_gpa) +static void guest_code(uint64_t base_gva) { volatile uint64_t val __used; int i; for (i = 0; i < TEST_NPAGES; i++) { - uint64_t *src = (uint64_t *)(base_gpa + i * PAGE_SIZE); + uint64_t *src = (uint64_t *)(base_gva + i * PAGE_SIZE); val = *src; } @@ -161,6 +161,7 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset, static void __test_pre_fault_memory(unsigned long vm_type, bool private) { + uint64_t gpa, gva, alignment, guest_page_size; const struct vm_shape shape = { .mode = VM_MODE_DEFAULT, .type = vm_type, @@ -170,35 +171,30 @@ static void __test_pre_fault_memory(unsigned long vm_type, bool private) struct kvm_vm *vm; struct ucall uc; - uint64_t guest_test_phys_mem; - uint64_t guest_test_virt_mem; - uint64_t alignment, guest_page_size; - vm = vm_create_shape_with_one_vcpu(shape, &vcpu, guest_code); alignment = guest_page_size = vm_guest_mode_params[VM_MODE_DEFAULT].page_size; - guest_test_phys_mem = (vm->max_gfn - TEST_NPAGES) * guest_page_size; + gpa = (vm->max_gfn - TEST_NPAGES) * guest_page_size; #ifdef __s390x__ alignment = max(0x100000UL, guest_page_size); #else alignment = SZ_2M; #endif - guest_test_phys_mem = align_down(guest_test_phys_mem, alignment); - guest_test_virt_mem = guest_test_phys_mem & ((1ULL << (vm->va_bits - 1)) - 1); + gpa = align_down(gpa, alignment); + gva = gpa & ((1ULL << (vm->va_bits - 1)) - 1); - vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, - guest_test_phys_mem, TEST_SLOT, TEST_NPAGES, - private ? KVM_MEM_GUEST_MEMFD : 0); - virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, TEST_NPAGES); + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, gpa, TEST_SLOT, + TEST_NPAGES, private ? KVM_MEM_GUEST_MEMFD : 0); + virt_map(vm, gva, gpa, TEST_NPAGES); if (private) - vm_mem_set_private(vm, guest_test_phys_mem, TEST_SIZE); + vm_mem_set_private(vm, gpa, TEST_SIZE); - pre_fault_memory(vcpu, guest_test_phys_mem, 0, SZ_2M, 0, private); - pre_fault_memory(vcpu, guest_test_phys_mem, SZ_2M, PAGE_SIZE * 2, PAGE_SIZE, private); - pre_fault_memory(vcpu, guest_test_phys_mem, TEST_SIZE, PAGE_SIZE, PAGE_SIZE, private); + pre_fault_memory(vcpu, gpa, 0, SZ_2M, 0, private); + pre_fault_memory(vcpu, gpa, SZ_2M, PAGE_SIZE * 2, PAGE_SIZE, private); + pre_fault_memory(vcpu, gpa, TEST_SIZE, PAGE_SIZE, PAGE_SIZE, private); - vcpu_args_set(vcpu, 1, guest_test_virt_mem); + vcpu_args_set(vcpu, 1, gva); vcpu_run(vcpu); run = vcpu->run; diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c index 705ab3d7778b..cb54a56990a0 100644 --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c @@ -133,6 +133,7 @@ bool filter_reg(__u64 reg) case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_SUSP: case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_STA: case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT: + case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_MPXY: case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_EXPERIMENTAL: case KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_VENDOR: return true; @@ -639,6 +640,7 @@ static const char *sbi_ext_single_id_to_str(__u64 reg_off) KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_SUSP), KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_STA), KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_FWFT), + KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_MPXY), KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_EXPERIMENTAL), KVM_SBI_EXT_ARR(KVM_RISCV_SBI_EXT_VENDOR), }; @@ -1142,6 +1144,7 @@ KVM_SBI_EXT_SUBLIST_CONFIG(sta, STA); KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU); KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN); KVM_SBI_EXT_SIMPLE_CONFIG(susp, SUSP); +KVM_SBI_EXT_SIMPLE_CONFIG(mpxy, MPXY); KVM_SBI_EXT_SUBLIST_CONFIG(fwft, FWFT); KVM_ISA_EXT_SUBLIST_CONFIG(aia, AIA); @@ -1222,6 +1225,7 @@ struct vcpu_reg_list *vcpu_configs[] = { &config_sbi_pmu, &config_sbi_dbcn, &config_sbi_susp, + &config_sbi_mpxy, &config_sbi_fwft, &config_aia, &config_fp_f, diff --git a/tools/testing/selftests/kvm/s390/user_operexec.c b/tools/testing/selftests/kvm/s390/user_operexec.c new file mode 100644 index 000000000000..714906c1d12a --- /dev/null +++ b/tools/testing/selftests/kvm/s390/user_operexec.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Test operation exception forwarding. + * + * Copyright IBM Corp. 2025 + * + * Authors: + * Janosch Frank <frankja@linux.ibm.com> + */ +#include "kselftest.h" +#include "kvm_util.h" +#include "test_util.h" +#include "sie.h" + +#include <linux/kvm.h> + +static void guest_code_instr0(void) +{ + asm(".word 0x0000"); +} + +static void test_user_instr0(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int rc; + + vm = vm_create_with_one_vcpu(&vcpu, guest_code_instr0); + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0); + TEST_ASSERT_EQ(0, rc); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0); + + kvm_vm_free(vm); +} + +static void guest_code_user_operexec(void) +{ + asm(".word 0x0807"); +} + +static void test_user_operexec(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int rc; + + vm = vm_create_with_one_vcpu(&vcpu, guest_code_user_operexec); + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0); + TEST_ASSERT_EQ(0, rc); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0807); + + kvm_vm_free(vm); + + /* + * Since user_operexec is the superset it can be used for the + * 0 instruction. + */ + vm = vm_create_with_one_vcpu(&vcpu, guest_code_instr0); + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0); + TEST_ASSERT_EQ(0, rc); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0); + + kvm_vm_free(vm); +} + +/* combine user_instr0 and user_operexec */ +static void test_user_operexec_combined(void) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + int rc; + + vm = vm_create_with_one_vcpu(&vcpu, guest_code_user_operexec); + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0); + TEST_ASSERT_EQ(0, rc); + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0); + TEST_ASSERT_EQ(0, rc); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0807); + + kvm_vm_free(vm); + + /* Reverse enablement order */ + vm = vm_create_with_one_vcpu(&vcpu, guest_code_user_operexec); + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_OPEREXEC, 0); + TEST_ASSERT_EQ(0, rc); + rc = __vm_enable_cap(vm, KVM_CAP_S390_USER_INSTR0, 0); + TEST_ASSERT_EQ(0, rc); + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_S390_SIEIC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.icptcode, ICPT_OPEREXC); + TEST_ASSERT_EQ(vcpu->run->s390_sieic.ipa, 0x0807); + + kvm_vm_free(vm); +} + +/* + * Run all tests above. + * + * Enablement after VCPU has been added is automatically tested since + * we enable the capability after VCPU creation. + */ +static struct testdef { + const char *name; + void (*test)(void); +} testlist[] = { + { "instr0", test_user_instr0 }, + { "operexec", test_user_operexec }, + { "operexec_combined", test_user_operexec_combined}, +}; + +int main(int argc, char *argv[]) +{ + int idx; + + TEST_REQUIRE(kvm_has_cap(KVM_CAP_S390_USER_INSTR0)); + + ksft_print_header(); + ksft_set_plan(ARRAY_SIZE(testlist)); + for (idx = 0; idx < ARRAY_SIZE(testlist); idx++) { + testlist[idx].test(); + ksft_test_result_pass("%s\n", testlist[idx].name); + } + ksft_finished(); +} diff --git a/tools/testing/selftests/kvm/x86/hyperv_features.c b/tools/testing/selftests/kvm/x86/hyperv_features.c index 99d327084172..130b9ce7e5dd 100644 --- a/tools/testing/selftests/kvm/x86/hyperv_features.c +++ b/tools/testing/selftests/kvm/x86/hyperv_features.c @@ -94,7 +94,7 @@ static void guest_hcall(vm_vaddr_t pgs_gpa, struct hcall_data *hcall) if (!(hcall->control & HV_HYPERCALL_FAST_BIT)) { input = pgs_gpa; - output = pgs_gpa + 4096; + output = pgs_gpa + PAGE_SIZE; } else { input = output = 0; } diff --git a/tools/testing/selftests/kvm/x86/hyperv_ipi.c b/tools/testing/selftests/kvm/x86/hyperv_ipi.c index 2b5b4bc6ef7e..ca61836c4e32 100644 --- a/tools/testing/selftests/kvm/x86/hyperv_ipi.c +++ b/tools/testing/selftests/kvm/x86/hyperv_ipi.c @@ -102,7 +102,7 @@ static void sender_guest_code(void *hcall_page, vm_vaddr_t pgs_gpa) /* 'Slow' HvCallSendSyntheticClusterIpi to RECEIVER_VCPU_ID_1 */ ipi->vector = IPI_VECTOR; ipi->cpu_mask = 1 << RECEIVER_VCPU_ID_1; - hyperv_hypercall(HVCALL_SEND_IPI, pgs_gpa, pgs_gpa + 4096); + hyperv_hypercall(HVCALL_SEND_IPI, pgs_gpa, pgs_gpa + PAGE_SIZE); nop_loop(); GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_1] == ++ipis_expected[0]); GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_2] == ipis_expected[1]); @@ -116,13 +116,13 @@ static void sender_guest_code(void *hcall_page, vm_vaddr_t pgs_gpa) GUEST_SYNC(stage++); /* 'Slow' HvCallSendSyntheticClusterIpiEx to RECEIVER_VCPU_ID_1 */ - memset(hcall_page, 0, 4096); + memset(hcall_page, 0, PAGE_SIZE); ipi_ex->vector = IPI_VECTOR; ipi_ex->vp_set.format = HV_GENERIC_SET_SPARSE_4K; ipi_ex->vp_set.valid_bank_mask = 1 << 0; ipi_ex->vp_set.bank_contents[0] = BIT(RECEIVER_VCPU_ID_1); hyperv_hypercall(HVCALL_SEND_IPI_EX | (1 << HV_HYPERCALL_VARHEAD_OFFSET), - pgs_gpa, pgs_gpa + 4096); + pgs_gpa, pgs_gpa + PAGE_SIZE); nop_loop(); GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_1] == ++ipis_expected[0]); GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_2] == ipis_expected[1]); @@ -138,13 +138,13 @@ static void sender_guest_code(void *hcall_page, vm_vaddr_t pgs_gpa) GUEST_SYNC(stage++); /* 'Slow' HvCallSendSyntheticClusterIpiEx to RECEIVER_VCPU_ID_2 */ - memset(hcall_page, 0, 4096); + memset(hcall_page, 0, PAGE_SIZE); ipi_ex->vector = IPI_VECTOR; ipi_ex->vp_set.format = HV_GENERIC_SET_SPARSE_4K; ipi_ex->vp_set.valid_bank_mask = 1 << 1; ipi_ex->vp_set.bank_contents[0] = BIT(RECEIVER_VCPU_ID_2 - 64); hyperv_hypercall(HVCALL_SEND_IPI_EX | (1 << HV_HYPERCALL_VARHEAD_OFFSET), - pgs_gpa, pgs_gpa + 4096); + pgs_gpa, pgs_gpa + PAGE_SIZE); nop_loop(); GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_1] == ipis_expected[0]); GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_2] == ++ipis_expected[1]); @@ -160,14 +160,14 @@ static void sender_guest_code(void *hcall_page, vm_vaddr_t pgs_gpa) GUEST_SYNC(stage++); /* 'Slow' HvCallSendSyntheticClusterIpiEx to both RECEIVER_VCPU_ID_{1,2} */ - memset(hcall_page, 0, 4096); + memset(hcall_page, 0, PAGE_SIZE); ipi_ex->vector = IPI_VECTOR; ipi_ex->vp_set.format = HV_GENERIC_SET_SPARSE_4K; ipi_ex->vp_set.valid_bank_mask = 1 << 1 | 1; ipi_ex->vp_set.bank_contents[0] = BIT(RECEIVER_VCPU_ID_1); ipi_ex->vp_set.bank_contents[1] = BIT(RECEIVER_VCPU_ID_2 - 64); hyperv_hypercall(HVCALL_SEND_IPI_EX | (2 << HV_HYPERCALL_VARHEAD_OFFSET), - pgs_gpa, pgs_gpa + 4096); + pgs_gpa, pgs_gpa + PAGE_SIZE); nop_loop(); GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_1] == ++ipis_expected[0]); GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_2] == ++ipis_expected[1]); @@ -183,10 +183,10 @@ static void sender_guest_code(void *hcall_page, vm_vaddr_t pgs_gpa) GUEST_SYNC(stage++); /* 'Slow' HvCallSendSyntheticClusterIpiEx to HV_GENERIC_SET_ALL */ - memset(hcall_page, 0, 4096); + memset(hcall_page, 0, PAGE_SIZE); ipi_ex->vector = IPI_VECTOR; ipi_ex->vp_set.format = HV_GENERIC_SET_ALL; - hyperv_hypercall(HVCALL_SEND_IPI_EX, pgs_gpa, pgs_gpa + 4096); + hyperv_hypercall(HVCALL_SEND_IPI_EX, pgs_gpa, pgs_gpa + PAGE_SIZE); nop_loop(); GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_1] == ++ipis_expected[0]); GUEST_ASSERT(ipis_rcvd[RECEIVER_VCPU_ID_2] == ++ipis_expected[1]); diff --git a/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c b/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c index 077cd0ec3040..a3b7ce155981 100644 --- a/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c +++ b/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c @@ -621,7 +621,7 @@ int main(int argc, char *argv[]) for (i = 0; i < NTEST_PAGES; i++) { pte = vm_get_page_table_entry(vm, data->test_pages + i * PAGE_SIZE); gpa = addr_hva2gpa(vm, pte); - __virt_pg_map(vm, gva + PAGE_SIZE * i, gpa & PAGE_MASK, PG_LEVEL_4K); + virt_pg_map(vm, gva + PAGE_SIZE * i, gpa & PAGE_MASK); data->test_pages_pte[i] = gva + (gpa & ~PAGE_MASK); } diff --git a/tools/testing/selftests/kvm/x86/vmx_close_while_nested_test.c b/tools/testing/selftests/kvm/x86/nested_close_kvm_test.c index dad988351493..f001cb836bfa 100644 --- a/tools/testing/selftests/kvm/x86/vmx_close_while_nested_test.c +++ b/tools/testing/selftests/kvm/x86/nested_close_kvm_test.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * vmx_close_while_nested - * * Copyright (C) 2019, Red Hat, Inc. * * Verify that nothing bad happens if a KVM user exits with open @@ -12,6 +10,7 @@ #include "kvm_util.h" #include "processor.h" #include "vmx.h" +#include "svm_util.h" #include <string.h> #include <sys/ioctl.h> @@ -22,6 +21,8 @@ enum { PORT_L0_EXIT = 0x2000, }; +#define L2_GUEST_STACK_SIZE 64 + static void l2_guest_code(void) { /* Exit to L0 */ @@ -29,9 +30,8 @@ static void l2_guest_code(void) : : [port] "d" (PORT_L0_EXIT) : "rax"); } -static void l1_guest_code(struct vmx_pages *vmx_pages) +static void l1_vmx_code(struct vmx_pages *vmx_pages) { -#define L2_GUEST_STACK_SIZE 64 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); @@ -45,19 +45,43 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_ASSERT(0); } +static void l1_svm_code(struct svm_test_data *svm) +{ + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + + /* Prepare the VMCB for L2 execution. */ + generic_svm_setup(svm, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT(0); +} + +static void l1_guest_code(void *data) +{ + if (this_cpu_has(X86_FEATURE_VMX)) + l1_vmx_code(data); + else + l1_svm_code(data); +} + int main(int argc, char *argv[]) { - vm_vaddr_t vmx_pages_gva; + vm_vaddr_t guest_gva; struct kvm_vcpu *vcpu; struct kvm_vm *vm; - TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || + kvm_cpu_has(X86_FEATURE_SVM)); vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); - /* Allocate VMX pages and shared descriptors (vmx_pages). */ - vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vcpu, 1, vmx_pages_gva); + if (kvm_cpu_has(X86_FEATURE_VMX)) + vcpu_alloc_vmx(vm, &guest_gva); + else + vcpu_alloc_svm(vm, &guest_gva); + + vcpu_args_set(vcpu, 1, guest_gva); for (;;) { volatile struct kvm_run *run = vcpu->run; diff --git a/tools/testing/selftests/kvm/x86/nested_invalid_cr3_test.c b/tools/testing/selftests/kvm/x86/nested_invalid_cr3_test.c new file mode 100644 index 000000000000..a6b6da9cf7fe --- /dev/null +++ b/tools/testing/selftests/kvm/x86/nested_invalid_cr3_test.c @@ -0,0 +1,116 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025, Google LLC. + * + * This test verifies that L1 fails to enter L2 with an invalid CR3, and + * succeeds otherwise. + */ +#include "kvm_util.h" +#include "vmx.h" +#include "svm_util.h" +#include "kselftest.h" + + +#define L2_GUEST_STACK_SIZE 64 + +static void l2_guest_code(void) +{ + vmcall(); +} + +static void l1_svm_code(struct svm_test_data *svm) +{ + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + uintptr_t save_cr3; + + generic_svm_setup(svm, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + /* Try to run L2 with invalid CR3 and make sure it fails */ + save_cr3 = svm->vmcb->save.cr3; + svm->vmcb->save.cr3 = -1ull; + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT(svm->vmcb->control.exit_code == SVM_EXIT_ERR); + + /* Now restore CR3 and make sure L2 runs successfully */ + svm->vmcb->save.cr3 = save_cr3; + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT(svm->vmcb->control.exit_code == SVM_EXIT_VMMCALL); + + GUEST_DONE(); +} + +static void l1_vmx_code(struct vmx_pages *vmx_pages) +{ + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + uintptr_t save_cr3; + + GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_ASSERT(load_vmcs(vmx_pages)); + + prepare_vmcs(vmx_pages, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + /* Try to run L2 with invalid CR3 and make sure it fails */ + save_cr3 = vmreadz(GUEST_CR3); + vmwrite(GUEST_CR3, -1ull); + GUEST_ASSERT(!vmlaunch()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == + (EXIT_REASON_FAILED_VMENTRY | EXIT_REASON_INVALID_STATE)); + + /* Now restore CR3 and make sure L2 runs successfully */ + vmwrite(GUEST_CR3, save_cr3); + GUEST_ASSERT(!vmlaunch()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + + GUEST_DONE(); +} + +static void l1_guest_code(void *data) +{ + if (this_cpu_has(X86_FEATURE_VMX)) + l1_vmx_code(data); + else + l1_svm_code(data); +} + +int main(int argc, char *argv[]) +{ + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + vm_vaddr_t guest_gva = 0; + + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || + kvm_cpu_has(X86_FEATURE_SVM)); + + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); + + if (kvm_cpu_has(X86_FEATURE_VMX)) + vcpu_alloc_vmx(vm, &guest_gva); + else + vcpu_alloc_svm(vm, &guest_gva); + + vcpu_args_set(vcpu, 1, guest_gva); + + for (;;) { + struct ucall uc; + + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + case UCALL_SYNC: + break; + case UCALL_DONE: + goto done; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + } + } + +done: + kvm_vm_free(vm); + return 0; +} diff --git a/tools/testing/selftests/kvm/x86/vmx_tsc_adjust_test.c b/tools/testing/selftests/kvm/x86/nested_tsc_adjust_test.c index 2ceb5c78c442..2839f650e5c9 100644 --- a/tools/testing/selftests/kvm/x86/vmx_tsc_adjust_test.c +++ b/tools/testing/selftests/kvm/x86/nested_tsc_adjust_test.c @@ -1,7 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * vmx_tsc_adjust_test - * * Copyright (C) 2018, Google LLC. * * IA32_TSC_ADJUST test @@ -22,6 +20,7 @@ #include "kvm_util.h" #include "processor.h" #include "vmx.h" +#include "svm_util.h" #include <string.h> #include <sys/ioctl.h> @@ -35,6 +34,8 @@ #define TSC_ADJUST_VALUE (1ll << 32) #define TSC_OFFSET_VALUE -(1ll << 48) +#define L2_GUEST_STACK_SIZE 64 + enum { PORT_ABORT = 0x1000, PORT_REPORT, @@ -72,42 +73,47 @@ static void l2_guest_code(void) __asm__ __volatile__("vmcall"); } -static void l1_guest_code(struct vmx_pages *vmx_pages) +static void l1_guest_code(void *data) { -#define L2_GUEST_STACK_SIZE 64 unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; - uint32_t control; - uintptr_t save_cr3; + /* Set TSC from L1 and make sure TSC_ADJUST is updated correctly */ GUEST_ASSERT(rdtsc() < TSC_ADJUST_VALUE); wrmsr(MSR_IA32_TSC, rdtsc() - TSC_ADJUST_VALUE); check_ia32_tsc_adjust(-1 * TSC_ADJUST_VALUE); - GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); - GUEST_ASSERT(load_vmcs(vmx_pages)); - - /* Prepare the VMCS for L2 execution. */ - prepare_vmcs(vmx_pages, l2_guest_code, - &l2_guest_stack[L2_GUEST_STACK_SIZE]); - control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); - control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_USE_TSC_OFFSETTING; - vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); - vmwrite(TSC_OFFSET, TSC_OFFSET_VALUE); - - /* Jump into L2. First, test failure to load guest CR3. */ - save_cr3 = vmreadz(GUEST_CR3); - vmwrite(GUEST_CR3, -1ull); - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == - (EXIT_REASON_FAILED_VMENTRY | EXIT_REASON_INVALID_STATE)); - check_ia32_tsc_adjust(-1 * TSC_ADJUST_VALUE); - vmwrite(GUEST_CR3, save_cr3); - - GUEST_ASSERT(!vmlaunch()); - GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + /* + * Run L2 with TSC_OFFSET. L2 will write to TSC, and L1 is not + * intercepting the write so it should update L1's TSC_ADJUST. + */ + if (this_cpu_has(X86_FEATURE_VMX)) { + struct vmx_pages *vmx_pages = data; + uint32_t control; + + GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_ASSERT(load_vmcs(vmx_pages)); + + prepare_vmcs(vmx_pages, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + control = vmreadz(CPU_BASED_VM_EXEC_CONTROL); + control |= CPU_BASED_USE_MSR_BITMAPS | CPU_BASED_USE_TSC_OFFSETTING; + vmwrite(CPU_BASED_VM_EXEC_CONTROL, control); + vmwrite(TSC_OFFSET, TSC_OFFSET_VALUE); + + GUEST_ASSERT(!vmlaunch()); + GUEST_ASSERT(vmreadz(VM_EXIT_REASON) == EXIT_REASON_VMCALL); + } else { + struct svm_test_data *svm = data; + + generic_svm_setup(svm, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + svm->vmcb->control.tsc_offset = TSC_OFFSET_VALUE; + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT(svm->vmcb->control.exit_code == SVM_EXIT_VMMCALL); + } check_ia32_tsc_adjust(-2 * TSC_ADJUST_VALUE); - GUEST_DONE(); } @@ -119,16 +125,19 @@ static void report(int64_t val) int main(int argc, char *argv[]) { - vm_vaddr_t vmx_pages_gva; + vm_vaddr_t nested_gva; struct kvm_vcpu *vcpu; - TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || + kvm_cpu_has(X86_FEATURE_SVM)); - vm = vm_create_with_one_vcpu(&vcpu, (void *) l1_guest_code); + vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); + if (kvm_cpu_has(X86_FEATURE_VMX)) + vcpu_alloc_vmx(vm, &nested_gva); + else + vcpu_alloc_svm(vm, &nested_gva); - /* Allocate VMX pages and shared descriptors (vmx_pages). */ - vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vcpu, 1, vmx_pages_gva); + vcpu_args_set(vcpu, 1, nested_gva); for (;;) { struct ucall uc; diff --git a/tools/testing/selftests/kvm/x86/vmx_nested_tsc_scaling_test.c b/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c index 1759fa5cb3f2..4260c9e4f489 100644 --- a/tools/testing/selftests/kvm/x86/vmx_nested_tsc_scaling_test.c +++ b/tools/testing/selftests/kvm/x86/nested_tsc_scaling_test.c @@ -13,6 +13,7 @@ #include "kvm_util.h" #include "vmx.h" +#include "svm_util.h" #include "kselftest.h" /* L2 is scaled up (from L1's perspective) by this factor */ @@ -79,7 +80,30 @@ static void l2_guest_code(void) __asm__ __volatile__("vmcall"); } -static void l1_guest_code(struct vmx_pages *vmx_pages) +static void l1_svm_code(struct svm_test_data *svm) +{ + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + + /* check that L1's frequency looks alright before launching L2 */ + check_tsc_freq(UCHECK_L1); + + generic_svm_setup(svm, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + /* enable TSC scaling for L2 */ + wrmsr(MSR_AMD64_TSC_RATIO, L2_SCALE_FACTOR << 32); + + /* launch L2 */ + run_guest(svm->vmcb, svm->vmcb_gpa); + GUEST_ASSERT(svm->vmcb->control.exit_code == SVM_EXIT_VMMCALL); + + /* check that L1's frequency still looks good */ + check_tsc_freq(UCHECK_L1); + + GUEST_DONE(); +} + +static void l1_vmx_code(struct vmx_pages *vmx_pages) { unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; uint32_t control; @@ -116,11 +140,19 @@ static void l1_guest_code(struct vmx_pages *vmx_pages) GUEST_DONE(); } +static void l1_guest_code(void *data) +{ + if (this_cpu_has(X86_FEATURE_VMX)) + l1_vmx_code(data); + else + l1_svm_code(data); +} + int main(int argc, char *argv[]) { struct kvm_vcpu *vcpu; struct kvm_vm *vm; - vm_vaddr_t vmx_pages_gva; + vm_vaddr_t guest_gva = 0; uint64_t tsc_start, tsc_end; uint64_t tsc_khz; @@ -129,7 +161,8 @@ int main(int argc, char *argv[]) uint64_t l1_tsc_freq = 0; uint64_t l2_tsc_freq = 0; - TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX) || + kvm_cpu_has(X86_FEATURE_SVM)); TEST_REQUIRE(kvm_has_cap(KVM_CAP_TSC_CONTROL)); TEST_REQUIRE(sys_clocksource_is_based_on_tsc()); @@ -152,8 +185,13 @@ int main(int argc, char *argv[]) printf("real TSC frequency is around: %"PRIu64"\n", l0_tsc_freq); vm = vm_create_with_one_vcpu(&vcpu, l1_guest_code); - vcpu_alloc_vmx(vm, &vmx_pages_gva); - vcpu_args_set(vcpu, 1, vmx_pages_gva); + + if (kvm_cpu_has(X86_FEATURE_VMX)) + vcpu_alloc_vmx(vm, &guest_gva); + else + vcpu_alloc_svm(vm, &guest_gva); + + vcpu_args_set(vcpu, 1, guest_gva); tsc_khz = __vcpu_ioctl(vcpu, KVM_GET_TSC_KHZ, NULL); TEST_ASSERT(tsc_khz != -1, "vcpu ioctl KVM_GET_TSC_KHZ failed"); diff --git a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c index 82a8d88b5338..1969f4ab9b28 100644 --- a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c +++ b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c @@ -380,7 +380,7 @@ static void test_mem_conversions(enum vm_mem_backing_src_type src_type, uint32_t struct kvm_vcpu *vcpus[KVM_MAX_VCPUS]; pthread_t threads[KVM_MAX_VCPUS]; struct kvm_vm *vm; - int memfd, i, r; + int memfd, i; const struct vm_shape shape = { .mode = VM_MODE_DEFAULT, @@ -428,11 +428,8 @@ static void test_mem_conversions(enum vm_mem_backing_src_type src_type, uint32_t * should prevent the VM from being fully destroyed until the last * reference to the guest_memfd is also put. */ - r = fallocate(memfd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, memfd_size); - TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("fallocate()", r)); - - r = fallocate(memfd, FALLOC_FL_KEEP_SIZE, 0, memfd_size); - TEST_ASSERT(!r, __KVM_SYSCALL_ERROR("fallocate()", r)); + kvm_fallocate(memfd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE, 0, memfd_size); + kvm_fallocate(memfd, FALLOC_FL_KEEP_SIZE, 0, memfd_size); close(memfd); } diff --git a/tools/testing/selftests/kvm/x86/sev_smoke_test.c b/tools/testing/selftests/kvm/x86/sev_smoke_test.c index 77256c89bb8d..86ad1c7d068f 100644 --- a/tools/testing/selftests/kvm/x86/sev_smoke_test.c +++ b/tools/testing/selftests/kvm/x86/sev_smoke_test.c @@ -104,7 +104,7 @@ static void test_sync_vmsa(uint32_t type, uint64_t policy) vm_sev_launch(vm, policy, NULL); /* This page is shared, so make it decrypted. */ - memset(hva, 0, 4096); + memset(hva, 0, PAGE_SIZE); vcpu_run(vcpu); diff --git a/tools/testing/selftests/kvm/x86/state_test.c b/tools/testing/selftests/kvm/x86/state_test.c index 141b7fc0c965..f2c7a1c297e3 100644 --- a/tools/testing/selftests/kvm/x86/state_test.c +++ b/tools/testing/selftests/kvm/x86/state_test.c @@ -141,7 +141,7 @@ static void __attribute__((__flatten__)) guest_code(void *arg) if (this_cpu_has(X86_FEATURE_XSAVE)) { uint64_t supported_xcr0 = this_cpu_supported_xcr0(); - uint8_t buffer[4096]; + uint8_t buffer[PAGE_SIZE]; memset(buffer, 0xcc, sizeof(buffer)); diff --git a/tools/testing/selftests/kvm/x86/userspace_io_test.c b/tools/testing/selftests/kvm/x86/userspace_io_test.c index 9481cbcf284f..be7d72f3c029 100644 --- a/tools/testing/selftests/kvm/x86/userspace_io_test.c +++ b/tools/testing/selftests/kvm/x86/userspace_io_test.c @@ -85,7 +85,7 @@ int main(int argc, char *argv[]) regs.rcx = 1; if (regs.rcx == 3) regs.rcx = 8192; - memset((void *)run + run->io.data_offset, 0xaa, 4096); + memset((void *)run + run->io.data_offset, 0xaa, PAGE_SIZE); vcpu_regs_set(vcpu, ®s); } diff --git a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c index fa512d033205..98cb6bdab3e6 100644 --- a/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c +++ b/tools/testing/selftests/kvm/x86/vmx_dirty_log_test.c @@ -120,17 +120,17 @@ static void test_vmx_dirty_log(bool enable_ept) * GPAs as the EPT enabled case. */ if (enable_ept) { - prepare_eptp(vmx, vm, 0); + prepare_eptp(vmx, vm); nested_map_memslot(vmx, vm, 0); - nested_map(vmx, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, 4096); - nested_map(vmx, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, 4096); + nested_map(vmx, vm, NESTED_TEST_MEM1, GUEST_TEST_MEM, PAGE_SIZE); + nested_map(vmx, vm, NESTED_TEST_MEM2, GUEST_TEST_MEM, PAGE_SIZE); } bmap = bitmap_zalloc(TEST_MEM_PAGES); host_test_mem = addr_gpa2hva(vm, GUEST_TEST_MEM); while (!done) { - memset(host_test_mem, 0xaa, TEST_MEM_PAGES * 4096); + memset(host_test_mem, 0xaa, TEST_MEM_PAGES * PAGE_SIZE); vcpu_run(vcpu); TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); @@ -153,9 +153,9 @@ static void test_vmx_dirty_log(bool enable_ept) } TEST_ASSERT(!test_bit(1, bmap), "Page 1 incorrectly reported dirty"); - TEST_ASSERT(host_test_mem[4096 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 1 written by guest"); + TEST_ASSERT(host_test_mem[PAGE_SIZE / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 1 written by guest"); TEST_ASSERT(!test_bit(2, bmap), "Page 2 incorrectly reported dirty"); - TEST_ASSERT(host_test_mem[8192 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 2 written by guest"); + TEST_ASSERT(host_test_mem[PAGE_SIZE*2 / 8] == 0xaaaaaaaaaaaaaaaaULL, "Page 2 written by guest"); break; case UCALL_DONE: done = true; diff --git a/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c b/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c new file mode 100644 index 000000000000..cf1d2d1f2a8f --- /dev/null +++ b/tools/testing/selftests/kvm/x86/vmx_nested_la57_state_test.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025, Google LLC. + * + * Test KVM's ability to save and restore nested state when the L1 guest + * is using 5-level paging and the L2 guest is using 4-level paging. + * + * This test would have failed prior to commit 9245fd6b8531 ("KVM: x86: + * model canonical checks more precisely"). + */ +#include "test_util.h" +#include "kvm_util.h" +#include "processor.h" +#include "vmx.h" + +#define LA57_GS_BASE 0xff2bc0311fb00000ull + +static void l2_guest_code(void) +{ + /* + * Sync with L0 to trigger save/restore. After + * resuming, execute VMCALL to exit back to L1. + */ + GUEST_SYNC(1); + vmcall(); +} + +static void l1_guest_code(struct vmx_pages *vmx_pages) +{ +#define L2_GUEST_STACK_SIZE 64 + unsigned long l2_guest_stack[L2_GUEST_STACK_SIZE]; + u64 guest_cr4; + vm_paddr_t pml5_pa, pml4_pa; + u64 *pml5; + u64 exit_reason; + + /* Set GS_BASE to a value that is only canonical with LA57. */ + wrmsr(MSR_GS_BASE, LA57_GS_BASE); + GUEST_ASSERT(rdmsr(MSR_GS_BASE) == LA57_GS_BASE); + + GUEST_ASSERT(vmx_pages->vmcs_gpa); + GUEST_ASSERT(prepare_for_vmx_operation(vmx_pages)); + GUEST_ASSERT(load_vmcs(vmx_pages)); + + prepare_vmcs(vmx_pages, l2_guest_code, + &l2_guest_stack[L2_GUEST_STACK_SIZE]); + + /* + * Set up L2 with a 4-level page table by pointing its CR3 to + * L1's first PML4 table and clearing CR4.LA57. This creates + * the CR4.LA57 mismatch that exercises the bug. + */ + pml5_pa = get_cr3() & PHYSICAL_PAGE_MASK; + pml5 = (u64 *)pml5_pa; + pml4_pa = pml5[0] & PHYSICAL_PAGE_MASK; + vmwrite(GUEST_CR3, pml4_pa); + + guest_cr4 = vmreadz(GUEST_CR4); + guest_cr4 &= ~X86_CR4_LA57; + vmwrite(GUEST_CR4, guest_cr4); + + GUEST_ASSERT(!vmlaunch()); + + exit_reason = vmreadz(VM_EXIT_REASON); + GUEST_ASSERT(exit_reason == EXIT_REASON_VMCALL); +} + +void guest_code(struct vmx_pages *vmx_pages) +{ + l1_guest_code(vmx_pages); + GUEST_DONE(); +} + +int main(int argc, char *argv[]) +{ + vm_vaddr_t vmx_pages_gva = 0; + struct kvm_vm *vm; + struct kvm_vcpu *vcpu; + struct kvm_x86_state *state; + struct ucall uc; + int stage; + + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX)); + TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_LA57)); + TEST_REQUIRE(kvm_has_cap(KVM_CAP_NESTED_STATE)); + + vm = vm_create_with_one_vcpu(&vcpu, guest_code); + + /* + * L1 needs to read its own PML5 table to set up L2. Identity map + * the PML5 table to facilitate this. + */ + virt_map(vm, vm->pgd, vm->pgd, 1); + + vcpu_alloc_vmx(vm, &vmx_pages_gva); + vcpu_args_set(vcpu, 1, vmx_pages_gva); + + for (stage = 1;; stage++) { + vcpu_run(vcpu); + TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO); + + switch (get_ucall(vcpu, &uc)) { + case UCALL_ABORT: + REPORT_GUEST_ASSERT(uc); + /* NOT REACHED */ + case UCALL_SYNC: + break; + case UCALL_DONE: + goto done; + default: + TEST_FAIL("Unknown ucall %lu", uc.cmd); + } + + TEST_ASSERT(uc.args[1] == stage, + "Expected stage %d, got stage %lu", stage, (ulong)uc.args[1]); + if (stage == 1) { + pr_info("L2 is active; performing save/restore.\n"); + state = vcpu_save_state(vcpu); + + kvm_vm_release(vm); + + /* Restore state in a new VM. */ + vcpu = vm_recreate_with_one_vcpu(vm); + vcpu_load_state(vcpu, state); + kvm_x86_state_cleanup(state); + } + } + +done: + kvm_vm_free(vm); + return 0; +} diff --git a/tools/testing/selftests/kvm/x86/xapic_ipi_test.c b/tools/testing/selftests/kvm/x86/xapic_ipi_test.c index 35cb9de54a82..ae4a4b6c05ca 100644 --- a/tools/testing/selftests/kvm/x86/xapic_ipi_test.c +++ b/tools/testing/selftests/kvm/x86/xapic_ipi_test.c @@ -256,7 +256,7 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs, int nodes = 0; time_t start_time, last_update, now; time_t interval_secs = 1; - int i, r; + int i; int from, to; unsigned long bit; uint64_t hlt_count; @@ -267,9 +267,8 @@ void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs, delay_usecs); /* Get set of first 64 numa nodes available */ - r = get_mempolicy(NULL, &nodemask, sizeof(nodemask) * 8, + kvm_get_mempolicy(NULL, &nodemask, sizeof(nodemask) * 8, 0, MPOL_F_MEMS_ALLOWED); - TEST_ASSERT(r == 0, "get_mempolicy failed errno=%d", errno); fprintf(stderr, "Numa nodes found amongst first %lu possible nodes " "(each 1-bit indicates node is present): %#lx\n", diff --git a/tools/testing/selftests/landlock/Makefile b/tools/testing/selftests/landlock/Makefile index a3f449914bf9..044b83bde16e 100644 --- a/tools/testing/selftests/landlock/Makefile +++ b/tools/testing/selftests/landlock/Makefile @@ -4,7 +4,7 @@ CFLAGS += -Wall -O2 $(KHDR_INCLUDES) -LOCAL_HDRS += common.h +LOCAL_HDRS += $(wildcard *.h) src_test := $(wildcard *_test.c) diff --git a/tools/testing/selftests/landlock/audit.h b/tools/testing/selftests/landlock/audit.h index 02fd1393947a..44eb433e9666 100644 --- a/tools/testing/selftests/landlock/audit.h +++ b/tools/testing/selftests/landlock/audit.h @@ -20,7 +20,7 @@ #include <sys/time.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) diff --git a/tools/testing/selftests/landlock/common.h b/tools/testing/selftests/landlock/common.h index 9acecae36f51..230b75f6015b 100644 --- a/tools/testing/selftests/landlock/common.h +++ b/tools/testing/selftests/landlock/common.h @@ -17,7 +17,7 @@ #include <sys/wait.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "wrappers.h" #define TMP_DIR "tmp" diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index fa0f18ec62c4..eee814e09dd7 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -2267,6 +2267,22 @@ static int test_exchange(const char *const oldpath, const char *const newpath) return 0; } +static int test_renameat(int olddirfd, const char *oldpath, int newdirfd, + const char *newpath) +{ + if (renameat2(olddirfd, oldpath, newdirfd, newpath, 0)) + return errno; + return 0; +} + +static int test_exchangeat(int olddirfd, const char *oldpath, int newdirfd, + const char *newpath) +{ + if (renameat2(olddirfd, oldpath, newdirfd, newpath, RENAME_EXCHANGE)) + return errno; + return 0; +} + TEST_F_FORK(layout1, rename_file) { const struct rule rules[] = { @@ -4561,6 +4577,18 @@ TEST_F_FORK(ioctl, handle_file_access_file) FIXTURE(layout1_bind) {}; /* clang-format on */ +static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3"; +static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1"; + +/* Move targets for disconnected path tests. */ +static const char dir_s4d1[] = TMP_DIR "/s4d1"; +static const char file1_s4d1[] = TMP_DIR "/s4d1/f1"; +static const char file2_s4d1[] = TMP_DIR "/s4d1/f2"; +static const char dir_s4d2[] = TMP_DIR "/s4d1/s4d2"; +static const char file1_s4d2[] = TMP_DIR "/s4d1/s4d2/f1"; +static const char file1_name[] = "f1"; +static const char file2_name[] = "f2"; + FIXTURE_SETUP(layout1_bind) { prepare_layout(_metadata); @@ -4576,14 +4604,14 @@ FIXTURE_TEARDOWN_PARENT(layout1_bind) { /* umount(dir_s2d2)) is handled by namespace lifetime. */ + remove_path(file1_s4d1); + remove_path(file2_s4d1); + remove_layout1(_metadata); cleanup_layout(_metadata); } -static const char bind_dir_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3"; -static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1"; - /* * layout1_bind hierarchy: * @@ -4594,20 +4622,25 @@ static const char bind_file1_s1d3[] = TMP_DIR "/s2d1/s2d2/s1d3/f1"; * │ └── s1d2 * │ ├── f1 * │ ├── f2 - * │ └── s1d3 + * │ └── s1d3 [disconnected by path_disconnected] * │ ├── f1 * │ └── f2 * ├── s2d1 * │ ├── f1 - * │ └── s2d2 + * │ └── s2d2 [bind mount from s1d2] * │ ├── f1 * │ ├── f2 * │ └── s1d3 * │ ├── f1 * │ └── f2 - * └── s3d1 - * └── s3d2 - * └── s3d3 + * ├── s3d1 + * │ └── s3d2 + * │ └── s3d3 + * └── s4d1 [renamed from s1d3 by path_disconnected] + * ├── f1 + * ├── f2 + * └── s4d2 + * └── f1 */ TEST_F_FORK(layout1_bind, no_restriction) @@ -4806,6 +4839,1431 @@ TEST_F_FORK(layout1_bind, reparent_cross_mount) ASSERT_EQ(0, rename(bind_file1_s1d3, file1_s2d2)); } +/* + * Make sure access to file through a disconnected path works as expected. + * This test moves s1d3 to s4d1. + */ +TEST_F_FORK(layout1_bind, path_disconnected) +{ + const struct rule layer1_allow_all[] = { + { + .path = TMP_DIR, + .access = ACCESS_ALL, + }, + {}, + }; + const struct rule layer2_allow_just_f1[] = { + { + .path = file1_s1d3, + .access = LANDLOCK_ACCESS_FS_READ_FILE, + }, + {}, + }; + const struct rule layer3_only_s1d2[] = { + { + .path = dir_s1d2, + .access = LANDLOCK_ACCESS_FS_READ_FILE, + }, + {}, + }; + + /* Landlock should not deny access just because it is disconnected. */ + int ruleset_fd_l1 = + create_ruleset(_metadata, ACCESS_ALL, layer1_allow_all); + + /* Creates the new ruleset now before we move the dir containing the file. */ + int ruleset_fd_l2 = + create_ruleset(_metadata, ACCESS_RW, layer2_allow_just_f1); + int ruleset_fd_l3 = + create_ruleset(_metadata, ACCESS_RW, layer3_only_s1d2); + int bind_s1d3_fd; + + ASSERT_LE(0, ruleset_fd_l1); + ASSERT_LE(0, ruleset_fd_l2); + ASSERT_LE(0, ruleset_fd_l3); + + enforce_ruleset(_metadata, ruleset_fd_l1); + EXPECT_EQ(0, close(ruleset_fd_l1)); + + bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC); + ASSERT_LE(0, bind_s1d3_fd); + + /* Tests access is possible before we move. */ + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, "..", O_RDONLY | O_DIRECTORY)); + + /* Makes it disconnected. */ + ASSERT_EQ(0, rename(dir_s1d3, dir_s4d1)) + { + TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d1, + strerror(errno)); + } + + /* Tests that access is still possible. */ + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY)); + + /* + * Tests that ".." is not possible (not because of Landlock, but just + * because it's disconnected). + */ + EXPECT_EQ(ENOENT, + test_open_rel(bind_s1d3_fd, "..", O_RDONLY | O_DIRECTORY)); + + /* This should still work with a narrower rule. */ + enforce_ruleset(_metadata, ruleset_fd_l2); + EXPECT_EQ(0, close(ruleset_fd_l2)); + + EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY)); + /* + * Accessing a file through a disconnected file descriptor can still be + * allowed by a rule tied to this file, even if it is no longer visible in + * its mount point. + */ + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY)); + + enforce_ruleset(_metadata, ruleset_fd_l3); + EXPECT_EQ(0, close(ruleset_fd_l3)); + + EXPECT_EQ(EACCES, test_open(file1_s4d1, O_RDONLY)); + /* + * Accessing a file through a disconnected file descriptor can still be + * allowed by a rule tied to the original mount point, even if it is no + * longer visible in its mount point. + */ + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY)); +} + +/* + * Test that renameat with disconnected paths works under Landlock. This test + * moves s1d3 to s4d2, so that we can have a rule allowing refers on the move + * target's immediate parent. + */ +TEST_F_FORK(layout1_bind, path_disconnected_rename) +{ + const struct rule layer1[] = { + { + .path = dir_s1d2, + .access = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_READ_FILE, + }, + { + .path = dir_s4d1, + .access = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_MAKE_DIR | + LANDLOCK_ACCESS_FS_REMOVE_DIR | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_REMOVE_FILE | + LANDLOCK_ACCESS_FS_READ_FILE, + }, + {} + }; + + /* This layer only handles LANDLOCK_ACCESS_FS_READ_FILE. */ + const struct rule layer2_only_s1d2[] = { + { + .path = dir_s1d2, + .access = LANDLOCK_ACCESS_FS_READ_FILE, + }, + {}, + }; + int ruleset_fd_l1, ruleset_fd_l2; + pid_t child_pid; + int bind_s1d3_fd, status; + + ASSERT_EQ(0, mkdir(dir_s4d1, 0755)) + { + TH_LOG("Failed to create %s: %s", dir_s4d1, strerror(errno)); + } + ruleset_fd_l1 = create_ruleset(_metadata, ACCESS_ALL, layer1); + ruleset_fd_l2 = create_ruleset(_metadata, LANDLOCK_ACCESS_FS_READ_FILE, + layer2_only_s1d2); + ASSERT_LE(0, ruleset_fd_l1); + ASSERT_LE(0, ruleset_fd_l2); + + enforce_ruleset(_metadata, ruleset_fd_l1); + EXPECT_EQ(0, close(ruleset_fd_l1)); + + bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC); + ASSERT_LE(0, bind_s1d3_fd); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + + /* Tests ENOENT priority over EACCES for disconnected directory. */ + EXPECT_EQ(EACCES, test_open_rel(bind_s1d3_fd, "..", O_DIRECTORY)); + ASSERT_EQ(0, rename(dir_s1d3, dir_s4d2)) + { + TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d2, + strerror(errno)); + } + EXPECT_EQ(ENOENT, test_open_rel(bind_s1d3_fd, "..", O_DIRECTORY)); + + /* + * The file is no longer under s1d2 but we should still be able to access it + * with layer 2 because its mount point is evaluated as the first valid + * directory because it was initially a parent. Do a fork to test this so + * we don't prevent ourselves from renaming it back later. + */ + child_pid = fork(); + ASSERT_LE(0, child_pid); + if (child_pid == 0) { + enforce_ruleset(_metadata, ruleset_fd_l2); + EXPECT_EQ(0, close(ruleset_fd_l2)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(EACCES, test_open(file1_s4d2, O_RDONLY)); + + /* + * Tests that access widening checks indeed prevents us from renaming it + * back. + */ + EXPECT_EQ(-1, rename(dir_s4d2, dir_s1d3)); + EXPECT_EQ(EXDEV, errno); + + /* + * Including through the now disconnected fd (but it should return + * EXDEV). + */ + EXPECT_EQ(-1, renameat(bind_s1d3_fd, file1_name, AT_FDCWD, + file1_s2d2)); + EXPECT_EQ(EXDEV, errno); + _exit(_metadata->exit_code); + return; + } + + EXPECT_EQ(child_pid, waitpid(child_pid, &status, 0)); + EXPECT_EQ(1, WIFEXITED(status)); + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + + ASSERT_EQ(0, rename(dir_s4d2, dir_s1d3)) + { + TH_LOG("Failed to rename %s back to %s: %s", dir_s4d1, dir_s1d3, + strerror(errno)); + } + + /* Now checks that we can access it under l2. */ + child_pid = fork(); + ASSERT_LE(0, child_pid); + if (child_pid == 0) { + enforce_ruleset(_metadata, ruleset_fd_l2); + EXPECT_EQ(0, close(ruleset_fd_l2)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(0, test_open(file1_s1d3, O_RDONLY)); + _exit(_metadata->exit_code); + return; + } + + EXPECT_EQ(child_pid, waitpid(child_pid, &status, 0)); + EXPECT_EQ(1, WIFEXITED(status)); + EXPECT_EQ(EXIT_SUCCESS, WEXITSTATUS(status)); + + /* + * Also test that we can rename via a disconnected path. We move the + * dir back to the disconnected place first, then we rename file1 to + * file2 through our dir fd. + */ + ASSERT_EQ(0, rename(dir_s1d3, dir_s4d2)) + { + TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d2, + strerror(errno)); + } + ASSERT_EQ(0, + renameat(bind_s1d3_fd, file1_name, bind_s1d3_fd, file2_name)) + { + TH_LOG("Failed to rename %s to %s within disconnected %s: %s", + file1_name, file2_name, bind_dir_s1d3, strerror(errno)); + } + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file2_name, O_RDONLY)); + ASSERT_EQ(0, renameat(bind_s1d3_fd, file2_name, AT_FDCWD, file1_s2d2)) + { + TH_LOG("Failed to rename %s to %s through disconnected %s: %s", + file2_name, file1_s2d2, bind_dir_s1d3, strerror(errno)); + } + EXPECT_EQ(0, test_open(file1_s2d2, O_RDONLY)); + EXPECT_EQ(0, test_open(file1_s1d2, O_RDONLY)); + + /* Move it back using the disconnected path as the target. */ + ASSERT_EQ(0, renameat(AT_FDCWD, file1_s2d2, bind_s1d3_fd, file1_name)) + { + TH_LOG("Failed to rename %s to %s through disconnected %s: %s", + file1_s1d2, file1_name, bind_dir_s1d3, strerror(errno)); + } + + /* Now make it connected again. */ + ASSERT_EQ(0, rename(dir_s4d2, dir_s1d3)) + { + TH_LOG("Failed to rename %s back to %s: %s", dir_s4d2, dir_s1d3, + strerror(errno)); + } + + /* Checks again that we can access it under l2. */ + enforce_ruleset(_metadata, ruleset_fd_l2); + EXPECT_EQ(0, close(ruleset_fd_l2)); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + EXPECT_EQ(0, test_open(file1_s1d3, O_RDONLY)); +} + +/* + * Test that linkat(2) with disconnected paths works under Landlock. This + * test moves s1d3 to s4d1. + */ +TEST_F_FORK(layout1_bind, path_disconnected_link) +{ + /* Ruleset to be applied after renaming s1d3 to s4d1. */ + const struct rule layer1[] = { + { + .path = dir_s4d1, + .access = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_REMOVE_FILE, + }, + { + .path = dir_s2d2, + .access = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_REMOVE_FILE, + }, + {} + }; + int ruleset_fd, bind_s1d3_fd; + + /* Removes unneeded files created by layout1, otherwise it will EEXIST. */ + ASSERT_EQ(0, unlink(file1_s1d2)); + ASSERT_EQ(0, unlink(file2_s1d3)); + + bind_s1d3_fd = open(bind_dir_s1d3, O_PATH | O_CLOEXEC); + ASSERT_LE(0, bind_s1d3_fd); + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)); + + /* Disconnects bind_s1d3_fd. */ + ASSERT_EQ(0, rename(dir_s1d3, dir_s4d1)) + { + TH_LOG("Failed to rename %s to %s: %s", dir_s1d3, dir_s4d1, + strerror(errno)); + } + + /* Need this later to test different parent link. */ + ASSERT_EQ(0, mkdir(dir_s4d2, 0755)) + { + TH_LOG("Failed to create %s: %s", dir_s4d2, strerror(errno)); + } + + ruleset_fd = create_ruleset(_metadata, ACCESS_ALL, layer1); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + /* From disconnected to connected. */ + ASSERT_EQ(0, linkat(bind_s1d3_fd, file1_name, AT_FDCWD, file1_s2d2, 0)) + { + TH_LOG("Failed to link %s to %s via disconnected %s: %s", + file1_name, file1_s2d2, bind_dir_s1d3, strerror(errno)); + } + + /* Tests that we can access via the new link... */ + EXPECT_EQ(0, test_open(file1_s2d2, O_RDONLY)) + { + TH_LOG("Failed to open newly linked %s: %s", file1_s2d2, + strerror(errno)); + } + + /* ...as well as the old one. */ + EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY)) + { + TH_LOG("Failed to open original %s: %s", file1_s4d1, + strerror(errno)); + } + + /* From connected to disconnected. */ + ASSERT_EQ(0, unlink(file1_s4d1)); + ASSERT_EQ(0, linkat(AT_FDCWD, file1_s2d2, bind_s1d3_fd, file2_name, 0)) + { + TH_LOG("Failed to link %s to %s via disconnected %s: %s", + file1_s2d2, file2_name, bind_dir_s1d3, strerror(errno)); + } + EXPECT_EQ(0, test_open(file2_s4d1, O_RDONLY)); + ASSERT_EQ(0, unlink(file1_s2d2)); + + /* From disconnected to disconnected (same parent). */ + ASSERT_EQ(0, + linkat(bind_s1d3_fd, file2_name, bind_s1d3_fd, file1_name, 0)) + { + TH_LOG("Failed to link %s to %s within disconnected %s: %s", + file2_name, file1_name, bind_dir_s1d3, strerror(errno)); + } + EXPECT_EQ(0, test_open(file1_s4d1, O_RDONLY)) + { + TH_LOG("Failed to open newly linked %s: %s", file1_s4d1, + strerror(errno)); + } + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, file1_name, O_RDONLY)) + { + TH_LOG("Failed to open %s through newly created link under disconnected path: %s", + file1_name, strerror(errno)); + } + ASSERT_EQ(0, unlink(file2_s4d1)); + + /* From disconnected to disconnected (different parent). */ + ASSERT_EQ(0, + linkat(bind_s1d3_fd, file1_name, bind_s1d3_fd, "s4d2/f1", 0)) + { + TH_LOG("Failed to link %s to %s within disconnected %s: %s", + file1_name, "s4d2/f1", bind_dir_s1d3, strerror(errno)); + } + EXPECT_EQ(0, test_open(file1_s4d2, O_RDONLY)) + { + TH_LOG("Failed to open %s after link: %s", file1_s4d2, + strerror(errno)); + } + EXPECT_EQ(0, test_open_rel(bind_s1d3_fd, "s4d2/f1", O_RDONLY)) + { + TH_LOG("Failed to open %s through disconnected path after link: %s", + "s4d2/f1", strerror(errno)); + } +} + +/* + * layout4_disconnected_leafs with bind mount and renames: + * + * tmp + * ├── s1d1 + * │ └── s1d2 [source of the bind mount] + * │ ├── s1d31 + * │ │ └── s1d41 [now renamed beneath s3d1] + * │ │ ├── f1 + * │ │ └── f2 + * │ └── s1d32 + * │ └── s1d42 [now renamed beneath s4d1] + * │ ├── f3 + * │ └── f4 + * ├── s2d1 + * │ └── s2d2 [bind mount of s1d2] + * │ ├── s1d31 + * │ │ └── s1d41 [opened FD, now renamed beneath s3d1] + * │ │ ├── f1 + * │ │ └── f2 + * │ └── s1d32 + * │ └── s1d42 [opened FD, now renamed beneath s4d1] + * │ ├── f3 + * │ └── f4 + * ├── s3d1 + * │ └── s1d41 [renamed here] + * │ ├── f1 + * │ └── f2 + * └── s4d1 + * └── s1d42 [renamed here] + * ├── f3 + * └── f4 + */ +/* clang-format off */ +FIXTURE(layout4_disconnected_leafs) { + int s2d2_fd; +}; +/* clang-format on */ + +FIXTURE_SETUP(layout4_disconnected_leafs) +{ + prepare_layout(_metadata); + + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f1"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f2"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f3"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f4"); + create_directory(_metadata, TMP_DIR "/s2d1/s2d2"); + create_directory(_metadata, TMP_DIR "/s3d1"); + create_directory(_metadata, TMP_DIR "/s4d1"); + + self->s2d2_fd = + open(TMP_DIR "/s2d1/s2d2", O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, self->s2d2_fd); + + set_cap(_metadata, CAP_SYS_ADMIN); + ASSERT_EQ(0, mount(TMP_DIR "/s1d1/s1d2", TMP_DIR "/s2d1/s2d2", NULL, + MS_BIND, NULL)); + clear_cap(_metadata, CAP_SYS_ADMIN); +} + +FIXTURE_TEARDOWN_PARENT(layout4_disconnected_leafs) +{ + /* umount(TMP_DIR "/s2d1") is handled by namespace lifetime. */ + + /* Removes files after renames. */ + remove_path(TMP_DIR "/s3d1/s1d41/f1"); + remove_path(TMP_DIR "/s3d1/s1d41/f2"); + remove_path(TMP_DIR "/s4d1/s1d42/f1"); + remove_path(TMP_DIR "/s4d1/s1d42/f3"); + remove_path(TMP_DIR "/s4d1/s1d42/f4"); + remove_path(TMP_DIR "/s4d1/s1d42/f5"); + + cleanup_layout(_metadata); +} + +FIXTURE_VARIANT(layout4_disconnected_leafs) +{ + /* + * Parent of the bind mount source. It should always be ignored when + * testing against files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_s1d1; + /* + * Source of bind mount (to s2d2). It should always be enforced when + * testing against files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_s1d2; + /* + * Original parent of s1d41. It should always be ignored when testing + * against files under the s1d41 disconnected directory. + */ + const __u64 allowed_s1d31; + /* + * Original parent of s1d42. It should always be ignored when testing + * against files under the s1d42 disconnected directory. + */ + const __u64 allowed_s1d32; + /* + * Opened and disconnected source directory. It should always be enforced + * when testing against files under the s1d41 disconnected directory. + */ + const __u64 allowed_s1d41; + /* + * Opened and disconnected source directory. It should always be enforced + * when testing against files under the s1d42 disconnected directory. + */ + const __u64 allowed_s1d42; + /* + * File in the s1d41 disconnected directory. It should always be enforced + * when testing against itself under the s1d41 disconnected directory. + */ + const __u64 allowed_f1; + /* + * File in the s1d41 disconnected directory. It should always be enforced + * when testing against itself under the s1d41 disconnected directory. + */ + const __u64 allowed_f2; + /* + * File in the s1d42 disconnected directory. It should always be enforced + * when testing against itself under the s1d42 disconnected directory. + */ + const __u64 allowed_f3; + /* + * Parent of the bind mount destination. It should always be enforced when + * testing against files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_s2d1; + /* + * Directory covered by the bind mount. It should always be ignored when + * testing against files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_s2d2; + /* + * New parent of the renamed s1d41. It should always be ignored when + * testing against files under the s1d41 disconnected directory. + */ + const __u64 allowed_s3d1; + /* + * New parent of the renamed s1d42. It should always be ignored when + * testing against files under the s1d42 disconnected directory. + */ + const __u64 allowed_s4d1; + + /* Expected result of the call to open([fd:s1d41]/f1, O_RDONLY). */ + const int expected_read_result; + /* Expected result of the call to renameat([fd:s1d41]/f1, [fd:s1d42]/f1). */ + const int expected_rename_result; + /* + * Expected result of the call to renameat([fd:s1d41]/f2, [fd:s1d42]/f3, + * RENAME_EXCHANGE). + */ + const int expected_exchange_result; + /* Expected result of the call to renameat([fd:s1d42]/f4, [fd:s1d42]/f5). */ + const int expected_same_dir_rename_result; +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d1_mount_src_parent) { + /* clang-format on */ + .allowed_s1d1 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_refer) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_create) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d2_mount_src_rename) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d31_s1d32_old_parent) { + /* clang-format on */ + .allowed_s1d31 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s1d32 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_refer) { + /* clang-format on */ + .allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE, + .allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_create) { + /* clang-format on */ + .allowed_s1d41 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s1d42 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_even) { + /* clang-format on */ + .allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* The destination directory has more access right. */ +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_more) { + /* clang-format on */ + .allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_EXECUTE, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + /* Access denied. */ + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* The destination directory has less access right. */ +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s1d41_s1d42_disconnected_rename_less) { + /* clang-format on */ + .allowed_s1d41 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_EXECUTE, + .allowed_s1d42 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + /* Access allowed. */ + .expected_rename_result = 0, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_create) { + /* clang-format on */ + .allowed_s2d1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_refer) { + /* clang-format on */ + .allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d1_mount_dst_parent_mini) { + /* clang-format on */ + .allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s2d2_covered_by_mount) { + /* clang-format on */ + .allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* Tests collect_domain_accesses(). */ +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_new_parent_refer) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_new_parent_create) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s4d1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, + s3d1_s4d1_disconnected_rename_even){ + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* The destination directory has more access right. */ +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_disconnected_rename_more) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_EXECUTE, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + /* Access denied. */ + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* The destination directory has less access right. */ +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, s3d1_s4d1_disconnected_rename_less) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG | + LANDLOCK_ACCESS_FS_EXECUTE, + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + /* Access allowed. */ + .expected_rename_result = 0, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout4_disconnected_leafs, f1_f2_f3) { + /* clang-format on */ + .allowed_f1 = LANDLOCK_ACCESS_FS_READ_FILE, + .allowed_f2 = LANDLOCK_ACCESS_FS_READ_FILE, + .allowed_f3 = LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +TEST_F_FORK(layout4_disconnected_leafs, read_rename_exchange) +{ + const __u64 handled_access = + LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_MAKE_REG; + const struct rule rules[] = { + { + .path = TMP_DIR "/s1d1", + .access = variant->allowed_s1d1, + }, + { + .path = TMP_DIR "/s1d1/s1d2", + .access = variant->allowed_s1d2, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d31", + .access = variant->allowed_s1d31, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d32", + .access = variant->allowed_s1d32, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41", + .access = variant->allowed_s1d41, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d32/s1d42", + .access = variant->allowed_s1d42, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f1", + .access = variant->allowed_f1, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d31/s1d41/f2", + .access = variant->allowed_f2, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d32/s1d42/f3", + .access = variant->allowed_f3, + }, + { + .path = TMP_DIR "/s2d1", + .access = variant->allowed_s2d1, + }, + /* s2d2_fd */ + { + .path = TMP_DIR "/s3d1", + .access = variant->allowed_s3d1, + }, + { + .path = TMP_DIR "/s4d1", + .access = variant->allowed_s4d1, + }, + {}, + }; + int ruleset_fd, s1d41_bind_fd, s1d42_bind_fd; + + ruleset_fd = create_ruleset(_metadata, handled_access, rules); + ASSERT_LE(0, ruleset_fd); + + /* Adds rule for the covered directory. */ + if (variant->allowed_s2d2) { + ASSERT_EQ(0, landlock_add_rule( + ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, + &(struct landlock_path_beneath_attr){ + .parent_fd = self->s2d2_fd, + .allowed_access = + variant->allowed_s2d2, + }, + 0)); + } + EXPECT_EQ(0, close(self->s2d2_fd)); + + s1d41_bind_fd = open(TMP_DIR "/s2d1/s2d2/s1d31/s1d41", + O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, s1d41_bind_fd); + s1d42_bind_fd = open(TMP_DIR "/s2d1/s2d2/s1d32/s1d42", + O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, s1d42_bind_fd); + + /* Disconnects and checks source and destination directories. */ + EXPECT_EQ(0, test_open_rel(s1d41_bind_fd, "..", O_DIRECTORY)); + EXPECT_EQ(0, test_open_rel(s1d42_bind_fd, "..", O_DIRECTORY)); + /* Renames to make it accessible through s3d1/s1d41 */ + ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s1d1/s1d2/s1d31/s1d41", + AT_FDCWD, TMP_DIR "/s3d1/s1d41")); + /* Renames to make it accessible through s4d1/s1d42 */ + ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s1d1/s1d2/s1d32/s1d42", + AT_FDCWD, TMP_DIR "/s4d1/s1d42")); + EXPECT_EQ(ENOENT, test_open_rel(s1d41_bind_fd, "..", O_DIRECTORY)); + EXPECT_EQ(ENOENT, test_open_rel(s1d42_bind_fd, "..", O_DIRECTORY)); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + EXPECT_EQ(variant->expected_read_result, + test_open_rel(s1d41_bind_fd, "f1", O_RDONLY)); + + EXPECT_EQ(variant->expected_rename_result, + test_renameat(s1d41_bind_fd, "f1", s1d42_bind_fd, "f1")); + EXPECT_EQ(variant->expected_exchange_result, + test_exchangeat(s1d41_bind_fd, "f2", s1d42_bind_fd, "f3")); + + EXPECT_EQ(variant->expected_same_dir_rename_result, + test_renameat(s1d42_bind_fd, "f4", s1d42_bind_fd, "f5")); +} + +/* + * layout5_disconnected_branch before rename: + * + * tmp + * ├── s1d1 + * │ └── s1d2 [source of the first bind mount] + * │ └── s1d3 + * │ ├── s1d41 + * │ │ ├── f1 + * │ │ └── f2 + * │ └── s1d42 + * │ ├── f3 + * │ └── f4 + * ├── s2d1 + * │ └── s2d2 [source of the second bind mount] + * │ └── s2d3 + * │ └── s2d4 [first s1d2 bind mount] + * │ └── s1d3 + * │ ├── s1d41 + * │ │ ├── f1 + * │ │ └── f2 + * │ └── s1d42 + * │ ├── f3 + * │ └── f4 + * ├── s3d1 + * │ └── s3d2 [second s2d2 bind mount] + * │ └── s2d3 + * │ └── s2d4 [first s1d2 bind mount] + * │ └── s1d3 + * │ ├── s1d41 + * │ │ ├── f1 + * │ │ └── f2 + * │ └── s1d42 + * │ ├── f3 + * │ └── f4 + * └── s4d1 + * + * After rename: + * + * tmp + * ├── s1d1 + * │ └── s1d2 [source of the first bind mount] + * │ └── s1d3 + * │ ├── s1d41 + * │ │ ├── f1 + * │ │ └── f2 + * │ └── s1d42 + * │ ├── f3 + * │ └── f4 + * ├── s2d1 + * │ └── s2d2 [source of the second bind mount] + * ├── s3d1 + * │ └── s3d2 [second s2d2 bind mount] + * └── s4d1 + * └── s2d3 [renamed here] + * └── s2d4 [first s1d2 bind mount] + * └── s1d3 + * ├── s1d41 + * │ ├── f1 + * │ └── f2 + * └── s1d42 + * ├── f3 + * └── f4 + * + * Decision path for access from the s3d1/s3d2/s2d3/s2d4/s1d3 file descriptor: + * 1. first bind mount: s1d3 -> s1d2 + * 2. second bind mount: s2d3 + * 3. tmp mount: s4d1 -> tmp [disconnected branch] + * 4. second bind mount: s2d2 + * 5. tmp mount: s3d1 -> tmp + * 6. parent mounts: [...] -> / + * + * The s4d1 directory is evaluated even if it is not in the s2d2 mount. + */ + +/* clang-format off */ +FIXTURE(layout5_disconnected_branch) { + int s2d4_fd, s3d2_fd; +}; +/* clang-format on */ + +FIXTURE_SETUP(layout5_disconnected_branch) +{ + prepare_layout(_metadata); + + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f1"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f2"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f3"); + create_file(_metadata, TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f4"); + create_directory(_metadata, TMP_DIR "/s2d1/s2d2/s2d3/s2d4"); + create_directory(_metadata, TMP_DIR "/s3d1/s3d2"); + create_directory(_metadata, TMP_DIR "/s4d1"); + + self->s2d4_fd = open(TMP_DIR "/s2d1/s2d2/s2d3/s2d4", + O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, self->s2d4_fd); + + self->s3d2_fd = + open(TMP_DIR "/s3d1/s3d2", O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, self->s3d2_fd); + + set_cap(_metadata, CAP_SYS_ADMIN); + ASSERT_EQ(0, mount(TMP_DIR "/s1d1/s1d2", TMP_DIR "/s2d1/s2d2/s2d3/s2d4", + NULL, MS_BIND, NULL)); + ASSERT_EQ(0, mount(TMP_DIR "/s2d1/s2d2", TMP_DIR "/s3d1/s3d2", NULL, + MS_BIND | MS_REC, NULL)); + clear_cap(_metadata, CAP_SYS_ADMIN); +} + +FIXTURE_TEARDOWN_PARENT(layout5_disconnected_branch) +{ + /* Bind mounts are handled by namespace lifetime. */ + + /* Removes files after renames. */ + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f1"); + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d41/f2"); + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f1"); + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f3"); + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f4"); + remove_path(TMP_DIR "/s1d1/s1d2/s1d3/s1d42/f5"); + + cleanup_layout(_metadata); +} + +FIXTURE_VARIANT(layout5_disconnected_branch) +{ + /* + * Parent of all files. It should always be enforced when testing against + * files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_base; + /* + * Parent of the first bind mount source. It should always be ignored when + * testing against files under the s1d41 or s1d42 disconnected directories. + */ + const __u64 allowed_s1d1; + const __u64 allowed_s1d2; + const __u64 allowed_s1d3; + const __u64 allowed_s2d1; + const __u64 allowed_s2d2; + const __u64 allowed_s2d3; + const __u64 allowed_s2d4; + const __u64 allowed_s3d1; + const __u64 allowed_s3d2; + const __u64 allowed_s4d1; + + /* Expected result of the call to open([fd:s1d3]/s1d41/f1, O_RDONLY). */ + const int expected_read_result; + /* + * Expected result of the call to renameat([fd:s1d3]/s1d41/f1, + * [fd:s1d3]/s1d42/f1). + */ + const int expected_rename_result; + /* + * Expected result of the call to renameat([fd:s1d3]/s1d41/f2, + * [fd:s1d3]/s1d42/f3, RENAME_EXCHANGE). + */ + const int expected_exchange_result; + /* + * Expected result of the call to renameat([fd:s1d3]/s1d42/f4, + * [fd:s1d3]/s1d42/f5). + */ + const int expected_same_dir_rename_result; +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d1_mount1_src_parent) { + /* clang-format on */ + .allowed_s1d1 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_refer) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_create) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d2_mount1_src_rename) { + /* clang-format on */ + .allowed_s1d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_refer) { + /* clang-format on */ + .allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_create) { + /* clang-format on */ + .allowed_s1d3 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_rename) { + /* clang-format on */ + .allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s1d3_fd_full) { + /* clang-format on */ + .allowed_s1d3 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d1_mount2_src_parent) { + /* clang-format on */ + .allowed_s2d1 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_refer) { + /* clang-format on */ + .allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_create) { + /* clang-format on */ + .allowed_s2d2 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d2_mount2_src_rename) { + /* clang-format on */ + .allowed_s2d2 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_refer) { + /* clang-format on */ + .allowed_s2d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_create) { + /* clang-format on */ + .allowed_s2d3 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d3_mount1_dst_parent_rename) { + /* clang-format on */ + .allowed_s2d3 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s2d4_mount1_dst) { + /* clang-format on */ + .allowed_s2d4 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_refer) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_create) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d1_mount2_dst_parent_rename) { + /* clang-format on */ + .allowed_s3d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s3d2_mount1_dst) { + /* clang-format on */ + .allowed_s3d2 = LANDLOCK_ACCESS_FS_REFER | + LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_refer) { + /* clang-format on */ + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE, + .expected_read_result = 0, + .expected_same_dir_rename_result = EACCES, + .expected_rename_result = EACCES, + .expected_exchange_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_create) { + /* clang-format on */ + .allowed_s4d1 = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = 0, + .expected_same_dir_rename_result = 0, + .expected_rename_result = EXDEV, + .expected_exchange_result = EXDEV, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(layout5_disconnected_branch, s4d1_rename_parent_rename) { + /* clang-format on */ + .allowed_s4d1 = LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_MAKE_REG, + .expected_read_result = EACCES, + .expected_same_dir_rename_result = 0, + .expected_rename_result = 0, + .expected_exchange_result = 0, +}; + +TEST_F_FORK(layout5_disconnected_branch, read_rename_exchange) +{ + const __u64 handled_access = + LANDLOCK_ACCESS_FS_REFER | LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_MAKE_REG; + const struct rule rules[] = { + { + .path = TMP_DIR "/s1d1", + .access = variant->allowed_s1d1, + }, + { + .path = TMP_DIR "/s1d1/s1d2", + .access = variant->allowed_s1d2, + }, + { + .path = TMP_DIR "/s1d1/s1d2/s1d3", + .access = variant->allowed_s1d3, + }, + { + .path = TMP_DIR "/s2d1", + .access = variant->allowed_s2d1, + }, + { + .path = TMP_DIR "/s2d1/s2d2", + .access = variant->allowed_s2d2, + }, + { + .path = TMP_DIR "/s2d1/s2d2/s2d3", + .access = variant->allowed_s2d3, + }, + /* s2d4_fd */ + { + .path = TMP_DIR "/s3d1", + .access = variant->allowed_s3d1, + }, + /* s3d2_fd */ + { + .path = TMP_DIR "/s4d1", + .access = variant->allowed_s4d1, + }, + {}, + }; + int ruleset_fd, s1d3_bind_fd; + + ruleset_fd = create_ruleset(_metadata, handled_access, rules); + ASSERT_LE(0, ruleset_fd); + + /* Adds rules for the covered directories. */ + if (variant->allowed_s2d4) { + ASSERT_EQ(0, landlock_add_rule( + ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, + &(struct landlock_path_beneath_attr){ + .parent_fd = self->s2d4_fd, + .allowed_access = + variant->allowed_s2d4, + }, + 0)); + } + EXPECT_EQ(0, close(self->s2d4_fd)); + + if (variant->allowed_s3d2) { + ASSERT_EQ(0, landlock_add_rule( + ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, + &(struct landlock_path_beneath_attr){ + .parent_fd = self->s3d2_fd, + .allowed_access = + variant->allowed_s3d2, + }, + 0)); + } + EXPECT_EQ(0, close(self->s3d2_fd)); + + s1d3_bind_fd = open(TMP_DIR "/s3d1/s3d2/s2d3/s2d4/s1d3", + O_DIRECTORY | O_PATH | O_CLOEXEC); + ASSERT_LE(0, s1d3_bind_fd); + + /* Disconnects and checks source and destination directories. */ + EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "..", O_DIRECTORY)); + EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "../..", O_DIRECTORY)); + /* Renames to make it accessible through s3d1/s1d41 */ + ASSERT_EQ(0, test_renameat(AT_FDCWD, TMP_DIR "/s2d1/s2d2/s2d3", + AT_FDCWD, TMP_DIR "/s4d1/s2d3")); + EXPECT_EQ(0, test_open_rel(s1d3_bind_fd, "..", O_DIRECTORY)); + EXPECT_EQ(ENOENT, test_open_rel(s1d3_bind_fd, "../..", O_DIRECTORY)); + + enforce_ruleset(_metadata, ruleset_fd); + EXPECT_EQ(0, close(ruleset_fd)); + + EXPECT_EQ(variant->expected_read_result, + test_open_rel(s1d3_bind_fd, "s1d41/f1", O_RDONLY)); + + EXPECT_EQ(variant->expected_rename_result, + test_renameat(s1d3_bind_fd, "s1d41/f1", s1d3_bind_fd, + "s1d42/f1")); + EXPECT_EQ(variant->expected_exchange_result, + test_exchangeat(s1d3_bind_fd, "s1d41/f2", s1d3_bind_fd, + "s1d42/f3")); + + EXPECT_EQ(variant->expected_same_dir_rename_result, + test_renameat(s1d3_bind_fd, "s1d42/f4", s1d3_bind_fd, + "s1d42/f5")); +} + #define LOWER_BASE TMP_DIR "/lower" #define LOWER_DATA LOWER_BASE "/data" static const char lower_fl1[] = LOWER_DATA "/fl1"; diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk index a448fae57831..f02cc8a2e4ae 100644 --- a/tools/testing/selftests/lib.mk +++ b/tools/testing/selftests/lib.mk @@ -199,6 +199,9 @@ clean: $(if $(TEST_GEN_MODS_DIR),clean_mods_dir) # Build with _GNU_SOURCE by default CFLAGS += -D_GNU_SOURCE= +# Additional include paths needed by kselftest.h and local headers +CFLAGS += -I${top_srcdir}/tools/testing/selftests + # Enables to extend CFLAGS and LDFLAGS from command line, e.g. # make USERCFLAGS=-Werror USERLDFLAGS=-static CFLAGS += $(USERCFLAGS) diff --git a/tools/testing/selftests/liveupdate/.gitignore b/tools/testing/selftests/liveupdate/.gitignore new file mode 100644 index 000000000000..661827083ab6 --- /dev/null +++ b/tools/testing/selftests/liveupdate/.gitignore @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-only +* +!/**/ +!*.c +!*.h +!*.sh +!.gitignore +!config +!Makefile diff --git a/tools/testing/selftests/liveupdate/Makefile b/tools/testing/selftests/liveupdate/Makefile new file mode 100644 index 000000000000..080754787ede --- /dev/null +++ b/tools/testing/selftests/liveupdate/Makefile @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-only + +LIB_C += luo_test_utils.c + +TEST_GEN_PROGS += liveupdate + +TEST_GEN_PROGS_EXTENDED += luo_kexec_simple +TEST_GEN_PROGS_EXTENDED += luo_multi_session + +TEST_FILES += do_kexec.sh + +include ../lib.mk + +CFLAGS += $(KHDR_INCLUDES) +CFLAGS += -Wall -O2 -Wno-unused-function +CFLAGS += -MD + +LIB_O := $(patsubst %.c, $(OUTPUT)/%.o, $(LIB_C)) +TEST_O := $(patsubst %, %.o, $(TEST_GEN_PROGS)) +TEST_O += $(patsubst %, %.o, $(TEST_GEN_PROGS_EXTENDED)) + +TEST_DEP_FILES := $(patsubst %.o, %.d, $(LIB_O)) +TEST_DEP_FILES += $(patsubst %.o, %.d, $(TEST_O)) +-include $(TEST_DEP_FILES) + +$(LIB_O): $(OUTPUT)/%.o: %.c + $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $@ + +$(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/%: %.o $(LIB_O) + $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) $< $(LIB_O) $(LDLIBS) -o $@ + +EXTRA_CLEAN += $(LIB_O) +EXTRA_CLEAN += $(TEST_O) +EXTRA_CLEAN += $(TEST_DEP_FILES) diff --git a/tools/testing/selftests/liveupdate/config b/tools/testing/selftests/liveupdate/config new file mode 100644 index 000000000000..91d03f9a6a39 --- /dev/null +++ b/tools/testing/selftests/liveupdate/config @@ -0,0 +1,11 @@ +CONFIG_BLK_DEV_INITRD=y +CONFIG_KEXEC_FILE=y +CONFIG_KEXEC_HANDOVER=y +CONFIG_KEXEC_HANDOVER_ENABLE_DEFAULT=y +CONFIG_KEXEC_HANDOVER_DEBUGFS=y +CONFIG_KEXEC_HANDOVER_DEBUG=y +CONFIG_LIVEUPDATE=y +CONFIG_LIVEUPDATE_TEST=y +CONFIG_MEMFD_CREATE=y +CONFIG_TMPFS=y +CONFIG_SHMEM=y diff --git a/tools/testing/selftests/liveupdate/do_kexec.sh b/tools/testing/selftests/liveupdate/do_kexec.sh new file mode 100755 index 000000000000..3c7c6cafbef8 --- /dev/null +++ b/tools/testing/selftests/liveupdate/do_kexec.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +set -e + +# Use $KERNEL and $INITRAMFS to pass custom Kernel and optional initramfs + +KERNEL="${KERNEL:-/boot/bzImage}" +set -- -l -s --reuse-cmdline "$KERNEL" + +INITRAMFS="${INITRAMFS:-/boot/initramfs}" +if [ -f "$INITRAMFS" ]; then + set -- "$@" --initrd="$INITRAMFS" +fi + +kexec "$@" +kexec -e diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c new file mode 100644 index 000000000000..c2878e3d5ef9 --- /dev/null +++ b/tools/testing/selftests/liveupdate/liveupdate.c @@ -0,0 +1,348 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (c) 2025, Google LLC. + * Pasha Tatashin <pasha.tatashin@soleen.com> + */ + +/* + * Selftests for the Live Update Orchestrator. + * This test suite verifies the functionality and behavior of the + * /dev/liveupdate character device and its session management capabilities. + * + * Tests include: + * - Device access: basic open/close, and enforcement of exclusive access. + * - Session management: creation of unique sessions, and duplicate name detection. + * - Resource preservation: successfully preserving individual and multiple memfds, + * verifying contents remain accessible. + * - Complex multi-session scenarios involving mixed empty and populated files. + */ + +#include <errno.h> +#include <fcntl.h> +#include <string.h> +#include <sys/ioctl.h> +#include <unistd.h> + +#include <linux/liveupdate.h> + +#include "../kselftest.h" +#include "../kselftest_harness.h" + +#define LIVEUPDATE_DEV "/dev/liveupdate" + +FIXTURE(liveupdate_device) { + int fd1; + int fd2; +}; + +FIXTURE_SETUP(liveupdate_device) +{ + self->fd1 = -1; + self->fd2 = -1; +} + +FIXTURE_TEARDOWN(liveupdate_device) +{ + if (self->fd1 >= 0) + close(self->fd1); + if (self->fd2 >= 0) + close(self->fd2); +} + +/* + * Test Case: Basic Open and Close + * + * Verifies that the /dev/liveupdate device can be opened and subsequently + * closed without errors. Skips if the device does not exist. + */ +TEST_F(liveupdate_device, basic_open_close) +{ + self->fd1 = open(LIVEUPDATE_DEV, O_RDWR); + + if (self->fd1 < 0 && errno == ENOENT) + SKIP(return, "%s does not exist.", LIVEUPDATE_DEV); + + ASSERT_GE(self->fd1, 0); + ASSERT_EQ(close(self->fd1), 0); + self->fd1 = -1; +} + +/* + * Test Case: Exclusive Open Enforcement + * + * Verifies that the /dev/liveupdate device can only be opened by one process + * at a time. It checks that a second attempt to open the device fails with + * the EBUSY error code. + */ +TEST_F(liveupdate_device, exclusive_open) +{ + self->fd1 = open(LIVEUPDATE_DEV, O_RDWR); + + if (self->fd1 < 0 && errno == ENOENT) + SKIP(return, "%s does not exist.", LIVEUPDATE_DEV); + + ASSERT_GE(self->fd1, 0); + self->fd2 = open(LIVEUPDATE_DEV, O_RDWR); + EXPECT_LT(self->fd2, 0); + EXPECT_EQ(errno, EBUSY); +} + +/* Helper function to create a LUO session via ioctl. */ +static int create_session(int lu_fd, const char *name) +{ + struct liveupdate_ioctl_create_session args = {}; + + args.size = sizeof(args); + strncpy((char *)args.name, name, sizeof(args.name) - 1); + + if (ioctl(lu_fd, LIVEUPDATE_IOCTL_CREATE_SESSION, &args)) + return -errno; + + return args.fd; +} + +/* + * Test Case: Create Duplicate Session + * + * Verifies that attempting to create two sessions with the same name fails + * on the second attempt with EEXIST. + */ +TEST_F(liveupdate_device, create_duplicate_session) +{ + int session_fd1, session_fd2; + + self->fd1 = open(LIVEUPDATE_DEV, O_RDWR); + if (self->fd1 < 0 && errno == ENOENT) + SKIP(return, "%s does not exist", LIVEUPDATE_DEV); + + ASSERT_GE(self->fd1, 0); + + session_fd1 = create_session(self->fd1, "duplicate-session-test"); + ASSERT_GE(session_fd1, 0); + + session_fd2 = create_session(self->fd1, "duplicate-session-test"); + EXPECT_LT(session_fd2, 0); + EXPECT_EQ(-session_fd2, EEXIST); + + ASSERT_EQ(close(session_fd1), 0); +} + +/* + * Test Case: Create Distinct Sessions + * + * Verifies that creating two sessions with different names succeeds. + */ +TEST_F(liveupdate_device, create_distinct_sessions) +{ + int session_fd1, session_fd2; + + self->fd1 = open(LIVEUPDATE_DEV, O_RDWR); + if (self->fd1 < 0 && errno == ENOENT) + SKIP(return, "%s does not exist", LIVEUPDATE_DEV); + + ASSERT_GE(self->fd1, 0); + + session_fd1 = create_session(self->fd1, "distinct-session-1"); + ASSERT_GE(session_fd1, 0); + + session_fd2 = create_session(self->fd1, "distinct-session-2"); + ASSERT_GE(session_fd2, 0); + + ASSERT_EQ(close(session_fd1), 0); + ASSERT_EQ(close(session_fd2), 0); +} + +static int preserve_fd(int session_fd, int fd_to_preserve, __u64 token) +{ + struct liveupdate_session_preserve_fd args = {}; + + args.size = sizeof(args); + args.fd = fd_to_preserve; + args.token = token; + + if (ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &args)) + return -errno; + + return 0; +} + +/* + * Test Case: Preserve MemFD + * + * Verifies that a valid memfd can be successfully preserved in a session and + * that its contents remain intact after the preservation call. + */ +TEST_F(liveupdate_device, preserve_memfd) +{ + const char *test_str = "hello liveupdate"; + char read_buf[64] = {}; + int session_fd, mem_fd; + + self->fd1 = open(LIVEUPDATE_DEV, O_RDWR); + if (self->fd1 < 0 && errno == ENOENT) + SKIP(return, "%s does not exist", LIVEUPDATE_DEV); + ASSERT_GE(self->fd1, 0); + + session_fd = create_session(self->fd1, "preserve-memfd-test"); + ASSERT_GE(session_fd, 0); + + mem_fd = memfd_create("test-memfd", 0); + ASSERT_GE(mem_fd, 0); + + ASSERT_EQ(write(mem_fd, test_str, strlen(test_str)), strlen(test_str)); + ASSERT_EQ(preserve_fd(session_fd, mem_fd, 0x1234), 0); + ASSERT_EQ(close(session_fd), 0); + + ASSERT_EQ(lseek(mem_fd, 0, SEEK_SET), 0); + ASSERT_EQ(read(mem_fd, read_buf, sizeof(read_buf)), strlen(test_str)); + ASSERT_STREQ(read_buf, test_str); + ASSERT_EQ(close(mem_fd), 0); +} + +/* + * Test Case: Preserve Multiple MemFDs + * + * Verifies that multiple memfds can be preserved in a single session, + * each with a unique token, and that their contents remain distinct and + * correct after preservation. + */ +TEST_F(liveupdate_device, preserve_multiple_memfds) +{ + const char *test_str1 = "data for memfd one"; + const char *test_str2 = "data for memfd two"; + char read_buf[64] = {}; + int session_fd, mem_fd1, mem_fd2; + + self->fd1 = open(LIVEUPDATE_DEV, O_RDWR); + if (self->fd1 < 0 && errno == ENOENT) + SKIP(return, "%s does not exist", LIVEUPDATE_DEV); + ASSERT_GE(self->fd1, 0); + + session_fd = create_session(self->fd1, "preserve-multi-memfd-test"); + ASSERT_GE(session_fd, 0); + + mem_fd1 = memfd_create("test-memfd-1", 0); + ASSERT_GE(mem_fd1, 0); + mem_fd2 = memfd_create("test-memfd-2", 0); + ASSERT_GE(mem_fd2, 0); + + ASSERT_EQ(write(mem_fd1, test_str1, strlen(test_str1)), strlen(test_str1)); + ASSERT_EQ(write(mem_fd2, test_str2, strlen(test_str2)), strlen(test_str2)); + + ASSERT_EQ(preserve_fd(session_fd, mem_fd1, 0xAAAA), 0); + ASSERT_EQ(preserve_fd(session_fd, mem_fd2, 0xBBBB), 0); + + memset(read_buf, 0, sizeof(read_buf)); + ASSERT_EQ(lseek(mem_fd1, 0, SEEK_SET), 0); + ASSERT_EQ(read(mem_fd1, read_buf, sizeof(read_buf)), strlen(test_str1)); + ASSERT_STREQ(read_buf, test_str1); + + memset(read_buf, 0, sizeof(read_buf)); + ASSERT_EQ(lseek(mem_fd2, 0, SEEK_SET), 0); + ASSERT_EQ(read(mem_fd2, read_buf, sizeof(read_buf)), strlen(test_str2)); + ASSERT_STREQ(read_buf, test_str2); + + ASSERT_EQ(close(mem_fd1), 0); + ASSERT_EQ(close(mem_fd2), 0); + ASSERT_EQ(close(session_fd), 0); +} + +/* + * Test Case: Preserve Complex Scenario + * + * Verifies a more complex scenario with multiple sessions and a mix of empty + * and non-empty memfds distributed across them. + */ +TEST_F(liveupdate_device, preserve_complex_scenario) +{ + const char *data1 = "data for session 1"; + const char *data2 = "data for session 2"; + char read_buf[64] = {}; + int session_fd1, session_fd2; + int mem_fd_data1, mem_fd_empty1, mem_fd_data2, mem_fd_empty2; + + self->fd1 = open(LIVEUPDATE_DEV, O_RDWR); + if (self->fd1 < 0 && errno == ENOENT) + SKIP(return, "%s does not exist", LIVEUPDATE_DEV); + ASSERT_GE(self->fd1, 0); + + session_fd1 = create_session(self->fd1, "complex-session-1"); + ASSERT_GE(session_fd1, 0); + session_fd2 = create_session(self->fd1, "complex-session-2"); + ASSERT_GE(session_fd2, 0); + + mem_fd_data1 = memfd_create("data1", 0); + ASSERT_GE(mem_fd_data1, 0); + ASSERT_EQ(write(mem_fd_data1, data1, strlen(data1)), strlen(data1)); + + mem_fd_empty1 = memfd_create("empty1", 0); + ASSERT_GE(mem_fd_empty1, 0); + + mem_fd_data2 = memfd_create("data2", 0); + ASSERT_GE(mem_fd_data2, 0); + ASSERT_EQ(write(mem_fd_data2, data2, strlen(data2)), strlen(data2)); + + mem_fd_empty2 = memfd_create("empty2", 0); + ASSERT_GE(mem_fd_empty2, 0); + + ASSERT_EQ(preserve_fd(session_fd1, mem_fd_data1, 0x1111), 0); + ASSERT_EQ(preserve_fd(session_fd1, mem_fd_empty1, 0x2222), 0); + ASSERT_EQ(preserve_fd(session_fd2, mem_fd_data2, 0x3333), 0); + ASSERT_EQ(preserve_fd(session_fd2, mem_fd_empty2, 0x4444), 0); + + ASSERT_EQ(lseek(mem_fd_data1, 0, SEEK_SET), 0); + ASSERT_EQ(read(mem_fd_data1, read_buf, sizeof(read_buf)), strlen(data1)); + ASSERT_STREQ(read_buf, data1); + + memset(read_buf, 0, sizeof(read_buf)); + ASSERT_EQ(lseek(mem_fd_data2, 0, SEEK_SET), 0); + ASSERT_EQ(read(mem_fd_data2, read_buf, sizeof(read_buf)), strlen(data2)); + ASSERT_STREQ(read_buf, data2); + + ASSERT_EQ(lseek(mem_fd_empty1, 0, SEEK_SET), 0); + ASSERT_EQ(read(mem_fd_empty1, read_buf, sizeof(read_buf)), 0); + + ASSERT_EQ(lseek(mem_fd_empty2, 0, SEEK_SET), 0); + ASSERT_EQ(read(mem_fd_empty2, read_buf, sizeof(read_buf)), 0); + + ASSERT_EQ(close(mem_fd_data1), 0); + ASSERT_EQ(close(mem_fd_empty1), 0); + ASSERT_EQ(close(mem_fd_data2), 0); + ASSERT_EQ(close(mem_fd_empty2), 0); + ASSERT_EQ(close(session_fd1), 0); + ASSERT_EQ(close(session_fd2), 0); +} + +/* + * Test Case: Preserve Unsupported File Descriptor + * + * Verifies that attempting to preserve a file descriptor that does not have + * a registered Live Update handler fails gracefully. + * Uses /dev/null as a representative of a file type (character device) + * that is not supported by the orchestrator. + */ +TEST_F(liveupdate_device, preserve_unsupported_fd) +{ + int session_fd, unsupported_fd; + int ret; + + self->fd1 = open(LIVEUPDATE_DEV, O_RDWR); + if (self->fd1 < 0 && errno == ENOENT) + SKIP(return, "%s does not exist", LIVEUPDATE_DEV); + ASSERT_GE(self->fd1, 0); + + session_fd = create_session(self->fd1, "unsupported-fd-test"); + ASSERT_GE(session_fd, 0); + + unsupported_fd = open("/dev/null", O_RDWR); + ASSERT_GE(unsupported_fd, 0); + + ret = preserve_fd(session_fd, unsupported_fd, 0xDEAD); + EXPECT_EQ(ret, -ENOENT); + + ASSERT_EQ(close(unsupported_fd), 0); + ASSERT_EQ(close(session_fd), 0); +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/liveupdate/luo_kexec_simple.c b/tools/testing/selftests/liveupdate/luo_kexec_simple.c new file mode 100644 index 000000000000..d7ac1f3dc4cb --- /dev/null +++ b/tools/testing/selftests/liveupdate/luo_kexec_simple.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (c) 2025, Google LLC. + * Pasha Tatashin <pasha.tatashin@soleen.com> + * + * A simple selftest to validate the end-to-end lifecycle of a LUO session + * across a single kexec reboot. + */ + +#include "luo_test_utils.h" + +#define TEST_SESSION_NAME "test-session" +#define TEST_MEMFD_TOKEN 0x1A +#define TEST_MEMFD_DATA "hello kexec world" + +/* Constants for the state-tracking mechanism, specific to this test file. */ +#define STATE_SESSION_NAME "kexec_simple_state" +#define STATE_MEMFD_TOKEN 999 + +/* Stage 1: Executed before the kexec reboot. */ +static void run_stage_1(int luo_fd) +{ + int session_fd; + + ksft_print_msg("[STAGE 1] Starting pre-kexec setup...\n"); + + ksft_print_msg("[STAGE 1] Creating state file for next stage (2)...\n"); + create_state_file(luo_fd, STATE_SESSION_NAME, STATE_MEMFD_TOKEN, 2); + + ksft_print_msg("[STAGE 1] Creating session '%s' and preserving memfd...\n", + TEST_SESSION_NAME); + session_fd = luo_create_session(luo_fd, TEST_SESSION_NAME); + if (session_fd < 0) + fail_exit("luo_create_session for '%s'", TEST_SESSION_NAME); + + if (create_and_preserve_memfd(session_fd, TEST_MEMFD_TOKEN, + TEST_MEMFD_DATA) < 0) { + fail_exit("create_and_preserve_memfd for token %#x", + TEST_MEMFD_TOKEN); + } + + close(luo_fd); + daemonize_and_wait(); +} + +/* Stage 2: Executed after the kexec reboot. */ +static void run_stage_2(int luo_fd, int state_session_fd) +{ + int session_fd, mfd, stage; + + ksft_print_msg("[STAGE 2] Starting post-kexec verification...\n"); + + restore_and_read_stage(state_session_fd, STATE_MEMFD_TOKEN, &stage); + if (stage != 2) + fail_exit("Expected stage 2, but state file contains %d", stage); + + ksft_print_msg("[STAGE 2] Retrieving session '%s'...\n", TEST_SESSION_NAME); + session_fd = luo_retrieve_session(luo_fd, TEST_SESSION_NAME); + if (session_fd < 0) + fail_exit("luo_retrieve_session for '%s'", TEST_SESSION_NAME); + + ksft_print_msg("[STAGE 2] Restoring and verifying memfd (token %#x)...\n", + TEST_MEMFD_TOKEN); + mfd = restore_and_verify_memfd(session_fd, TEST_MEMFD_TOKEN, + TEST_MEMFD_DATA); + if (mfd < 0) + fail_exit("restore_and_verify_memfd for token %#x", TEST_MEMFD_TOKEN); + close(mfd); + + ksft_print_msg("[STAGE 2] Test data verified successfully.\n"); + ksft_print_msg("[STAGE 2] Finalizing test session...\n"); + if (luo_session_finish(session_fd) < 0) + fail_exit("luo_session_finish for test session"); + close(session_fd); + + ksft_print_msg("[STAGE 2] Finalizing state session...\n"); + if (luo_session_finish(state_session_fd) < 0) + fail_exit("luo_session_finish for state session"); + close(state_session_fd); + + ksft_print_msg("\n--- SIMPLE KEXEC TEST PASSED ---\n"); +} + +int main(int argc, char *argv[]) +{ + return luo_test(argc, argv, STATE_SESSION_NAME, + run_stage_1, run_stage_2); +} diff --git a/tools/testing/selftests/liveupdate/luo_multi_session.c b/tools/testing/selftests/liveupdate/luo_multi_session.c new file mode 100644 index 000000000000..0ee2d795beef --- /dev/null +++ b/tools/testing/selftests/liveupdate/luo_multi_session.c @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (c) 2025, Google LLC. + * Pasha Tatashin <pasha.tatashin@soleen.com> + * + * A selftest to validate the end-to-end lifecycle of multiple LUO sessions + * across a kexec reboot, including empty sessions and sessions with multiple + * files. + */ + +#include "luo_test_utils.h" + +#define SESSION_EMPTY_1 "multi-test-empty-1" +#define SESSION_EMPTY_2 "multi-test-empty-2" +#define SESSION_FILES_1 "multi-test-files-1" +#define SESSION_FILES_2 "multi-test-files-2" + +#define MFD1_TOKEN 0x1001 +#define MFD2_TOKEN 0x2002 +#define MFD3_TOKEN 0x3003 + +#define MFD1_DATA "Data for session files 1" +#define MFD2_DATA "First file for session files 2" +#define MFD3_DATA "Second file for session files 2" + +#define STATE_SESSION_NAME "kexec_multi_state" +#define STATE_MEMFD_TOKEN 998 + +/* Stage 1: Executed before the kexec reboot. */ +static void run_stage_1(int luo_fd) +{ + int s_empty1_fd, s_empty2_fd, s_files1_fd, s_files2_fd; + + ksft_print_msg("[STAGE 1] Starting pre-kexec setup for multi-session test...\n"); + + ksft_print_msg("[STAGE 1] Creating state file for next stage (2)...\n"); + create_state_file(luo_fd, STATE_SESSION_NAME, STATE_MEMFD_TOKEN, 2); + + ksft_print_msg("[STAGE 1] Creating empty sessions '%s' and '%s'...\n", + SESSION_EMPTY_1, SESSION_EMPTY_2); + s_empty1_fd = luo_create_session(luo_fd, SESSION_EMPTY_1); + if (s_empty1_fd < 0) + fail_exit("luo_create_session for '%s'", SESSION_EMPTY_1); + + s_empty2_fd = luo_create_session(luo_fd, SESSION_EMPTY_2); + if (s_empty2_fd < 0) + fail_exit("luo_create_session for '%s'", SESSION_EMPTY_2); + + ksft_print_msg("[STAGE 1] Creating session '%s' with one memfd...\n", + SESSION_FILES_1); + + s_files1_fd = luo_create_session(luo_fd, SESSION_FILES_1); + if (s_files1_fd < 0) + fail_exit("luo_create_session for '%s'", SESSION_FILES_1); + if (create_and_preserve_memfd(s_files1_fd, MFD1_TOKEN, MFD1_DATA) < 0) { + fail_exit("create_and_preserve_memfd for token %#x", + MFD1_TOKEN); + } + + ksft_print_msg("[STAGE 1] Creating session '%s' with two memfds...\n", + SESSION_FILES_2); + + s_files2_fd = luo_create_session(luo_fd, SESSION_FILES_2); + if (s_files2_fd < 0) + fail_exit("luo_create_session for '%s'", SESSION_FILES_2); + if (create_and_preserve_memfd(s_files2_fd, MFD2_TOKEN, MFD2_DATA) < 0) { + fail_exit("create_and_preserve_memfd for token %#x", + MFD2_TOKEN); + } + if (create_and_preserve_memfd(s_files2_fd, MFD3_TOKEN, MFD3_DATA) < 0) { + fail_exit("create_and_preserve_memfd for token %#x", + MFD3_TOKEN); + } + + close(luo_fd); + daemonize_and_wait(); +} + +/* Stage 2: Executed after the kexec reboot. */ +static void run_stage_2(int luo_fd, int state_session_fd) +{ + int s_empty1_fd, s_empty2_fd, s_files1_fd, s_files2_fd; + int mfd1, mfd2, mfd3, stage; + + ksft_print_msg("[STAGE 2] Starting post-kexec verification...\n"); + + restore_and_read_stage(state_session_fd, STATE_MEMFD_TOKEN, &stage); + if (stage != 2) { + fail_exit("Expected stage 2, but state file contains %d", + stage); + } + + ksft_print_msg("[STAGE 2] Retrieving all sessions...\n"); + s_empty1_fd = luo_retrieve_session(luo_fd, SESSION_EMPTY_1); + if (s_empty1_fd < 0) + fail_exit("luo_retrieve_session for '%s'", SESSION_EMPTY_1); + + s_empty2_fd = luo_retrieve_session(luo_fd, SESSION_EMPTY_2); + if (s_empty2_fd < 0) + fail_exit("luo_retrieve_session for '%s'", SESSION_EMPTY_2); + + s_files1_fd = luo_retrieve_session(luo_fd, SESSION_FILES_1); + if (s_files1_fd < 0) + fail_exit("luo_retrieve_session for '%s'", SESSION_FILES_1); + + s_files2_fd = luo_retrieve_session(luo_fd, SESSION_FILES_2); + if (s_files2_fd < 0) + fail_exit("luo_retrieve_session for '%s'", SESSION_FILES_2); + + ksft_print_msg("[STAGE 2] Verifying contents of session '%s'...\n", + SESSION_FILES_1); + mfd1 = restore_and_verify_memfd(s_files1_fd, MFD1_TOKEN, MFD1_DATA); + if (mfd1 < 0) + fail_exit("restore_and_verify_memfd for token %#x", MFD1_TOKEN); + close(mfd1); + + ksft_print_msg("[STAGE 2] Verifying contents of session '%s'...\n", + SESSION_FILES_2); + + mfd2 = restore_and_verify_memfd(s_files2_fd, MFD2_TOKEN, MFD2_DATA); + if (mfd2 < 0) + fail_exit("restore_and_verify_memfd for token %#x", MFD2_TOKEN); + close(mfd2); + + mfd3 = restore_and_verify_memfd(s_files2_fd, MFD3_TOKEN, MFD3_DATA); + if (mfd3 < 0) + fail_exit("restore_and_verify_memfd for token %#x", MFD3_TOKEN); + close(mfd3); + + ksft_print_msg("[STAGE 2] Test data verified successfully.\n"); + + ksft_print_msg("[STAGE 2] Finalizing all test sessions...\n"); + if (luo_session_finish(s_empty1_fd) < 0) + fail_exit("luo_session_finish for '%s'", SESSION_EMPTY_1); + close(s_empty1_fd); + + if (luo_session_finish(s_empty2_fd) < 0) + fail_exit("luo_session_finish for '%s'", SESSION_EMPTY_2); + close(s_empty2_fd); + + if (luo_session_finish(s_files1_fd) < 0) + fail_exit("luo_session_finish for '%s'", SESSION_FILES_1); + close(s_files1_fd); + + if (luo_session_finish(s_files2_fd) < 0) + fail_exit("luo_session_finish for '%s'", SESSION_FILES_2); + close(s_files2_fd); + + ksft_print_msg("[STAGE 2] Finalizing state session...\n"); + if (luo_session_finish(state_session_fd) < 0) + fail_exit("luo_session_finish for state session"); + close(state_session_fd); + + ksft_print_msg("\n--- MULTI-SESSION KEXEC TEST PASSED ---\n"); +} + +int main(int argc, char *argv[]) +{ + return luo_test(argc, argv, STATE_SESSION_NAME, + run_stage_1, run_stage_2); +} diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.c b/tools/testing/selftests/liveupdate/luo_test_utils.c new file mode 100644 index 000000000000..3c8721c505df --- /dev/null +++ b/tools/testing/selftests/liveupdate/luo_test_utils.c @@ -0,0 +1,266 @@ +// SPDX-License-Identifier: GPL-2.0-only + +/* + * Copyright (c) 2025, Google LLC. + * Pasha Tatashin <pasha.tatashin@soleen.com> + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/syscall.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdarg.h> + +#include "luo_test_utils.h" + +int luo_open_device(void) +{ + return open(LUO_DEVICE, O_RDWR); +} + +int luo_create_session(int luo_fd, const char *name) +{ + struct liveupdate_ioctl_create_session arg = { .size = sizeof(arg) }; + + snprintf((char *)arg.name, LIVEUPDATE_SESSION_NAME_LENGTH, "%.*s", + LIVEUPDATE_SESSION_NAME_LENGTH - 1, name); + + if (ioctl(luo_fd, LIVEUPDATE_IOCTL_CREATE_SESSION, &arg) < 0) + return -errno; + + return arg.fd; +} + +int luo_retrieve_session(int luo_fd, const char *name) +{ + struct liveupdate_ioctl_retrieve_session arg = { .size = sizeof(arg) }; + + snprintf((char *)arg.name, LIVEUPDATE_SESSION_NAME_LENGTH, "%.*s", + LIVEUPDATE_SESSION_NAME_LENGTH - 1, name); + + if (ioctl(luo_fd, LIVEUPDATE_IOCTL_RETRIEVE_SESSION, &arg) < 0) + return -errno; + + return arg.fd; +} + +int create_and_preserve_memfd(int session_fd, int token, const char *data) +{ + struct liveupdate_session_preserve_fd arg = { .size = sizeof(arg) }; + long page_size = sysconf(_SC_PAGE_SIZE); + void *map = MAP_FAILED; + int mfd = -1, ret = -1; + + mfd = memfd_create("test_mfd", 0); + if (mfd < 0) + return -errno; + + if (ftruncate(mfd, page_size) != 0) + goto out; + + map = mmap(NULL, page_size, PROT_WRITE, MAP_SHARED, mfd, 0); + if (map == MAP_FAILED) + goto out; + + snprintf(map, page_size, "%s", data); + munmap(map, page_size); + + arg.fd = mfd; + arg.token = token; + if (ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &arg) < 0) + goto out; + + ret = 0; +out: + if (ret != 0 && errno != 0) + ret = -errno; + if (mfd >= 0) + close(mfd); + return ret; +} + +int restore_and_verify_memfd(int session_fd, int token, + const char *expected_data) +{ + struct liveupdate_session_retrieve_fd arg = { .size = sizeof(arg) }; + long page_size = sysconf(_SC_PAGE_SIZE); + void *map = MAP_FAILED; + int mfd = -1, ret = -1; + + arg.token = token; + if (ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg) < 0) + return -errno; + mfd = arg.fd; + + map = mmap(NULL, page_size, PROT_READ, MAP_SHARED, mfd, 0); + if (map == MAP_FAILED) + goto out; + + if (expected_data && strcmp(expected_data, map) != 0) { + ksft_print_msg("Data mismatch! Expected '%s', Got '%s'\n", + expected_data, (char *)map); + ret = -EINVAL; + goto out_munmap; + } + + ret = mfd; +out_munmap: + munmap(map, page_size); +out: + if (ret < 0 && errno != 0) + ret = -errno; + if (ret < 0 && mfd >= 0) + close(mfd); + return ret; +} + +int luo_session_finish(int session_fd) +{ + struct liveupdate_session_finish arg = { .size = sizeof(arg) }; + + if (ioctl(session_fd, LIVEUPDATE_SESSION_FINISH, &arg) < 0) + return -errno; + + return 0; +} + +void create_state_file(int luo_fd, const char *session_name, int token, + int next_stage) +{ + char buf[32]; + int state_session_fd; + + state_session_fd = luo_create_session(luo_fd, session_name); + if (state_session_fd < 0) + fail_exit("luo_create_session for state tracking"); + + snprintf(buf, sizeof(buf), "%d", next_stage); + if (create_and_preserve_memfd(state_session_fd, token, buf) < 0) + fail_exit("create_and_preserve_memfd for state tracking"); + + /* + * DO NOT close session FD, otherwise it is going to be unpreserved + */ +} + +void restore_and_read_stage(int state_session_fd, int token, int *stage) +{ + char buf[32] = {0}; + int mfd; + + mfd = restore_and_verify_memfd(state_session_fd, token, NULL); + if (mfd < 0) + fail_exit("failed to restore state memfd"); + + if (read(mfd, buf, sizeof(buf) - 1) < 0) + fail_exit("failed to read state mfd"); + + *stage = atoi(buf); + + close(mfd); +} + +void daemonize_and_wait(void) +{ + pid_t pid; + + ksft_print_msg("[STAGE 1] Forking persistent child to hold sessions...\n"); + + pid = fork(); + if (pid < 0) + fail_exit("fork failed"); + + if (pid > 0) { + ksft_print_msg("[STAGE 1] Child PID: %d. Resources are pinned.\n", pid); + ksft_print_msg("[STAGE 1] You may now perform kexec reboot.\n"); + exit(EXIT_SUCCESS); + } + + /* Detach from terminal so closing the window doesn't kill us */ + if (setsid() < 0) + fail_exit("setsid failed"); + + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + /* Change dir to root to avoid locking filesystems */ + if (chdir("/") < 0) + exit(EXIT_FAILURE); + + while (1) + sleep(60); +} + +static int parse_stage_args(int argc, char *argv[]) +{ + static struct option long_options[] = { + {"stage", required_argument, 0, 's'}, + {0, 0, 0, 0} + }; + int option_index = 0; + int stage = 1; + int opt; + + optind = 1; + while ((opt = getopt_long(argc, argv, "s:", long_options, &option_index)) != -1) { + switch (opt) { + case 's': + stage = atoi(optarg); + if (stage != 1 && stage != 2) + fail_exit("Invalid stage argument"); + break; + default: + fail_exit("Unknown argument"); + } + } + return stage; +} + +int luo_test(int argc, char *argv[], + const char *state_session_name, + luo_test_stage1_fn stage1, + luo_test_stage2_fn stage2) +{ + int target_stage = parse_stage_args(argc, argv); + int luo_fd = luo_open_device(); + int state_session_fd; + int detected_stage; + + if (luo_fd < 0) { + ksft_exit_skip("Failed to open %s. Is the luo module loaded?\n", + LUO_DEVICE); + } + + state_session_fd = luo_retrieve_session(luo_fd, state_session_name); + if (state_session_fd == -ENOENT) + detected_stage = 1; + else if (state_session_fd >= 0) + detected_stage = 2; + else + fail_exit("Failed to check for state session"); + + if (target_stage != detected_stage) { + ksft_exit_fail_msg("Stage mismatch Requested --stage %d, but system is in stage %d.\n" + "(State session %s: %s)\n", + target_stage, detected_stage, state_session_name, + (detected_stage == 2) ? "EXISTS" : "MISSING"); + } + + if (target_stage == 1) + stage1(luo_fd); + else + stage2(luo_fd, state_session_fd); + + return 0; +} diff --git a/tools/testing/selftests/liveupdate/luo_test_utils.h b/tools/testing/selftests/liveupdate/luo_test_utils.h new file mode 100644 index 000000000000..90099bf49577 --- /dev/null +++ b/tools/testing/selftests/liveupdate/luo_test_utils.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2025, Google LLC. + * Pasha Tatashin <pasha.tatashin@soleen.com> + * + * Utility functions for LUO kselftests. + */ + +#ifndef LUO_TEST_UTILS_H +#define LUO_TEST_UTILS_H + +#include <errno.h> +#include <string.h> +#include <linux/liveupdate.h> +#include "../kselftest.h" + +#define LUO_DEVICE "/dev/liveupdate" + +#define fail_exit(fmt, ...) \ + ksft_exit_fail_msg("[%s:%d] " fmt " (errno: %s)\n", \ + __func__, __LINE__, ##__VA_ARGS__, strerror(errno)) + +int luo_open_device(void); +int luo_create_session(int luo_fd, const char *name); +int luo_retrieve_session(int luo_fd, const char *name); +int luo_session_finish(int session_fd); + +int create_and_preserve_memfd(int session_fd, int token, const char *data); +int restore_and_verify_memfd(int session_fd, int token, const char *expected_data); + +void create_state_file(int luo_fd, const char *session_name, int token, + int next_stage); +void restore_and_read_stage(int state_session_fd, int token, int *stage); + +void daemonize_and_wait(void); + +typedef void (*luo_test_stage1_fn)(int luo_fd); +typedef void (*luo_test_stage2_fn)(int luo_fd, int state_session_fd); + +int luo_test(int argc, char *argv[], const char *state_session_name, + luo_test_stage1_fn stage1, luo_test_stage2_fn stage2); + +#endif /* LUO_TEST_UTILS_H */ diff --git a/tools/testing/selftests/lsm/lsm_get_self_attr_test.c b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c index df215e4aa63f..60caf8528f81 100644 --- a/tools/testing/selftests/lsm/lsm_get_self_attr_test.c +++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c @@ -13,7 +13,7 @@ #include <stdio.h> #include <unistd.h> #include <sys/types.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "common.h" static struct lsm_ctx *next_ctx(struct lsm_ctx *ctxp) diff --git a/tools/testing/selftests/lsm/lsm_list_modules_test.c b/tools/testing/selftests/lsm/lsm_list_modules_test.c index 1cc8a977c711..54d59044ace1 100644 --- a/tools/testing/selftests/lsm/lsm_list_modules_test.c +++ b/tools/testing/selftests/lsm/lsm_list_modules_test.c @@ -12,7 +12,7 @@ #include <stdio.h> #include <unistd.h> #include <sys/types.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "common.h" TEST(size_null_lsm_list_modules) diff --git a/tools/testing/selftests/lsm/lsm_set_self_attr_test.c b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c index 732e89fe99c0..dcb6f8aa772e 100644 --- a/tools/testing/selftests/lsm/lsm_set_self_attr_test.c +++ b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c @@ -12,7 +12,7 @@ #include <stdio.h> #include <unistd.h> #include <sys/types.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "common.h" TEST(ctx_null_lsm_set_self_attr) diff --git a/tools/testing/selftests/media_tests/media_device_open.c b/tools/testing/selftests/media_tests/media_device_open.c index 93183a37b133..4396bf2273a4 100644 --- a/tools/testing/selftests/media_tests/media_device_open.c +++ b/tools/testing/selftests/media_tests/media_device_open.c @@ -34,7 +34,7 @@ #include <sys/stat.h> #include <linux/media.h> -#include "../kselftest.h" +#include "kselftest.h" int main(int argc, char **argv) { diff --git a/tools/testing/selftests/media_tests/media_device_test.c b/tools/testing/selftests/media_tests/media_device_test.c index 4b9953359e40..6e4a8090a0eb 100644 --- a/tools/testing/selftests/media_tests/media_device_test.c +++ b/tools/testing/selftests/media_tests/media_device_test.c @@ -39,7 +39,7 @@ #include <time.h> #include <linux/media.h> -#include "../kselftest.h" +#include "kselftest.h" int main(int argc, char **argv) { diff --git a/tools/testing/selftests/membarrier/membarrier_test_impl.h b/tools/testing/selftests/membarrier/membarrier_test_impl.h index af89855adb7b..f6d7c44b2288 100644 --- a/tools/testing/selftests/membarrier/membarrier_test_impl.h +++ b/tools/testing/selftests/membarrier/membarrier_test_impl.h @@ -7,7 +7,7 @@ #include <string.h> #include <pthread.h> -#include "../kselftest.h" +#include "kselftest.h" static int registrations; diff --git a/tools/testing/selftests/mincore/mincore_selftest.c b/tools/testing/selftests/mincore/mincore_selftest.c index 17ed3e9917ca..cdd022c1c497 100644 --- a/tools/testing/selftests/mincore/mincore_selftest.c +++ b/tools/testing/selftests/mincore/mincore_selftest.c @@ -15,8 +15,8 @@ #include <string.h> #include <fcntl.h> -#include "../kselftest.h" -#include "../kselftest_harness.h" +#include "kselftest.h" +#include "kselftest_harness.h" /* Default test file size: 4MB */ #define MB (1UL << 20) diff --git a/tools/testing/selftests/mm/compaction_test.c b/tools/testing/selftests/mm/compaction_test.c index 9bc4591c7b16..30209c40b697 100644 --- a/tools/testing/selftests/mm/compaction_test.c +++ b/tools/testing/selftests/mm/compaction_test.c @@ -16,7 +16,7 @@ #include <unistd.h> #include <string.h> -#include "../kselftest.h" +#include "kselftest.h" #define MAP_SIZE_MB 100 #define MAP_SIZE (MAP_SIZE_MB * 1024 * 1024) diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c index 6560c26f47d1..accfd198dbda 100644 --- a/tools/testing/selftests/mm/cow.c +++ b/tools/testing/selftests/mm/cow.c @@ -27,7 +27,7 @@ #endif /* LOCAL_CONFIG_HAVE_LIBURING */ #include "../../../../mm/gup_test.h" -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" #include "thp_settings.h" diff --git a/tools/testing/selftests/mm/droppable.c b/tools/testing/selftests/mm/droppable.c index f3d9ecf96890..44940f75c461 100644 --- a/tools/testing/selftests/mm/droppable.c +++ b/tools/testing/selftests/mm/droppable.c @@ -13,7 +13,7 @@ #include <sys/mman.h> #include <linux/mman.h> -#include "../kselftest.h" +#include "kselftest.h" int main(int argc, char *argv[]) { diff --git a/tools/testing/selftests/mm/guard-regions.c b/tools/testing/selftests/mm/guard-regions.c index 795bf3f39f44..dbd21d66d383 100644 --- a/tools/testing/selftests/mm/guard-regions.c +++ b/tools/testing/selftests/mm/guard-regions.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #define _GNU_SOURCE -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <asm-generic/mman.h> /* Force the import of the tools version. */ #include <assert.h> #include <errno.h> diff --git a/tools/testing/selftests/mm/gup_longterm.c b/tools/testing/selftests/mm/gup_longterm.c index 268dadb8ce43..6279893a0adc 100644 --- a/tools/testing/selftests/mm/gup_longterm.c +++ b/tools/testing/selftests/mm/gup_longterm.c @@ -27,7 +27,7 @@ #endif /* LOCAL_CONFIG_HAVE_LIBURING */ #include "../../../../mm/gup_test.h" -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" static size_t pagesize; diff --git a/tools/testing/selftests/mm/gup_test.c b/tools/testing/selftests/mm/gup_test.c index 40c1538a17b4..fb8f9ae49efa 100644 --- a/tools/testing/selftests/mm/gup_test.c +++ b/tools/testing/selftests/mm/gup_test.c @@ -12,7 +12,7 @@ #include <pthread.h> #include <assert.h> #include <mm/gup_test.h> -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" #define MB (1UL << 20) diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c index 5a1525f72daa..e8328c89d855 100644 --- a/tools/testing/selftests/mm/hmm-tests.c +++ b/tools/testing/selftests/mm/hmm-tests.c @@ -10,7 +10,7 @@ * bugs. */ -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <errno.h> #include <fcntl.h> diff --git a/tools/testing/selftests/mm/hugepage-mmap.c b/tools/testing/selftests/mm/hugepage-mmap.c index 3b1b532f1cbb..d543419de040 100644 --- a/tools/testing/selftests/mm/hugepage-mmap.c +++ b/tools/testing/selftests/mm/hugepage-mmap.c @@ -15,7 +15,7 @@ #include <unistd.h> #include <sys/mman.h> #include <fcntl.h> -#include "../kselftest.h" +#include "kselftest.h" #define LENGTH (256UL*1024*1024) #define PROTECTION (PROT_READ | PROT_WRITE) diff --git a/tools/testing/selftests/mm/hugepage-mremap.c b/tools/testing/selftests/mm/hugepage-mremap.c index 2bd1dac75c3f..b8f7d92e5a35 100644 --- a/tools/testing/selftests/mm/hugepage-mremap.c +++ b/tools/testing/selftests/mm/hugepage-mremap.c @@ -24,7 +24,7 @@ #include <sys/ioctl.h> #include <string.h> #include <stdbool.h> -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" #define DEFAULT_LENGTH_MB 10UL diff --git a/tools/testing/selftests/mm/hugetlb-madvise.c b/tools/testing/selftests/mm/hugetlb-madvise.c index c5940c0595be..05d9d2805ae4 100644 --- a/tools/testing/selftests/mm/hugetlb-madvise.c +++ b/tools/testing/selftests/mm/hugetlb-madvise.c @@ -19,7 +19,7 @@ #include <sys/mman.h> #include <fcntl.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" #define MIN_FREE_PAGES 20 #define NR_HUGE_PAGES 10 /* common number of pages to map/allocate */ diff --git a/tools/testing/selftests/mm/hugetlb-read-hwpoison.c b/tools/testing/selftests/mm/hugetlb-read-hwpoison.c index ba6cc6f9cabc..46230462ad48 100644 --- a/tools/testing/selftests/mm/hugetlb-read-hwpoison.c +++ b/tools/testing/selftests/mm/hugetlb-read-hwpoison.c @@ -11,7 +11,7 @@ #include <errno.h> #include <stdbool.h> -#include "../kselftest.h" +#include "kselftest.h" #define PREFIX " ... " #define ERROR_PREFIX " !!! " diff --git a/tools/testing/selftests/mm/hugetlb-soft-offline.c b/tools/testing/selftests/mm/hugetlb-soft-offline.c index f086f0e04756..a8bc02688085 100644 --- a/tools/testing/selftests/mm/hugetlb-soft-offline.c +++ b/tools/testing/selftests/mm/hugetlb-soft-offline.c @@ -24,7 +24,7 @@ #include <sys/statfs.h> #include <sys/types.h> -#include "../kselftest.h" +#include "kselftest.h" #ifndef MADV_SOFT_OFFLINE #define MADV_SOFT_OFFLINE 101 diff --git a/tools/testing/selftests/mm/hugetlb_dio.c b/tools/testing/selftests/mm/hugetlb_dio.c index db63abe5ee5e..9ac62eb4c97d 100644 --- a/tools/testing/selftests/mm/hugetlb_dio.c +++ b/tools/testing/selftests/mm/hugetlb_dio.c @@ -18,7 +18,7 @@ #include <string.h> #include <sys/mman.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" void run_dio_using_hugetlb(unsigned int start_off, unsigned int end_off) { diff --git a/tools/testing/selftests/mm/hugetlb_fault_after_madv.c b/tools/testing/selftests/mm/hugetlb_fault_after_madv.c index e2640529dbb2..b4b257775b74 100644 --- a/tools/testing/selftests/mm/hugetlb_fault_after_madv.c +++ b/tools/testing/selftests/mm/hugetlb_fault_after_madv.c @@ -9,7 +9,7 @@ #include <signal.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" #define INLOOP_ITER 100 diff --git a/tools/testing/selftests/mm/hugetlb_madv_vs_map.c b/tools/testing/selftests/mm/hugetlb_madv_vs_map.c index 8f122a0f0828..efd774b41389 100644 --- a/tools/testing/selftests/mm/hugetlb_madv_vs_map.c +++ b/tools/testing/selftests/mm/hugetlb_madv_vs_map.c @@ -25,7 +25,7 @@ #include <unistd.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" #define INLOOP_ITER 100 diff --git a/tools/testing/selftests/mm/ksm_functional_tests.c b/tools/testing/selftests/mm/ksm_functional_tests.c index 95afa5cfc062..8d874c4754f3 100644 --- a/tools/testing/selftests/mm/ksm_functional_tests.c +++ b/tools/testing/selftests/mm/ksm_functional_tests.c @@ -21,7 +21,7 @@ #include <sys/wait.h> #include <linux/userfaultfd.h> -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" #define KiB 1024u diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c index b77462b5c240..a0b48b839d54 100644 --- a/tools/testing/selftests/mm/ksm_tests.c +++ b/tools/testing/selftests/mm/ksm_tests.c @@ -12,7 +12,7 @@ #include <stdint.h> #include <err.h> -#include "../kselftest.h" +#include "kselftest.h" #include <include/vdso/time64.h> #include "vm_util.h" #include "thp_settings.h" diff --git a/tools/testing/selftests/mm/madv_populate.c b/tools/testing/selftests/mm/madv_populate.c index d8d11bc67ddc..88050e0f829a 100644 --- a/tools/testing/selftests/mm/madv_populate.c +++ b/tools/testing/selftests/mm/madv_populate.c @@ -17,7 +17,7 @@ #include <linux/mman.h> #include <sys/mman.h> -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" /* diff --git a/tools/testing/selftests/mm/map_fixed_noreplace.c b/tools/testing/selftests/mm/map_fixed_noreplace.c index 1e9980b8993c..11241edde7fe 100644 --- a/tools/testing/selftests/mm/map_fixed_noreplace.c +++ b/tools/testing/selftests/mm/map_fixed_noreplace.c @@ -12,7 +12,7 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" static void dump_maps(void) { diff --git a/tools/testing/selftests/mm/map_hugetlb.c b/tools/testing/selftests/mm/map_hugetlb.c index b47399feab53..aa409107611b 100644 --- a/tools/testing/selftests/mm/map_hugetlb.c +++ b/tools/testing/selftests/mm/map_hugetlb.c @@ -11,7 +11,7 @@ #include <sys/mman.h> #include <fcntl.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" #define LENGTH (256UL*1024*1024) #define PROTECTION (PROT_READ | PROT_WRITE) diff --git a/tools/testing/selftests/mm/map_populate.c b/tools/testing/selftests/mm/map_populate.c index 9df2636c829b..712327f4e932 100644 --- a/tools/testing/selftests/mm/map_populate.c +++ b/tools/testing/selftests/mm/map_populate.c @@ -16,7 +16,7 @@ #include <stdlib.h> #include <string.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" diff --git a/tools/testing/selftests/mm/mdwe_test.c b/tools/testing/selftests/mm/mdwe_test.c index 200bedcdc32e..647779653da0 100644 --- a/tools/testing/selftests/mm/mdwe_test.c +++ b/tools/testing/selftests/mm/mdwe_test.c @@ -14,7 +14,7 @@ #include <sys/wait.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #ifndef __aarch64__ # define PROT_BTI 0 diff --git a/tools/testing/selftests/mm/memfd_secret.c b/tools/testing/selftests/mm/memfd_secret.c index 9a0597310a76..aac4f795c327 100644 --- a/tools/testing/selftests/mm/memfd_secret.c +++ b/tools/testing/selftests/mm/memfd_secret.c @@ -22,7 +22,7 @@ #include <stdio.h> #include <fcntl.h> -#include "../kselftest.h" +#include "kselftest.h" #define fail(fmt, ...) ksft_test_result_fail(fmt, ##__VA_ARGS__) #define pass(fmt, ...) ksft_test_result_pass(fmt, ##__VA_ARGS__) diff --git a/tools/testing/selftests/mm/merge.c b/tools/testing/selftests/mm/merge.c index cc4253f47f10..363c1033cc7d 100644 --- a/tools/testing/selftests/mm/merge.c +++ b/tools/testing/selftests/mm/merge.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #define _GNU_SOURCE -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <linux/prctl.h> #include <fcntl.h> #include <stdio.h> diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c index ea945eebec2f..ee24b88c2b24 100644 --- a/tools/testing/selftests/mm/migration.c +++ b/tools/testing/selftests/mm/migration.c @@ -4,7 +4,7 @@ * paths in the kernel. */ -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "thp_settings.h" #include <strings.h> diff --git a/tools/testing/selftests/mm/mkdirty.c b/tools/testing/selftests/mm/mkdirty.c index 09feeb453646..68dd447a5454 100644 --- a/tools/testing/selftests/mm/mkdirty.c +++ b/tools/testing/selftests/mm/mkdirty.c @@ -22,7 +22,7 @@ #include <linux/userfaultfd.h> #include <linux/mempolicy.h> -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" static size_t pagesize; diff --git a/tools/testing/selftests/mm/mlock-random-test.c b/tools/testing/selftests/mm/mlock-random-test.c index b8d7e966f44c..9d349c151360 100644 --- a/tools/testing/selftests/mm/mlock-random-test.c +++ b/tools/testing/selftests/mm/mlock-random-test.c @@ -13,7 +13,7 @@ #include <sys/ipc.h> #include <sys/shm.h> #include <time.h> -#include "../kselftest.h" +#include "kselftest.h" #include "mlock2.h" #define CHUNK_UNIT (128 * 1024) diff --git a/tools/testing/selftests/mm/mlock2-tests.c b/tools/testing/selftests/mm/mlock2-tests.c index 3e90ff37e336..b474f2b20def 100644 --- a/tools/testing/selftests/mm/mlock2-tests.c +++ b/tools/testing/selftests/mm/mlock2-tests.c @@ -7,7 +7,7 @@ #include <sys/time.h> #include <sys/resource.h> #include <stdbool.h> -#include "../kselftest.h" +#include "kselftest.h" #include "mlock2.h" struct vm_boundaries { diff --git a/tools/testing/selftests/mm/mrelease_test.c b/tools/testing/selftests/mm/mrelease_test.c index 100370a7111d..64e8d00ae944 100644 --- a/tools/testing/selftests/mm/mrelease_test.c +++ b/tools/testing/selftests/mm/mrelease_test.c @@ -12,7 +12,7 @@ #include <unistd.h> #include <asm-generic/unistd.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" #define MB(x) (x << 20) #define MAX_SIZE_MB 1024 diff --git a/tools/testing/selftests/mm/mremap_dontunmap.c b/tools/testing/selftests/mm/mremap_dontunmap.c index 1d75084b9ca5..a4f75d836733 100644 --- a/tools/testing/selftests/mm/mremap_dontunmap.c +++ b/tools/testing/selftests/mm/mremap_dontunmap.c @@ -14,7 +14,7 @@ #include <string.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" unsigned long page_size; char *page_buffer; diff --git a/tools/testing/selftests/mm/mremap_test.c b/tools/testing/selftests/mm/mremap_test.c index 5f073504e0b1..308576437228 100644 --- a/tools/testing/selftests/mm/mremap_test.c +++ b/tools/testing/selftests/mm/mremap_test.c @@ -16,7 +16,7 @@ #include <time.h> #include <stdbool.h> -#include "../kselftest.h" +#include "kselftest.h" #define EXPECT_SUCCESS 0 #define EXPECT_FAILURE 1 diff --git a/tools/testing/selftests/mm/mseal_test.c b/tools/testing/selftests/mm/mseal_test.c index 005f29c86484..faad4833366a 100644 --- a/tools/testing/selftests/mm/mseal_test.c +++ b/tools/testing/selftests/mm/mseal_test.c @@ -8,7 +8,7 @@ #include <sys/time.h> #include <sys/resource.h> #include <stdbool.h> -#include "../kselftest.h" +#include "kselftest.h" #include <syscall.h> #include <errno.h> #include <stdio.h> diff --git a/tools/testing/selftests/mm/on-fault-limit.c b/tools/testing/selftests/mm/on-fault-limit.c index 431c1277d83a..fc4117453c84 100644 --- a/tools/testing/selftests/mm/on-fault-limit.c +++ b/tools/testing/selftests/mm/on-fault-limit.c @@ -5,7 +5,7 @@ #include <string.h> #include <sys/time.h> #include <sys/resource.h> -#include "../kselftest.h" +#include "kselftest.h" static void test_limit(void) { diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c index 4fc8e578ec7c..2cb5441f29c7 100644 --- a/tools/testing/selftests/mm/pagemap_ioctl.c +++ b/tools/testing/selftests/mm/pagemap_ioctl.c @@ -8,7 +8,7 @@ #include <errno.h> #include <malloc.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" #include <linux/types.h> #include <linux/memfd.h> #include <linux/userfaultfd.h> diff --git a/tools/testing/selftests/mm/pfnmap.c b/tools/testing/selftests/mm/pfnmap.c index 88659f0a90ea..f546dfb10cae 100644 --- a/tools/testing/selftests/mm/pfnmap.c +++ b/tools/testing/selftests/mm/pfnmap.c @@ -22,7 +22,7 @@ #include <sys/mman.h> #include <sys/wait.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "vm_util.h" static sigjmp_buf sigjmp_buf_env; diff --git a/tools/testing/selftests/mm/pkey-helpers.h b/tools/testing/selftests/mm/pkey-helpers.h index fa15f006fa68..7c29f075e40b 100644 --- a/tools/testing/selftests/mm/pkey-helpers.h +++ b/tools/testing/selftests/mm/pkey-helpers.h @@ -16,7 +16,7 @@ #include <linux/mman.h> #include <linux/types.h> -#include "../kselftest.h" +#include "kselftest.h" /* Define some kernel-like types */ typedef __u8 u8; diff --git a/tools/testing/selftests/mm/prctl_thp_disable.c b/tools/testing/selftests/mm/prctl_thp_disable.c index 84b4a4b345af..ca27200596a4 100644 --- a/tools/testing/selftests/mm/prctl_thp_disable.c +++ b/tools/testing/selftests/mm/prctl_thp_disable.c @@ -13,7 +13,7 @@ #include <sys/prctl.h> #include <sys/wait.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "thp_settings.h" #include "vm_util.h" diff --git a/tools/testing/selftests/mm/process_madv.c b/tools/testing/selftests/mm/process_madv.c index 471cae8427f1..cd4610baf5d7 100644 --- a/tools/testing/selftests/mm/process_madv.c +++ b/tools/testing/selftests/mm/process_madv.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #define _GNU_SOURCE -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <errno.h> #include <setjmp.h> #include <signal.h> diff --git a/tools/testing/selftests/mm/rmap.c b/tools/testing/selftests/mm/rmap.c index 13f7bccfd0a9..53f2058b0ef2 100644 --- a/tools/testing/selftests/mm/rmap.c +++ b/tools/testing/selftests/mm/rmap.c @@ -5,7 +5,7 @@ * Author(s): Wei Yang <richard.weiyang@gmail.com> */ -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <strings.h> #include <pthread.h> #include <numa.h> diff --git a/tools/testing/selftests/mm/soft-dirty.c b/tools/testing/selftests/mm/soft-dirty.c index c3a9585de98c..59c0dbe99a9b 100644 --- a/tools/testing/selftests/mm/soft-dirty.c +++ b/tools/testing/selftests/mm/soft-dirty.c @@ -7,7 +7,7 @@ #include <malloc.h> #include <sys/mman.h> -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" #include "thp_settings.h" diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c index 743af3c05190..40799f3f0213 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -20,7 +20,7 @@ #include <stdbool.h> #include <time.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" uint64_t pagesize; unsigned int pageshift; diff --git a/tools/testing/selftests/mm/thuge-gen.c b/tools/testing/selftests/mm/thuge-gen.c index 4f5e290ff1a6..77813d34dcc2 100644 --- a/tools/testing/selftests/mm/thuge-gen.c +++ b/tools/testing/selftests/mm/thuge-gen.c @@ -27,7 +27,7 @@ #include <stdarg.h> #include <string.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" #if !defined(MAP_HUGETLB) #define MAP_HUGETLB 0x40000 diff --git a/tools/testing/selftests/mm/transhuge-stress.c b/tools/testing/selftests/mm/transhuge-stress.c index 68201192e37c..bcad47c09518 100644 --- a/tools/testing/selftests/mm/transhuge-stress.c +++ b/tools/testing/selftests/mm/transhuge-stress.c @@ -16,7 +16,7 @@ #include <string.h> #include <sys/mman.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" int backing_fd = -1; int mmap_flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE; diff --git a/tools/testing/selftests/mm/uffd-common.h b/tools/testing/selftests/mm/uffd-common.h index 37d3ca55905f..844a85ab31eb 100644 --- a/tools/testing/selftests/mm/uffd-common.h +++ b/tools/testing/selftests/mm/uffd-common.h @@ -35,7 +35,7 @@ #include <sys/random.h> #include <stdatomic.h> -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" #define UFFD_FLAGS (O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY) diff --git a/tools/testing/selftests/mm/uffd-wp-mremap.c b/tools/testing/selftests/mm/uffd-wp-mremap.c index 4e4a591cf527..17186d4a4147 100644 --- a/tools/testing/selftests/mm/uffd-wp-mremap.c +++ b/tools/testing/selftests/mm/uffd-wp-mremap.c @@ -7,7 +7,7 @@ #include <assert.h> #include <linux/mman.h> #include <sys/mman.h> -#include "../kselftest.h" +#include "kselftest.h" #include "thp_settings.h" #include "uffd-common.h" diff --git a/tools/testing/selftests/mm/va_high_addr_switch.c b/tools/testing/selftests/mm/va_high_addr_switch.c index 306eba825107..02f290a69132 100644 --- a/tools/testing/selftests/mm/va_high_addr_switch.c +++ b/tools/testing/selftests/mm/va_high_addr_switch.c @@ -10,7 +10,7 @@ #include <string.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" /* * The hint addr value is used to allocate addresses diff --git a/tools/testing/selftests/mm/virtual_address_range.c b/tools/testing/selftests/mm/virtual_address_range.c index 81b33d8f78f4..4f0923825ed7 100644 --- a/tools/testing/selftests/mm/virtual_address_range.c +++ b/tools/testing/selftests/mm/virtual_address_range.c @@ -16,7 +16,7 @@ #include <fcntl.h> #include "vm_util.h" -#include "../kselftest.h" +#include "kselftest.h" /* * Maximum address range mapped with a single mmap() diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c index 605cb58ea5c3..d954bf91afd5 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -9,7 +9,7 @@ #include <linux/fs.h> #include <sys/syscall.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #include "vm_util.h" #define PMD_SIZE_FILE_PATH "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size" diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h index a8abdf414d46..6ad32b1830f1 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -6,7 +6,7 @@ #include <stdarg.h> #include <strings.h> /* ffsl() */ #include <unistd.h> /* _SC_PAGESIZE */ -#include "../kselftest.h" +#include "kselftest.h" #include <linux/fs.h> #define BIT_ULL(nr) (1ULL << (nr)) diff --git a/tools/testing/selftests/mount_setattr/mount_setattr_test.c b/tools/testing/selftests/mount_setattr/mount_setattr_test.c index a688871a98eb..7aec3ae82a44 100644 --- a/tools/testing/selftests/mount_setattr/mount_setattr_test.c +++ b/tools/testing/selftests/mount_setattr/mount_setattr_test.c @@ -21,7 +21,7 @@ #include <linux/mount.h> #include "../filesystems/wrappers.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #ifndef CLONE_NEWNS #define CLONE_NEWNS 0x00020000 diff --git a/tools/testing/selftests/move_mount_set_group/move_mount_set_group_test.c b/tools/testing/selftests/move_mount_set_group/move_mount_set_group_test.c index bcf51d785a37..12434415ec36 100644 --- a/tools/testing/selftests/move_mount_set_group/move_mount_set_group_test.c +++ b/tools/testing/selftests/move_mount_set_group/move_mount_set_group_test.c @@ -15,7 +15,7 @@ #include <stdarg.h> #include <sys/syscall.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #ifndef CLONE_NEWNS #define CLONE_NEWNS 0x00020000 diff --git a/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c index 9403ac01ba11..b16029c40c0f 100644 --- a/tools/testing/selftests/mqueue/mq_open_tests.c +++ b/tools/testing/selftests/mqueue/mq_open_tests.c @@ -33,7 +33,7 @@ #include <mqueue.h> #include <error.h> -#include "../kselftest.h" +#include "kselftest.h" static char *usage = "Usage:\n" diff --git a/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c index fb898850867c..303c46eebd94 100644 --- a/tools/testing/selftests/mqueue/mq_perf_tests.c +++ b/tools/testing/selftests/mqueue/mq_perf_tests.c @@ -40,7 +40,7 @@ #include <popt.h> #include <error.h> -#include "../kselftest.h" +#include "kselftest.h" static char *usage = "Usage:\n" diff --git a/tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c b/tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c index 0d2af30c3bf5..cb0ca6ed7ebe 100644 --- a/tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c +++ b/tools/testing/selftests/mseal_system_mappings/sysmap_is_sealed.c @@ -11,8 +11,8 @@ #include <string.h> #include <stdbool.h> -#include "../kselftest.h" -#include "../kselftest_harness.h" +#include "kselftest.h" +#include "kselftest_harness.h" #define VMFLAGS "VmFlags:" #define MSEAL_FLAGS "sl" diff --git a/tools/testing/selftests/namespaces/file_handle_test.c b/tools/testing/selftests/namespaces/file_handle_test.c index f1bc5773f552..064b41ad96b2 100644 --- a/tools/testing/selftests/namespaces/file_handle_test.c +++ b/tools/testing/selftests/namespaces/file_handle_test.c @@ -14,7 +14,7 @@ #include <sys/wait.h> #include <unistd.h> #include <linux/unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #ifndef FD_NSFS_ROOT #define FD_NSFS_ROOT -10003 /* Root of the nsfs filesystem */ diff --git a/tools/testing/selftests/namespaces/init_ino_test.c b/tools/testing/selftests/namespaces/init_ino_test.c index 5b6993c3740b..e4394a2fa0a9 100644 --- a/tools/testing/selftests/namespaces/init_ino_test.c +++ b/tools/testing/selftests/namespaces/init_ino_test.c @@ -11,7 +11,7 @@ #include <string.h> #include <linux/nsfs.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" struct ns_info { const char *name; diff --git a/tools/testing/selftests/namespaces/nsid_test.c b/tools/testing/selftests/namespaces/nsid_test.c index 527ade0a8673..b4a14c6693a5 100644 --- a/tools/testing/selftests/namespaces/nsid_test.c +++ b/tools/testing/selftests/namespaces/nsid_test.c @@ -20,7 +20,7 @@ #include <linux/fs.h> #include <linux/limits.h> #include <linux/nsfs.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" /* Fixture for tests that create child processes */ FIXTURE(nsid) { diff --git a/tools/testing/selftests/nci/nci_dev.c b/tools/testing/selftests/nci/nci_dev.c index 6dec59d64083..312f84ee0444 100644 --- a/tools/testing/selftests/nci/nci_dev.c +++ b/tools/testing/selftests/nci/nci_dev.c @@ -16,7 +16,7 @@ #include <sys/socket.h> #include <linux/nfc.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN)) #define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN) diff --git a/tools/testing/selftests/net/af_unix/diag_uid.c b/tools/testing/selftests/net/af_unix/diag_uid.c index 79a3dd75590e..da7d50cedee6 100644 --- a/tools/testing/selftests/net/af_unix/diag_uid.c +++ b/tools/testing/selftests/net/af_unix/diag_uid.c @@ -14,7 +14,7 @@ #include <sys/types.h> #include <sys/un.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" FIXTURE(diag_uid) { diff --git a/tools/testing/selftests/net/af_unix/msg_oob.c b/tools/testing/selftests/net/af_unix/msg_oob.c index b5f474969917..1b499d56656c 100644 --- a/tools/testing/selftests/net/af_unix/msg_oob.c +++ b/tools/testing/selftests/net/af_unix/msg_oob.c @@ -11,7 +11,7 @@ #include <sys/signalfd.h> #include <sys/socket.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define BUF_SZ 32 diff --git a/tools/testing/selftests/net/af_unix/scm_inq.c b/tools/testing/selftests/net/af_unix/scm_inq.c index fc467714387e..3a86be9bda17 100644 --- a/tools/testing/selftests/net/af_unix/scm_inq.c +++ b/tools/testing/selftests/net/af_unix/scm_inq.c @@ -6,7 +6,7 @@ #include <sys/socket.h> #include <sys/types.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define NR_CHUNKS 100 #define MSG_LEN 256 diff --git a/tools/testing/selftests/net/af_unix/scm_pidfd.c b/tools/testing/selftests/net/af_unix/scm_pidfd.c index ef2921988e5f..2c18b92a2603 100644 --- a/tools/testing/selftests/net/af_unix/scm_pidfd.c +++ b/tools/testing/selftests/net/af_unix/scm_pidfd.c @@ -16,7 +16,7 @@ #include <sys/wait.h> #include "../../pidfd/pidfd.h" -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define clean_errno() (errno == 0 ? "None" : strerror(errno)) #define log_err(MSG, ...) \ diff --git a/tools/testing/selftests/net/af_unix/scm_rights.c b/tools/testing/selftests/net/af_unix/scm_rights.c index 914f99d153ce..d82a79c21c17 100644 --- a/tools/testing/selftests/net/af_unix/scm_rights.c +++ b/tools/testing/selftests/net/af_unix/scm_rights.c @@ -10,7 +10,7 @@ #include <sys/socket.h> #include <sys/un.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" FIXTURE(scm_rights) { diff --git a/tools/testing/selftests/net/af_unix/unix_connect.c b/tools/testing/selftests/net/af_unix/unix_connect.c index d799fd8f5c7c..870ca96fa8ea 100644 --- a/tools/testing/selftests/net/af_unix/unix_connect.c +++ b/tools/testing/selftests/net/af_unix/unix_connect.c @@ -10,7 +10,7 @@ #include <sys/socket.h> #include <sys/un.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" FIXTURE(unix_connect) { diff --git a/tools/testing/selftests/net/bind_timewait.c b/tools/testing/selftests/net/bind_timewait.c index cb9fdf51ea59..40126f9b901e 100644 --- a/tools/testing/selftests/net/bind_timewait.c +++ b/tools/testing/selftests/net/bind_timewait.c @@ -4,7 +4,7 @@ #include <sys/socket.h> #include <netinet/in.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" FIXTURE(bind_timewait) { diff --git a/tools/testing/selftests/net/bind_wildcard.c b/tools/testing/selftests/net/bind_wildcard.c index b7b54d646b93..7d11548b2c61 100644 --- a/tools/testing/selftests/net/bind_wildcard.c +++ b/tools/testing/selftests/net/bind_wildcard.c @@ -4,7 +4,7 @@ #include <sys/socket.h> #include <netinet/in.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static const __u32 in4addr_any = INADDR_ANY; static const __u32 in4addr_loopback = INADDR_LOOPBACK; diff --git a/tools/testing/selftests/net/can/test_raw_filter.c b/tools/testing/selftests/net/can/test_raw_filter.c index 4101c36390fd..bb8ae8854273 100644 --- a/tools/testing/selftests/net/can/test_raw_filter.c +++ b/tools/testing/selftests/net/can/test_raw_filter.c @@ -19,7 +19,7 @@ #include <linux/can.h> #include <linux/can/raw.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define ID 0x123 diff --git a/tools/testing/selftests/net/cmsg_sender.c b/tools/testing/selftests/net/cmsg_sender.c index ded9b925865e..67a72b1a2f3d 100644 --- a/tools/testing/selftests/net/cmsg_sender.c +++ b/tools/testing/selftests/net/cmsg_sender.c @@ -16,7 +16,7 @@ #include <linux/udp.h> #include <sys/socket.h> -#include "../kselftest.h" +#include "kselftest.h" enum { ERN_SUCCESS = 0, diff --git a/tools/testing/selftests/net/epoll_busy_poll.c b/tools/testing/selftests/net/epoll_busy_poll.c index 16e457c2f877..adf8dd0b5e0b 100644 --- a/tools/testing/selftests/net/epoll_busy_poll.c +++ b/tools/testing/selftests/net/epoll_busy_poll.c @@ -23,7 +23,7 @@ #include <sys/ioctl.h> #include <sys/socket.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" /* if the headers haven't been updated, we need to define some things */ #if !defined(EPOLL_IOC_TYPE) diff --git a/tools/testing/selftests/net/ip_local_port_range.c b/tools/testing/selftests/net/ip_local_port_range.c index 29451d2244b7..e6834a6cfc8f 100644 --- a/tools/testing/selftests/net/ip_local_port_range.c +++ b/tools/testing/selftests/net/ip_local_port_range.c @@ -10,7 +10,7 @@ #include <fcntl.h> #include <netinet/ip.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #ifndef IP_LOCAL_PORT_RANGE #define IP_LOCAL_PORT_RANGE 51 diff --git a/tools/testing/selftests/net/ipsec.c b/tools/testing/selftests/net/ipsec.c index 9b44a091802c..0ccf484b1d9d 100644 --- a/tools/testing/selftests/net/ipsec.c +++ b/tools/testing/selftests/net/ipsec.c @@ -34,7 +34,7 @@ #include <time.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #define printk(fmt, ...) \ ksft_print_msg("%d[%u] " fmt "\n", getpid(), __LINE__, ##__VA_ARGS__) diff --git a/tools/testing/selftests/net/ipv6_fragmentation.c b/tools/testing/selftests/net/ipv6_fragmentation.c index 267ef62b5c72..672c9fe086a7 100644 --- a/tools/testing/selftests/net/ipv6_fragmentation.c +++ b/tools/testing/selftests/net/ipv6_fragmentation.c @@ -34,7 +34,7 @@ #include <sys/ioctl.h> #include <sys/socket.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #define MTU 1500 #define LARGER_THAN_MTU 8192 diff --git a/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c b/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c index 5f827e10717d..5cecb8a1bc94 100644 --- a/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c +++ b/tools/testing/selftests/net/netfilter/conntrack_dump_flush.c @@ -10,7 +10,7 @@ #include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink_conntrack.h> #include <linux/netfilter/nf_conntrack_tcp.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define TEST_ZONE_ID 123 #define NF_CT_DEFAULT_ZONE_ID 0 diff --git a/tools/testing/selftests/net/netlink-dumps.c b/tools/testing/selftests/net/netlink-dumps.c index 679b6c77ace7..51129c564d0a 100644 --- a/tools/testing/selftests/net/netlink-dumps.c +++ b/tools/testing/selftests/net/netlink-dumps.c @@ -18,7 +18,7 @@ #include <linux/mqueue.h> #include <linux/rtnetlink.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <ynl.h> diff --git a/tools/testing/selftests/net/ovpn/ovpn-cli.c b/tools/testing/selftests/net/ovpn/ovpn-cli.c index 0a5226196a2e..0f3babf19fd0 100644 --- a/tools/testing/selftests/net/ovpn/ovpn-cli.c +++ b/tools/testing/selftests/net/ovpn/ovpn-cli.c @@ -32,7 +32,7 @@ #include <sys/socket.h> -#include "../../kselftest.h" +#include "kselftest.h" /* defines to make checkpatch happy */ #define strscpy strncpy diff --git a/tools/testing/selftests/net/proc_net_pktgen.c b/tools/testing/selftests/net/proc_net_pktgen.c index 69444fb29577..fab3b5c2e25d 100644 --- a/tools/testing/selftests/net/proc_net_pktgen.c +++ b/tools/testing/selftests/net/proc_net_pktgen.c @@ -10,7 +10,7 @@ #include <stdlib.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static const char ctrl_cmd_stop[] = "stop"; static const char ctrl_cmd_start[] = "start"; diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c index 84c524357075..ab8d8b7e6cb0 100644 --- a/tools/testing/selftests/net/psock_fanout.c +++ b/tools/testing/selftests/net/psock_fanout.c @@ -54,7 +54,7 @@ #include <unistd.h> #include "psock_lib.h" -#include "../kselftest.h" +#include "kselftest.h" #define RING_NUM_FRAMES 20 diff --git a/tools/testing/selftests/net/psock_tpacket.c b/tools/testing/selftests/net/psock_tpacket.c index 2938045c5cf9..7caf3135448d 100644 --- a/tools/testing/selftests/net/psock_tpacket.c +++ b/tools/testing/selftests/net/psock_tpacket.c @@ -46,7 +46,7 @@ #include "psock_lib.h" -#include "../kselftest.h" +#include "kselftest.h" #ifndef bug_on # define bug_on(cond) assert(!(cond)) diff --git a/tools/testing/selftests/net/reuseaddr_ports_exhausted.c b/tools/testing/selftests/net/reuseaddr_ports_exhausted.c index 7b9bf8a7bbe1..5aad27a0d13a 100644 --- a/tools/testing/selftests/net/reuseaddr_ports_exhausted.c +++ b/tools/testing/selftests/net/reuseaddr_ports_exhausted.c @@ -22,7 +22,7 @@ #include <sys/socket.h> #include <sys/types.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" struct reuse_opts { int reuseaddr[2]; diff --git a/tools/testing/selftests/net/reuseport_bpf.c b/tools/testing/selftests/net/reuseport_bpf.c index 65aea27d761c..b6634d6da3d6 100644 --- a/tools/testing/selftests/net/reuseport_bpf.c +++ b/tools/testing/selftests/net/reuseport_bpf.c @@ -24,7 +24,7 @@ #include <sys/resource.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" struct test_params { int recv_family; diff --git a/tools/testing/selftests/net/reuseport_bpf_numa.c b/tools/testing/selftests/net/reuseport_bpf_numa.c index c9ba36aa688e..2ffd957ffb15 100644 --- a/tools/testing/selftests/net/reuseport_bpf_numa.c +++ b/tools/testing/selftests/net/reuseport_bpf_numa.c @@ -23,7 +23,7 @@ #include <unistd.h> #include <numa.h> -#include "../kselftest.h" +#include "kselftest.h" static const int PORT = 8888; diff --git a/tools/testing/selftests/net/rxtimestamp.c b/tools/testing/selftests/net/rxtimestamp.c index 16ac4df55fdb..b81ed0352d6c 100644 --- a/tools/testing/selftests/net/rxtimestamp.c +++ b/tools/testing/selftests/net/rxtimestamp.c @@ -18,7 +18,7 @@ #include <linux/net_tstamp.h> #include <linux/errqueue.h> -#include "../kselftest.h" +#include "kselftest.h" struct options { int so_timestamp; diff --git a/tools/testing/selftests/net/sk_so_peek_off.c b/tools/testing/selftests/net/sk_so_peek_off.c index d87dd8d8d491..2a3f5c604f52 100644 --- a/tools/testing/selftests/net/sk_so_peek_off.c +++ b/tools/testing/selftests/net/sk_so_peek_off.c @@ -8,7 +8,7 @@ #include <sys/types.h> #include <netinet/in.h> #include <arpa/inet.h> -#include "../kselftest.h" +#include "kselftest.h" static char *afstr(int af, int proto) { diff --git a/tools/testing/selftests/net/so_incoming_cpu.c b/tools/testing/selftests/net/so_incoming_cpu.c index e9fa14e10732..4740701f1a9a 100644 --- a/tools/testing/selftests/net/so_incoming_cpu.c +++ b/tools/testing/selftests/net/so_incoming_cpu.c @@ -9,7 +9,7 @@ #include <sys/socket.h> #include <sys/sysinfo.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" FIXTURE(so_incoming_cpu) { diff --git a/tools/testing/selftests/net/socket.c b/tools/testing/selftests/net/socket.c index be1080003c61..9e270548dad8 100644 --- a/tools/testing/selftests/net/socket.c +++ b/tools/testing/selftests/net/socket.c @@ -7,7 +7,7 @@ #include <sys/socket.h> #include <netinet/in.h> -#include "../kselftest.h" +#include "kselftest.h" struct socket_testcase { int domain; diff --git a/tools/testing/selftests/net/tap.c b/tools/testing/selftests/net/tap.c index 247c3b3ac1c9..9ec1c9b50e77 100644 --- a/tools/testing/selftests/net/tap.c +++ b/tools/testing/selftests/net/tap.c @@ -17,7 +17,7 @@ #include <linux/virtio_net.h> #include <netinet/ip.h> #include <netinet/udp.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static const char param_dev_tap_name[] = "xmacvtap0"; static const char param_dev_dummy_name[] = "xdummy0"; diff --git a/tools/testing/selftests/net/tcp_ao/lib/setup.c b/tools/testing/selftests/net/tcp_ao/lib/setup.c index a27cc03c9fbd..49aec2922a31 100644 --- a/tools/testing/selftests/net/tcp_ao/lib/setup.c +++ b/tools/testing/selftests/net/tcp_ao/lib/setup.c @@ -9,7 +9,7 @@ * Can't be included in the header: it defines static variables which * will be unique to every object. Let's include it only once here. */ -#include "../../../kselftest.h" +#include "kselftest.h" /* Prevent overriding of one thread's output by another */ static pthread_mutex_t ksft_print_lock = PTHREAD_MUTEX_INITIALIZER; diff --git a/tools/testing/selftests/net/tcp_fastopen_backup_key.c b/tools/testing/selftests/net/tcp_fastopen_backup_key.c index c1cb0c75156a..4b3f9b5e50fe 100644 --- a/tools/testing/selftests/net/tcp_fastopen_backup_key.c +++ b/tools/testing/selftests/net/tcp_fastopen_backup_key.c @@ -26,7 +26,7 @@ #include <fcntl.h> #include <time.h> -#include "../kselftest.h" +#include "kselftest.h" #ifndef TCP_FASTOPEN_KEY #define TCP_FASTOPEN_KEY 33 diff --git a/tools/testing/selftests/net/tcp_port_share.c b/tools/testing/selftests/net/tcp_port_share.c index 4c39d599dfce..6146b62610df 100644 --- a/tools/testing/selftests/net/tcp_port_share.c +++ b/tools/testing/selftests/net/tcp_port_share.c @@ -10,7 +10,7 @@ #include <sched.h> #include <stdlib.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define DST_PORT 30000 #define SRC_PORT 40000 diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index da1b50b30719..a3ef4b57eb5f 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -21,7 +21,7 @@ #include <sys/socket.h> #include <sys/stat.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define TLS_PAYLOAD_MAX_LEN 16384 #define SOL_TLS 282 diff --git a/tools/testing/selftests/net/tun.c b/tools/testing/selftests/net/tun.c index fa83918b62d1..0efc67b0357a 100644 --- a/tools/testing/selftests/net/tun.c +++ b/tools/testing/selftests/net/tun.c @@ -15,7 +15,7 @@ #include <sys/ioctl.h> #include <sys/socket.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static int tun_attach(int fd, char *dev) { diff --git a/tools/testing/selftests/net/udpgso_bench_tx.c b/tools/testing/selftests/net/udpgso_bench_tx.c index 477392715a9a..86d80cce55b4 100644 --- a/tools/testing/selftests/net/udpgso_bench_tx.c +++ b/tools/testing/selftests/net/udpgso_bench_tx.c @@ -25,7 +25,7 @@ #include <sys/types.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #ifndef ETH_MAX_MTU #define ETH_MAX_MTU 0xFFFFU diff --git a/tools/testing/selftests/openat2/helpers.h b/tools/testing/selftests/openat2/helpers.h index 7056340b9339..510e60602511 100644 --- a/tools/testing/selftests/openat2/helpers.h +++ b/tools/testing/selftests/openat2/helpers.h @@ -12,7 +12,7 @@ #include <stdbool.h> #include <errno.h> #include <linux/types.h> -#include "../kselftest.h" +#include "kselftest.h" #define ARRAY_LEN(X) (sizeof (X) / sizeof (*(X))) #define BUILD_BUG_ON(e) ((void)(sizeof(struct { int:(-!!(e)); }))) diff --git a/tools/testing/selftests/openat2/openat2_test.c b/tools/testing/selftests/openat2/openat2_test.c index 5790ab446527..0e161ef9e9e4 100644 --- a/tools/testing/selftests/openat2/openat2_test.c +++ b/tools/testing/selftests/openat2/openat2_test.c @@ -15,7 +15,7 @@ #include <stdbool.h> #include <string.h> -#include "../kselftest.h" +#include "kselftest.h" #include "helpers.h" /* diff --git a/tools/testing/selftests/openat2/rename_attack_test.c b/tools/testing/selftests/openat2/rename_attack_test.c index 0a770728b436..aa5699e45729 100644 --- a/tools/testing/selftests/openat2/rename_attack_test.c +++ b/tools/testing/selftests/openat2/rename_attack_test.c @@ -22,7 +22,7 @@ #include <limits.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #include "helpers.h" /* Construct a test directory with the following structure: diff --git a/tools/testing/selftests/openat2/resolve_test.c b/tools/testing/selftests/openat2/resolve_test.c index bbafad440893..a76ef15ceb90 100644 --- a/tools/testing/selftests/openat2/resolve_test.c +++ b/tools/testing/selftests/openat2/resolve_test.c @@ -14,7 +14,7 @@ #include <stdbool.h> #include <string.h> -#include "../kselftest.h" +#include "kselftest.h" #include "helpers.h" /* diff --git a/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c b/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c index cd9075444c32..23aac6f97061 100644 --- a/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c +++ b/tools/testing/selftests/pci_endpoint/pci_endpoint_test.c @@ -20,7 +20,7 @@ #include "../../../../include/uapi/linux/pcitest.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define pci_ep_ioctl(cmd, arg) \ ({ \ diff --git a/tools/testing/selftests/perf_events/mmap.c b/tools/testing/selftests/perf_events/mmap.c index ea0427aac1f9..d1fa8ec58987 100644 --- a/tools/testing/selftests/perf_events/mmap.c +++ b/tools/testing/selftests/perf_events/mmap.c @@ -14,7 +14,7 @@ #include <linux/perf_event.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define RB_SIZE 0x3000 #define AUX_SIZE 0x10000 diff --git a/tools/testing/selftests/perf_events/remove_on_exec.c b/tools/testing/selftests/perf_events/remove_on_exec.c index 5814611a1dc7..89e7b06835df 100644 --- a/tools/testing/selftests/perf_events/remove_on_exec.c +++ b/tools/testing/selftests/perf_events/remove_on_exec.c @@ -30,7 +30,7 @@ #include <sys/syscall.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static volatile int signal_count; diff --git a/tools/testing/selftests/perf_events/sigtrap_threads.c b/tools/testing/selftests/perf_events/sigtrap_threads.c index d1d8483ac628..b5cf8355345d 100644 --- a/tools/testing/selftests/perf_events/sigtrap_threads.c +++ b/tools/testing/selftests/perf_events/sigtrap_threads.c @@ -31,7 +31,7 @@ #include <sys/syscall.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define NUM_THREADS 5 diff --git a/tools/testing/selftests/perf_events/watermark_signal.c b/tools/testing/selftests/perf_events/watermark_signal.c index b3a72f0ac522..0f64b9b17081 100644 --- a/tools/testing/selftests/perf_events/watermark_signal.c +++ b/tools/testing/selftests/perf_events/watermark_signal.c @@ -15,7 +15,7 @@ #include <sys/wait.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static int sigio_count; diff --git a/tools/testing/selftests/pid_namespace/pid_max.c b/tools/testing/selftests/pid_namespace/pid_max.c index 96f274f0582b..c9519e7385b6 100644 --- a/tools/testing/selftests/pid_namespace/pid_max.c +++ b/tools/testing/selftests/pid_namespace/pid_max.c @@ -13,7 +13,7 @@ #include <sys/mount.h> #include <sys/wait.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "../pidfd/pidfd.h" #define __STACK_SIZE (8 * 1024 * 1024) diff --git a/tools/testing/selftests/pid_namespace/regression_enomem.c b/tools/testing/selftests/pid_namespace/regression_enomem.c index 7d84097ad45c..059e7ec5b4fd 100644 --- a/tools/testing/selftests/pid_namespace/regression_enomem.c +++ b/tools/testing/selftests/pid_namespace/regression_enomem.c @@ -11,7 +11,7 @@ #include <syscall.h> #include <sys/wait.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "../pidfd/pidfd.h" /* diff --git a/tools/testing/selftests/pidfd/pidfd.h b/tools/testing/selftests/pidfd/pidfd.h index d60f10a873bb..9085c1a3c005 100644 --- a/tools/testing/selftests/pidfd/pidfd.h +++ b/tools/testing/selftests/pidfd/pidfd.h @@ -25,7 +25,7 @@ #undef SCHED_FLAG_KEEP_ALL #undef SCHED_FLAG_UTIL_CLAMP -#include "../kselftest.h" +#include "kselftest.h" #include "../clone3/clone3_selftests.h" #ifndef FD_PIDFS_ROOT diff --git a/tools/testing/selftests/pidfd/pidfd_bind_mount.c b/tools/testing/selftests/pidfd/pidfd_bind_mount.c index c094aeb1c620..1fdf49939524 100644 --- a/tools/testing/selftests/pidfd/pidfd_bind_mount.c +++ b/tools/testing/selftests/pidfd/pidfd_bind_mount.c @@ -14,7 +14,7 @@ #include <unistd.h> #include "pidfd.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "../filesystems/wrappers.h" FIXTURE(pidfd_bind_mount) { diff --git a/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c b/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c index f718aac75068..9935e9471c77 100644 --- a/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c +++ b/tools/testing/selftests/pidfd/pidfd_fdinfo_test.c @@ -16,7 +16,7 @@ #include <sys/mount.h> #include "pidfd.h" -#include "../kselftest.h" +#include "kselftest.h" struct error { int code; diff --git a/tools/testing/selftests/pidfd/pidfd_file_handle_test.c b/tools/testing/selftests/pidfd/pidfd_file_handle_test.c index 6bd2e9c9565b..68918734dcf3 100644 --- a/tools/testing/selftests/pidfd/pidfd_file_handle_test.c +++ b/tools/testing/selftests/pidfd/pidfd_file_handle_test.c @@ -20,7 +20,7 @@ #include <sys/stat.h> #include "pidfd.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" FIXTURE(file_handle) { diff --git a/tools/testing/selftests/pidfd/pidfd_getfd_test.c b/tools/testing/selftests/pidfd/pidfd_getfd_test.c index cd51d547b751..ea45b37001b0 100644 --- a/tools/testing/selftests/pidfd/pidfd_getfd_test.c +++ b/tools/testing/selftests/pidfd/pidfd_getfd_test.c @@ -19,7 +19,7 @@ #include <linux/kcmp.h> #include "pidfd.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" /* * UNKNOWN_FD is an fd number that should never exist in the child, as it is diff --git a/tools/testing/selftests/pidfd/pidfd_info_test.c b/tools/testing/selftests/pidfd/pidfd_info_test.c index cb5430a2fd75..6571e04acd88 100644 --- a/tools/testing/selftests/pidfd/pidfd_info_test.c +++ b/tools/testing/selftests/pidfd/pidfd_info_test.c @@ -21,7 +21,7 @@ #include <sys/stat.h> #include "pidfd.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" FIXTURE(pidfd_info) { diff --git a/tools/testing/selftests/pidfd/pidfd_open_test.c b/tools/testing/selftests/pidfd/pidfd_open_test.c index cd3de40e4977..318e6f09c8e0 100644 --- a/tools/testing/selftests/pidfd/pidfd_open_test.c +++ b/tools/testing/selftests/pidfd/pidfd_open_test.c @@ -20,7 +20,7 @@ #include <unistd.h> #include "pidfd.h" -#include "../kselftest.h" +#include "kselftest.h" static int safe_int(const char *numstr, int *converted) { diff --git a/tools/testing/selftests/pidfd/pidfd_poll_test.c b/tools/testing/selftests/pidfd/pidfd_poll_test.c index 55d74a50358f..232304f818c7 100644 --- a/tools/testing/selftests/pidfd/pidfd_poll_test.c +++ b/tools/testing/selftests/pidfd/pidfd_poll_test.c @@ -14,7 +14,7 @@ #include <unistd.h> #include "pidfd.h" -#include "../kselftest.h" +#include "kselftest.h" static bool timeout; diff --git a/tools/testing/selftests/pidfd/pidfd_setattr_test.c b/tools/testing/selftests/pidfd/pidfd_setattr_test.c index d7de05edc4b3..e8562a2992f3 100644 --- a/tools/testing/selftests/pidfd/pidfd_setattr_test.c +++ b/tools/testing/selftests/pidfd/pidfd_setattr_test.c @@ -22,7 +22,7 @@ #include <sys/xattr.h> #include "pidfd.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" FIXTURE(pidfs_setattr) { diff --git a/tools/testing/selftests/pidfd/pidfd_setns_test.c b/tools/testing/selftests/pidfd/pidfd_setns_test.c index e6a079b3d5e2..107edecff224 100644 --- a/tools/testing/selftests/pidfd/pidfd_setns_test.c +++ b/tools/testing/selftests/pidfd/pidfd_setns_test.c @@ -18,7 +18,7 @@ #include <sys/stat.h> #include "pidfd.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" enum { PIDFD_NS_USER, diff --git a/tools/testing/selftests/pidfd/pidfd_test.c b/tools/testing/selftests/pidfd/pidfd_test.c index fcd85cad9f18..932cbd8caa77 100644 --- a/tools/testing/selftests/pidfd/pidfd_test.c +++ b/tools/testing/selftests/pidfd/pidfd_test.c @@ -20,7 +20,7 @@ #include <unistd.h> #include "pidfd.h" -#include "../kselftest.h" +#include "kselftest.h" #define str(s) _str(s) #define _str(s) #s diff --git a/tools/testing/selftests/pidfd/pidfd_wait.c b/tools/testing/selftests/pidfd/pidfd_wait.c index 1e2d49751cde..4bf702d62c1c 100644 --- a/tools/testing/selftests/pidfd/pidfd_wait.c +++ b/tools/testing/selftests/pidfd/pidfd_wait.c @@ -17,7 +17,7 @@ #include <unistd.h> #include "pidfd.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define ptr_to_u64(ptr) ((__u64)((uintptr_t)(ptr))) diff --git a/tools/testing/selftests/pidfd/pidfd_xattr_test.c b/tools/testing/selftests/pidfd/pidfd_xattr_test.c index 5cf7bb0e4bf2..fd57511af7e4 100644 --- a/tools/testing/selftests/pidfd/pidfd_xattr_test.c +++ b/tools/testing/selftests/pidfd/pidfd_xattr_test.c @@ -22,7 +22,7 @@ #include <sys/xattr.h> #include "pidfd.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" FIXTURE(pidfs_xattr) { diff --git a/tools/testing/selftests/prctl/set-anon-vma-name-test.c b/tools/testing/selftests/prctl/set-anon-vma-name-test.c index 4275cb256dce..ac6721b184a6 100644 --- a/tools/testing/selftests/prctl/set-anon-vma-name-test.c +++ b/tools/testing/selftests/prctl/set-anon-vma-name-test.c @@ -10,7 +10,7 @@ #include <sys/mman.h> #include <string.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define AREA_SIZE 1024 diff --git a/tools/testing/selftests/prctl/set-process-name.c b/tools/testing/selftests/prctl/set-process-name.c index 562f707ba771..3f7b146d36df 100644 --- a/tools/testing/selftests/prctl/set-process-name.c +++ b/tools/testing/selftests/prctl/set-process-name.c @@ -7,7 +7,7 @@ #include <sys/prctl.h> #include <string.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define CHANGE_NAME "changename" #define EMPTY_NAME "" diff --git a/tools/testing/selftests/proc/proc-maps-race.c b/tools/testing/selftests/proc/proc-maps-race.c index a546475db550..a734553718da 100644 --- a/tools/testing/selftests/proc/proc-maps-race.c +++ b/tools/testing/selftests/proc/proc-maps-race.c @@ -23,7 +23,7 @@ * */ #define _GNU_SOURCE -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <errno.h> #include <fcntl.h> #include <pthread.h> diff --git a/tools/testing/selftests/proc/proc-pid-vm.c b/tools/testing/selftests/proc/proc-pid-vm.c index 978cbcb3eb11..4e6a3e53f975 100644 --- a/tools/testing/selftests/proc/proc-pid-vm.c +++ b/tools/testing/selftests/proc/proc-pid-vm.c @@ -51,7 +51,7 @@ #define __maybe_unused __attribute__((__unused__)) #endif -#include "../kselftest.h" +#include "kselftest.h" static inline long sys_execveat(int dirfd, const char *pathname, char **argv, char **envp, int flags) { diff --git a/tools/testing/selftests/proc/proc-pidns.c b/tools/testing/selftests/proc/proc-pidns.c index 52500597f951..25b9a2933c45 100644 --- a/tools/testing/selftests/proc/proc-pidns.c +++ b/tools/testing/selftests/proc/proc-pidns.c @@ -16,7 +16,7 @@ #include <sys/stat.h> #include <sys/prctl.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define ASSERT_ERRNO(expected, _t, seen) \ __EXPECT(expected, #expected, \ diff --git a/tools/testing/selftests/ptrace/get_set_sud.c b/tools/testing/selftests/ptrace/get_set_sud.c index 5297b10d25c3..2e619c7599bb 100644 --- a/tools/testing/selftests/ptrace/get_set_sud.c +++ b/tools/testing/selftests/ptrace/get_set_sud.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #define _GNU_SOURCE -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <stdio.h> #include <string.h> #include <errno.h> diff --git a/tools/testing/selftests/ptrace/get_syscall_info.c b/tools/testing/selftests/ptrace/get_syscall_info.c index 5bcd1c7b5be6..3f5c3a9fdaba 100644 --- a/tools/testing/selftests/ptrace/get_syscall_info.c +++ b/tools/testing/selftests/ptrace/get_syscall_info.c @@ -7,7 +7,7 @@ * matches userspace expectations. */ -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <err.h> #include <signal.h> #include <asm/unistd.h> diff --git a/tools/testing/selftests/ptrace/set_syscall_info.c b/tools/testing/selftests/ptrace/set_syscall_info.c index 4198248ef874..1cc411a41cd6 100644 --- a/tools/testing/selftests/ptrace/set_syscall_info.c +++ b/tools/testing/selftests/ptrace/set_syscall_info.c @@ -7,7 +7,7 @@ * matches userspace expectations. */ -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <err.h> #include <fcntl.h> #include <signal.h> diff --git a/tools/testing/selftests/ptrace/vmaccess.c b/tools/testing/selftests/ptrace/vmaccess.c index 4db327b44586..3801b5831527 100644 --- a/tools/testing/selftests/ptrace/vmaccess.c +++ b/tools/testing/selftests/ptrace/vmaccess.c @@ -7,7 +7,7 @@ * when de_thread is blocked with ->cred_guard_mutex held. */ -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include <stdio.h> #include <fcntl.h> #include <pthread.h> diff --git a/tools/testing/selftests/resctrl/resctrl.h b/tools/testing/selftests/resctrl/resctrl.h index cd3adfc14969..3c51bdac2dfa 100644 --- a/tools/testing/selftests/resctrl/resctrl.h +++ b/tools/testing/selftests/resctrl/resctrl.h @@ -23,7 +23,7 @@ #include <asm/unistd.h> #include <linux/perf_event.h> #include <linux/compiler.h> -#include "../kselftest.h" +#include "kselftest.h" #define MB (1024 * 1024) #define RESCTRL_PATH "/sys/fs/resctrl" diff --git a/tools/testing/selftests/ring-buffer/map_test.c b/tools/testing/selftests/ring-buffer/map_test.c index a58f520f2f41..f24677737066 100644 --- a/tools/testing/selftests/ring-buffer/map_test.c +++ b/tools/testing/selftests/ring-buffer/map_test.c @@ -17,7 +17,7 @@ #include <sys/ioctl.h> #include "../user_events/user_events_selftests.h" /* share tracefs setup */ -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define TRACEFS_ROOT "/sys/kernel/tracing" diff --git a/tools/testing/selftests/riscv/abi/pointer_masking.c b/tools/testing/selftests/riscv/abi/pointer_masking.c index 059d2e87eb1f..2d540af7b558 100644 --- a/tools/testing/selftests/riscv/abi/pointer_masking.c +++ b/tools/testing/selftests/riscv/abi/pointer_masking.c @@ -9,7 +9,7 @@ #include <sys/wait.h> #include <unistd.h> -#include "../../kselftest.h" +#include "kselftest.h" #ifndef PR_PMLEN_SHIFT #define PR_PMLEN_SHIFT 24 diff --git a/tools/testing/selftests/riscv/hwprobe/cbo.c b/tools/testing/selftests/riscv/hwprobe/cbo.c index 5e96ef785d0d..f254b2edd6ce 100644 --- a/tools/testing/selftests/riscv/hwprobe/cbo.c +++ b/tools/testing/selftests/riscv/hwprobe/cbo.c @@ -15,24 +15,31 @@ #include <linux/compiler.h> #include <linux/kernel.h> #include <asm/ucontext.h> +#include <getopt.h> #include "hwprobe.h" -#include "../../kselftest.h" +#include "kselftest.h" #define MK_CBO(fn) le32_bswap((uint32_t)(fn) << 20 | 10 << 15 | 2 << 12 | 0 << 7 | 15) +#define MK_PREFETCH(fn) \ + le32_bswap(0 << 25 | (uint32_t)(fn) << 20 | 10 << 15 | 6 << 12 | 0 << 7 | 19) static char mem[4096] __aligned(4096) = { [0 ... 4095] = 0xa5 }; -static bool illegal_insn; +static bool got_fault; -static void sigill_handler(int sig, siginfo_t *info, void *context) +static void fault_handler(int sig, siginfo_t *info, void *context) { unsigned long *regs = (unsigned long *)&((ucontext_t *)context)->uc_mcontext; uint32_t insn = *(uint32_t *)regs[0]; - assert(insn == MK_CBO(regs[11])); + if (sig == SIGILL) + assert(insn == MK_CBO(regs[11])); - illegal_insn = true; + if (sig == SIGSEGV || sig == SIGBUS) + assert(insn == MK_PREFETCH(regs[11])); + + got_fault = true; regs[0] += 4; } @@ -45,39 +52,51 @@ static void sigill_handler(int sig, siginfo_t *info, void *context) : : "r" (base), "i" (fn), "i" (MK_CBO(fn)) : "a0", "a1", "memory"); \ }) +#define prefetch_insn(base, fn) \ +({ \ + asm volatile( \ + "mv a0, %0\n" \ + "li a1, %1\n" \ + ".4byte %2\n" \ + : : "r" (base), "i" (fn), "i" (MK_PREFETCH(fn)) : "a0", "a1"); \ +}) + static void cbo_inval(char *base) { cbo_insn(base, 0); } static void cbo_clean(char *base) { cbo_insn(base, 1); } static void cbo_flush(char *base) { cbo_insn(base, 2); } static void cbo_zero(char *base) { cbo_insn(base, 4); } +static void prefetch_i(char *base) { prefetch_insn(base, 0); } +static void prefetch_r(char *base) { prefetch_insn(base, 1); } +static void prefetch_w(char *base) { prefetch_insn(base, 3); } static void test_no_cbo_inval(void *arg) { ksft_print_msg("Testing cbo.inval instruction remain privileged\n"); - illegal_insn = false; + got_fault = false; cbo_inval(&mem[0]); - ksft_test_result(illegal_insn, "No cbo.inval\n"); + ksft_test_result(got_fault, "No cbo.inval\n"); } static void test_no_zicbom(void *arg) { ksft_print_msg("Testing Zicbom instructions remain privileged\n"); - illegal_insn = false; + got_fault = false; cbo_clean(&mem[0]); - ksft_test_result(illegal_insn, "No cbo.clean\n"); + ksft_test_result(got_fault, "No cbo.clean\n"); - illegal_insn = false; + got_fault = false; cbo_flush(&mem[0]); - ksft_test_result(illegal_insn, "No cbo.flush\n"); + ksft_test_result(got_fault, "No cbo.flush\n"); } static void test_no_zicboz(void *arg) { ksft_print_msg("No Zicboz, testing cbo.zero remains privileged\n"); - illegal_insn = false; + got_fault = false; cbo_zero(&mem[0]); - ksft_test_result(illegal_insn, "No cbo.zero\n"); + ksft_test_result(got_fault, "No cbo.zero\n"); } static bool is_power_of_2(__u64 n) @@ -85,6 +104,51 @@ static bool is_power_of_2(__u64 n) return n != 0 && (n & (n - 1)) == 0; } +static void test_zicbop(void *arg) +{ + struct riscv_hwprobe pair = { + .key = RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE, + }; + struct sigaction act = { + .sa_sigaction = &fault_handler, + .sa_flags = SA_SIGINFO + }; + struct sigaction dfl = { + .sa_handler = SIG_DFL + }; + cpu_set_t *cpus = (cpu_set_t *)arg; + __u64 block_size; + long rc; + + rc = sigaction(SIGSEGV, &act, NULL); + assert(rc == 0); + rc = sigaction(SIGBUS, &act, NULL); + assert(rc == 0); + + rc = riscv_hwprobe(&pair, 1, sizeof(cpu_set_t), (unsigned long *)cpus, 0); + block_size = pair.value; + ksft_test_result(rc == 0 && pair.key == RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE && + is_power_of_2(block_size), "Zicbop block size\n"); + ksft_print_msg("Zicbop block size: %llu\n", block_size); + + got_fault = false; + prefetch_i(&mem[0]); + prefetch_r(&mem[0]); + prefetch_w(&mem[0]); + ksft_test_result(!got_fault, "Zicbop prefetch.* on valid address\n"); + + got_fault = false; + prefetch_i(NULL); + prefetch_r(NULL); + prefetch_w(NULL); + ksft_test_result(!got_fault, "Zicbop prefetch.* on NULL\n"); + + rc = sigaction(SIGBUS, &dfl, NULL); + assert(rc == 0); + rc = sigaction(SIGSEGV, &dfl, NULL); + assert(rc == 0); +} + static void test_zicbom(void *arg) { struct riscv_hwprobe pair = { @@ -100,13 +164,13 @@ static void test_zicbom(void *arg) is_power_of_2(block_size), "Zicbom block size\n"); ksft_print_msg("Zicbom block size: %llu\n", block_size); - illegal_insn = false; + got_fault = false; cbo_clean(&mem[block_size]); - ksft_test_result(!illegal_insn, "cbo.clean\n"); + ksft_test_result(!got_fault, "cbo.clean\n"); - illegal_insn = false; + got_fault = false; cbo_flush(&mem[block_size]); - ksft_test_result(!illegal_insn, "cbo.flush\n"); + ksft_test_result(!got_fault, "cbo.flush\n"); } static void test_zicboz(void *arg) @@ -125,11 +189,11 @@ static void test_zicboz(void *arg) is_power_of_2(block_size), "Zicboz block size\n"); ksft_print_msg("Zicboz block size: %llu\n", block_size); - illegal_insn = false; + got_fault = false; cbo_zero(&mem[block_size]); - ksft_test_result(!illegal_insn, "cbo.zero\n"); + ksft_test_result(!got_fault, "cbo.zero\n"); - if (illegal_insn || !is_power_of_2(block_size)) { + if (got_fault || !is_power_of_2(block_size)) { ksft_test_result_skip("cbo.zero check\n"); return; } @@ -177,7 +241,19 @@ static void check_no_zicbo_cpus(cpu_set_t *cpus, __u64 cbo) rc = riscv_hwprobe(&pair, 1, sizeof(cpu_set_t), (unsigned long *)&one_cpu, 0); assert(rc == 0 && pair.key == RISCV_HWPROBE_KEY_IMA_EXT_0); - cbostr = cbo == RISCV_HWPROBE_EXT_ZICBOZ ? "Zicboz" : "Zicbom"; + switch (cbo) { + case RISCV_HWPROBE_EXT_ZICBOZ: + cbostr = "Zicboz"; + break; + case RISCV_HWPROBE_EXT_ZICBOM: + cbostr = "Zicbom"; + break; + case RISCV_HWPROBE_EXT_ZICBOP: + cbostr = "Zicbop"; + break; + default: + ksft_exit_fail_msg("Internal error: invalid cbo %llu\n", cbo); + } if (pair.value & cbo) ksft_exit_fail_msg("%s is only present on a subset of harts.\n" @@ -194,6 +270,7 @@ enum { TEST_ZICBOM, TEST_NO_ZICBOM, TEST_NO_CBO_INVAL, + TEST_ZICBOP, }; static struct test_info { @@ -206,26 +283,51 @@ static struct test_info { [TEST_ZICBOM] = { .nr_tests = 3, test_zicbom }, [TEST_NO_ZICBOM] = { .nr_tests = 2, test_no_zicbom }, [TEST_NO_CBO_INVAL] = { .nr_tests = 1, test_no_cbo_inval }, + [TEST_ZICBOP] = { .nr_tests = 3, test_zicbop }, +}; + +static const struct option long_opts[] = { + {"zicbom-raises-sigill", no_argument, 0, 'm'}, + {"zicboz-raises-sigill", no_argument, 0, 'z'}, + {0, 0, 0, 0} }; int main(int argc, char **argv) { struct sigaction act = { - .sa_sigaction = &sigill_handler, + .sa_sigaction = &fault_handler, .sa_flags = SA_SIGINFO, }; struct riscv_hwprobe pair; unsigned int plan = 0; cpu_set_t cpus; long rc; - int i; - - if (argc > 1 && !strcmp(argv[1], "--sigill")) { - rc = sigaction(SIGILL, &act, NULL); - assert(rc == 0); - tests[TEST_NO_ZICBOZ].enabled = true; - tests[TEST_NO_ZICBOM].enabled = true; - tests[TEST_NO_CBO_INVAL].enabled = true; + int i, opt, long_index; + + long_index = 0; + + while ((opt = getopt_long(argc, argv, "mz", long_opts, &long_index)) != -1) { + switch (opt) { + case 'm': + tests[TEST_NO_ZICBOM].enabled = true; + tests[TEST_NO_CBO_INVAL].enabled = true; + rc = sigaction(SIGILL, &act, NULL); + assert(rc == 0); + break; + case 'z': + tests[TEST_NO_ZICBOZ].enabled = true; + tests[TEST_NO_CBO_INVAL].enabled = true; + rc = sigaction(SIGILL, &act, NULL); + assert(rc == 0); + break; + case '?': + fprintf(stderr, + "Usage: %s [--zicbom-raises-sigill|-m] [--zicboz-raises-sigill|-z]\n", + argv[0]); + exit(1); + default: + break; + } } rc = sched_getaffinity(0, sizeof(cpu_set_t), &cpus); @@ -253,6 +355,11 @@ int main(int argc, char **argv) check_no_zicbo_cpus(&cpus, RISCV_HWPROBE_EXT_ZICBOM); } + if (pair.value & RISCV_HWPROBE_EXT_ZICBOP) + tests[TEST_ZICBOP].enabled = true; + else + check_no_zicbo_cpus(&cpus, RISCV_HWPROBE_EXT_ZICBOP); + for (i = 0; i < ARRAY_SIZE(tests); ++i) plan += tests[i].enabled ? tests[i].nr_tests : 0; diff --git a/tools/testing/selftests/riscv/hwprobe/hwprobe.c b/tools/testing/selftests/riscv/hwprobe/hwprobe.c index fd73c87804f3..54c435af9923 100644 --- a/tools/testing/selftests/riscv/hwprobe/hwprobe.c +++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only #include "hwprobe.h" -#include "../../kselftest.h" +#include "kselftest.h" int main(int argc, char **argv) { diff --git a/tools/testing/selftests/riscv/hwprobe/which-cpus.c b/tools/testing/selftests/riscv/hwprobe/which-cpus.c index 82c121412dfc..3ab53067e8dd 100644 --- a/tools/testing/selftests/riscv/hwprobe/which-cpus.c +++ b/tools/testing/selftests/riscv/hwprobe/which-cpus.c @@ -14,7 +14,7 @@ #include <assert.h> #include "hwprobe.h" -#include "../../kselftest.h" +#include "kselftest.h" static void help(void) { diff --git a/tools/testing/selftests/riscv/mm/mmap_bottomup.c b/tools/testing/selftests/riscv/mm/mmap_bottomup.c index f9ccae50349b..461a65c9be00 100644 --- a/tools/testing/selftests/riscv/mm/mmap_bottomup.c +++ b/tools/testing/selftests/riscv/mm/mmap_bottomup.c @@ -2,7 +2,7 @@ #include <sys/mman.h> #include <mmap_test.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" TEST(infinite_rlimit) { diff --git a/tools/testing/selftests/riscv/mm/mmap_default.c b/tools/testing/selftests/riscv/mm/mmap_default.c index 3f53b6ecc326..58db7d172af2 100644 --- a/tools/testing/selftests/riscv/mm/mmap_default.c +++ b/tools/testing/selftests/riscv/mm/mmap_default.c @@ -2,7 +2,7 @@ #include <sys/mman.h> #include <mmap_test.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" TEST(default_rlimit) { diff --git a/tools/testing/selftests/riscv/mm/mmap_test.h b/tools/testing/selftests/riscv/mm/mmap_test.h index 75918d15919f..266a6becdeba 100644 --- a/tools/testing/selftests/riscv/mm/mmap_test.h +++ b/tools/testing/selftests/riscv/mm/mmap_test.h @@ -5,7 +5,7 @@ #include <sys/resource.h> #include <stddef.h> #include <strings.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define TOP_DOWN 0 #define BOTTOM_UP 1 diff --git a/tools/testing/selftests/riscv/sigreturn/sigreturn.c b/tools/testing/selftests/riscv/sigreturn/sigreturn.c index ed351a1cb917..e10873d95fed 100644 --- a/tools/testing/selftests/riscv/sigreturn/sigreturn.c +++ b/tools/testing/selftests/riscv/sigreturn/sigreturn.c @@ -4,7 +4,7 @@ #include <stdlib.h> #include <ucontext.h> #include <linux/ptrace.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #define RISCV_V_MAGIC 0x53465457 #define DEFAULT_VALUE 2 diff --git a/tools/testing/selftests/riscv/vector/Makefile b/tools/testing/selftests/riscv/vector/Makefile index 6f7497f4e7b3..2c2a33fc083e 100644 --- a/tools/testing/selftests/riscv/vector/Makefile +++ b/tools/testing/selftests/riscv/vector/Makefile @@ -2,7 +2,7 @@ # Copyright (C) 2021 ARM Limited # Originally tools/testing/arm64/abi/Makefile -TEST_GEN_PROGS := v_initval vstate_prctl +TEST_GEN_PROGS := v_initval vstate_prctl vstate_ptrace TEST_GEN_PROGS_EXTENDED := vstate_exec_nolibc v_exec_initval_nolibc include ../../lib.mk @@ -26,3 +26,6 @@ $(OUTPUT)/v_initval: v_initval.c $(OUTPUT)/sys_hwprobe.o $(OUTPUT)/v_helpers.o $(OUTPUT)/v_exec_initval_nolibc: v_exec_initval_nolibc.c $(CC) -nostdlib -static -include ../../../../include/nolibc/nolibc.h \ -Wall $(CFLAGS) $(LDFLAGS) $^ -o $@ -lgcc + +$(OUTPUT)/vstate_ptrace: vstate_ptrace.c $(OUTPUT)/sys_hwprobe.o $(OUTPUT)/v_helpers.o + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^ diff --git a/tools/testing/selftests/riscv/vector/v_initval.c b/tools/testing/selftests/riscv/vector/v_initval.c index be9e1d18ad29..5fd2382e15a2 100644 --- a/tools/testing/selftests/riscv/vector/v_initval.c +++ b/tools/testing/selftests/riscv/vector/v_initval.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #include "v_helpers.h" #define NEXT_PROGRAM "./v_exec_initval_nolibc" diff --git a/tools/testing/selftests/riscv/vector/vstate_prctl.c b/tools/testing/selftests/riscv/vector/vstate_prctl.c index 62fbb17a0556..d607af3900c1 100644 --- a/tools/testing/selftests/riscv/vector/vstate_prctl.c +++ b/tools/testing/selftests/riscv/vector/vstate_prctl.c @@ -6,7 +6,7 @@ #include <sys/types.h> #include <stdlib.h> -#include "../../kselftest_harness.h" +#include "kselftest_harness.h" #include "v_helpers.h" #define NEXT_PROGRAM "./vstate_exec_nolibc" diff --git a/tools/testing/selftests/riscv/vector/vstate_ptrace.c b/tools/testing/selftests/riscv/vector/vstate_ptrace.c new file mode 100644 index 000000000000..1479abc0c9cb --- /dev/null +++ b/tools/testing/selftests/riscv/vector/vstate_ptrace.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include <stdio.h> +#include <stdlib.h> +#include <asm/ptrace.h> +#include <linux/elf.h> +#include <sys/ptrace.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include "../../kselftest.h" +#include "v_helpers.h" + +int parent_set_val, child_set_val; + +static long do_ptrace(enum __ptrace_request op, pid_t pid, long type, size_t size, void *data) +{ + struct iovec v_iovec = { + .iov_len = size, + .iov_base = data + }; + + return ptrace(op, pid, type, &v_iovec); +} + +static int do_child(void) +{ + int out; + + if (ptrace(PTRACE_TRACEME, -1, NULL, NULL)) { + ksft_perror("PTRACE_TRACEME failed\n"); + return EXIT_FAILURE; + } + + asm volatile (".option push\n\t" + ".option arch, +v\n\t" + ".option norvc\n\t" + "vsetivli x0, 1, e32, m1, ta, ma\n\t" + "vmv.s.x v31, %[in]\n\t" + "ebreak\n\t" + "vmv.x.s %[out], v31\n\t" + ".option pop\n\t" + : [out] "=r" (out) + : [in] "r" (child_set_val)); + + if (out != parent_set_val) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +static void do_parent(pid_t child) +{ + int status; + void *data = NULL; + + /* Attach to the child */ + while (waitpid(child, &status, 0)) { + if (WIFEXITED(status)) { + ksft_test_result(WEXITSTATUS(status) == 0, "SETREGSET vector\n"); + goto out; + } else if (WIFSTOPPED(status) && (WSTOPSIG(status) == SIGTRAP)) { + size_t size; + void *data, *v31; + struct __riscv_v_regset_state *v_regset_hdr; + struct user_regs_struct *gpreg; + + size = sizeof(*v_regset_hdr); + data = malloc(size); + if (!data) + goto out; + v_regset_hdr = (struct __riscv_v_regset_state *)data; + + if (do_ptrace(PTRACE_GETREGSET, child, NT_RISCV_VECTOR, size, data)) + goto out; + + ksft_print_msg("vlenb %ld\n", v_regset_hdr->vlenb); + data = realloc(data, size + v_regset_hdr->vlenb * 32); + if (!data) + goto out; + v_regset_hdr = (struct __riscv_v_regset_state *)data; + v31 = (void *)(data + size + v_regset_hdr->vlenb * 31); + size += v_regset_hdr->vlenb * 32; + + if (do_ptrace(PTRACE_GETREGSET, child, NT_RISCV_VECTOR, size, data)) + goto out; + + ksft_test_result(*(int *)v31 == child_set_val, "GETREGSET vector\n"); + + *(int *)v31 = parent_set_val; + if (do_ptrace(PTRACE_SETREGSET, child, NT_RISCV_VECTOR, size, data)) + goto out; + + /* move the pc forward */ + size = sizeof(*gpreg); + data = realloc(data, size); + gpreg = (struct user_regs_struct *)data; + + if (do_ptrace(PTRACE_GETREGSET, child, NT_PRSTATUS, size, data)) + goto out; + + gpreg->pc += 4; + if (do_ptrace(PTRACE_SETREGSET, child, NT_PRSTATUS, size, data)) + goto out; + } + + ptrace(PTRACE_CONT, child, NULL, NULL); + } + +out: + free(data); +} + +int main(void) +{ + pid_t child; + + ksft_set_plan(2); + if (!is_vector_supported() && !is_xtheadvector_supported()) + ksft_exit_skip("Vector not supported\n"); + + srandom(getpid()); + parent_set_val = rand(); + child_set_val = rand(); + + child = fork(); + if (child < 0) + ksft_exit_fail_msg("Fork failed %d\n", child); + + if (!child) + return do_child(); + + do_parent(child); + + ksft_finished(); +} diff --git a/tools/testing/selftests/rseq/basic_percpu_ops_test.c b/tools/testing/selftests/rseq/basic_percpu_ops_test.c index 2348d2c20d0a..1193612bf327 100644 --- a/tools/testing/selftests/rseq/basic_percpu_ops_test.c +++ b/tools/testing/selftests/rseq/basic_percpu_ops_test.c @@ -9,7 +9,7 @@ #include <string.h> #include <stddef.h> -#include "../kselftest.h" +#include "kselftest.h" #include "rseq.h" #ifdef BUILDOPT_RSEQ_PERCPU_MM_CID diff --git a/tools/testing/selftests/rseq/rseq.c b/tools/testing/selftests/rseq/rseq.c index dcac5cbe7933..a736727b83c1 100644 --- a/tools/testing/selftests/rseq/rseq.c +++ b/tools/testing/selftests/rseq/rseq.c @@ -33,7 +33,7 @@ #include <linux/compiler.h> -#include "../kselftest.h" +#include "kselftest.h" #include "rseq.h" /* diff --git a/tools/testing/selftests/rtc/rtctest.c b/tools/testing/selftests/rtc/rtctest.c index be175c0e6ae3..8047d9879039 100644 --- a/tools/testing/selftests/rtc/rtctest.c +++ b/tools/testing/selftests/rtc/rtctest.c @@ -16,7 +16,7 @@ #include <time.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define NUM_UIE 3 #define ALARM_DELTA 3 diff --git a/tools/testing/selftests/seccomp/seccomp_benchmark.c b/tools/testing/selftests/seccomp/seccomp_benchmark.c index 5822e25e0217..ea4068cdefd6 100644 --- a/tools/testing/selftests/seccomp/seccomp_benchmark.c +++ b/tools/testing/selftests/seccomp/seccomp_benchmark.c @@ -20,7 +20,7 @@ #include <sys/syscall.h> #include <sys/types.h> -#include "../kselftest.h" +#include "kselftest.h" unsigned long long timing(clockid_t clk_id, unsigned long long samples) { diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 874f17763536..32e2d4df397b 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -54,7 +54,7 @@ #include <sys/syscall.h> #include <poll.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "../clone3/clone3_selftests.h" /* Attempt to de-conflict with the selftests tree. */ diff --git a/tools/testing/selftests/sgx/main.c b/tools/testing/selftests/sgx/main.c index 9820b3809c69..13b84e54ce38 100644 --- a/tools/testing/selftests/sgx/main.c +++ b/tools/testing/selftests/sgx/main.c @@ -18,7 +18,7 @@ #include <sys/types.h> #include <sys/auxv.h> #include "defines.h" -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "main.h" static const uint64_t MAGIC = 0x1122334455667788ULL; diff --git a/tools/testing/selftests/signal/mangle_uc_sigmask.c b/tools/testing/selftests/signal/mangle_uc_sigmask.c index b79ab92178a8..11dbc14bbc8e 100644 --- a/tools/testing/selftests/signal/mangle_uc_sigmask.c +++ b/tools/testing/selftests/signal/mangle_uc_sigmask.c @@ -39,7 +39,7 @@ #include <signal.h> #include <ucontext.h> -#include "../kselftest.h" +#include "kselftest.h" void handler_verify_ucontext(int signo, siginfo_t *info, void *uc) { diff --git a/tools/testing/selftests/signal/sas.c b/tools/testing/selftests/signal/sas.c index 07227fab1cc9..306b996ab365 100644 --- a/tools/testing/selftests/signal/sas.c +++ b/tools/testing/selftests/signal/sas.c @@ -19,7 +19,7 @@ #include <errno.h> #include <sys/auxv.h> -#include "../kselftest.h" +#include "kselftest.h" #include "current_stack_pointer.h" #ifndef SS_AUTODISARM diff --git a/tools/testing/selftests/sparc64/drivers/adi-test.c b/tools/testing/selftests/sparc64/drivers/adi-test.c index 84e5d9fd20b0..b986714e7a52 100644 --- a/tools/testing/selftests/sparc64/drivers/adi-test.c +++ b/tools/testing/selftests/sparc64/drivers/adi-test.c @@ -16,7 +16,7 @@ #include <sys/stat.h> #include <unistd.h> -#include "../../kselftest.h" +#include "kselftest.h" #define DEBUG_LEVEL_1_BIT (0x0001) #define DEBUG_LEVEL_2_BIT (0x0002) diff --git a/tools/testing/selftests/sync/sync_test.c b/tools/testing/selftests/sync/sync_test.c index 93db5aa246a3..2b44e5d88b63 100644 --- a/tools/testing/selftests/sync/sync_test.c +++ b/tools/testing/selftests/sync/sync_test.c @@ -34,7 +34,7 @@ #include <errno.h> #include <string.h> -#include "../kselftest.h" +#include "kselftest.h" #include "synctest.h" static int run_test(int (*test)(void), char *name) diff --git a/tools/testing/selftests/syscall_user_dispatch/sud_test.c b/tools/testing/selftests/syscall_user_dispatch/sud_test.c index 2eb2c06303f2..b855c6000287 100644 --- a/tools/testing/selftests/syscall_user_dispatch/sud_test.c +++ b/tools/testing/selftests/syscall_user_dispatch/sud_test.c @@ -14,7 +14,7 @@ #include <stdlib.h> #include <asm/unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #ifndef PR_SET_SYSCALL_USER_DISPATCH # define PR_SET_SYSCALL_USER_DISPATCH 59 diff --git a/tools/testing/selftests/tdx/tdx_guest_test.c b/tools/testing/selftests/tdx/tdx_guest_test.c index 81d8cb88ea1a..dfaefa685519 100644 --- a/tools/testing/selftests/tdx/tdx_guest_test.c +++ b/tools/testing/selftests/tdx/tdx_guest_test.c @@ -13,7 +13,7 @@ #include <fcntl.h> #include <linux/tdx-guest.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define TDX_GUEST_DEVNAME "/dev/tdx_guest" #define HEX_DUMP_SIZE 8 diff --git a/tools/testing/selftests/timens/timens.h b/tools/testing/selftests/timens/timens.h index d4fc52d47146..7ca4b46ca61d 100644 --- a/tools/testing/selftests/timens/timens.h +++ b/tools/testing/selftests/timens/timens.h @@ -7,7 +7,7 @@ #include <stdlib.h> #include <stdbool.h> -#include "../kselftest.h" +#include "kselftest.h" #ifndef CLONE_NEWTIME # define CLONE_NEWTIME 0x00000080 diff --git a/tools/testing/selftests/timers/adjtick.c b/tools/testing/selftests/timers/adjtick.c index 777d9494b683..5b3ef708d6e9 100644 --- a/tools/testing/selftests/timers/adjtick.c +++ b/tools/testing/selftests/timers/adjtick.c @@ -24,7 +24,7 @@ #include <time.h> #include <include/vdso/time64.h> -#include "../kselftest.h" +#include "kselftest.h" #define MILLION 1000000 diff --git a/tools/testing/selftests/timers/alarmtimer-suspend.c b/tools/testing/selftests/timers/alarmtimer-suspend.c index a9ef76ea6051..aa66c805f6a4 100644 --- a/tools/testing/selftests/timers/alarmtimer-suspend.c +++ b/tools/testing/selftests/timers/alarmtimer-suspend.c @@ -30,7 +30,7 @@ #include <pthread.h> #include <include/vdso/time64.h> #include <errno.h> -#include "../kselftest.h" +#include "kselftest.h" #define UNREASONABLE_LAT (NSEC_PER_SEC * 5) /* hopefully we resume in 5 secs */ diff --git a/tools/testing/selftests/timers/change_skew.c b/tools/testing/selftests/timers/change_skew.c index 18e794a46c23..387fda10fcd8 100644 --- a/tools/testing/selftests/timers/change_skew.c +++ b/tools/testing/selftests/timers/change_skew.c @@ -28,7 +28,7 @@ #include <sys/time.h> #include <sys/timex.h> #include <time.h> -#include "../kselftest.h" +#include "kselftest.h" int change_skew_test(int ppm) { diff --git a/tools/testing/selftests/timers/clocksource-switch.c b/tools/testing/selftests/timers/clocksource-switch.c index 83faa4e354e3..db62a764c29e 100644 --- a/tools/testing/selftests/timers/clocksource-switch.c +++ b/tools/testing/selftests/timers/clocksource-switch.c @@ -34,7 +34,7 @@ #include <sys/wait.h> #include <time.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" int get_clocksources(char list[][30]) diff --git a/tools/testing/selftests/timers/freq-step.c b/tools/testing/selftests/timers/freq-step.c index 73b636f89fdc..cfa46dafe3e8 100644 --- a/tools/testing/selftests/timers/freq-step.c +++ b/tools/testing/selftests/timers/freq-step.c @@ -15,7 +15,7 @@ #include <time.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" #define SAMPLES 100 #define SAMPLE_READINGS 10 diff --git a/tools/testing/selftests/timers/inconsistency-check.c b/tools/testing/selftests/timers/inconsistency-check.c index 9d1573769d55..e53e63e18683 100644 --- a/tools/testing/selftests/timers/inconsistency-check.c +++ b/tools/testing/selftests/timers/inconsistency-check.c @@ -29,7 +29,7 @@ #include <string.h> #include <signal.h> #include <include/vdso/time64.h> -#include "../kselftest.h" +#include "kselftest.h" /* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */ #define CLOCK_HWSPECIFIC 10 diff --git a/tools/testing/selftests/timers/leap-a-day.c b/tools/testing/selftests/timers/leap-a-day.c index 04004a7c0934..3568cfb3e815 100644 --- a/tools/testing/selftests/timers/leap-a-day.c +++ b/tools/testing/selftests/timers/leap-a-day.c @@ -49,7 +49,7 @@ #include <signal.h> #include <unistd.h> #include <include/vdso/time64.h> -#include "../kselftest.h" +#include "kselftest.h" #define CLOCK_TAI 11 diff --git a/tools/testing/selftests/timers/leapcrash.c b/tools/testing/selftests/timers/leapcrash.c index 8fd065eec904..c2d3bccb52f2 100644 --- a/tools/testing/selftests/timers/leapcrash.c +++ b/tools/testing/selftests/timers/leapcrash.c @@ -22,7 +22,7 @@ #include <sys/timex.h> #include <string.h> #include <signal.h> -#include "../kselftest.h" +#include "kselftest.h" /* clear NTP time_status & time_state */ int clear_time_state(void) diff --git a/tools/testing/selftests/timers/mqueue-lat.c b/tools/testing/selftests/timers/mqueue-lat.c index 63de2334a291..c0d9368e4fca 100644 --- a/tools/testing/selftests/timers/mqueue-lat.c +++ b/tools/testing/selftests/timers/mqueue-lat.c @@ -30,7 +30,7 @@ #include <errno.h> #include <mqueue.h> #include <include/vdso/time64.h> -#include "../kselftest.h" +#include "kselftest.h" #define TARGET_TIMEOUT 100000000 /* 100ms in nanoseconds */ diff --git a/tools/testing/selftests/timers/nanosleep.c b/tools/testing/selftests/timers/nanosleep.c index 10badae13ebe..a054680b3372 100644 --- a/tools/testing/selftests/timers/nanosleep.c +++ b/tools/testing/selftests/timers/nanosleep.c @@ -28,7 +28,7 @@ #include <string.h> #include <signal.h> #include <include/vdso/time64.h> -#include "../kselftest.h" +#include "kselftest.h" /* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */ #define CLOCK_HWSPECIFIC 10 diff --git a/tools/testing/selftests/timers/nsleep-lat.c b/tools/testing/selftests/timers/nsleep-lat.c index de23dc0c9f97..a7ba1eb1e21b 100644 --- a/tools/testing/selftests/timers/nsleep-lat.c +++ b/tools/testing/selftests/timers/nsleep-lat.c @@ -25,7 +25,7 @@ #include <string.h> #include <signal.h> #include <include/vdso/time64.h> -#include "../kselftest.h" +#include "kselftest.h" #define UNRESONABLE_LATENCY 40000000 /* 40ms in nanosecs */ diff --git a/tools/testing/selftests/timers/posix_timers.c b/tools/testing/selftests/timers/posix_timers.c index a563c438ac79..38512623622a 100644 --- a/tools/testing/selftests/timers/posix_timers.c +++ b/tools/testing/selftests/timers/posix_timers.c @@ -20,7 +20,7 @@ #include <pthread.h> #include <stdbool.h> -#include "../kselftest.h" +#include "kselftest.h" #define DELAY 2 diff --git a/tools/testing/selftests/timers/raw_skew.c b/tools/testing/selftests/timers/raw_skew.c index 957f7cd29cb1..a7bae7d80916 100644 --- a/tools/testing/selftests/timers/raw_skew.c +++ b/tools/testing/selftests/timers/raw_skew.c @@ -26,7 +26,7 @@ #include <sys/timex.h> #include <time.h> #include <include/vdso/time64.h> -#include "../kselftest.h" +#include "kselftest.h" #define shift_right(x, s) ({ \ __typeof__(x) __x = (x); \ diff --git a/tools/testing/selftests/timers/rtcpie.c b/tools/testing/selftests/timers/rtcpie.c index 7c07edd0d450..4ba42d198b7e 100644 --- a/tools/testing/selftests/timers/rtcpie.c +++ b/tools/testing/selftests/timers/rtcpie.c @@ -18,7 +18,7 @@ #include <stdlib.h> #include <errno.h> -#include "../kselftest.h" +#include "kselftest.h" /* * This expects the new RTC class driver framework, working with diff --git a/tools/testing/selftests/timers/set-2038.c b/tools/testing/selftests/timers/set-2038.c index ed244315e11c..ecc171de4728 100644 --- a/tools/testing/selftests/timers/set-2038.c +++ b/tools/testing/selftests/timers/set-2038.c @@ -28,7 +28,7 @@ #include <time.h> #include <sys/time.h> #include <include/vdso/time64.h> -#include "../kselftest.h" +#include "kselftest.h" #define KTIME_MAX ((long long)~((unsigned long long)1 << 63)) #define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) diff --git a/tools/testing/selftests/timers/set-tai.c b/tools/testing/selftests/timers/set-tai.c index 5b67462efcd6..e283c04284af 100644 --- a/tools/testing/selftests/timers/set-tai.c +++ b/tools/testing/selftests/timers/set-tai.c @@ -23,7 +23,7 @@ #include <string.h> #include <signal.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" int set_tai(int offset) { diff --git a/tools/testing/selftests/timers/set-timer-lat.c b/tools/testing/selftests/timers/set-timer-lat.c index 9d8437c13929..44d2e3614fa5 100644 --- a/tools/testing/selftests/timers/set-timer-lat.c +++ b/tools/testing/selftests/timers/set-timer-lat.c @@ -29,7 +29,7 @@ #include <stdlib.h> #include <pthread.h> #include <include/vdso/time64.h> -#include "../kselftest.h" +#include "kselftest.h" /* CLOCK_HWSPECIFIC == CLOCK_SGI_CYCLE (Deprecated) */ #define CLOCK_HWSPECIFIC 10 diff --git a/tools/testing/selftests/timers/set-tz.c b/tools/testing/selftests/timers/set-tz.c index 20daaf1782b7..334f36c0eda6 100644 --- a/tools/testing/selftests/timers/set-tz.c +++ b/tools/testing/selftests/timers/set-tz.c @@ -23,7 +23,7 @@ #include <string.h> #include <signal.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" int set_tz(int min, int dst) { diff --git a/tools/testing/selftests/timers/skew_consistency.c b/tools/testing/selftests/timers/skew_consistency.c index 46c391d7f45d..53ee5d710ff4 100644 --- a/tools/testing/selftests/timers/skew_consistency.c +++ b/tools/testing/selftests/timers/skew_consistency.c @@ -34,7 +34,7 @@ #include <fcntl.h> #include <string.h> #include <sys/wait.h> -#include "../kselftest.h" +#include "kselftest.h" int main(int argc, char **argv) { diff --git a/tools/testing/selftests/timers/threadtest.c b/tools/testing/selftests/timers/threadtest.c index d5564bbf0e50..60b8b21bf782 100644 --- a/tools/testing/selftests/timers/threadtest.c +++ b/tools/testing/selftests/timers/threadtest.c @@ -21,7 +21,7 @@ #include <stdlib.h> #include <sys/time.h> #include <pthread.h> -#include "../kselftest.h" +#include "kselftest.h" /* serializes shared list access */ pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER; diff --git a/tools/testing/selftests/timers/valid-adjtimex.c b/tools/testing/selftests/timers/valid-adjtimex.c index 6b7801055ad1..e1e56d3097d6 100644 --- a/tools/testing/selftests/timers/valid-adjtimex.c +++ b/tools/testing/selftests/timers/valid-adjtimex.c @@ -30,7 +30,7 @@ #include <signal.h> #include <unistd.h> #include <include/vdso/time64.h> -#include "../kselftest.h" +#include "kselftest.h" #define ADJ_SETOFFSET 0x0100 diff --git a/tools/testing/selftests/tmpfs/bug-link-o-tmpfile.c b/tools/testing/selftests/tmpfs/bug-link-o-tmpfile.c index 02ecfe687dc2..5cb4e404a2bd 100644 --- a/tools/testing/selftests/tmpfs/bug-link-o-tmpfile.c +++ b/tools/testing/selftests/tmpfs/bug-link-o-tmpfile.c @@ -23,7 +23,7 @@ #include <sys/mount.h> #include <unistd.h> -#include "../kselftest.h" +#include "kselftest.h" int main(void) { diff --git a/tools/testing/selftests/tty/.gitignore b/tools/testing/selftests/tty/.gitignore index fe70462a4aad..2453685d2493 100644 --- a/tools/testing/selftests/tty/.gitignore +++ b/tools/testing/selftests/tty/.gitignore @@ -1,2 +1,3 @@ # SPDX-License-Identifier: GPL-2.0-only +tty_tiocsti_test tty_tstamp_update diff --git a/tools/testing/selftests/tty/Makefile b/tools/testing/selftests/tty/Makefile index 50d7027b2ae3..7f6fbe5a0cd5 100644 --- a/tools/testing/selftests/tty/Makefile +++ b/tools/testing/selftests/tty/Makefile @@ -1,5 +1,9 @@ # SPDX-License-Identifier: GPL-2.0 CFLAGS = -O2 -Wall -TEST_GEN_PROGS := tty_tstamp_update +TEST_GEN_PROGS := tty_tstamp_update tty_tiocsti_test +LDLIBS += -lcap include ../lib.mk + +# Add libcap for TIOCSTI test +$(OUTPUT)/tty_tiocsti_test: LDLIBS += -lcap diff --git a/tools/testing/selftests/tty/config b/tools/testing/selftests/tty/config new file mode 100644 index 000000000000..c6373aba6636 --- /dev/null +++ b/tools/testing/selftests/tty/config @@ -0,0 +1 @@ +CONFIG_LEGACY_TIOCSTI=y diff --git a/tools/testing/selftests/tty/tty_tiocsti_test.c b/tools/testing/selftests/tty/tty_tiocsti_test.c new file mode 100644 index 000000000000..5e767e6cb3ef --- /dev/null +++ b/tools/testing/selftests/tty/tty_tiocsti_test.c @@ -0,0 +1,650 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * TTY Tests - TIOCSTI + * + * Copyright © 2025 Abhinav Saxena <xandfury@gmail.com> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <stdbool.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/wait.h> +#include <pwd.h> +#include <termios.h> +#include <grp.h> +#include <sys/capability.h> +#include <sys/prctl.h> +#include <pty.h> +#include <utmp.h> + +#include "../kselftest_harness.h" + +enum test_type { + TEST_PTY_TIOCSTI_BASIC, + TEST_PTY_TIOCSTI_FD_PASSING, + /* other tests cases such as serial may be added. */ +}; + +/* + * Test Strategy: + * - Basic tests: Use PTY with/without TIOCSCTTY (controlling terminal for + * current process) + * - FD passing tests: Child creates PTY, parent receives FD (demonstrates + * security issue) + * + * SECURITY VULNERABILITY DEMONSTRATION: + * FD passing tests show that TIOCSTI uses CURRENT process credentials, not + * opener credentials. This means privileged processes can be given FDs from + * unprivileged processes and successfully perform TIOCSTI operations that the + * unprivileged process couldn't do directly. + * + * Attack scenario: + * 1. Unprivileged process opens TTY (direct TIOCSTI fails due to lack of + * privileges) + * 2. Unprivileged process passes FD to privileged process via SCM_RIGHTS + * 3. Privileged process can use TIOCSTI on the FD (succeeds due to its + * privileges) + * 4. Result: Effective privilege escalation via file descriptor passing + * + * This matches the kernel logic in tiocsti(): + * 1. if (!tty_legacy_tiocsti && !capable(CAP_SYS_ADMIN)) return -EIO; + * 2. if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) + * return -EPERM; + * Note: Both checks use capable() on CURRENT process, not FD opener! + * + * If the file credentials were also checked along with the capable() checks + * then the results for FD pass tests would be consistent with the basic tests. + */ + +FIXTURE(tiocsti) +{ + int pty_master_fd; /* PTY - for basic tests */ + int pty_slave_fd; + bool has_pty; + bool initial_cap_sys_admin; + int original_legacy_tiocsti_setting; + bool can_modify_sysctl; +}; + +FIXTURE_VARIANT(tiocsti) +{ + const enum test_type test_type; + const bool controlling_tty; /* true=current->signal->tty == tty */ + const int legacy_tiocsti; /* 0=restricted, 1=permissive */ + const bool requires_cap; /* true=with CAP_SYS_ADMIN, false=without */ + const int expected_success; /* 0=success, -EIO/-EPERM=specific error */ +}; + +/* + * Tests Controlling Terminal Variants (current->signal->tty == tty) + * + * TIOCSTI Test Matrix: + * + * | legacy_tiocsti | CAP_SYS_ADMIN | Expected Result | Error | + * |----------------|---------------|-----------------|-------| + * | 1 (permissive) | true | SUCCESS | - | + * | 1 (permissive) | false | SUCCESS | - | + * | 0 (restricted) | true | SUCCESS | - | + * | 0 (restricted) | false | FAILURE | -EIO | + */ + +/* clang-format off */ +FIXTURE_VARIANT_ADD(tiocsti, basic_pty_permissive_withcap) { + .test_type = TEST_PTY_TIOCSTI_BASIC, + .controlling_tty = true, + .legacy_tiocsti = 1, + .requires_cap = true, + .expected_success = 0, +}; + +FIXTURE_VARIANT_ADD(tiocsti, basic_pty_permissive_nocap) { + .test_type = TEST_PTY_TIOCSTI_BASIC, + .controlling_tty = true, + .legacy_tiocsti = 1, + .requires_cap = false, + .expected_success = 0, +}; + +FIXTURE_VARIANT_ADD(tiocsti, basic_pty_restricted_withcap) { + .test_type = TEST_PTY_TIOCSTI_BASIC, + .controlling_tty = true, + .legacy_tiocsti = 0, + .requires_cap = true, + .expected_success = 0, +}; + +FIXTURE_VARIANT_ADD(tiocsti, basic_pty_restricted_nocap) { + .test_type = TEST_PTY_TIOCSTI_BASIC, + .controlling_tty = true, + .legacy_tiocsti = 0, + .requires_cap = false, + .expected_success = -EIO, /* FAILURE: legacy restriction */ +}; /* clang-format on */ + +/* + * Note for FD Passing Test Variants + * Since we're testing the scenario where an unprivileged process pass an FD + * to a privileged one, .requires_cap here means the caps of the child process. + * Not the parent; parent would always be privileged. + */ + +/* clang-format off */ +FIXTURE_VARIANT_ADD(tiocsti, fdpass_pty_permissive_withcap) { + .test_type = TEST_PTY_TIOCSTI_FD_PASSING, + .controlling_tty = true, + .legacy_tiocsti = 1, + .requires_cap = true, + .expected_success = 0, +}; + +FIXTURE_VARIANT_ADD(tiocsti, fdpass_pty_permissive_nocap) { + .test_type = TEST_PTY_TIOCSTI_FD_PASSING, + .controlling_tty = true, + .legacy_tiocsti = 1, + .requires_cap = false, + .expected_success = 0, +}; + +FIXTURE_VARIANT_ADD(tiocsti, fdpass_pty_restricted_withcap) { + .test_type = TEST_PTY_TIOCSTI_FD_PASSING, + .controlling_tty = true, + .legacy_tiocsti = 0, + .requires_cap = true, + .expected_success = 0, +}; + +FIXTURE_VARIANT_ADD(tiocsti, fdpass_pty_restricted_nocap) { + .test_type = TEST_PTY_TIOCSTI_FD_PASSING, + .controlling_tty = true, + .legacy_tiocsti = 0, + .requires_cap = false, + .expected_success = -EIO, +}; /* clang-format on */ + +/* + * Non-Controlling Terminal Variants (current->signal->tty != tty) + * + * TIOCSTI Test Matrix: + * + * | legacy_tiocsti | CAP_SYS_ADMIN | Expected Result | Error | + * |----------------|---------------|-----------------|-------| + * | 1 (permissive) | true | SUCCESS | - | + * | 1 (permissive) | false | FAILURE | -EPERM| + * | 0 (restricted) | true | SUCCESS | - | + * | 0 (restricted) | false | FAILURE | -EIO | + */ + +/* clang-format off */ +FIXTURE_VARIANT_ADD(tiocsti, basic_nopty_permissive_withcap) { + .test_type = TEST_PTY_TIOCSTI_BASIC, + .controlling_tty = false, + .legacy_tiocsti = 1, + .requires_cap = true, + .expected_success = 0, +}; + +FIXTURE_VARIANT_ADD(tiocsti, basic_nopty_permissive_nocap) { + .test_type = TEST_PTY_TIOCSTI_BASIC, + .controlling_tty = false, + .legacy_tiocsti = 1, + .requires_cap = false, + .expected_success = -EPERM, +}; + +FIXTURE_VARIANT_ADD(tiocsti, basic_nopty_restricted_withcap) { + .test_type = TEST_PTY_TIOCSTI_BASIC, + .controlling_tty = false, + .legacy_tiocsti = 0, + .requires_cap = true, + .expected_success = 0, +}; + +FIXTURE_VARIANT_ADD(tiocsti, basic_nopty_restricted_nocap) { + .test_type = TEST_PTY_TIOCSTI_BASIC, + .controlling_tty = false, + .legacy_tiocsti = 0, + .requires_cap = false, + .expected_success = -EIO, +}; + +FIXTURE_VARIANT_ADD(tiocsti, fdpass_nopty_permissive_withcap) { + .test_type = TEST_PTY_TIOCSTI_FD_PASSING, + .controlling_tty = false, + .legacy_tiocsti = 1, + .requires_cap = true, + .expected_success = 0, +}; + +FIXTURE_VARIANT_ADD(tiocsti, fdpass_nopty_permissive_nocap) { + .test_type = TEST_PTY_TIOCSTI_FD_PASSING, + .controlling_tty = false, + .legacy_tiocsti = 1, + .requires_cap = false, + .expected_success = -EPERM, +}; + +FIXTURE_VARIANT_ADD(tiocsti, fdpass_nopty_restricted_withcap) { + .test_type = TEST_PTY_TIOCSTI_FD_PASSING, + .controlling_tty = false, + .legacy_tiocsti = 0, + .requires_cap = true, + .expected_success = 0, +}; + +FIXTURE_VARIANT_ADD(tiocsti, fdpass_nopty_restricted_nocap) { + .test_type = TEST_PTY_TIOCSTI_FD_PASSING, + .controlling_tty = false, + .legacy_tiocsti = 0, + .requires_cap = false, + .expected_success = -EIO, +}; /* clang-format on */ + +/* Helper function to send FD via SCM_RIGHTS */ +static int send_fd_via_socket(int socket_fd, int fd_to_send) +{ + struct msghdr msg = { 0 }; + struct cmsghdr *cmsg; + char cmsg_buf[CMSG_SPACE(sizeof(int))]; + char dummy_data = 'F'; + struct iovec iov = { .iov_base = &dummy_data, .iov_len = 1 }; + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsg_buf; + msg.msg_controllen = sizeof(cmsg_buf); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + + memcpy(CMSG_DATA(cmsg), &fd_to_send, sizeof(int)); + + return sendmsg(socket_fd, &msg, 0) < 0 ? -1 : 0; +} + +/* Helper function to receive FD via SCM_RIGHTS */ +static int recv_fd_via_socket(int socket_fd) +{ + struct msghdr msg = { 0 }; + struct cmsghdr *cmsg; + char cmsg_buf[CMSG_SPACE(sizeof(int))]; + char dummy_data; + struct iovec iov = { .iov_base = &dummy_data, .iov_len = 1 }; + int received_fd = -1; + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsg_buf; + msg.msg_controllen = sizeof(cmsg_buf); + + if (recvmsg(socket_fd, &msg, 0) < 0) + return -1; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS) { + memcpy(&received_fd, CMSG_DATA(cmsg), sizeof(int)); + break; + } + } + + return received_fd; +} + +static inline bool has_cap_sys_admin(void) +{ + cap_t caps = cap_get_proc(); + + if (!caps) + return false; + + cap_flag_value_t cap_val; + bool has_cap = (cap_get_flag(caps, CAP_SYS_ADMIN, CAP_EFFECTIVE, + &cap_val) == 0) && + (cap_val == CAP_SET); + + cap_free(caps); + return has_cap; +} + +/* + * Switch to non-root user and clear all capabilities + */ +static inline bool drop_all_privs(struct __test_metadata *_metadata) +{ + /* Drop supplementary groups */ + ASSERT_EQ(setgroups(0, NULL), 0); + + /* Switch to non-root user */ + ASSERT_EQ(setgid(1000), 0); + ASSERT_EQ(setuid(1000), 0); + + /* Clear all capabilities */ + cap_t empty = cap_init(); + + ASSERT_NE(empty, NULL); + ASSERT_EQ(cap_set_proc(empty), 0); + cap_free(empty); + + /* Prevent privilege regain */ + ASSERT_EQ(prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0), 0); + + /* Verify privilege drop */ + ASSERT_FALSE(has_cap_sys_admin()); + return true; +} + +static inline int get_legacy_tiocsti_setting(struct __test_metadata *_metadata) +{ + FILE *fp; + int value = -1; + + fp = fopen("/proc/sys/dev/tty/legacy_tiocsti", "r"); + if (!fp) { + /* legacy_tiocsti sysctl not available (kernel < 6.2) */ + return -1; + } + + if (fscanf(fp, "%d", &value) == 1 && fclose(fp) == 0) { + if (value < 0 || value > 1) + value = -1; /* Invalid value */ + } else { + value = -1; /* Failed to parse */ + } + + return value; +} + +static inline bool set_legacy_tiocsti_setting(struct __test_metadata *_metadata, + int value) +{ + FILE *fp; + bool success = false; + + /* Sanity-check the value */ + ASSERT_GE(value, 0); + ASSERT_LE(value, 1); + + /* + * Try to open for writing; if we lack permission, return false so + * the test harness will skip variants that need to change it + */ + fp = fopen("/proc/sys/dev/tty/legacy_tiocsti", "w"); + if (!fp) + return false; + + /* Write the new setting */ + if (fprintf(fp, "%d\n", value) > 0 && fclose(fp) == 0) + success = true; + else + TH_LOG("Failed to write legacy_tiocsti: %s", strerror(errno)); + + return success; +} + +/* + * TIOCSTI injection test function + * @tty_fd: TTY slave file descriptor to test TIOCSTI on + * Returns: 0 on success, -errno on failure + */ +static inline int test_tiocsti_injection(struct __test_metadata *_metadata, + int tty_fd) +{ + int ret; + char inject_char = 'V'; + + errno = 0; + ret = ioctl(tty_fd, TIOCSTI, &inject_char); + return ret == 0 ? 0 : -errno; +} + +/* + * Child process: test TIOCSTI directly with capability/controlling + * terminal setup + */ +static void run_basic_tiocsti_test(struct __test_metadata *_metadata, + FIXTURE_DATA(tiocsti) * self, + const FIXTURE_VARIANT(tiocsti) * variant) +{ + /* Handle capability requirements */ + if (self->initial_cap_sys_admin && !variant->requires_cap) + ASSERT_TRUE(drop_all_privs(_metadata)); + + if (variant->controlling_tty) { + /* + * Create new session and set PTY as + * controlling terminal + */ + pid_t sid = setsid(); + + ASSERT_GE(sid, 0); + ASSERT_EQ(ioctl(self->pty_slave_fd, TIOCSCTTY, 0), 0); + } + + /* + * Validate test environment setup and verify final + * capability state matches expectation + * after potential drop. + */ + ASSERT_TRUE(self->has_pty); + ASSERT_EQ(has_cap_sys_admin(), variant->requires_cap); + + /* Test TIOCSTI and validate result */ + int result = test_tiocsti_injection(_metadata, self->pty_slave_fd); + + /* Check against expected result from variant */ + EXPECT_EQ(result, variant->expected_success); + _exit(0); +} + +/* + * Child process: create PTY and then pass FD to parent via SCM_RIGHTS + */ +static void run_fdpass_tiocsti_test(struct __test_metadata *_metadata, + const FIXTURE_VARIANT(tiocsti) * variant, + int sockfd) +{ + signal(SIGHUP, SIG_IGN); + + /* Handle privilege dropping */ + if (!variant->requires_cap && has_cap_sys_admin()) + ASSERT_TRUE(drop_all_privs(_metadata)); + + /* Create child's PTY */ + int child_master_fd, child_slave_fd; + + ASSERT_EQ(openpty(&child_master_fd, &child_slave_fd, NULL, NULL, NULL), + 0); + + if (variant->controlling_tty) { + pid_t sid = setsid(); + + ASSERT_GE(sid, 0); + ASSERT_EQ(ioctl(child_slave_fd, TIOCSCTTY, 0), 0); + } + + /* Test child's direct TIOCSTI for reference */ + int direct_result = test_tiocsti_injection(_metadata, child_slave_fd); + + EXPECT_EQ(direct_result, variant->expected_success); + + /* Send FD to parent */ + ASSERT_EQ(send_fd_via_socket(sockfd, child_slave_fd), 0); + + /* Wait for parent completion signal */ + char sync_byte; + ssize_t bytes_read = read(sockfd, &sync_byte, 1); + + ASSERT_EQ(bytes_read, 1); + + close(child_master_fd); + close(child_slave_fd); + close(sockfd); + _exit(0); +} + +FIXTURE_SETUP(tiocsti) +{ + /* Create PTY pair for basic tests */ + self->has_pty = (openpty(&self->pty_master_fd, &self->pty_slave_fd, + NULL, NULL, NULL) == 0); + if (!self->has_pty) { + self->pty_master_fd = -1; + self->pty_slave_fd = -1; + } + + self->initial_cap_sys_admin = has_cap_sys_admin(); + self->original_legacy_tiocsti_setting = + get_legacy_tiocsti_setting(_metadata); + + if (self->original_legacy_tiocsti_setting < 0) + SKIP(return, + "legacy_tiocsti sysctl not available (kernel < 6.2)"); + + /* Common skip conditions */ + if (variant->test_type == TEST_PTY_TIOCSTI_BASIC && !self->has_pty) + SKIP(return, "PTY not available for controlling terminal test"); + + if (variant->test_type == TEST_PTY_TIOCSTI_FD_PASSING && + !self->initial_cap_sys_admin) + SKIP(return, "FD Pass tests require CAP_SYS_ADMIN"); + + if (variant->requires_cap && !self->initial_cap_sys_admin) + SKIP(return, "Test requires initial CAP_SYS_ADMIN"); + + /* Test if we can modify the sysctl (requires appropriate privileges) */ + self->can_modify_sysctl = set_legacy_tiocsti_setting( + _metadata, self->original_legacy_tiocsti_setting); + + /* Sysctl setup based on variant */ + if (self->can_modify_sysctl && + self->original_legacy_tiocsti_setting != variant->legacy_tiocsti) { + if (!set_legacy_tiocsti_setting(_metadata, + variant->legacy_tiocsti)) + SKIP(return, "Failed to set legacy_tiocsti sysctl"); + + } else if (!self->can_modify_sysctl && + self->original_legacy_tiocsti_setting != + variant->legacy_tiocsti) + SKIP(return, "legacy_tiocsti setting mismatch"); +} + +FIXTURE_TEARDOWN(tiocsti) +{ + /* + * Backup restoration - + * each test should restore its own sysctl changes + */ + if (self->can_modify_sysctl) { + int current_value = get_legacy_tiocsti_setting(_metadata); + + if (current_value != self->original_legacy_tiocsti_setting) { + TH_LOG("Backup: Restoring legacy_tiocsti from %d to %d", + current_value, + self->original_legacy_tiocsti_setting); + set_legacy_tiocsti_setting( + _metadata, + self->original_legacy_tiocsti_setting); + } + } + + if (self->has_pty) { + if (self->pty_master_fd >= 0) + close(self->pty_master_fd); + if (self->pty_slave_fd >= 0) + close(self->pty_slave_fd); + } +} + +TEST_F(tiocsti, test) +{ + int status; + pid_t child_pid; + + if (variant->test_type == TEST_PTY_TIOCSTI_BASIC) { + /* ===== BASIC TIOCSTI TEST ===== */ + child_pid = fork(); + ASSERT_GE(child_pid, 0); + + /* Perform the actual test in the child process */ + if (child_pid == 0) + run_basic_tiocsti_test(_metadata, self, variant); + + } else { + /* ===== FD PASSING SECURITY TEST ===== */ + int sockpair[2]; + + ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM, 0, sockpair), 0); + + child_pid = fork(); + ASSERT_GE(child_pid, 0); + + if (child_pid == 0) { + /* Child process - create PTY and send FD */ + close(sockpair[0]); + run_fdpass_tiocsti_test(_metadata, variant, + sockpair[1]); + } + + /* Parent process - receive FD and test TIOCSTI */ + close(sockpair[1]); + + int received_fd = recv_fd_via_socket(sockpair[0]); + + ASSERT_GE(received_fd, 0); + + bool parent_has_cap = self->initial_cap_sys_admin; + + TH_LOG("=== TIOCSTI FD Passing Test Context ==="); + TH_LOG("legacy_tiocsti: %d, Parent CAP_SYS_ADMIN: %s, Child: %s", + variant->legacy_tiocsti, parent_has_cap ? "yes" : "no", + variant->requires_cap ? "kept" : "dropped"); + + /* SECURITY TEST: Try TIOCSTI with FD opened by child */ + int result = test_tiocsti_injection(_metadata, received_fd); + + /* Log security concern if demonstrated */ + if (result == 0 && !variant->requires_cap) { + TH_LOG("*** SECURITY CONCERN DEMONSTRATED ***"); + TH_LOG("Privileged parent can use TIOCSTI on FD from unprivileged child"); + TH_LOG("This shows current process credentials are used, not opener credentials"); + } + + EXPECT_EQ(result, variant->expected_success) + { + TH_LOG("FD passing: expected error %d, got %d", + variant->expected_success, result); + } + + /* Signal child completion */ + char sync_byte = 'D'; + ssize_t bytes_written = write(sockpair[0], &sync_byte, 1); + + ASSERT_EQ(bytes_written, 1); + + close(received_fd); + close(sockpair[0]); + } + + /* Common child process cleanup for both test types */ + ASSERT_EQ(waitpid(child_pid, &status, 0), child_pid); + + if (WIFSIGNALED(status)) { + TH_LOG("Child terminated by signal %d", WTERMSIG(status)); + ASSERT_FALSE(WIFSIGNALED(status)) + { + TH_LOG("Child process failed assertion"); + } + } else { + EXPECT_EQ(WEXITSTATUS(status), 0); + } +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/tty/tty_tstamp_update.c b/tools/testing/selftests/tty/tty_tstamp_update.c index 9e1a40f5db17..bc3291dcd18b 100644 --- a/tools/testing/selftests/tty/tty_tstamp_update.c +++ b/tools/testing/selftests/tty/tty_tstamp_update.c @@ -9,7 +9,7 @@ #include <unistd.h> #include <linux/limits.h> -#include "../kselftest.h" +#include "kselftest.h" #define MIN_TTY_PATH_LEN 8 diff --git a/tools/testing/selftests/uevent/uevent_filtering.c b/tools/testing/selftests/uevent/uevent_filtering.c index dbe55f3a66f4..974b076f9235 100644 --- a/tools/testing/selftests/uevent/uevent_filtering.c +++ b/tools/testing/selftests/uevent/uevent_filtering.c @@ -19,7 +19,7 @@ #include <sys/wait.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #define __DEV_FULL "/sys/devices/virtual/mem/full/uevent" #define __UEVENT_BUFFER_SIZE (2048 * 2) diff --git a/tools/testing/selftests/user_events/abi_test.c b/tools/testing/selftests/user_events/abi_test.c index 7288a05136ba..85892b3b719c 100644 --- a/tools/testing/selftests/user_events/abi_test.c +++ b/tools/testing/selftests/user_events/abi_test.c @@ -20,7 +20,7 @@ #include <string.h> #include <asm/unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "user_events_selftests.h" const char *data_file = "/sys/kernel/tracing/user_events_data"; diff --git a/tools/testing/selftests/user_events/dyn_test.c b/tools/testing/selftests/user_events/dyn_test.c index 54c9412f8dee..78e3c33f4015 100644 --- a/tools/testing/selftests/user_events/dyn_test.c +++ b/tools/testing/selftests/user_events/dyn_test.c @@ -14,7 +14,7 @@ #include <sys/stat.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "user_events_selftests.h" const char *dyn_file = "/sys/kernel/tracing/dynamic_events"; diff --git a/tools/testing/selftests/user_events/ftrace_test.c b/tools/testing/selftests/user_events/ftrace_test.c index 0bb46793dcd4..decce06b9ba8 100644 --- a/tools/testing/selftests/user_events/ftrace_test.c +++ b/tools/testing/selftests/user_events/ftrace_test.c @@ -15,7 +15,7 @@ #include <sys/uio.h> #include <unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "user_events_selftests.h" const char *data_file = "/sys/kernel/tracing/user_events_data"; diff --git a/tools/testing/selftests/user_events/perf_test.c b/tools/testing/selftests/user_events/perf_test.c index 68625362add2..cafec0e52eb3 100644 --- a/tools/testing/selftests/user_events/perf_test.c +++ b/tools/testing/selftests/user_events/perf_test.c @@ -16,7 +16,7 @@ #include <unistd.h> #include <asm/unistd.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" #include "user_events_selftests.h" const char *data_file = "/sys/kernel/tracing/user_events_data"; diff --git a/tools/testing/selftests/user_events/user_events_selftests.h b/tools/testing/selftests/user_events/user_events_selftests.h index e1c3c063c031..3b5d37e46f8a 100644 --- a/tools/testing/selftests/user_events/user_events_selftests.h +++ b/tools/testing/selftests/user_events/user_events_selftests.h @@ -9,7 +9,7 @@ #include <unistd.h> #include <errno.h> -#include "../kselftest.h" +#include "kselftest.h" static inline void tracefs_unmount(void) { diff --git a/tools/testing/selftests/vDSO/vdso_test_abi.c b/tools/testing/selftests/vDSO/vdso_test_abi.c index 238d609a457a..c620317eaeea 100644 --- a/tools/testing/selftests/vDSO/vdso_test_abi.c +++ b/tools/testing/selftests/vDSO/vdso_test_abi.c @@ -18,7 +18,7 @@ #include <unistd.h> #include <sys/syscall.h> -#include "../kselftest.h" +#include "kselftest.h" #include "vdso_config.h" #include "vdso_call.h" #include "parse_vdso.h" diff --git a/tools/testing/selftests/vDSO/vdso_test_chacha.c b/tools/testing/selftests/vDSO/vdso_test_chacha.c index 0aad682b12c8..9a5c9c05e09c 100644 --- a/tools/testing/selftests/vDSO/vdso_test_chacha.c +++ b/tools/testing/selftests/vDSO/vdso_test_chacha.c @@ -10,7 +10,7 @@ #include <string.h> #include <stdint.h> #include <stdbool.h> -#include "../kselftest.h" +#include "kselftest.h" #if defined(__aarch64__) static bool cpu_has_capabilities(void) diff --git a/tools/testing/selftests/vDSO/vdso_test_correctness.c b/tools/testing/selftests/vDSO/vdso_test_correctness.c index da651cf53c6c..055af95aa552 100644 --- a/tools/testing/selftests/vDSO/vdso_test_correctness.c +++ b/tools/testing/selftests/vDSO/vdso_test_correctness.c @@ -21,7 +21,7 @@ #include "vdso_config.h" #include "vdso_call.h" -#include "../kselftest.h" +#include "kselftest.h" static const char **name; diff --git a/tools/testing/selftests/vDSO/vdso_test_getcpu.c b/tools/testing/selftests/vDSO/vdso_test_getcpu.c index cdeaed45fb26..bea8ad54da11 100644 --- a/tools/testing/selftests/vDSO/vdso_test_getcpu.c +++ b/tools/testing/selftests/vDSO/vdso_test_getcpu.c @@ -11,7 +11,7 @@ #include <sys/auxv.h> #include <sys/time.h> -#include "../kselftest.h" +#include "kselftest.h" #include "parse_vdso.h" #include "vdso_config.h" #include "vdso_call.h" diff --git a/tools/testing/selftests/vDSO/vdso_test_getrandom.c b/tools/testing/selftests/vDSO/vdso_test_getrandom.c index dd1132508a0d..ef402001e898 100644 --- a/tools/testing/selftests/vDSO/vdso_test_getrandom.c +++ b/tools/testing/selftests/vDSO/vdso_test_getrandom.c @@ -23,7 +23,7 @@ #include <linux/random.h> #include <linux/ptrace.h> -#include "../kselftest.h" +#include "kselftest.h" #include "parse_vdso.h" #include "vdso_config.h" #include "vdso_call.h" diff --git a/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c b/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c index 9ce795b806f0..912edadad92c 100644 --- a/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c +++ b/tools/testing/selftests/vDSO/vdso_test_gettimeofday.c @@ -16,7 +16,7 @@ #include <sys/time.h> #endif -#include "../kselftest.h" +#include "kselftest.h" #include "parse_vdso.h" #include "vdso_config.h" #include "vdso_call.h" diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index 13fdb4b0b10f..8e34b9bfc96b 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -19,7 +19,7 @@ #include <linux/types.h> #include <linux/vfio.h> -#include "../../../kselftest.h" +#include "kselftest.h" #include <libvfio.h> #define PCI_SYSFS_PATH "/sys/bus/pci/devices" diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c index ca0e25efbfa1..6827f4a6febe 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_driver.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_driver.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -#include "../../../kselftest.h" +#include "kselftest.h" #include <libvfio.h> #ifdef __x86_64__ diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c index 5397822c3dd4..16eba2ecca47 100644 --- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c @@ -12,7 +12,7 @@ #include <libvfio.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static const char *device_bdf; diff --git a/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c b/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c index caf1c6291f3d..17017ed3beac 100644 --- a/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c +++ b/tools/testing/selftests/vfio/vfio_iommufd_setup_test.c @@ -11,7 +11,7 @@ #include <unistd.h> #include <libvfio.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static const char iommu_dev_path[] = "/dev/iommu"; static const char *cdev_path; diff --git a/tools/testing/selftests/vfio/vfio_pci_device_test.c b/tools/testing/selftests/vfio/vfio_pci_device_test.c index ecbb669b3765..7c0fe8ce3a61 100644 --- a/tools/testing/selftests/vfio/vfio_pci_device_test.c +++ b/tools/testing/selftests/vfio/vfio_pci_device_test.c @@ -12,7 +12,7 @@ #include <libvfio.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static const char *device_bdf; diff --git a/tools/testing/selftests/vfio/vfio_pci_driver_test.c b/tools/testing/selftests/vfio/vfio_pci_driver_test.c index f0ca8310d6a8..afa0480ddd9b 100644 --- a/tools/testing/selftests/vfio/vfio_pci_driver_test.c +++ b/tools/testing/selftests/vfio/vfio_pci_driver_test.c @@ -7,7 +7,7 @@ #include <libvfio.h> -#include "../kselftest_harness.h" +#include "kselftest_harness.h" static const char *device_bdf; diff --git a/tools/testing/selftests/wireguard/qemu/kernel.config b/tools/testing/selftests/wireguard/qemu/kernel.config index 936b18be07cf..0504c11c2de6 100644 --- a/tools/testing/selftests/wireguard/qemu/kernel.config +++ b/tools/testing/selftests/wireguard/qemu/kernel.config @@ -81,7 +81,7 @@ CONFIG_WQ_WATCHDOG=y CONFIG_DETECT_HUNG_TASK=y CONFIG_BOOTPARAM_HARDLOCKUP_PANIC=y CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y -CONFIG_BOOTPARAM_HUNG_TASK_PANIC=y +CONFIG_BOOTPARAM_HUNG_TASK_PANIC=1 CONFIG_PANIC_TIMEOUT=-1 CONFIG_STACKTRACE=y CONFIG_EARLY_PRINTK=y diff --git a/tools/testing/selftests/x86/corrupt_xstate_header.c b/tools/testing/selftests/x86/corrupt_xstate_header.c index 93a89a5997ca..f4d67b050275 100644 --- a/tools/testing/selftests/x86/corrupt_xstate_header.c +++ b/tools/testing/selftests/x86/corrupt_xstate_header.c @@ -17,7 +17,7 @@ #include <stdint.h> #include <sys/wait.h> -#include "../kselftest.h" /* For __cpuid_count() */ +#include "kselftest.h" /* For __cpuid_count() */ #include "helpers.h" static inline int xsave_enabled(void) diff --git a/tools/testing/selftests/x86/helpers.h b/tools/testing/selftests/x86/helpers.h index 6deaad035161..4c747a1278d9 100644 --- a/tools/testing/selftests/x86/helpers.h +++ b/tools/testing/selftests/x86/helpers.h @@ -7,7 +7,7 @@ #include <asm/processor-flags.h> -#include "../kselftest.h" +#include "kselftest.h" static inline unsigned long get_eflags(void) { diff --git a/tools/testing/selftests/x86/lam.c b/tools/testing/selftests/x86/lam.c index 0873b0e5f48b..1919fa6daec0 100644 --- a/tools/testing/selftests/x86/lam.c +++ b/tools/testing/selftests/x86/lam.c @@ -18,7 +18,7 @@ #include <sys/uio.h> #include <linux/io_uring.h> -#include "../kselftest.h" +#include "kselftest.h" #ifndef __x86_64__ # error This test is 64-bit only diff --git a/tools/testing/selftests/x86/syscall_numbering.c b/tools/testing/selftests/x86/syscall_numbering.c index 41c42b7b54a6..ca0eca7b9dce 100644 --- a/tools/testing/selftests/x86/syscall_numbering.c +++ b/tools/testing/selftests/x86/syscall_numbering.c @@ -25,7 +25,7 @@ #include <sys/mman.h> #include <linux/ptrace.h> -#include "../kselftest.h" +#include "kselftest.h" /* Common system call numbers */ #define SYS_READ 0 diff --git a/tools/testing/selftests/x86/test_mremap_vdso.c b/tools/testing/selftests/x86/test_mremap_vdso.c index 94bee6e0c813..a5edf6c5f17e 100644 --- a/tools/testing/selftests/x86/test_mremap_vdso.c +++ b/tools/testing/selftests/x86/test_mremap_vdso.c @@ -20,7 +20,7 @@ #include <sys/auxv.h> #include <sys/syscall.h> #include <sys/wait.h> -#include "../kselftest.h" +#include "kselftest.h" #define PAGE_SIZE 4096 diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c index 918eaec8bfbe..f1c3df642352 100644 --- a/tools/testing/selftests/x86/test_vsyscall.c +++ b/tools/testing/selftests/x86/test_vsyscall.c @@ -21,7 +21,7 @@ #include <sys/uio.h> #include "helpers.h" -#include "../kselftest.h" +#include "kselftest.h" #ifdef __x86_64__ #define TOTAL_TESTS 13 diff --git a/tools/testing/selftests/x86/xstate.h b/tools/testing/selftests/x86/xstate.h index e91e3092b5d2..6ee816e7625a 100644 --- a/tools/testing/selftests/x86/xstate.h +++ b/tools/testing/selftests/x86/xstate.h @@ -4,7 +4,7 @@ #include <stdint.h> -#include "../kselftest.h" +#include "kselftest.h" #define XSAVE_HDR_OFFSET 512 #define XSAVE_HDR_SIZE 64 |
