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 struct sbi_ret 50 sbi_get_spec_version(void) 51 { 52 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_SPEC_VERSION)); 53 } 54 55 static struct sbi_ret 56 sbi_get_impl_id(void) 57 { 58 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_ID)); 59 } 60 61 static struct sbi_ret 62 sbi_get_impl_version(void) 63 { 64 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_IMPL_VERSION)); 65 } 66 67 static struct sbi_ret 68 sbi_get_mvendorid(void) 69 { 70 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MVENDORID)); 71 } 72 73 74 static struct sbi_ret 75 sbi_get_marchid(void) 76 { 77 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MARCHID)); 78 } 79 80 static struct sbi_ret 81 sbi_get_mimpid(void) 82 { 83 return (SBI_CALL0(SBI_EXT_ID_BASE, SBI_BASE_GET_MIMPID)); 84 } 85 86 static void 87 sbi_shutdown_final(void *dummy __unused, int howto) 88 { 89 if ((howto & RB_POWEROFF) != 0) 90 sbi_shutdown(); 91 } 92 93 void 94 sbi_print_version(void) 95 { 96 u_int major; 97 u_int minor; 98 99 /* For legacy SBI implementations. */ 100 if (sbi_spec_version == 0) { 101 printf("SBI: Unknown (Legacy) Implementation\n"); 102 printf("SBI Specification Version: 0.1\n"); 103 return; 104 } 105 106 switch (sbi_impl_id) { 107 case (SBI_IMPL_ID_BBL): 108 printf("SBI: Berkely Boot Loader %u\n", sbi_impl_version); 109 break; 110 case (SBI_IMPL_ID_OPENSBI): 111 major = sbi_impl_version >> OPENSBI_VERSION_MAJOR_OFFSET; 112 minor = sbi_impl_version & OPENSBI_VERSION_MINOR_MASK; 113 printf("SBI: OpenSBI v%u.%u\n", major, minor); 114 break; 115 default: 116 printf("SBI: Unrecognized Implementation: %u\n", sbi_impl_id); 117 break; 118 } 119 120 major = (sbi_spec_version & SBI_SPEC_VERS_MAJOR_MASK) >> 121 SBI_SPEC_VERS_MAJOR_OFFSET; 122 minor = (sbi_spec_version & SBI_SPEC_VERS_MINOR_MASK); 123 printf("SBI Specification Version: %u.%u\n", major, minor); 124 } 125 126 int 127 sbi_hsm_hart_start(u_long hart, u_long start_addr, u_long priv) 128 { 129 struct sbi_ret ret; 130 131 ret = SBI_CALL3(SBI_EXT_ID_HSM, SBI_HSM_HART_START, hart, start_addr, priv); 132 return (ret.error != 0 ? (int)ret.error : 0); 133 } 134 135 void 136 sbi_hsm_hart_stop(void) 137 { 138 (void)SBI_CALL0(SBI_EXT_ID_HSM, SBI_HSM_HART_STOP); 139 } 140 141 int 142 sbi_hsm_hart_status(u_long hart) 143 { 144 struct sbi_ret ret; 145 146 ret = SBI_CALL1(SBI_EXT_ID_HSM, SBI_HSM_HART_STATUS, hart); 147 148 return (ret.error != 0 ? (int)ret.error : (int)ret.value); 149 } 150 151 void 152 sbi_init(void) 153 { 154 struct sbi_ret sret; 155 156 /* 157 * Get the spec version. For legacy SBI implementations this will 158 * return an error, otherwise it is guaranteed to succeed. 159 */ 160 sret = sbi_get_spec_version(); 161 if (sret.error != 0) { 162 /* We are running a legacy SBI implementation. */ 163 sbi_spec_version = 0; 164 return; 165 } 166 167 /* Set the SBI implementation info. */ 168 sbi_spec_version = sret.value; 169 sbi_impl_id = sbi_get_impl_id().value; 170 sbi_impl_version = sbi_get_impl_version().value; 171 172 /* Set the hardware implementation info. */ 173 mvendorid = sbi_get_mvendorid().value; 174 marchid = sbi_get_marchid().value; 175 mimpid = sbi_get_mimpid().value; 176 177 /* 178 * Probe for legacy extensions. Currently we rely on all of them 179 * to be implemented, but this is not guaranteed by the spec. 180 */ 181 KASSERT(sbi_probe_extension(SBI_SET_TIMER) != 0, 182 ("SBI doesn't implement sbi_set_timer()")); 183 KASSERT(sbi_probe_extension(SBI_CONSOLE_PUTCHAR) != 0, 184 ("SBI doesn't implement sbi_console_putchar()")); 185 KASSERT(sbi_probe_extension(SBI_CONSOLE_GETCHAR) != 0, 186 ("SBI doesn't implement sbi_console_getchar()")); 187 KASSERT(sbi_probe_extension(SBI_CLEAR_IPI) != 0, 188 ("SBI doesn't implement sbi_clear_ipi()")); 189 KASSERT(sbi_probe_extension(SBI_SEND_IPI) != 0, 190 ("SBI doesn't implement sbi_send_ipi()")); 191 KASSERT(sbi_probe_extension(SBI_REMOTE_FENCE_I) != 0, 192 ("SBI doesn't implement sbi_remote_fence_i()")); 193 KASSERT(sbi_probe_extension(SBI_REMOTE_SFENCE_VMA) != 0, 194 ("SBI doesn't implement sbi_remote_sfence_vma()")); 195 KASSERT(sbi_probe_extension(SBI_REMOTE_SFENCE_VMA_ASID) != 0, 196 ("SBI doesn't implement sbi_remote_sfence_vma_asid()")); 197 KASSERT(sbi_probe_extension(SBI_SHUTDOWN) != 0, 198 ("SBI doesn't implement sbi_shutdown()")); 199 } 200 201 static void 202 sbi_late_init(void *dummy __unused) 203 { 204 EVENTHANDLER_REGISTER(shutdown_final, sbi_shutdown_final, NULL, 205 SHUTDOWN_PRI_LAST); 206 } 207 208 SYSINIT(sbi, SI_SUB_KLD, SI_ORDER_ANY, sbi_late_init, NULL); 209