* [PATCH v5 0/2] riscv: hwprobe: Add Zicbop support
@ 2025-11-18 16:23 Yao Zihong
2025-11-18 16:23 ` [PATCH v5 1/2] riscv: hwprobe: Expose Zicbop extension and its block size Yao Zihong
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Yao Zihong @ 2025-11-18 16:23 UTC (permalink / raw)
To: linux-riscv, linux-kernel
Cc: ajones, alexghiti, shuah, samuel.holland, evan, cleger,
zihong.plct, zihongyao, zhangyin2018, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti
Changes since v4:
------------------
- Fixed style problems. (Andrew Jones)
- Updated the selftest gating logic: the cbo.inval test is now also
enabled when `--zicboz-raises-sigill` or `-z` is supplied, instead of
being skipped when these flags are present. (Andrew Jones)
Changes since v3:
------------------
- Dropped the test for Zicbop absence, as prefetch instructions are
architecturally defined as hints and should never raise SIGILL.
- Removed `--sigsegv` and `--sigbus` options; these faults should never
occur on compliant implementations, and the test now handles them
unconditionally for reporting purposes. (Andrew Jones)
- Split the previous --sigill option into two explicit
`--zicbom-raises-sigill` and `--zicboz-raises-sigill` to enable
extension-specific tests. (Andrew Jones)
Changes since v2:
------------------
- Squashed the previous UAPI/kernel/doc patches(originally 1/4, 2/4, 3/4)
into a single hwprobe patch for simplicity.
- Selftests:
* Dropped the `memory` clobber from the prefetch inline asm since it is
pure hint.
* Fixed style problems. (Andrew Jones)
* Merged the standalone prefetch test into
`tools/testing/selftests/riscv/hwprobe/cbo.c` (Andrew Jones)
* Switched to `getopt_long` for option parsing. (Andrew Jones)
Changes since v1:
------------------
- Bumped RISCV_HWPROBE_MAX_KEY (modified 1/4).
- Added documentation for the Zicbop hwprobe bit/key (new 3/4).
- Added a selftest(prefetch.c) for Zicbop (new 4/4).
Hi all,
This patch adds UAPI and kernel plumbing to expose the Zicbop extension
presence and its block size through hwprobe. The interface mirrors
Zicbom/Zicboz. This allows userspace to safely discover and optimize
for Zicbop when available.
Background: Zicbop is mandated by the RVA22U64 profile. Downstream may
combine the presence bit with ZICBOP_BLOCK_SIZE to make profile-level
policy decisions or enable Zicbop-specific optimizations.
Yao Zihong (2):
riscv: hwprobe: Expose Zicbop extension and its block size
selftests/riscv: Add Zicbop prefetch test
Documentation/arch/riscv/hwprobe.rst | 8 +-
arch/riscv/include/asm/hwprobe.h | 2 +-
arch/riscv/include/uapi/asm/hwprobe.h | 2 +
arch/riscv/kernel/sys_hwprobe.c | 6 +
tools/testing/selftests/riscv/hwprobe/cbo.c | 165 ++++++++++++++++----
5 files changed, 152 insertions(+), 31 deletions(-)
--
2.47.2
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v5 1/2] riscv: hwprobe: Expose Zicbop extension and its block size 2025-11-18 16:23 [PATCH v5 0/2] riscv: hwprobe: Add Zicbop support Yao Zihong @ 2025-11-18 16:23 ` Yao Zihong 2025-11-18 16:23 ` [PATCH v5 2/2] selftests/riscv: Add Zicbop prefetch test Yao Zihong 2025-11-19 12:30 ` [PATCH v5 0/2] riscv: hwprobe: Add Zicbop support patchwork-bot+linux-riscv 2 siblings, 0 replies; 6+ messages in thread From: Yao Zihong @ 2025-11-18 16:23 UTC (permalink / raw) To: linux-riscv, linux-kernel Cc: ajones, alexghiti, shuah, samuel.holland, evan, cleger, zihong.plct, zihongyao, zhangyin2018, Jonathan Corbet, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Cyan Yang, Inochi Amaoto, Nam Cao, Aleksa Paunovic, Jingwei Wang, Charlie Jenkins, Yunhui Cui, Miquel Sabaté Solà, Thomas Weißschuh, open list:DOCUMENTATION - Add `RISCV_HWPROBE_EXT_ZICBOP` to report the presence of the Zicbop extension. - Add `RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE` to expose the block size (in bytes) when Zicbop is supported. - Update hwprobe.rst to document the new extension bit and block size key, following the existing Zicbom/Zicboz style. Reviewed-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Yao Zihong <zihong.plct@isrc.iscas.ac.cn> --- Documentation/arch/riscv/hwprobe.rst | 8 +++++++- arch/riscv/include/asm/hwprobe.h | 2 +- arch/riscv/include/uapi/asm/hwprobe.h | 2 ++ arch/riscv/kernel/sys_hwprobe.c | 6 ++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst index 2f449c9b15bd..52f12af43b9d 100644 --- a/Documentation/arch/riscv/hwprobe.rst +++ b/Documentation/arch/riscv/hwprobe.rst @@ -275,6 +275,9 @@ The following keys are defined: ratified in commit 49f49c842ff9 ("Update to Rafified state") of riscv-zabha. + * :c:macro:`RISCV_HWPROBE_EXT_ZICBOP`: The Zicbop extension is supported, as + ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs. + * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated. Returns similar values to :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was mistakenly classified as a bitmask rather than a value. @@ -369,4 +372,7 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFWMACCQQQ`: The Xsfvfwmaccqqq vendor extension is supported in version 1.0 of Matrix Multiply Accumulate - Instruction Extensions Specification. \ No newline at end of file + Instruction Extensions Specification. + +* :c:macro:`RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE`: An unsigned int which + represents the size of the Zicbop block in bytes. diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h index 58f8dda73259..8c572a464719 100644 --- a/arch/riscv/include/asm/hwprobe.h +++ b/arch/riscv/include/asm/hwprobe.h @@ -8,7 +8,7 @@ #include <uapi/asm/hwprobe.h> -#define RISCV_HWPROBE_MAX_KEY 14 +#define RISCV_HWPROBE_MAX_KEY 15 static inline bool riscv_hwprobe_key_is_valid(__s64 key) { diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index 5d30a4fae37a..9cc508be54c5 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -82,6 +82,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_EXT_ZAAMO (1ULL << 56) #define RISCV_HWPROBE_EXT_ZALRSC (1ULL << 57) #define RISCV_HWPROBE_EXT_ZABHA (1ULL << 58) +#define RISCV_HWPROBE_EXT_ZICBOP (1ULL << 59) #define RISCV_HWPROBE_KEY_CPUPERF_0 5 #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) #define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0) @@ -107,6 +108,7 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE 12 #define RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0 13 #define RISCV_HWPROBE_KEY_VENDOR_EXT_MIPS_0 14 +#define RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE 15 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ /* Flags */ diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c index 199d13f86f31..6b33fd88bf3e 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -122,6 +122,7 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, EXT_KEY(ZCB); EXT_KEY(ZCMOP); EXT_KEY(ZICBOM); + EXT_KEY(ZICBOP); EXT_KEY(ZICBOZ); EXT_KEY(ZICNTR); EXT_KEY(ZICOND); @@ -302,6 +303,11 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair, if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOM)) pair->value = riscv_cbom_block_size; break; + case RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE: + pair->value = 0; + if (hwprobe_ext0_has(cpus, RISCV_HWPROBE_EXT_ZICBOP)) + pair->value = riscv_cbop_block_size; + break; case RISCV_HWPROBE_KEY_HIGHEST_VIRT_ADDRESS: pair->value = user_max_virt_addr(); break; -- 2.47.2 _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v5 2/2] selftests/riscv: Add Zicbop prefetch test 2025-11-18 16:23 [PATCH v5 0/2] riscv: hwprobe: Add Zicbop support Yao Zihong 2025-11-18 16:23 ` [PATCH v5 1/2] riscv: hwprobe: Expose Zicbop extension and its block size Yao Zihong @ 2025-11-18 16:23 ` Yao Zihong 2025-11-18 16:45 ` Andrew Jones 2025-11-19 12:30 ` [PATCH v5 0/2] riscv: hwprobe: Add Zicbop support patchwork-bot+linux-riscv 2 siblings, 1 reply; 6+ messages in thread From: Yao Zihong @ 2025-11-18 16:23 UTC (permalink / raw) To: linux-riscv, linux-kernel Cc: ajones, alexghiti, shuah, samuel.holland, evan, cleger, zihong.plct, zihongyao, zhangyin2018, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Yunhui Cui, open list:KERNEL SELFTEST FRAMEWORK Add selftests to cbo.c to verify Zicbop extension behavior, and split the previous `--sigill` mode into two options so they can be tested independently. The test checks: - That hwprobe correctly reports Zicbop presence and block size. - That prefetch instructions execute without exception on valid and NULL addresses when Zicbop is present. Signed-off-by: Yao Zihong <zihong.plct@isrc.iscas.ac.cn> --- tools/testing/selftests/riscv/hwprobe/cbo.c | 165 ++++++++++++++++---- 1 file changed, 136 insertions(+), 29 deletions(-) diff --git a/tools/testing/selftests/riscv/hwprobe/cbo.c b/tools/testing/selftests/riscv/hwprobe/cbo.c index 5e96ef785d0d..6d99726aceac 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" #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; -- 2.47.2 _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v5 2/2] selftests/riscv: Add Zicbop prefetch test 2025-11-18 16:23 ` [PATCH v5 2/2] selftests/riscv: Add Zicbop prefetch test Yao Zihong @ 2025-11-18 16:45 ` Andrew Jones 2025-11-20 11:23 ` Yao Zihong 0 siblings, 1 reply; 6+ messages in thread From: Andrew Jones @ 2025-11-18 16:45 UTC (permalink / raw) To: Yao Zihong Cc: linux-riscv, linux-kernel, alexghiti, shuah, samuel.holland, evan, cleger, zihongyao, zhangyin2018, Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Yunhui Cui, open list:KERNEL SELFTEST FRAMEWORK On Wed, Nov 19, 2025 at 12:23:25AM +0800, Yao Zihong wrote: > Add selftests to cbo.c to verify Zicbop extension behavior, and split > the previous `--sigill` mode into two options so they can be tested > independently. > > The test checks: > - That hwprobe correctly reports Zicbop presence and block size. > - That prefetch instructions execute without exception on valid and NULL > addresses when Zicbop is present. > > Signed-off-by: Yao Zihong <zihong.plct@isrc.iscas.ac.cn> > --- > tools/testing/selftests/riscv/hwprobe/cbo.c | 165 ++++++++++++++++---- > 1 file changed, 136 insertions(+), 29 deletions(-) > > diff --git a/tools/testing/selftests/riscv/hwprobe/cbo.c b/tools/testing/selftests/riscv/hwprobe/cbo.c > index 5e96ef785d0d..6d99726aceac 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" > > #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; I would have written it like below to avoid four redundant lines case 'm': case 'z': tests[opt == 'm' ? TEST_NO_ZICBOM : 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; > > -- > 2.47.2 > Anyway, Reviewed-by: Andrew Jones <ajones@ventanamicro.com> _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v5 2/2] selftests/riscv: Add Zicbop prefetch test 2025-11-18 16:45 ` Andrew Jones @ 2025-11-20 11:23 ` Yao Zihong 0 siblings, 0 replies; 6+ messages in thread From: Yao Zihong @ 2025-11-20 11:23 UTC (permalink / raw) To: ajones Cc: alex, alexghiti, aou, cleger, cuiyunhui, evan, linux-kernel, linux-kselftest, linux-riscv, palmer, pjw, samuel.holland, shuah, zhangyin2018, zihong.plct, zihongyao Hi Andrew, On Tue, 18 Nov 2025 10:45:43 -0600, Andrew Jones wrote: > I would have written it like below to avoid four redundant lines > > case 'm': case 'z': > tests[opt == 'm' ? TEST_NO_ZICBOM : TEST_NO_ZICBOZ].enabled = true; > tests[TEST_NO_CBO_INVAL].enabled = true; > rc = sigaction(SIGILL, &act, NULL); > assert(rc == 0); > break; I'll apply this style pattern in future patches, or in a v6 if we end up needing one. Thanks, Zihong _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v5 0/2] riscv: hwprobe: Add Zicbop support 2025-11-18 16:23 [PATCH v5 0/2] riscv: hwprobe: Add Zicbop support Yao Zihong 2025-11-18 16:23 ` [PATCH v5 1/2] riscv: hwprobe: Expose Zicbop extension and its block size Yao Zihong 2025-11-18 16:23 ` [PATCH v5 2/2] selftests/riscv: Add Zicbop prefetch test Yao Zihong @ 2025-11-19 12:30 ` patchwork-bot+linux-riscv 2 siblings, 0 replies; 6+ messages in thread From: patchwork-bot+linux-riscv @ 2025-11-19 12:30 UTC (permalink / raw) To: Yao Zihong Cc: linux-riscv, linux-kernel, ajones, alexghiti, shuah, samuel.holland, evan, cleger, zihongyao, zhangyin2018, pjw, palmer, aou, alex Hello: This series was applied to riscv/linux.git (for-next) by Paul Walmsley <pjw@kernel.org>: On Wed, 19 Nov 2025 00:23:23 +0800 you wrote: > Changes since v4: > ------------------ > - Fixed style problems. (Andrew Jones) > - Updated the selftest gating logic: the cbo.inval test is now also > enabled when `--zicboz-raises-sigill` or `-z` is supplied, instead of > being skipped when these flags are present. (Andrew Jones) > > [...] Here is the summary with links: - [v5,1/2] riscv: hwprobe: Expose Zicbop extension and its block size https://git.kernel.org/riscv/c/22813b82af1e - [v5,2/2] selftests/riscv: Add Zicbop prefetch test https://git.kernel.org/riscv/c/b291b9de3182 You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html _______________________________________________ linux-riscv mailing list linux-riscv@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-riscv ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2025-11-20 11:25 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-11-18 16:23 [PATCH v5 0/2] riscv: hwprobe: Add Zicbop support Yao Zihong 2025-11-18 16:23 ` [PATCH v5 1/2] riscv: hwprobe: Expose Zicbop extension and its block size Yao Zihong 2025-11-18 16:23 ` [PATCH v5 2/2] selftests/riscv: Add Zicbop prefetch test Yao Zihong 2025-11-18 16:45 ` Andrew Jones 2025-11-20 11:23 ` Yao Zihong 2025-11-19 12:30 ` [PATCH v5 0/2] riscv: hwprobe: Add Zicbop support patchwork-bot+linux-riscv
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox