xref: /kvm-unit-tests/riscv/sbi-fwft.c (revision f1302432275128322c9f5c99f4fdc3a5fc288820)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * SBI verification
4  *
5  * Copyright (C) 2024, Rivos Inc., Clément Léger <cleger@rivosinc.com>
6  */
7 #include <libcflat.h>
8 #include <stdlib.h>
9 
10 #include <asm/csr.h>
11 #include <asm/processor.h>
12 #include <asm/ptrace.h>
13 #include <asm/sbi.h>
14 
15 #include "sbi-tests.h"
16 
17 void check_fwft(void);
18 
19 
20 static struct sbiret fwft_set_raw(unsigned long feature, unsigned long value, unsigned long flags)
21 {
22 	return sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_SET, feature, value, flags, 0, 0, 0);
23 }
24 
25 static struct sbiret fwft_set(uint32_t feature, unsigned long value, unsigned long flags)
26 {
27 	return fwft_set_raw(feature, value, flags);
28 }
29 
30 static struct sbiret fwft_get_raw(unsigned long feature)
31 {
32 	return sbi_ecall(SBI_EXT_FWFT, SBI_EXT_FWFT_GET, feature, 0, 0, 0, 0, 0);
33 }
34 
35 static struct sbiret fwft_get(uint32_t feature)
36 {
37 	return fwft_get_raw(feature);
38 }
39 
40 static void fwft_check_reserved(unsigned long id)
41 {
42 	struct sbiret ret;
43 
44 	ret = fwft_get(id);
45 	sbiret_report_error(&ret, SBI_ERR_DENIED, "get reserved feature 0x%lx", id);
46 
47 	ret = fwft_set(id, 1, 0);
48 	sbiret_report_error(&ret, SBI_ERR_DENIED, "set reserved feature 0x%lx", id);
49 }
50 
51 static void fwft_check_base(void)
52 {
53 	report_prefix_push("base");
54 
55 	fwft_check_reserved(SBI_FWFT_LOCAL_RESERVED_START);
56 	fwft_check_reserved(SBI_FWFT_LOCAL_RESERVED_END);
57 	fwft_check_reserved(SBI_FWFT_GLOBAL_RESERVED_START);
58 	fwft_check_reserved(SBI_FWFT_GLOBAL_RESERVED_END);
59 
60 #if __riscv_xlen > 32
61 	/* Check id > 32 bits */
62 	{
63 		struct sbiret ret;
64 
65 		ret = fwft_get_raw(BIT(32));
66 		sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM,
67 				    "get feature with bit 32 set error");
68 
69 		ret = fwft_set_raw(BIT(32), 0, 0);
70 		sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM,
71 				    "set feature with bit 32 set error");
72 	}
73 #endif
74 
75 	report_prefix_pop();
76 }
77 
78 static bool misaligned_handled;
79 
80 static void misaligned_handler(struct pt_regs *regs)
81 {
82 	misaligned_handled = true;
83 	regs->epc += 4;
84 }
85 
86 static struct sbiret fwft_misaligned_exc_set(unsigned long value, unsigned long flags)
87 {
88 	return fwft_set(SBI_FWFT_MISALIGNED_EXC_DELEG, value, flags);
89 }
90 
91 static struct sbiret fwft_misaligned_exc_get(void)
92 {
93 	return fwft_get(SBI_FWFT_MISALIGNED_EXC_DELEG);
94 }
95 
96 static void fwft_check_misaligned_exc_deleg(void)
97 {
98 	struct sbiret ret;
99 
100 	report_prefix_push("misaligned_exc_deleg");
101 
102 	ret = fwft_misaligned_exc_get();
103 	if (ret.error == SBI_ERR_NOT_SUPPORTED) {
104 		report_skip("SBI_FWFT_MISALIGNED_EXC_DELEG is not supported");
105 		return;
106 	}
107 
108 	if (!sbiret_report_error(&ret, SBI_SUCCESS, "Get misaligned deleg feature"))
109 		return;
110 
111 	ret = fwft_misaligned_exc_set(2, 0);
112 	sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM,
113 			    "Set misaligned deleg feature invalid value 2");
114 	ret = fwft_misaligned_exc_set(0xFFFFFFFF, 0);
115 	sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM,
116 			    "Set misaligned deleg feature invalid value 0xFFFFFFFF");
117 
118 #if __riscv_xlen > 32
119 	ret = fwft_misaligned_exc_set(BIT(32), 0);
120 	sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM,
121 			    "Set misaligned deleg with invalid value > 32bits");
122 
123 	ret = fwft_misaligned_exc_set(0, BIT(32));
124 	sbiret_report_error(&ret, SBI_ERR_INVALID_PARAM,
125 			    "Set misaligned deleg with invalid flag > 32bits");
126 #endif
127 
128 	/* Set to 0 and check after with get */
129 	ret = fwft_misaligned_exc_set(0, 0);
130 	sbiret_report_error(&ret, SBI_SUCCESS, "Set misaligned deleg feature value 0");
131 	ret = fwft_misaligned_exc_get();
132 	sbiret_report(&ret, SBI_SUCCESS, 0, "Get misaligned deleg feature expected value 0");
133 
134 	/* Set to 1 and check after with get */
135 	ret = fwft_misaligned_exc_set(1, 0);
136 	sbiret_report_error(&ret, SBI_SUCCESS, "Set misaligned deleg feature value 1");
137 	ret = fwft_misaligned_exc_get();
138 	sbiret_report(&ret, SBI_SUCCESS, 1, "Get misaligned deleg feature expected value 1");
139 
140 	install_exception_handler(EXC_LOAD_MISALIGNED, misaligned_handler);
141 
142 	asm volatile (
143 		".option push\n"
144 		/*
145 		 * Disable compression so the lw takes exactly 4 bytes and thus
146 		 * can be skipped reliably from the exception handler.
147 		 */
148 		".option arch,-c\n"
149 		"lw %[val], 1(%[val_addr])\n"
150 		".option pop\n"
151 		: [val] "+r" (ret.value)
152 		: [val_addr] "r" (&ret.value)
153 		: "memory");
154 
155 	/*
156 	 * Even though the SBI delegated the misaligned exception to S-mode, it might not trap on
157 	 * misaligned load/store access, report that during tests.
158 	 */
159 	if (!misaligned_handled)
160 		report_skip("Misaligned load exception does not trap in S-mode");
161 	else
162 		report_pass("Misaligned load exception trap in S-mode");
163 
164 	install_exception_handler(EXC_LOAD_MISALIGNED, NULL);
165 
166 	/* Lock the feature */
167 	ret = fwft_misaligned_exc_set(0, SBI_FWFT_SET_FLAG_LOCK);
168 	sbiret_report_error(&ret, SBI_SUCCESS, "Set misaligned deleg feature value 0 and lock");
169 	ret = fwft_misaligned_exc_set(1, 0);
170 	sbiret_report_error(&ret, SBI_ERR_DENIED_LOCKED,
171 			    "Set locked misaligned deleg feature to new value");
172 	ret = fwft_misaligned_exc_get();
173 	sbiret_report(&ret, SBI_SUCCESS, 0, "Get misaligned deleg locked value 0");
174 
175 	report_prefix_pop();
176 }
177 
178 void check_fwft(void)
179 {
180 	report_prefix_push("fwft");
181 
182 	if (!sbi_probe(SBI_EXT_FWFT)) {
183 		report_skip("FWFT extension not available");
184 		report_prefix_pop();
185 		return;
186 	}
187 
188 	fwft_check_base();
189 	fwft_check_misaligned_exc_deleg();
190 
191 	report_prefix_pop();
192 }
193