1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 31 #include <sys/param.h> 32 #include <sys/kernel.h> 33 #include <sys/systm.h> 34 #include <sys/types.h> 35 #include <sys/eventhandler.h> 36 #include <sys/reboot.h> 37 38 #include <machine/md_var.h> 39 #include <machine/sbi.h> 40 41 /* SBI Implementation-Specific Definitions */ 42 #define OPENSBI_VERSION_MAJOR_OFFSET 16 43 #define OPENSBI_VERSION_MINOR_MASK 0xFFFF 44 45 u_long sbi_spec_version; 46 u_long sbi_impl_id; 47 u_long sbi_impl_version; 48 49 static bool has_time_extension = false; 50 static bool has_ipi_extension = false; 51 static bool has_rfnc_extension = false; 52 53 static struct sbi_ret 54 sbi_get_spec_version(void) 55 { 56 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_SPEC_VERSION)); 57 } 58 59 static struct sbi_ret 60 sbi_get_impl_id(void) 61 { 62 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_ID)); 63 } 64 65 static struct sbi_ret 66 sbi_get_impl_version(void) 67 { 68 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_VERSION)); 69 } 70 71 static struct sbi_ret 72 sbi_get_mvendorid(void) 73 { 74 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MVENDORID)); 75 } 76 77 static struct sbi_ret 78 sbi_get_marchid(void) 79 { 80 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MARCHID)); 81 } 82 83 static struct sbi_ret 84 sbi_get_mimpid(void) 85 { 86 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MIMPID)); 87 } 88 89 static void 90 sbi_shutdown_final(void *dummy __unused, int howto) 91 { 92 if ((howto & RB_POWEROFF) != 0) 93 sbi_shutdown(); 94 } 95 96 void 97 sbi_print_version(void) 98 { 99 u_int major; 100 u_int minor; 101 102 /* For legacy SBI implementations. */ 103 if (sbi_spec_version == 0) { 104 printf("SBI: Unknown (Legacy) Implementation\n"); 105 printf("SBI Specification Version: 0.1\n"); 106 return; 107 } 108 109 switch (sbi_impl_id) { 110 case (SBI_IMPL_ID_BBL): 111 printf("SBI: Berkely Boot Loader %lu\n", sbi_impl_version); 112 break; 113 case (SBI_IMPL_ID_OPENSBI): 114 major = sbi_impl_version >> OPENSBI_VERSION_MAJOR_OFFSET; 115 minor = sbi_impl_version & OPENSBI_VERSION_MINOR_MASK; 116 printf("SBI: OpenSBI v%u.%u\n", major, minor); 117 break; 118 default: 119 printf("SBI: Unrecognized Implementation: %lu\n", sbi_impl_id); 120 break; 121 } 122 123 major = (sbi_spec_version & SBI_SPEC_VERS_MAJOR_MASK) >> 124 SBI_SPEC_VERS_MAJOR_OFFSET; 125 minor = (sbi_spec_version & SBI_SPEC_VERS_MINOR_MASK); 126 printf("SBI Specification Version: %u.%u\n", major, minor); 127 } 128 129 void 130 sbi_set_timer(uint64_t val) 131 { 132 struct sbi_ret ret; 133 134 /* Use the TIME legacy replacement extension, if available. */ 135 if (has_time_extension) { 136 ret = SBI_CALL1(SBI_EXT_ID_TIME, SBI_TIME_SET_TIMER, val); 137 MPASS(ret.error == SBI_SUCCESS); 138 } else { 139 (void)SBI_CALL1(SBI_SET_TIMER, 0, val); 140 } 141 } 142 143 void 144 sbi_send_ipi(const u_long *hart_mask) 145 { 146 struct sbi_ret ret; 147 148 /* Use the IPI legacy replacement extension, if available. */ 149 if (has_ipi_extension) { 150 ret = SBI_CALL2(SBI_EXT_ID_IPI, SBI_IPI_SEND_IPI, 151 *hart_mask, 0); 152 MPASS(ret.error == SBI_SUCCESS); 153 } else { 154 (void)SBI_CALL1(SBI_SEND_IPI, 0, (uint64_t)hart_mask); 155 } 156 } 157 158 void 159 sbi_remote_fence_i(const u_long *hart_mask) 160 { 161 struct sbi_ret ret; 162 163 /* Use the RFENCE legacy replacement extension, if available. */ 164 if (has_rfnc_extension) { 165 ret = SBI_CALL2(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_FENCE_I, 166 *hart_mask, 0); 167 MPASS(ret.error == SBI_SUCCESS); 168 } else { 169 (void)SBI_CALL1(SBI_REMOTE_FENCE_I, 0, (uint64_t)hart_mask); 170 } 171 } 172 173 void 174 sbi_remote_sfence_vma(const u_long *hart_mask, u_long start, u_long size) 175 { 176 struct sbi_ret ret; 177 178 /* Use the RFENCE legacy replacement extension, if available. */ 179 if (has_rfnc_extension) { 180 ret = SBI_CALL4(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_SFENCE_VMA, 181 *hart_mask, 0, start, size); 182 MPASS(ret.error == SBI_SUCCESS); 183 } else { 184 (void)SBI_CALL3(SBI_REMOTE_SFENCE_VMA, 0, (uint64_t)hart_mask, 185 start, size); 186 } 187 } 188 189 void 190 sbi_remote_sfence_vma_asid(const u_long *hart_mask, u_long start, u_long size, 191 u_long asid) 192 { 193 struct sbi_ret ret; 194 195 /* Use the RFENCE legacy replacement extension, if available. */ 196 if (has_rfnc_extension) { 197 ret = SBI_CALL5(SBI_EXT_ID_RFNC, SBI_RFNC_REMOTE_SFENCE_VMA_ASID, 198 *hart_mask, 0, start, size, asid); 199 MPASS(ret.error == SBI_SUCCESS); 200 } else { 201 (void)SBI_CALL4(SBI_REMOTE_SFENCE_VMA_ASID, 0, 202 (uint64_t)hart_mask, start, size, asid); 203 } 204 } 205 206 int 207 sbi_hsm_hart_start(u_long hart, u_long start_addr, u_long priv) 208 { 209 struct sbi_ret ret; 210 211 ret = SBI_CALL3(SBI_EXT_ID_HSM, SBI_HSM_HART_START, hart, start_addr, priv); 212 return (ret.error != 0 ? (int)ret.error : 0); 213 } 214 215 void 216 sbi_hsm_hart_stop(void) 217 { 218 (void)SBI_CALL0(SBI_EXT_ID_HSM, SBI_HSM_HART_STOP); 219 } 220 221 int 222 sbi_hsm_hart_status(u_long hart) 223 { 224 struct sbi_ret ret; 225 226 ret = SBI_CALL1(SBI_EXT_ID_HSM, SBI_HSM_HART_STATUS, hart); 227 228 return (ret.error != 0 ? (int)ret.error : (int)ret.value); 229 } 230 231 void 232 sbi_init(void) 233 { 234 struct sbi_ret sret; 235 236 /* 237 * Get the spec version. For legacy SBI implementations this will 238 * return an error, otherwise it is guaranteed to succeed. 239 */ 240 sret = sbi_get_spec_version(); 241 if (sret.error != 0) { 242 /* We are running a legacy SBI implementation. */ 243 sbi_spec_version = 0; 244 return; 245 } 246 247 /* Set the SBI implementation info. */ 248 sbi_spec_version = sret.value; 249 sbi_impl_id = sbi_get_impl_id().value; 250 sbi_impl_version = sbi_get_impl_version().value; 251 252 /* Set the hardware implementation info. */ 253 mvendorid = sbi_get_mvendorid().value; 254 marchid = sbi_get_marchid().value; 255 mimpid = sbi_get_mimpid().value; 256 257 /* Probe for legacy replacement extensions. */ 258 if (sbi_probe_extension(SBI_EXT_ID_TIME) != 0) 259 has_time_extension = true; 260 if (sbi_probe_extension(SBI_EXT_ID_IPI) != 0) 261 has_ipi_extension = true; 262 if (sbi_probe_extension(SBI_EXT_ID_RFNC) != 0) 263 has_rfnc_extension = true; 264 265 /* 266 * Probe for legacy extensions. We still rely on many of them to be 267 * implemented, but this is not guaranteed by the spec. 268 */ 269 KASSERT(has_time_extension || sbi_probe_extension(SBI_SET_TIMER) != 0, 270 ("SBI doesn't implement sbi_set_timer()")); 271 KASSERT(sbi_probe_extension(SBI_CONSOLE_PUTCHAR) != 0, 272 ("SBI doesn't implement sbi_console_putchar()")); 273 KASSERT(sbi_probe_extension(SBI_CONSOLE_GETCHAR) != 0, 274 ("SBI doesn't implement sbi_console_getchar()")); 275 KASSERT(has_ipi_extension || sbi_probe_extension(SBI_SEND_IPI) != 0, 276 ("SBI doesn't implement sbi_send_ipi()")); 277 KASSERT(has_rfnc_extension || 278 sbi_probe_extension(SBI_REMOTE_FENCE_I) != 0, 279 ("SBI doesn't implement sbi_remote_fence_i()")); 280 KASSERT(has_rfnc_extension || 281 sbi_probe_extension(SBI_REMOTE_SFENCE_VMA) != 0, 282 ("SBI doesn't implement sbi_remote_sfence_vma()")); 283 KASSERT(has_rfnc_extension || 284 sbi_probe_extension(SBI_REMOTE_SFENCE_VMA_ASID) != 0, 285 ("SBI doesn't implement sbi_remote_sfence_vma_asid()")); 286 KASSERT(sbi_probe_extension(SBI_SHUTDOWN) != 0, 287 ("SBI doesn't implement sbi_shutdown()")); 288 } 289 290 static void 291 sbi_late_init(void *dummy __unused) 292 { 293 EVENTHANDLER_REGISTER(shutdown_final, sbi_shutdown_final, NULL, 294 SHUTDOWN_PRI_LAST); 295 } 296 297 SYSINIT(sbi, SI_SUB_KLD, SI_ORDER_ANY, sbi_late_init, NULL); 298