Message ID | 20230918131518.56803-14-ajones@ventanamicro.com (mailing list archive) |
---|---|
State | Accepted |
Commit | a29e2a48afe3549ee34d39cf42343ba3fced09c6 |
Headers | show |
Series | RISC-V: Enable cbo.zero in usermode | expand |
> -----Original Message----- > From: linux-riscv <linux-riscv-bounces@lists.infradead.org> On Behalf Of > Andrew Jones > Sent: Monday, September 18, 2023 9:15 PM > To: linux-riscv@lists.infradead.org > Cc: paul.walmsley@sifive.com; palmer@dabbelt.com; > aou@eecs.berkeley.edu; evan@rivosinc.com; conor.dooley@microchip.com; > apatel@ventanamicro.com; Wang, Xiao W <xiao.w.wang@intel.com> > Subject: [PATCH v4 6/6] RISC-V: selftests: Add CBO tests > > Add hwprobe test for Zicboz and its block size. Also, when Zicboz is > present, test that cbo.zero may be issued and works. Additionally > provide a command line option that enables testing that the Zicbom > instructions cause SIGILL and also that cbo.zero causes SIGILL when > Zicboz it's not present. The SIGILL tests require "opt-in" with a > command line option because the RISC-V ISA does not require > unimplemented standard opcodes to issue illegal-instruction > exceptions (but hopefully most platforms do). > > Pinning the test to a subset of cpus with taskset will also restrict > the hwprobe calls to that set. > > Signed-off-by: Andrew Jones <ajones@ventanamicro.com> > --- > .../testing/selftests/riscv/hwprobe/Makefile | 7 +- > tools/testing/selftests/riscv/hwprobe/cbo.c | 228 ++++++++++++++++++ > .../testing/selftests/riscv/hwprobe/hwprobe.c | 12 +- > .../testing/selftests/riscv/hwprobe/hwprobe.h | 15 ++ > 4 files changed, 250 insertions(+), 12 deletions(-) > create mode 100644 tools/testing/selftests/riscv/hwprobe/cbo.c > create mode 100644 tools/testing/selftests/riscv/hwprobe/hwprobe.h > > diff --git a/tools/testing/selftests/riscv/hwprobe/Makefile > b/tools/testing/selftests/riscv/hwprobe/Makefile > index 5f614c3ba598..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) -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 4f15f1f3b4c3..c474891df307 100644 > --- a/tools/testing/selftests/riscv/hwprobe/hwprobe.c > +++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.c > @@ -1,17 +1,7 @@ > // SPDX-License-Identifier: GPL-2.0-only > -#include <stddef.h> > -#include <asm/hwprobe.h> > - > +#include "hwprobe.h" > #include "../../kselftest.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); > - > int main(int argc, char **argv) > { > struct riscv_hwprobe pairs[8]; > 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 > -- > 2.41.0 > Reviewed-by: Xiao Wang <xiao.w.wang@intel.com> > > _______________________________________________ > linux-riscv mailing list > linux-riscv@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-riscv
diff --git a/tools/testing/selftests/riscv/hwprobe/Makefile b/tools/testing/selftests/riscv/hwprobe/Makefile index 5f614c3ba598..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) -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 4f15f1f3b4c3..c474891df307 100644 --- a/tools/testing/selftests/riscv/hwprobe/hwprobe.c +++ b/tools/testing/selftests/riscv/hwprobe/hwprobe.c @@ -1,17 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only -#include <stddef.h> -#include <asm/hwprobe.h> - +#include "hwprobe.h" #include "../../kselftest.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); - int main(int argc, char **argv) { struct riscv_hwprobe pairs[8]; 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
Add hwprobe test for Zicboz and its block size. Also, when Zicboz is present, test that cbo.zero may be issued and works. Additionally provide a command line option that enables testing that the Zicbom instructions cause SIGILL and also that cbo.zero causes SIGILL when Zicboz it's not present. The SIGILL tests require "opt-in" with a command line option because the RISC-V ISA does not require unimplemented standard opcodes to issue illegal-instruction exceptions (but hopefully most platforms do). Pinning the test to a subset of cpus with taskset will also restrict the hwprobe calls to that set. Signed-off-by: Andrew Jones <ajones@ventanamicro.com> --- .../testing/selftests/riscv/hwprobe/Makefile | 7 +- tools/testing/selftests/riscv/hwprobe/cbo.c | 228 ++++++++++++++++++ .../testing/selftests/riscv/hwprobe/hwprobe.c | 12 +- .../testing/selftests/riscv/hwprobe/hwprobe.h | 15 ++ 4 files changed, 250 insertions(+), 12 deletions(-) create mode 100644 tools/testing/selftests/riscv/hwprobe/cbo.c create mode 100644 tools/testing/selftests/riscv/hwprobe/hwprobe.h