1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2023 Ventana Micro Systems Inc.
5 * Run with 'taskset -c <cpu-list> cbo' to only execute hwprobe on a
6 * subset of cpus, as well as only executing the tests on those cpus.
15 #include <linux/compiler.h>
16 #include <linux/kernel.h>
17 #include <asm/ucontext.h>
20 #include "../../kselftest.h"
22 #define MK_CBO(fn) le32_bswap((uint32_t)(fn) << 20 | 10 << 15 | 2 << 12 | 0 << 7 | 15)
24 static char mem
[4096] __aligned(4096) = { [0 ... 4095] = 0xa5 };
26 static bool illegal_insn
;
28 static void sigill_handler(int sig
, siginfo_t
*info
, void *context
)
30 unsigned long *regs
= (unsigned long *)&((ucontext_t
*)context
)->uc_mcontext
;
31 uint32_t insn
= *(uint32_t *)regs
[0];
33 assert(insn
== MK_CBO(regs
[11]));
39 #define cbo_insn(base, fn) \
45 : : "r" (base), "i" (fn), "i" (MK_CBO(fn)) : "a0", "a1", "memory"); \
48 static void cbo_inval(char *base
) { cbo_insn(base
, 0); }
49 static void cbo_clean(char *base
) { cbo_insn(base
, 1); }
50 static void cbo_flush(char *base
) { cbo_insn(base
, 2); }
51 static void cbo_zero(char *base
) { cbo_insn(base
, 4); }
53 static void test_no_zicbom(void *arg
)
55 ksft_print_msg("Testing Zicbom instructions remain privileged\n");
59 ksft_test_result(illegal_insn
, "No cbo.clean\n");
63 ksft_test_result(illegal_insn
, "No cbo.flush\n");
67 ksft_test_result(illegal_insn
, "No cbo.inval\n");
70 static void test_no_zicboz(void *arg
)
72 ksft_print_msg("No Zicboz, testing cbo.zero remains privileged\n");
76 ksft_test_result(illegal_insn
, "No cbo.zero\n");
79 static bool is_power_of_2(__u64 n
)
81 return n
!= 0 && (n
& (n
- 1)) == 0;
84 static void test_zicboz(void *arg
)
86 struct riscv_hwprobe pair
= {
87 .key
= RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE
,
89 cpu_set_t
*cpus
= (cpu_set_t
*)arg
;
94 rc
= riscv_hwprobe(&pair
, 1, sizeof(cpu_set_t
), (unsigned long *)cpus
, 0);
95 block_size
= pair
.value
;
96 ksft_test_result(rc
== 0 && pair
.key
== RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE
&&
97 is_power_of_2(block_size
), "Zicboz block size\n");
98 ksft_print_msg("Zicboz block size: %llu\n", block_size
);
100 illegal_insn
= false;
101 cbo_zero(&mem
[block_size
]);
102 ksft_test_result(!illegal_insn
, "cbo.zero\n");
104 if (illegal_insn
|| !is_power_of_2(block_size
)) {
105 ksft_test_result_skip("cbo.zero check\n");
109 assert(block_size
<= 1024);
111 for (i
= 0; i
< 4096 / block_size
; ++i
) {
113 cbo_zero(&mem
[i
* block_size
]);
116 for (i
= 0; i
< 4096 / block_size
; ++i
) {
117 char expected
= i
% 2 ? 0x0 : 0xa5;
119 for (j
= 0; j
< block_size
; ++j
) {
120 if (mem
[i
* block_size
+ j
] != expected
) {
121 ksft_test_result_fail("cbo.zero check\n");
122 ksft_print_msg("cbo.zero check: mem[%llu] != 0x%x\n",
123 i
* block_size
+ j
, expected
);
129 ksft_test_result_pass("cbo.zero check\n");
132 static void check_no_zicboz_cpus(cpu_set_t
*cpus
)
134 struct riscv_hwprobe pair
= {
135 .key
= RISCV_HWPROBE_KEY_IMA_EXT_0
,
141 while (i
++ < CPU_COUNT(cpus
)) {
142 while (!CPU_ISSET(c
, cpus
))
146 CPU_SET(c
, &one_cpu
);
148 rc
= riscv_hwprobe(&pair
, 1, sizeof(cpu_set_t
), (unsigned long *)&one_cpu
, 0);
149 assert(rc
== 0 && pair
.key
== RISCV_HWPROBE_KEY_IMA_EXT_0
);
151 if (pair
.value
& RISCV_HWPROBE_EXT_ZICBOZ
)
152 ksft_exit_fail_msg("Zicboz is only present on a subset of harts.\n"
153 "Use taskset to select a set of harts where Zicboz\n"
154 "presence (present or not) is consistent for each hart\n");
165 static struct test_info
{
167 unsigned int nr_tests
;
168 void (*test_fn
)(void *arg
);
170 [TEST_ZICBOZ
] = { .nr_tests
= 3, test_zicboz
},
171 [TEST_NO_ZICBOZ
] = { .nr_tests
= 1, test_no_zicboz
},
172 [TEST_NO_ZICBOM
] = { .nr_tests
= 3, test_no_zicbom
},
175 int main(int argc
, char **argv
)
177 struct sigaction act
= {
178 .sa_sigaction
= &sigill_handler
,
179 .sa_flags
= SA_SIGINFO
,
181 struct riscv_hwprobe pair
;
182 unsigned int plan
= 0;
187 if (argc
> 1 && !strcmp(argv
[1], "--sigill")) {
188 rc
= sigaction(SIGILL
, &act
, NULL
);
190 tests
[TEST_NO_ZICBOZ
].enabled
= true;
191 tests
[TEST_NO_ZICBOM
].enabled
= true;
194 rc
= sched_getaffinity(0, sizeof(cpu_set_t
), &cpus
);
199 pair
.key
= RISCV_HWPROBE_KEY_IMA_EXT_0
;
200 rc
= riscv_hwprobe(&pair
, 1, sizeof(cpu_set_t
), (unsigned long *)&cpus
, 0);
202 ksft_exit_fail_msg("hwprobe() failed with %ld\n", rc
);
203 assert(rc
== 0 && pair
.key
== RISCV_HWPROBE_KEY_IMA_EXT_0
);
205 if (pair
.value
& RISCV_HWPROBE_EXT_ZICBOZ
) {
206 tests
[TEST_ZICBOZ
].enabled
= true;
207 tests
[TEST_NO_ZICBOZ
].enabled
= false;
209 check_no_zicboz_cpus(&cpus
);
212 for (i
= 0; i
< ARRAY_SIZE(tests
); ++i
)
213 plan
+= tests
[i
].enabled
? tests
[i
].nr_tests
: 0;
216 ksft_print_msg("No tests enabled.\n");
220 for (i
= 0; i
< ARRAY_SIZE(tests
); ++i
) {
221 if (tests
[i
].enabled
)
222 tests
[i
].test_fn(&cpus
);