1 /*- 2 * Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Portions of this software were developed by SRI International and the 6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Portions of this software were developed by the University of Cambridge 10 * Computer Laboratory as part of the CTSRD Project, with support from the 11 * UK Higher Education Innovation Fund (HEIF). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "opt_platform.h" 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/kernel.h> 43 #include <sys/pcpu.h> 44 #include <sys/sysctl.h> 45 46 #include <machine/cpu.h> 47 #include <machine/cpufunc.h> 48 #include <machine/elf.h> 49 #include <machine/md_var.h> 50 #include <machine/trap.h> 51 52 #ifdef FDT 53 #include <dev/fdt/fdt_common.h> 54 #include <dev/ofw/openfirm.h> 55 #include <dev/ofw/ofw_bus_subr.h> 56 #endif 57 58 char machine[] = "riscv"; 59 60 SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, 61 "Machine class"); 62 63 /* Hardware implementation info. These values may be empty. */ 64 register_t mvendorid; /* The CPU's JEDEC vendor ID */ 65 register_t marchid; /* The architecture ID */ 66 register_t mimpid; /* The implementation ID */ 67 68 struct cpu_desc { 69 u_int cpu_impl; 70 u_int cpu_part_num; 71 const char *cpu_impl_name; 72 const char *cpu_part_name; 73 }; 74 75 struct cpu_desc cpu_desc[MAXCPU]; 76 77 struct cpu_parts { 78 u_int part_id; 79 const char *part_name; 80 }; 81 #define CPU_PART_NONE { -1, "Unknown Processor" } 82 83 struct cpu_implementers { 84 u_int impl_id; 85 const char *impl_name; 86 }; 87 #define CPU_IMPLEMENTER_NONE { 0, "Unknown Implementer" } 88 89 /* 90 * CPU base 91 */ 92 static const struct cpu_parts cpu_parts_std[] = { 93 { CPU_PART_RV32, "RV32" }, 94 { CPU_PART_RV64, "RV64" }, 95 { CPU_PART_RV128, "RV128" }, 96 CPU_PART_NONE, 97 }; 98 99 /* 100 * Implementers table. 101 */ 102 const struct cpu_implementers cpu_implementers[] = { 103 { CPU_IMPL_UCB_ROCKET, "UC Berkeley Rocket" }, 104 CPU_IMPLEMENTER_NONE, 105 }; 106 107 #ifdef FDT 108 /* 109 * The ISA string is made up of a small prefix (e.g. rv64) and up to 26 letters 110 * indicating the presence of the 26 possible standard extensions. Therefore 32 111 * characters will be sufficient. 112 */ 113 #define ISA_NAME_MAXLEN 32 114 #define ISA_PREFIX ("rv" __XSTRING(__riscv_xlen)) 115 #define ISA_PREFIX_LEN (sizeof(ISA_PREFIX) - 1) 116 117 static void 118 fill_elf_hwcap(void *dummy __unused) 119 { 120 u_long caps[256] = {0}; 121 char isa[ISA_NAME_MAXLEN]; 122 u_long hwcap; 123 phandle_t node; 124 ssize_t len; 125 int i; 126 127 caps['i'] = caps['I'] = HWCAP_ISA_I; 128 caps['m'] = caps['M'] = HWCAP_ISA_M; 129 caps['a'] = caps['A'] = HWCAP_ISA_A; 130 #ifdef FPE 131 caps['f'] = caps['F'] = HWCAP_ISA_F; 132 caps['d'] = caps['D'] = HWCAP_ISA_D; 133 #endif 134 caps['c'] = caps['C'] = HWCAP_ISA_C; 135 136 node = OF_finddevice("/cpus"); 137 if (node == -1) { 138 if (bootverbose) 139 printf("fill_elf_hwcap: Can't find cpus node\n"); 140 return; 141 } 142 143 /* 144 * Iterate through the CPUs and examine their ISA string. While we 145 * could assign elf_hwcap to be whatever the boot CPU supports, to 146 * handle the (unusual) case of running a system with hetergeneous 147 * ISAs, keep only the extension bits that are common to all harts. 148 */ 149 for (node = OF_child(node); node > 0; node = OF_peer(node)) { 150 /* Skip any non-CPU nodes, such as cpu-map. */ 151 if (!ofw_bus_node_is_compatible(node, "riscv")) 152 continue; 153 154 len = OF_getprop(node, "riscv,isa", isa, sizeof(isa)); 155 KASSERT(len <= ISA_NAME_MAXLEN, ("ISA string truncated")); 156 if (len == -1) { 157 if (bootverbose) 158 printf("fill_elf_hwcap: " 159 "Can't find riscv,isa property\n"); 160 return; 161 } else if (strncmp(isa, ISA_PREFIX, ISA_PREFIX_LEN) != 0) { 162 if (bootverbose) 163 printf("fill_elf_hwcap: " 164 "Unsupported ISA string: %s\n", isa); 165 return; 166 } 167 168 hwcap = 0; 169 for (i = ISA_PREFIX_LEN; i < len; i++) 170 hwcap |= caps[(unsigned char)isa[i]]; 171 172 if (elf_hwcap != 0) 173 elf_hwcap &= hwcap; 174 else 175 elf_hwcap = hwcap; 176 177 } 178 } 179 180 SYSINIT(identcpu, SI_SUB_CPU, SI_ORDER_ANY, fill_elf_hwcap, NULL); 181 #endif 182 183 void 184 identify_cpu(void) 185 { 186 const struct cpu_parts *cpu_partsp; 187 uint32_t part_id; 188 uint32_t impl_id; 189 uint64_t mimpid; 190 uint64_t misa; 191 u_int cpu; 192 size_t i; 193 194 cpu_partsp = NULL; 195 196 /* TODO: can we get mimpid and misa somewhere ? */ 197 mimpid = 0; 198 misa = 0; 199 200 cpu = PCPU_GET(cpuid); 201 202 impl_id = CPU_IMPL(mimpid); 203 for (i = 0; i < nitems(cpu_implementers); i++) { 204 if (impl_id == cpu_implementers[i].impl_id || 205 cpu_implementers[i].impl_id == 0) { 206 cpu_desc[cpu].cpu_impl = impl_id; 207 cpu_desc[cpu].cpu_impl_name = cpu_implementers[i].impl_name; 208 cpu_partsp = cpu_parts_std; 209 break; 210 } 211 } 212 213 part_id = CPU_PART(misa); 214 for (i = 0; &cpu_partsp[i] != NULL; i++) { 215 if (part_id == cpu_partsp[i].part_id || 216 cpu_partsp[i].part_id == -1) { 217 cpu_desc[cpu].cpu_part_num = part_id; 218 cpu_desc[cpu].cpu_part_name = cpu_partsp[i].part_name; 219 break; 220 } 221 } 222 223 /* Print details for boot CPU or if we want verbose output */ 224 if (cpu == 0 || bootverbose) { 225 printf("CPU(%d): %s %s\n", cpu, 226 cpu_desc[cpu].cpu_impl_name, 227 cpu_desc[cpu].cpu_part_name); 228 } 229 } 230