xref: /freebsd/sys/riscv/riscv/sbi.c (revision 4b9d6057)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2019 Mitchell Horne <mhorne@FreeBSD.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/param.h>
29 #include <sys/kernel.h>
30 #include <sys/systm.h>
31 #include <sys/types.h>
32 #include <sys/eventhandler.h>
33 #include <sys/reboot.h>
34 
35 #include <machine/md_var.h>
36 #include <machine/sbi.h>
37 
38 /* SBI Implementation-Specific Definitions */
39 #define	OPENSBI_VERSION_MAJOR_OFFSET	16
40 #define	OPENSBI_VERSION_MINOR_MASK	0xFFFF
41 
42 u_long sbi_spec_version;
43 u_long sbi_impl_id;
44 u_long sbi_impl_version;
45 
46 static bool has_time_extension = false;
47 static bool has_ipi_extension = false;
48 static bool has_rfnc_extension = false;
49 static bool has_srst_extension = false;
50 
51 static struct sbi_ret
52 sbi_get_spec_version(void)
53 {
54 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_SPEC_VERSION));
55 }
56 
57 static struct sbi_ret
58 sbi_get_impl_id(void)
59 {
60 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_ID));
61 }
62 
63 static struct sbi_ret
64 sbi_get_impl_version(void)
65 {
66 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_VERSION));
67 }
68 
69 static struct sbi_ret
70 sbi_get_mvendorid(void)
71 {
72 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MVENDORID));
73 }
74 
75 static struct sbi_ret
76 sbi_get_marchid(void)
77 {
78 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MARCHID));
79 }
80 
81 static struct sbi_ret
82 sbi_get_mimpid(void)
83 {
84 	return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MIMPID));
85 }
86 
87 static void
88 sbi_shutdown_final(void *dummy __unused, int howto)
89 {
90 	if ((howto & RB_POWEROFF) != 0)
91 		sbi_system_reset(SBI_SRST_TYPE_SHUTDOWN, SBI_SRST_REASON_NONE);
92 }
93 
94 void
95 sbi_system_reset(u_long reset_type, u_long reset_reason)
96 {
97 	/* Use the SRST extension, if available. */
98 	if (has_srst_extension) {
99 		(void)SBI_CALL2(SBI_EXT_ID_SRST, SBI_SRST_SYSTEM_RESET,
100 		    reset_type, reset_reason);
101 	}
102 	(void)SBI_CALL0(SBI_SHUTDOWN, 0);
103 }
104 
105 void
106 sbi_print_version(void)
107 {
108 	u_int major;
109 	u_int minor;
110 
111 	/* For legacy SBI implementations. */
112 	if (sbi_spec_version == 0) {
113 		printf("SBI: Unknown (Legacy) Implementation\n");
114 		printf("SBI Specification Version: 0.1\n");
115 		return;
116 	}
117 
118 	switch (sbi_impl_id) {
119 	case (SBI_IMPL_ID_BBL):
120 		printf("SBI: Berkely Boot Loader %lu\n", sbi_impl_version);
121 		break;
122 	case (SBI_IMPL_ID_XVISOR):
123 		printf("SBI: eXtensible Versatile hypervISOR %lu\n",
124 		    sbi_impl_version);
125 		break;
126 	case (SBI_IMPL_ID_KVM):
127 		printf("SBI: Kernel-based Virtual Machine %lu\n",
128 		    sbi_impl_version);
129 		break;
130 	case (SBI_IMPL_ID_RUSTSBI):
131 		printf("SBI: RustSBI %lu\n", sbi_impl_version);
132 		break;
133 	case (SBI_IMPL_ID_DIOSIX):
134 		printf("SBI: Diosix %lu\n", sbi_impl_version);
135 		break;
136 	case (SBI_IMPL_ID_OPENSBI):
137 		major = sbi_impl_version >> OPENSBI_VERSION_MAJOR_OFFSET;
138 		minor = sbi_impl_version & OPENSBI_VERSION_MINOR_MASK;
139 		printf("SBI: OpenSBI v%u.%u\n", major, minor);
140 		break;
141 	default:
142 		printf("SBI: Unrecognized Implementation: %lu\n", sbi_impl_id);
143 		break;
144 	}
145 
146 	major = (sbi_spec_version & SBI_SPEC_VERS_MAJOR_MASK) >>
147 	    SBI_SPEC_VERS_MAJOR_OFFSET;
148 	minor = (sbi_spec_version & SBI_SPEC_VERS_MINOR_MASK);
149 	printf("SBI Specification Version: %u.%u\n", major, minor);
150 }
151 
152 void
153 sbi_set_timer(uint64_t val)
154 {
155 	struct sbi_ret ret __diagused;
156 
157 	/* Use the TIME legacy replacement extension, if available. */
158 	if (has_time_extension) {
159 		ret = SBI_CALL1(SBI_EXT_ID_TIME, SBI_TIME_SET_TIMER, val);
160 		MPASS(ret.error == SBI_SUCCESS);
161 	} else {
162 		(void)SBI_CALL1(SBI_SET_TIMER, 0, val);
163 	}
164 }
165 
166 void
167 sbi_send_ipi(const u_long *hart_mask)
168 {
169 	struct sbi_ret ret __diagused;
170 
171 	/* Use the IPI legacy replacement extension, if available. */
172 	if (has_ipi_extension) {
173 		ret = SBI_CALL2(SBI_EXT_ID_IPI, SBI_IPI_SEND_IPI,
174 		    *hart_mask, 0);
175 		MPASS(ret.error == SBI_SUCCESS);
176 	} else {
177 		(void)SBI_CALL1(SBI_SEND_IPI, 0, (uint64_t)hart_mask);
178 	}
179 }
180 
181 void
182 sbi_remote_fence_i(const u_long *hart_mask)
183 {
184 	struct sbi_ret ret __diagused;
185 
186 	/* Use the RFENCE legacy replacement extension, if available. */
187 	if (has_rfnc_extension) {
188 		ret = SBI_CALL2(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_FENCE_I,
189 		    *hart_mask, 0);
190 		MPASS(ret.error == SBI_SUCCESS);
191 	} else {
192 		(void)SBI_CALL1(SBI_REMOTE_FENCE_I, 0, (uint64_t)hart_mask);
193 	}
194 }
195 
196 void
197 sbi_remote_sfence_vma(const u_long *hart_mask, u_long start, u_long size)
198 {
199 	struct sbi_ret ret __diagused;
200 
201 	/* Use the RFENCE legacy replacement extension, if available. */
202 	if (has_rfnc_extension) {
203 		ret = SBI_CALL4(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_SFENCE_VMA,
204 		    *hart_mask, 0, start, size);
205 		MPASS(ret.error == SBI_SUCCESS);
206 	} else {
207 		(void)SBI_CALL3(SBI_REMOTE_SFENCE_VMA, 0, (uint64_t)hart_mask,
208 		    start, size);
209 	}
210 }
211 
212 void
213 sbi_remote_sfence_vma_asid(const u_long *hart_mask, u_long start, u_long size,
214     u_long asid)
215 {
216 	struct sbi_ret ret __diagused;
217 
218 	/* Use the RFENCE legacy replacement extension, if available. */
219 	if (has_rfnc_extension) {
220 		ret = SBI_CALL5(SBI_EXT_ID_RFNC,
221 		    SBI_RFNC_REMOTE_SFENCE_VMA_ASID, *hart_mask, 0, start,
222 		    size, asid);
223 		MPASS(ret.error == SBI_SUCCESS);
224 	} else {
225 		(void)SBI_CALL4(SBI_REMOTE_SFENCE_VMA_ASID, 0,
226 		    (uint64_t)hart_mask, start, size, asid);
227 	}
228 }
229 
230 int
231 sbi_hsm_hart_start(u_long hart, u_long start_addr, u_long priv)
232 {
233 	struct sbi_ret ret;
234 
235 	ret = SBI_CALL3(SBI_EXT_ID_HSM, SBI_HSM_HART_START, hart, start_addr,
236 	    priv);
237 	return (ret.error != 0 ? (int)ret.error : 0);
238 }
239 
240 void
241 sbi_hsm_hart_stop(void)
242 {
243 	(void)SBI_CALL0(SBI_EXT_ID_HSM, SBI_HSM_HART_STOP);
244 }
245 
246 int
247 sbi_hsm_hart_status(u_long hart)
248 {
249 	struct sbi_ret ret;
250 
251 	ret = SBI_CALL1(SBI_EXT_ID_HSM, SBI_HSM_HART_STATUS, hart);
252 
253 	return (ret.error != 0 ? (int)ret.error : (int)ret.value);
254 }
255 
256 void
257 sbi_init(void)
258 {
259 	struct sbi_ret sret;
260 
261 	/*
262 	 * Get the spec version. For legacy SBI implementations this will
263 	 * return an error, otherwise it is guaranteed to succeed.
264 	 */
265 	sret = sbi_get_spec_version();
266 	if (sret.error != 0) {
267 		/* We are running a legacy SBI implementation. */
268 		sbi_spec_version = 0;
269 		return;
270 	}
271 
272 	/* Set the SBI implementation info. */
273 	sbi_spec_version = sret.value;
274 	sbi_impl_id = sbi_get_impl_id().value;
275 	sbi_impl_version = sbi_get_impl_version().value;
276 
277 	/* Set the hardware implementation info. */
278 	mvendorid = sbi_get_mvendorid().value;
279 	marchid = sbi_get_marchid().value;
280 	mimpid = sbi_get_mimpid().value;
281 
282 	/* Probe for legacy replacement extensions. */
283 	if (sbi_probe_extension(SBI_EXT_ID_TIME) != 0)
284 		has_time_extension = true;
285 	if (sbi_probe_extension(SBI_EXT_ID_IPI) != 0)
286 		has_ipi_extension = true;
287 	if (sbi_probe_extension(SBI_EXT_ID_RFNC) != 0)
288 		has_rfnc_extension = true;
289 	if (sbi_probe_extension(SBI_EXT_ID_SRST) != 0)
290 		has_srst_extension = true;
291 
292 	/*
293 	 * Probe for legacy extensions. We still rely on many of them to be
294 	 * implemented, but this is not guaranteed by the spec.
295 	 */
296 	KASSERT(has_time_extension || sbi_probe_extension(SBI_SET_TIMER) != 0,
297 	    ("SBI doesn't implement sbi_set_timer()"));
298 	KASSERT(sbi_probe_extension(SBI_CONSOLE_PUTCHAR) != 0,
299 	    ("SBI doesn't implement sbi_console_putchar()"));
300 	KASSERT(sbi_probe_extension(SBI_CONSOLE_GETCHAR) != 0,
301 	    ("SBI doesn't implement sbi_console_getchar()"));
302 	KASSERT(has_ipi_extension || sbi_probe_extension(SBI_SEND_IPI) != 0,
303 	    ("SBI doesn't implement sbi_send_ipi()"));
304 	KASSERT(has_rfnc_extension ||
305 	    sbi_probe_extension(SBI_REMOTE_FENCE_I) != 0,
306 	    ("SBI doesn't implement sbi_remote_fence_i()"));
307 	KASSERT(has_rfnc_extension ||
308 	    sbi_probe_extension(SBI_REMOTE_SFENCE_VMA) != 0,
309 	    ("SBI doesn't implement sbi_remote_sfence_vma()"));
310 	KASSERT(has_rfnc_extension ||
311 	    sbi_probe_extension(SBI_REMOTE_SFENCE_VMA_ASID) != 0,
312 	    ("SBI doesn't implement sbi_remote_sfence_vma_asid()"));
313 	KASSERT(has_srst_extension || sbi_probe_extension(SBI_SHUTDOWN) != 0,
314 	    ("SBI doesn't implement a shutdown or reset extension"));
315 }
316 
317 static void
318 sbi_late_init(void *dummy __unused)
319 {
320 	EVENTHANDLER_REGISTER(shutdown_final, sbi_shutdown_final, NULL,
321 	    SHUTDOWN_PRI_LAST);
322 }
323 
324 SYSINIT(sbi, SI_SUB_KLD, SI_ORDER_ANY, sbi_late_init, NULL);
325