diff --git a/sys/riscv/include/cpu.h b/sys/riscv/include/cpu.h index ee7b1111af56..b33e34d350fb 100644 --- a/sys/riscv/include/cpu.h +++ b/sys/riscv/include/cpu.h @@ -1,94 +1,103 @@ /*- * Copyright (c) 2015-2018 Ruslan Bukin * All rights reserved. * * Portions of this software were developed by SRI International and the * University of Cambridge Computer Laboratory under DARPA/AFRL contract * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. * * Portions of this software were developed by the University of Cambridge * Computer Laboratory as part of the CTSRD Project, with support from the * UK Higher Education Innovation Fund (HEIF). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _MACHINE_CPU_H_ #define _MACHINE_CPU_H_ #include #include #include #define TRAPF_PC(tfp) ((tfp)->tf_sepc) #define TRAPF_USERMODE(tfp) (((tfp)->tf_sstatus & SSTATUS_SPP) == 0) #define cpu_getstack(td) ((td)->td_frame->tf_sp) #define cpu_setstack(td, sp) ((td)->td_frame->tf_sp = (sp)) #define cpu_spinwait() /* nothing */ #define cpu_lock_delay() DELAY(1) #ifdef _KERNEL /* - * 0x0000 CPU ID unimplemented - * 0x0001 UC Berkeley Rocket repo - * 0x0002­0x7FFE Reserved for open-source repos - * 0x7FFF Reserved for extension - * 0x8000 Reserved for anonymous source - * 0x8001­0xFFFE Reserved for proprietary implementations - * 0xFFFF Reserved for extension + * Core manufacturer IDs, as reported by the mvendorid CSR. */ +#define MVENDORID_UNIMPL 0x0 +#define MVENDORID_SIFIVE 0x489 +#define MVENDORID_THEAD 0x5b7 -#define CPU_IMPL_SHIFT 0 -#define CPU_IMPL_MASK (0xffff << CPU_IMPL_SHIFT) -#define CPU_IMPL(mimpid) ((mimpid & CPU_IMPL_MASK) >> CPU_IMPL_SHIFT) -#define CPU_IMPL_UNIMPLEMEN 0x0 -#define CPU_IMPL_UCB_ROCKET 0x1 +/* + * Micro-architecture ID register, marchid. + * + * IDs for open-source implementations are allocated globally. Commercial IDs + * will have the most-significant bit set. + */ +#define MARCHID_UNIMPL 0x0 +#define MARCHID_MSB (1ul << (XLEN - 1)) +#define MARCHID_OPENSOURCE(v) (v) +#define MARCHID_COMMERCIAL(v) (MARCHID_MSB | (v)) +#define MARCHID_IS_OPENSOURCE(m) (((m) & MARCHID_MSB) == 0) + +/* + * Open-source marchid values. + * + * https://github.com/riscv/riscv-isa-manual/blob/master/marchid.md + */ +#define MARCHID_UCB_ROCKET MARCHID_OPENSOURCE(1) +#define MARCHID_UCB_BOOM MARCHID_OPENSOURCE(2) +#define MARCHID_UCB_SPIKE MARCHID_OPENSOURCE(5) +#define MARCHID_UCAM_RVBS MARCHID_OPENSOURCE(10) -#define CPU_PART_SHIFT 62 -#define CPU_PART_MASK (0x3ul << CPU_PART_SHIFT) -#define CPU_PART(misa) ((misa & CPU_PART_MASK) >> CPU_PART_SHIFT) -#define CPU_PART_RV32 0x1 -#define CPU_PART_RV64 0x2 -#define CPU_PART_RV128 0x3 +/* SiFive marchid values */ +#define MARCHID_SIFIVE_U7 MARCHID_COMMERCIAL(7) extern char btext[]; extern char etext[]; void cpu_halt(void) __dead2; void cpu_reset(void) __dead2; void fork_trampoline(void); void identify_cpu(void); static __inline uint64_t get_cyclecount(void) { return (rdcycle()); } #endif #endif /* !_MACHINE_CPU_H_ */ diff --git a/sys/riscv/riscv/identcpu.c b/sys/riscv/riscv/identcpu.c index 4c151eb47939..5ffa038513ae 100644 --- a/sys/riscv/riscv/identcpu.c +++ b/sys/riscv/riscv/identcpu.c @@ -1,368 +1,388 @@ /*- * Copyright (c) 2015-2016 Ruslan Bukin * All rights reserved. * * Portions of this software were developed by SRI International and the * University of Cambridge Computer Laboratory under DARPA/AFRL contract * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. * * Portions of this software were developed by the University of Cambridge * Computer Laboratory as part of the CTSRD Project, with support from the * UK Higher Education Innovation Fund (HEIF). * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #ifdef FDT #include #include #include #endif char machine[] = "riscv"; SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, "Machine class"); /* Hardware implementation info. These values may be empty. */ register_t mvendorid; /* The CPU's JEDEC vendor ID */ register_t marchid; /* The architecture ID */ register_t mimpid; /* The implementation ID */ struct cpu_desc { - u_int cpu_impl; - u_int cpu_part_num; - const char *cpu_impl_name; - const char *cpu_part_name; + const char *cpu_mvendor_name; + const char *cpu_march_name; }; struct cpu_desc cpu_desc[MAXCPU]; -struct cpu_parts { - u_int part_id; - const char *part_name; +/* + * Micro-architecture tables. + */ +struct marchid_entry { + register_t march_id; + const char *march_name; }; -#define CPU_PART_NONE { -1, "Unknown Processor" } -struct cpu_implementers { - u_int impl_id; - const char *impl_name; +#define MARCHID_END { -1ul, NULL } + +/* Open-source RISC-V architecture IDs; globally allocated. */ +static const struct marchid_entry global_marchids[] = { + { MARCHID_UCB_ROCKET, "UC Berkeley Rocket" }, + { MARCHID_UCB_BOOM, "UC Berkeley Boom" }, + { MARCHID_UCB_SPIKE, "UC Berkeley Spike" }, + { MARCHID_UCAM_RVBS, "University of Cambridge RVBS" }, + MARCHID_END }; -#define CPU_IMPLEMENTER_NONE { 0, "Unknown Implementer" } -/* - * CPU base - */ -static const struct cpu_parts cpu_parts_std[] = { - { CPU_PART_RV32, "RV32" }, - { CPU_PART_RV64, "RV64" }, - { CPU_PART_RV128, "RV128" }, - CPU_PART_NONE, +static const struct marchid_entry sifive_marchids[] = { + { MARCHID_SIFIVE_U7, "6/7/P200/X200-Series Processor" }, + MARCHID_END }; /* - * Implementers table. + * Known CPU vendor/manufacturer table. */ -const struct cpu_implementers cpu_implementers[] = { - { CPU_IMPL_UCB_ROCKET, "UC Berkeley Rocket" }, - CPU_IMPLEMENTER_NONE, +static const struct { + register_t mvendor_id; + const char *mvendor_name; + const struct marchid_entry *marchid_table; +} mvendor_ids[] = { + { MVENDORID_UNIMPL, "Unspecified", NULL }, + { MVENDORID_SIFIVE, "SiFive", sifive_marchids }, + { MVENDORID_THEAD, "T-Head", NULL }, }; /* * The ISA string describes the complete set of instructions supported by a * RISC-V CPU. The string begins with a small prefix (e.g. rv64) indicating the * base ISA. It is followed first by single-letter ISA extensions, and then * multi-letter ISA extensions. * * Underscores are used mainly to separate consecutive multi-letter extensions, * but may optionally appear between any two extensions. An extension may be * followed by a version number, in the form of 'Mpm', where M is the * extension's major version number, and 'm' is the minor version number. * * The format is described in detail by the "ISA Extension Naming Conventions" * chapter of the unprivileged spec. */ #define ISA_PREFIX ("rv" __XSTRING(__riscv_xlen)) #define ISA_PREFIX_LEN (sizeof(ISA_PREFIX) - 1) static __inline int parse_ext_s(char *isa, int idx, int len) { /* * Proceed to the next multi-letter extension or the end of the * string. * * TODO: parse these once we gain support */ while (isa[idx] != '_' && idx < len) { idx++; } return (idx); } static __inline int parse_ext_x(char *isa, int idx, int len) { /* * Proceed to the next multi-letter extension or the end of the * string. */ while (isa[idx] != '_' && idx < len) { idx++; } return (idx); } static __inline int parse_ext_z(char *isa, int idx, int len) { /* * Proceed to the next multi-letter extension or the end of the * string. * * TODO: parse some of these. */ while (isa[idx] != '_' && idx < len) { idx++; } return (idx); } static __inline int parse_ext_version(char *isa, int idx, u_int *majorp __unused, u_int *minorp __unused) { /* Major version. */ while (isdigit(isa[idx])) idx++; if (isa[idx] != 'p') return (idx); else idx++; /* Minor version. */ while (isdigit(isa[idx])) idx++; return (idx); } /* * Parse the ISA string, building up the set of HWCAP bits as they are found. */ static void parse_riscv_isa(char *isa, int len, u_long *hwcapp) { u_long hwcap; int i; hwcap = 0; i = ISA_PREFIX_LEN; while (i < len) { switch(isa[i]) { case 'a': case 'c': #ifdef FPE case 'd': case 'f': #endif case 'i': case 'm': hwcap |= HWCAP_ISA_BIT(isa[i]); i++; break; case 'g': hwcap |= HWCAP_ISA_G; i++; break; case 's': /* * XXX: older versions of this string erroneously * indicated supervisor and user mode support as * single-letter extensions. Detect and skip both 's' * and 'u'. */ if (isa[i - 1] != '_' && isa[i + 1] == 'u') { i += 2; continue; } /* * Supervisor-level extension namespace. */ i = parse_ext_s(isa, i, len); break; case 'x': /* * Custom extension namespace. For now, we ignore * these. */ i = parse_ext_x(isa, i, len); break; case 'z': /* * Multi-letter standard extension namespace. */ i = parse_ext_z(isa, i, len); break; case '_': i++; continue; default: /* Unrecognized/unsupported. */ i++; break; } i = parse_ext_version(isa, i, NULL, NULL); } if (hwcapp != NULL) *hwcapp = hwcap; } #ifdef FDT static void fill_elf_hwcap(void *dummy __unused) { char isa[1024]; u_long hwcap; phandle_t node; ssize_t len; node = OF_finddevice("/cpus"); if (node == -1) { if (bootverbose) printf("fill_elf_hwcap: Can't find cpus node\n"); return; } /* * Iterate through the CPUs and examine their ISA string. While we * could assign elf_hwcap to be whatever the boot CPU supports, to * handle the (unusual) case of running a system with hetergeneous * ISAs, keep only the extension bits that are common to all harts. */ for (node = OF_child(node); node > 0; node = OF_peer(node)) { /* Skip any non-CPU nodes, such as cpu-map. */ if (!ofw_bus_node_is_compatible(node, "riscv")) continue; len = OF_getprop(node, "riscv,isa", isa, sizeof(isa)); KASSERT(len <= sizeof(isa), ("ISA string truncated")); if (len == -1) { if (bootverbose) printf("fill_elf_hwcap: " "Can't find riscv,isa property\n"); return; } else if (strncmp(isa, ISA_PREFIX, ISA_PREFIX_LEN) != 0) { if (bootverbose) printf("fill_elf_hwcap: " "Unsupported ISA string: %s\n", isa); return; } /* * The string is specified to be lowercase, but let's be * certain. */ for (int i = 0; i < len; i++) isa[i] = tolower(isa[i]); parse_riscv_isa(isa, len, &hwcap); if (elf_hwcap != 0) elf_hwcap &= hwcap; else elf_hwcap = hwcap; } } SYSINIT(identcpu, SI_SUB_CPU, SI_ORDER_ANY, fill_elf_hwcap, NULL); #endif -void -identify_cpu(void) +static void +identify_cpu_ids(struct cpu_desc *desc) { - const struct cpu_parts *cpu_partsp; - uint32_t part_id; - uint32_t impl_id; - uint64_t misa; - u_int cpu; - size_t i; - - cpu_partsp = NULL; + const struct marchid_entry *table = NULL; + int i; - /* TODO: can we get misa somewhere ? */ - misa = 0; + desc->cpu_mvendor_name = "Unknown"; + desc->cpu_march_name = "Unknown"; - cpu = PCPU_GET(cpuid); - - impl_id = CPU_IMPL(mimpid); - for (i = 0; i < nitems(cpu_implementers); i++) { - if (impl_id == cpu_implementers[i].impl_id || - cpu_implementers[i].impl_id == 0) { - cpu_desc[cpu].cpu_impl = impl_id; - cpu_desc[cpu].cpu_impl_name = cpu_implementers[i].impl_name; - cpu_partsp = cpu_parts_std; + /* + * Search for a recognized vendor, and possibly obtain the secondary + * table for marchid lookup. + */ + for (i = 0; i < nitems(mvendor_ids); i++) { + if (mvendorid == mvendor_ids[i].mvendor_id) { + desc->cpu_mvendor_name = mvendor_ids[i].mvendor_name; + table = mvendor_ids[i].marchid_table; break; } } - part_id = CPU_PART(misa); - for (i = 0; &cpu_partsp[i] != NULL; i++) { - if (part_id == cpu_partsp[i].part_id || - cpu_partsp[i].part_id == -1) { - cpu_desc[cpu].cpu_part_num = part_id; - cpu_desc[cpu].cpu_part_name = cpu_partsp[i].part_name; + if (marchid == MARCHID_UNIMPL) { + desc->cpu_march_name = "Unspecified"; + return; + } + + if (MARCHID_IS_OPENSOURCE(marchid)) { + table = global_marchids; + } else if (table == NULL) + return; + + for (i = 0; table[i].march_name != NULL; i++) { + if (marchid == table[i].march_id) { + desc->cpu_march_name = table[i].march_name; break; } } +} + +void +identify_cpu(void) +{ + struct cpu_desc *desc; + u_int cpu, hart; + + cpu = PCPU_GET(cpuid); + hart = PCPU_GET(hart); + desc = &cpu_desc[cpu]; + + identify_cpu_ids(desc); /* Print details for boot CPU or if we want verbose output */ if (cpu == 0 || bootverbose) { - printf("CPU(%d): %s %s\n", cpu, - cpu_desc[cpu].cpu_impl_name, - cpu_desc[cpu].cpu_part_name); + /* Summary line. */ + printf("CPU %-3u: Vendor=%s Core=%s (Hart %u)\n", cpu, + desc->cpu_mvendor_name, desc->cpu_march_name, hart); + + printf(" marchid=%#lx, mimpid=%#lx\n", marchid, mimpid); } }