diff options
author | Palmer Dabbelt <[email protected]> | 2023-09-21 04:22:30 -0700 |
---|---|---|
committer | Palmer Dabbelt <[email protected]> | 2023-10-31 19:15:47 -0700 |
commit | a9429d5f99bc25885ba5d4c2c58a25467f5d741b (patch) | |
tree | 79dd84651f19846d7ededca000db3e1d529375d5 | |
parent | 71e11d066c1db20f85240d248cd8c3c6ae8bd7d7 (diff) | |
parent | a29e2a48afe3549ee34d39cf42343ba3fced09c6 (diff) |
Merge patch series "RISC-V: Enable cbo.zero in usermode"
Andrew Jones <[email protected]> says:
In order for usermode to issue cbo.zero, it needs privilege granted to
issue the extension instruction (patch 2) and to know that the extension
is available and its block size (patch 3). Patch 1 could be separate from
this series (it just fixes up some error messages), patches 4-5 convert
the hwprobe selftest to a statically-linked, TAP test and patch 6 adds a
new hwprobe test for the new information as well as testing CBO
instructions can or cannot be issued as appropriate.
* b4-shazam-merge:
RISC-V: selftests: Add CBO tests
RISC-V: selftests: Convert hwprobe test to kselftest API
RISC-V: selftests: Statically link hwprobe test
RISC-V: hwprobe: Expose Zicboz extension and its block size
RISC-V: Enable cbo.zero in usermode
RISC-V: Make zicbom/zicboz errors consistent
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Palmer Dabbelt <[email protected]>
-rw-r--r-- | Documentation/riscv/hwprobe.rst | 6 | ||||
-rw-r--r-- | arch/riscv/include/asm/cpufeature.h | 1 | ||||
-rw-r--r-- | arch/riscv/include/asm/csr.h | 1 | ||||
-rw-r--r-- | arch/riscv/include/asm/hwcap.h | 16 | ||||
-rw-r--r-- | arch/riscv/include/asm/hwprobe.h | 2 | ||||
-rw-r--r-- | arch/riscv/include/uapi/asm/hwprobe.h | 2 | ||||
-rw-r--r-- | arch/riscv/kernel/cpufeature.c | 10 | ||||
-rw-r--r-- | arch/riscv/kernel/setup.c | 4 | ||||
-rw-r--r-- | arch/riscv/kernel/smpboot.c | 4 | ||||
-rw-r--r-- | arch/riscv/kernel/sys_riscv.c | 46 | ||||
-rw-r--r-- | tools/testing/selftests/riscv/hwprobe/Makefile | 9 | ||||
-rw-r--r-- | tools/testing/selftests/riscv/hwprobe/cbo.c | 228 | ||||
-rw-r--r-- | tools/testing/selftests/riscv/hwprobe/hwprobe.c | 64 | ||||
-rw-r--r-- | tools/testing/selftests/riscv/hwprobe/hwprobe.h | 15 |
14 files changed, 345 insertions, 63 deletions
diff --git a/Documentation/riscv/hwprobe.rst b/Documentation/riscv/hwprobe.rst index a52996b22f75..7b2384de471f 100644 --- a/Documentation/riscv/hwprobe.rst +++ b/Documentation/riscv/hwprobe.rst @@ -77,6 +77,9 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_EXT_ZBS`: The Zbs extension is supported, as defined in version 1.0 of the Bit-Manipulation ISA extensions. + * :c:macro:`RISCV_HWPROBE_EXT_ZICBOZ`: The Zicboz extension is supported, as + ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs. + * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: A bitmask that contains performance information about the selected set of processors. @@ -96,3 +99,6 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_MISALIGNED_UNSUPPORTED`: Misaligned accesses are not supported at all and will generate a misaligned address fault. + +* :c:macro:`RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE`: An unsigned int which + represents the size of the Zicboz block in bytes. diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index d0345bd659c9..13b7d35648a9 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -31,5 +31,6 @@ DECLARE_PER_CPU(long, misaligned_access_speed); extern struct riscv_isainfo hart_isa[NR_CPUS]; void check_unaligned_access(int cpu); +void riscv_user_isa_enable(void); #endif diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h index 777cb8299551..5fba25db82d2 100644 --- a/arch/riscv/include/asm/csr.h +++ b/arch/riscv/include/asm/csr.h @@ -275,6 +275,7 @@ #define CSR_SIE 0x104 #define CSR_STVEC 0x105 #define CSR_SCOUNTEREN 0x106 +#define CSR_SENVCFG 0x10a #define CSR_SSCRATCH 0x140 #define CSR_SEPC 0x141 #define CSR_SCAUSE 0x142 diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index b7b58258f6c7..31774bcdf1c6 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -70,6 +70,7 @@ #ifndef __ASSEMBLY__ #include <linux/jump_label.h> +#include <asm/cpufeature.h> unsigned long riscv_get_elf_hwcap(void); @@ -137,6 +138,21 @@ l_yes: return true; } +static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext) +{ + if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_likely(ext)) + return true; + + return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); +} + +static __always_inline bool riscv_cpu_has_extension_unlikely(int cpu, const unsigned long ext) +{ + if (IS_ENABLED(CONFIG_RISCV_ALTERNATIVE) && riscv_has_extension_unlikely(ext)) + return true; + + return __riscv_isa_extension_available(hart_isa[cpu].isa, ext); +} #endif #endif /* _ASM_RISCV_HWCAP_H */ diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h index 78936f4ff513..39df8604fea1 100644 --- a/arch/riscv/include/asm/hwprobe.h +++ b/arch/riscv/include/asm/hwprobe.h @@ -8,6 +8,6 @@ #include <uapi/asm/hwprobe.h> -#define RISCV_HWPROBE_MAX_KEY 5 +#define RISCV_HWPROBE_MAX_KEY 6 #endif diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index 006bfb48343d..86d08a0e617b 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -29,6 +29,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_EXT_ZBA (1 << 3) #define RISCV_HWPROBE_EXT_ZBB (1 << 4) #define RISCV_HWPROBE_EXT_ZBS (1 << 5) +#define RISCV_HWPROBE_EXT_ZICBOZ (1 << 6) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) @@ -36,6 +37,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0) #define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) #define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) +#define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ #endif diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 1cfbba65d11a..8ad6da03ee34 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -93,10 +93,10 @@ static bool riscv_isa_extension_check(int id) return true; case RISCV_ISA_EXT_ZICBOZ: if (!riscv_cboz_block_size) { - pr_err("Zicboz detected in ISA string, but no cboz-block-size found\n"); + pr_err("Zicboz detected in ISA string, disabling as no cboz-block-size found\n"); return false; } else if (!is_power_of_2(riscv_cboz_block_size)) { - pr_err("cboz-block-size present, but is not a power-of-2\n"); + pr_err("Zicboz disabled as cboz-block-size present, but is not a power-of-2\n"); return false; } return true; @@ -653,6 +653,12 @@ static int check_unaligned_access_boot_cpu(void) arch_initcall(check_unaligned_access_boot_cpu); +void riscv_user_isa_enable(void) +{ + if (riscv_cpu_has_extension_unlikely(smp_processor_id(), RISCV_ISA_EXT_ZICBOZ)) + csr_set(CSR_SENVCFG, ENVCFG_CBZE); +} + #ifdef CONFIG_RISCV_ALTERNATIVE /* * Alternative patch sites consider 48 bits when determining when to patch diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index e600aab116a4..8fd6c02353d4 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c @@ -26,6 +26,7 @@ #include <asm/acpi.h> #include <asm/alternative.h> #include <asm/cacheflush.h> +#include <asm/cpufeature.h> #include <asm/cpu_ops.h> #include <asm/early_ioremap.h> #include <asm/pgtable.h> @@ -314,10 +315,13 @@ void __init setup_arch(char **cmdline_p) riscv_fill_hwcap(); init_rt_signal_env(); apply_boot_alternatives(); + if (IS_ENABLED(CONFIG_RISCV_ISA_ZICBOM) && riscv_isa_extension_available(NULL, ZICBOM)) riscv_noncoherent_supported(); riscv_set_dma_cache_alignment(); + + riscv_user_isa_enable(); } static int __init topology_init(void) diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c index 1b8da4e40a4d..d1b0a6fc3adf 100644 --- a/arch/riscv/kernel/smpboot.c +++ b/arch/riscv/kernel/smpboot.c @@ -25,6 +25,8 @@ #include <linux/of.h> #include <linux/sched/task_stack.h> #include <linux/sched/mm.h> + +#include <asm/cpufeature.h> #include <asm/cpu_ops.h> #include <asm/cpufeature.h> #include <asm/irq.h> @@ -253,6 +255,8 @@ asmlinkage __visible void smp_callin(void) elf_hwcap &= ~COMPAT_HWCAP_ISA_V; } + riscv_user_isa_enable(); + /* * Remote TLB flushes are ignored while the CPU is offline, so emit * a local TLB flush right now just in case. diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index 473159b5f303..d7266a9abc66 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c @@ -145,26 +145,38 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, for_each_cpu(cpu, cpus) { struct riscv_isainfo *isainfo = &hart_isa[cpu]; - if (riscv_isa_extension_available(isainfo->isa, ZBA)) - pair->value |= RISCV_HWPROBE_EXT_ZBA; - else - missing |= RISCV_HWPROBE_EXT_ZBA; - - if (riscv_isa_extension_available(isainfo->isa, ZBB)) - pair->value |= RISCV_HWPROBE_EXT_ZBB; - else - missing |= RISCV_HWPROBE_EXT_ZBB; - - if (riscv_isa_extension_available(isainfo->isa, ZBS)) - pair->value |= RISCV_HWPROBE_EXT_ZBS; - else - missing |= RISCV_HWPROBE_EXT_ZBS; +#define EXT_KEY(ext) \ + do { \ + if (__riscv_isa_extension_available(isainfo->isa, RISCV_ISA_EXT_##ext)) \ + pair->value |= RISCV_HWPROBE_EXT_##ext; \ + else \ + missing |= RISCV_HWPROBE_EXT_##ext; \ + } while (false) + + /* + * Only use EXT_KEY() for extensions which can be exposed to userspace, + * regardless of the kernel's configuration, as no other checks, besides + * presence in the hart_isa bitmap, are made. + */ + EXT_KEY(ZBA); + EXT_KEY(ZBB); + EXT_KEY(ZBS); + EXT_KEY(ZICBOZ); +#undef EXT_KEY } /* Now turn off reporting features if any CPU is missing it. */ pair->value &= ~missing; } +static bool hwprobe_ext0_has(const struct cpumask *cpus, unsigned long ext) +{ + struct riscv_hwprobe pair; + + hwprobe_isa_ext0(&pair, cpus); + return (pair.value & ext); +} + static u64 hwprobe_misaligned(const struct cpumask *cpus) { int cpu; @@ -215,6 +227,12 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair, pair->value = hwprobe_misaligned(cpus); break; + case RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE: + pair->value = 0; + if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOZ)) + pair->value = riscv_cboz_block_size; + break; + /* * For forward compatibility, unknown keys don't fail the whole * call, but get their element key set to -1 and value set to 0 diff --git a/tools/testing/selftests/riscv/hwprobe/Makefile b/tools/testing/selftests/riscv/hwprobe/Makefile index ebdbb3c22e54..f224b84591fb 100644 --- a/tools/testing/selftests/riscv/hwprobe/Makefile +++ b/tools/testing/selftests/riscv/hwprobe/Makefile @@ -2,9 +2,14 @@ # Copyright (C) 2021 ARM Limited # Originally tools/testing/arm64/abi/Makefile -TEST_GEN_PROGS := hwprobe +CFLAGS += -I$(top_srcdir)/tools/include + +TEST_GEN_PROGS := hwprobe cbo include ../../lib.mk $(OUTPUT)/hwprobe: hwprobe.c sys_hwprobe.S - $(CC) -o$@ $(CFLAGS) $(LDFLAGS) $^ + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^ + +$(OUTPUT)/cbo: cbo.c sys_hwprobe.S + $(CC) -static -o$@ $(CFLAGS) $(LDFLAGS) $^ diff --git a/tools/testing/selftests/riscv/hwprobe/cbo.c b/tools/testing/selftests/riscv/hwprobe/cbo.c new file mode 100644 index 000000000000..50a2cc8aef38 --- /dev/null +++ b/tools/testing/selftests/riscv/hwprobe/cbo.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2023 Ventana Micro Systems Inc. + * + * Run with 'taskset -c <cpu-list> cbo' to only execute hwprobe on a + * subset of cpus, as well as only executing the tests on those cpus. + */ +#define _GNU_SOURCE +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <sched.h> +#include <signal.h> +#include <assert.h> +#include <linux/compiler.h> +#include <linux/kernel.h> +#include <asm/ucontext.h> + +#include "hwprobe.h" +#include "../../kselftest.h" + +#define MK_CBO(fn) cpu_to_le32((fn) << 20 | 10 << 15 | 2 << 12 | 0 << 7 | 15) + +static char mem[4096] __aligned(4096) = { [0 ... 4095] = 0xa5 }; + +static bool illegal_insn; + +static void sigill_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])); + + illegal_insn = true; + regs[0] += 4; +} + +static void cbo_insn(char *base, int fn) +{ + uint32_t insn = MK_CBO(fn); + + asm volatile( + "mv a0, %0\n" + "li a1, %1\n" + ".4byte %2\n" + : : "r" (base), "i" (fn), "i" (insn) : "a0", "a1", "memory"); +} + +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 test_no_zicbom(void *arg) +{ + ksft_print_msg("Testing Zicbom instructions remain privileged\n"); + + illegal_insn = false; + cbo_clean(&mem[0]); + ksft_test_result(illegal_insn, "No cbo.clean\n"); + + illegal_insn = false; + cbo_flush(&mem[0]); + ksft_test_result(illegal_insn, "No cbo.flush\n"); + + illegal_insn = false; + cbo_inval(&mem[0]); + ksft_test_result(illegal_insn, "No cbo.inval\n"); +} + +static void test_no_zicboz(void *arg) +{ + ksft_print_msg("No Zicboz, testing cbo.zero remains privileged\n"); + + illegal_insn = false; + cbo_zero(&mem[0]); + ksft_test_result(illegal_insn, "No cbo.zero\n"); +} + +static bool is_power_of_2(__u64 n) +{ + return n != 0 && (n & (n - 1)) == 0; +} + +static void test_zicboz(void *arg) +{ + struct riscv_hwprobe pair = { + .key = RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE, + }; + cpu_set_t *cpus = (cpu_set_t *)arg; + __u64 block_size; + int i, j; + long rc; + + 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_ZICBOZ_BLOCK_SIZE && + is_power_of_2(block_size), "Zicboz block size\n"); + ksft_print_msg("Zicboz block size: %ld\n", block_size); + + illegal_insn = false; + cbo_zero(&mem[block_size]); + ksft_test_result(!illegal_insn, "cbo.zero\n"); + + if (illegal_insn || !is_power_of_2(block_size)) { + ksft_test_result_skip("cbo.zero check\n"); + return; + } + + assert(block_size <= 1024); + + for (i = 0; i < 4096 / block_size; ++i) { + if (i % 2) + cbo_zero(&mem[i * block_size]); + } + + for (i = 0; i < 4096 / block_size; ++i) { + char expected = i % 2 ? 0x0 : 0xa5; + + for (j = 0; j < block_size; ++j) { + if (mem[i * block_size + j] != expected) { + ksft_test_result_fail("cbo.zero check\n"); + ksft_print_msg("cbo.zero check: mem[%d] != 0x%x\n", + i * block_size + j, expected); + return; + } + } + } + + ksft_test_result_pass("cbo.zero check\n"); +} + +static void check_no_zicboz_cpus(cpu_set_t *cpus) +{ + struct riscv_hwprobe pair = { + .key = RISCV_HWPROBE_KEY_IMA_EXT_0, + }; + cpu_set_t one_cpu; + int i = 0, c = 0; + long rc; + + while (i++ < CPU_COUNT(cpus)) { + while (!CPU_ISSET(c, cpus)) + ++c; + + CPU_ZERO(&one_cpu); + CPU_SET(c, &one_cpu); + + 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); + + if (pair.value & RISCV_HWPROBE_EXT_ZICBOZ) + ksft_exit_fail_msg("Zicboz is only present on a subset of harts.\n" + "Use taskset to select a set of harts where Zicboz\n" + "presence (present or not) is consistent for each hart\n"); + ++c; + } +} + +enum { + TEST_ZICBOZ, + TEST_NO_ZICBOZ, + TEST_NO_ZICBOM, +}; + +static struct test_info { + bool enabled; + unsigned int nr_tests; + void (*test_fn)(void *arg); +} tests[] = { + [TEST_ZICBOZ] = { .nr_tests = 3, test_zicboz }, + [TEST_NO_ZICBOZ] = { .nr_tests = 1, test_no_zicboz }, + [TEST_NO_ZICBOM] = { .nr_tests = 3, test_no_zicbom }, +}; + +int main(int argc, char **argv) +{ + struct sigaction act = { + .sa_sigaction = &sigill_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; + } + + rc = sched_getaffinity(0, sizeof(cpu_set_t), &cpus); + assert(rc == 0); + + ksft_print_header(); + + pair.key = RISCV_HWPROBE_KEY_IMA_EXT_0; + rc = riscv_hwprobe(&pair, 1, sizeof(cpu_set_t), (unsigned long *)&cpus, 0); + if (rc < 0) + ksft_exit_fail_msg("hwprobe() failed with %d\n", rc); + assert(rc == 0 && pair.key == RISCV_HWPROBE_KEY_IMA_EXT_0); + + if (pair.value & RISCV_HWPROBE_EXT_ZICBOZ) { + tests[TEST_ZICBOZ].enabled = true; + tests[TEST_NO_ZICBOZ].enabled = false; + } else { + check_no_zicboz_cpus(&cpus); + } + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + plan += tests[i].enabled ? tests[i].nr_tests : 0; + + if (plan == 0) + ksft_print_msg("No tests enabled.\n"); + else + ksft_set_plan(plan); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + if (tests[i].enabled) + tests[i].test_fn(&cpus); + } + + ksft_finished(); +} diff --git a/tools/testing/selftests/riscv/hwprobe/hwprobe.c b/tools/testing/selftests/riscv/hwprobe/hwprobe.c index 09f290a67420..c474891df307 100644 --- a/tools/testing/selftests/riscv/hwprobe/hwprobe.c +++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.c @@ -1,14 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only -#include <stddef.h> -#include <asm/hwprobe.h> - -/* - * Rather than relying on having a new enough libc to define this, just do it - * ourselves. This way we don't need to be coupled to a new-enough libc to - * contain the call. - */ -long riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, - size_t cpu_count, unsigned long *cpus, unsigned int flags); +#include "hwprobe.h" +#include "../../kselftest.h" int main(int argc, char **argv) { @@ -16,6 +8,9 @@ int main(int argc, char **argv) unsigned long cpus; long out; + ksft_print_header(); + ksft_set_plan(5); + /* Fake the CPU_SET ops. */ cpus = -1; @@ -25,13 +20,16 @@ int main(int argc, char **argv) */ for (long i = 0; i < 8; i++) pairs[i].key = i; + out = riscv_hwprobe(pairs, 8, 1, &cpus, 0); if (out != 0) - return -1; + ksft_exit_fail_msg("hwprobe() failed with %ld\n", out); + for (long i = 0; i < 4; ++i) { /* Fail if the kernel claims not to recognize a base key. */ if ((i < 4) && (pairs[i].key != i)) - return -2; + ksft_exit_fail_msg("Failed to recognize base key: key != i, " + "key=%ld, i=%ld\n", pairs[i].key, i); if (pairs[i].key != RISCV_HWPROBE_KEY_BASE_BEHAVIOR) continue; @@ -39,52 +37,30 @@ int main(int argc, char **argv) if (pairs[i].value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA) continue; - return -3; + ksft_exit_fail_msg("Unexpected pair: (%ld, %ld)\n", pairs[i].key, pairs[i].value); } - /* - * This should also work with a NULL CPU set, but should not work - * with an improperly supplied CPU set. - */ out = riscv_hwprobe(pairs, 8, 0, 0, 0); - if (out != 0) - return -4; + ksft_test_result(out == 0, "NULL CPU set\n"); out = riscv_hwprobe(pairs, 8, 0, &cpus, 0); - if (out == 0) - return -5; + ksft_test_result(out != 0, "Bad CPU set\n"); out = riscv_hwprobe(pairs, 8, 1, 0, 0); - if (out == 0) - return -6; + ksft_test_result(out != 0, "NULL CPU set with non-zero count\n"); - /* - * Check that keys work by providing one that we know exists, and - * checking to make sure the resultig pair is what we asked for. - */ pairs[0].key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR; out = riscv_hwprobe(pairs, 1, 1, &cpus, 0); - if (out != 0) - return -7; - if (pairs[0].key != RISCV_HWPROBE_KEY_BASE_BEHAVIOR) - return -8; + ksft_test_result(out == 0 && pairs[0].key == RISCV_HWPROBE_KEY_BASE_BEHAVIOR, + "Existing key is maintained\n"); - /* - * Check that an unknown key gets overwritten with -1, - * but doesn't block elements after it. - */ pairs[0].key = 0x5555; pairs[1].key = 1; pairs[1].value = 0xAAAA; out = riscv_hwprobe(pairs, 2, 0, 0, 0); - if (out != 0) - return -9; - - if (pairs[0].key != -1) - return -10; - - if ((pairs[1].key != 1) || (pairs[1].value == 0xAAAA)) - return -11; + ksft_test_result(out == 0 && pairs[0].key == -1 && + pairs[1].key == 1 && pairs[1].value != 0xAAAA, + "Unknown key overwritten with -1 and doesn't block other elements\n"); - return 0; + ksft_finished(); } diff --git a/tools/testing/selftests/riscv/hwprobe/hwprobe.h b/tools/testing/selftests/riscv/hwprobe/hwprobe.h new file mode 100644 index 000000000000..721b0ce73a56 --- /dev/null +++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef SELFTEST_RISCV_HWPROBE_H +#define SELFTEST_RISCV_HWPROBE_H +#include <stddef.h> +#include <asm/hwprobe.h> + +/* + * Rather than relying on having a new enough libc to define this, just do it + * ourselves. This way we don't need to be coupled to a new-enough libc to + * contain the call. + */ +long riscv_hwprobe(struct riscv_hwprobe *pairs, size_t pair_count, + size_t cpu_count, unsigned long *cpus, unsigned int flags); + +#endif |