Index: sys/riscv/include/elf.h =================================================================== --- sys/riscv/include/elf.h +++ sys/riscv/include/elf.h @@ -74,4 +74,12 @@ /* TODO: set correct value */ #define ET_DYN_LOAD_ADDR 0x100000 +/* Flags passed in AT_HWCAP */ +#define HWCAP_ISA_I (1 << ('I' - 'A')) +#define HWCAP_ISA_M (1 << ('M' - 'A')) +#define HWCAP_ISA_A (1 << ('A' - 'A')) +#define HWCAP_ISA_F (1 << ('F' - 'A')) +#define HWCAP_ISA_D (1 << ('D' - 'A')) +#define HWCAP_ISA_C (1 << ('C' - 'A')) + #endif /* !_MACHINE_ELF_H_ */ Index: sys/riscv/include/md_var.h =================================================================== --- sys/riscv/include/md_var.h +++ sys/riscv/include/md_var.h @@ -38,6 +38,7 @@ extern int szsigcode; extern uint64_t *vm_page_dump; extern int vm_page_dump_size; +extern u_long elf_hwcap; struct dumperinfo; Index: sys/riscv/riscv/elf_machdep.c =================================================================== --- sys/riscv/riscv/elf_machdep.c +++ sys/riscv/riscv/elf_machdep.c @@ -58,6 +58,8 @@ #include #include +u_long elf_hwcap; + struct sysentvec elf64_freebsd_sysvec = { .sv_size = SYS_MAXSYSCALL, .sv_table = sysent, @@ -90,6 +92,7 @@ .sv_schedtail = NULL, .sv_thread_detach = NULL, .sv_trap = NULL, + .sv_hwcap = &elf_hwcap, }; INIT_SYSENTVEC(elf64_sysvec, &elf64_freebsd_sysvec); Index: sys/riscv/riscv/identcpu.c =================================================================== --- sys/riscv/riscv/identcpu.c +++ sys/riscv/riscv/identcpu.c @@ -32,18 +32,28 @@ * SUCH DAMAGE. */ +#include "opt_platform.h" + #include __FBSDID("$FreeBSD$"); #include +#include +#include #include #include -#include #include #include +#include +#include #include +#ifdef FDT +#include +#include +#endif + char machine[] = "riscv"; SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, @@ -88,6 +98,77 @@ CPU_IMPLEMENTER_NONE, }; +#ifdef FDT +static int +fill_elf_hwcap(void) +{ + u_long caps[256] = {0}; + u_long hwcap; + /* There are 26 possible standard extensions and a small prefix, + * therefore 32 bytes is sufficent. */ + char isa[32]; + phandle_t node; + ssize_t len; + int i; + + caps['i'] = caps['I'] = HWCAP_ISA_I; + caps['m'] = caps['M'] = HWCAP_ISA_M; + caps['a'] = caps['A'] = HWCAP_ISA_A; +#ifdef FPE + caps['f'] = caps['F'] = HWCAP_ISA_F; + caps['d'] = caps['D'] = HWCAP_ISA_D; +#endif + caps['c'] = caps['C'] = HWCAP_ISA_C; + + node = OF_finddevice("/cpus"); + if (node == -1) { + if (bootverbose) + printf("Can't find cpus node\n"); + return (ENOENT); + } + + /* + * 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)) { + if (!fdt_is_compatible_strict(node, "riscv")) { + if (bootverbose) + printf("Can't find cpu\n"); + return (ENOENT); + } + + len = OF_getprop(node, "riscv,isa", (pcell_t *)isa, + sizeof(isa)); + if (len == -1) { + if (bootverbose) + printf("Can't find riscv,isa property\n"); + return (ENOENT); + } + isa[len - 1] = '\0'; + + /* + * The ISA string is prefixed with rvXX, where XX is the XLEN + * width (i.e. 32 or 64). Skip the prefix. + */ + hwcap = 0; + for (i = 4; i < len; i++) + hwcap |= caps[(unsigned char)isa[i]]; + + if (elf_hwcap != 0) + elf_hwcap &= hwcap; + else + elf_hwcap = hwcap; + } + + return (0); +} + +SYSINIT(identcpu, SI_SUB_CPU, SI_ORDER_ANY, fill_elf_hwcap, NULL); +#endif + void identify_cpu(void) {