1b86c6ba6SRichard Henderson /* 2b86c6ba6SRichard Henderson * SPDX-License-Identifier: GPL-2.0-or-later 3b86c6ba6SRichard Henderson * Host specific cpu identification for RISC-V. 4b86c6ba6SRichard Henderson */ 5b86c6ba6SRichard Henderson 6b86c6ba6SRichard Henderson #include "qemu/osdep.h" 7*f7230e09STANG Tiancheng #include "qemu/host-utils.h" 8b86c6ba6SRichard Henderson #include "host/cpuinfo.h" 9b86c6ba6SRichard Henderson 10e5717308SRichard Henderson #ifdef CONFIG_ASM_HWPROBE_H 11e5717308SRichard Henderson #include <asm/hwprobe.h> 12e5717308SRichard Henderson #include <sys/syscall.h> 13c5757f80SMilan P. Stanić #include <asm/unistd.h> 14e5717308SRichard Henderson #endif 15e5717308SRichard Henderson 16b86c6ba6SRichard Henderson unsigned cpuinfo; 17*f7230e09STANG Tiancheng unsigned riscv_lg2_vlenb; 18b86c6ba6SRichard Henderson static volatile sig_atomic_t got_sigill; 19b86c6ba6SRichard Henderson 20b86c6ba6SRichard Henderson static void sigill_handler(int signo, siginfo_t *si, void *data) 21b86c6ba6SRichard Henderson { 22b86c6ba6SRichard Henderson /* Skip the faulty instruction */ 23b86c6ba6SRichard Henderson ucontext_t *uc = (ucontext_t *)data; 24adc02842SRichard Henderson 25adc02842SRichard Henderson #ifdef __linux__ 26b86c6ba6SRichard Henderson uc->uc_mcontext.__gregs[REG_PC] += 4; 27adc02842SRichard Henderson #elif defined(__OpenBSD__) 28adc02842SRichard Henderson uc->sc_sepc += 4; 29adc02842SRichard Henderson #else 30adc02842SRichard Henderson # error Unsupported OS 31adc02842SRichard Henderson #endif 32b86c6ba6SRichard Henderson 33b86c6ba6SRichard Henderson got_sigill = 1; 34b86c6ba6SRichard Henderson } 35b86c6ba6SRichard Henderson 36b86c6ba6SRichard Henderson /* Called both as constructor and (possibly) via other constructors. */ 37b86c6ba6SRichard Henderson unsigned __attribute__((constructor)) cpuinfo_init(void) 38b86c6ba6SRichard Henderson { 39*f7230e09STANG Tiancheng unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZICOND | CPUINFO_ZVE64X; 40b86c6ba6SRichard Henderson unsigned info = cpuinfo; 41b86c6ba6SRichard Henderson 42b86c6ba6SRichard Henderson if (info) { 43b86c6ba6SRichard Henderson return info; 44b86c6ba6SRichard Henderson } 45b86c6ba6SRichard Henderson 46b86c6ba6SRichard Henderson /* Test for compile-time settings. */ 47b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zba) 48b86c6ba6SRichard Henderson info |= CPUINFO_ZBA; 49b86c6ba6SRichard Henderson #endif 50b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zbb) 51b86c6ba6SRichard Henderson info |= CPUINFO_ZBB; 52b86c6ba6SRichard Henderson #endif 53b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zicond) 54b86c6ba6SRichard Henderson info |= CPUINFO_ZICOND; 55b86c6ba6SRichard Henderson #endif 56*f7230e09STANG Tiancheng #if defined(__riscv_arch_test) && \ 57*f7230e09STANG Tiancheng (defined(__riscv_vector) || defined(__riscv_zve64x)) 58*f7230e09STANG Tiancheng info |= CPUINFO_ZVE64X; 59*f7230e09STANG Tiancheng #endif 60b86c6ba6SRichard Henderson left &= ~info; 61b86c6ba6SRichard Henderson 62e5717308SRichard Henderson #ifdef CONFIG_ASM_HWPROBE_H 63e5717308SRichard Henderson if (left) { 64e5717308SRichard Henderson /* 65e5717308SRichard Henderson * TODO: glibc 2.40 will introduce <sys/hwprobe.h>, which 66e5717308SRichard Henderson * provides __riscv_hwprobe and __riscv_hwprobe_one, 67e5717308SRichard Henderson * which is a slightly cleaner interface. 68e5717308SRichard Henderson */ 69e5717308SRichard Henderson struct riscv_hwprobe pair = { .key = RISCV_HWPROBE_KEY_IMA_EXT_0 }; 70e5717308SRichard Henderson if (syscall(__NR_riscv_hwprobe, &pair, 1, 0, NULL, 0) == 0 71e5717308SRichard Henderson && pair.key >= 0) { 72e5717308SRichard Henderson info |= pair.value & RISCV_HWPROBE_EXT_ZBA ? CPUINFO_ZBA : 0; 73e5717308SRichard Henderson info |= pair.value & RISCV_HWPROBE_EXT_ZBB ? CPUINFO_ZBB : 0; 74e5717308SRichard Henderson left &= ~(CPUINFO_ZBA | CPUINFO_ZBB); 75e5717308SRichard Henderson #ifdef RISCV_HWPROBE_EXT_ZICOND 76e5717308SRichard Henderson info |= pair.value & RISCV_HWPROBE_EXT_ZICOND ? CPUINFO_ZICOND : 0; 77e5717308SRichard Henderson left &= ~CPUINFO_ZICOND; 78e5717308SRichard Henderson #endif 79*f7230e09STANG Tiancheng /* For rv64, V is Zve64d, a superset of Zve64x. */ 80*f7230e09STANG Tiancheng info |= pair.value & RISCV_HWPROBE_IMA_V ? CPUINFO_ZVE64X : 0; 81*f7230e09STANG Tiancheng #ifdef RISCV_HWPROBE_EXT_ZVE64X 82*f7230e09STANG Tiancheng info |= pair.value & RISCV_HWPROBE_EXT_ZVE64X ? CPUINFO_ZVE64X : 0; 83*f7230e09STANG Tiancheng #endif 84e5717308SRichard Henderson } 85e5717308SRichard Henderson } 86e5717308SRichard Henderson #endif /* CONFIG_ASM_HWPROBE_H */ 87e5717308SRichard Henderson 88*f7230e09STANG Tiancheng /* 89*f7230e09STANG Tiancheng * We only detect support for vectors with hwprobe. All kernels with 90*f7230e09STANG Tiancheng * support for vectors in userspace also support the hwprobe syscall. 91*f7230e09STANG Tiancheng */ 92*f7230e09STANG Tiancheng left &= ~CPUINFO_ZVE64X; 93*f7230e09STANG Tiancheng 94b86c6ba6SRichard Henderson if (left) { 95b86c6ba6SRichard Henderson struct sigaction sa_old, sa_new; 96b86c6ba6SRichard Henderson 97b86c6ba6SRichard Henderson memset(&sa_new, 0, sizeof(sa_new)); 98b86c6ba6SRichard Henderson sa_new.sa_flags = SA_SIGINFO; 99b86c6ba6SRichard Henderson sa_new.sa_sigaction = sigill_handler; 100b86c6ba6SRichard Henderson sigaction(SIGILL, &sa_new, &sa_old); 101b86c6ba6SRichard Henderson 102b86c6ba6SRichard Henderson if (left & CPUINFO_ZBA) { 103b86c6ba6SRichard Henderson /* Probe for Zba: add.uw zero,zero,zero. */ 104b86c6ba6SRichard Henderson got_sigill = 0; 105b86c6ba6SRichard Henderson asm volatile(".insn r 0x3b, 0, 0x04, zero, zero, zero" 106b86c6ba6SRichard Henderson : : : "memory"); 107b86c6ba6SRichard Henderson info |= got_sigill ? 0 : CPUINFO_ZBA; 108b86c6ba6SRichard Henderson left &= ~CPUINFO_ZBA; 109b86c6ba6SRichard Henderson } 110b86c6ba6SRichard Henderson 111b86c6ba6SRichard Henderson if (left & CPUINFO_ZBB) { 112b86c6ba6SRichard Henderson /* Probe for Zbb: andn zero,zero,zero. */ 113b86c6ba6SRichard Henderson got_sigill = 0; 114b86c6ba6SRichard Henderson asm volatile(".insn r 0x33, 7, 0x20, zero, zero, zero" 115b86c6ba6SRichard Henderson : : : "memory"); 116b86c6ba6SRichard Henderson info |= got_sigill ? 0 : CPUINFO_ZBB; 117b86c6ba6SRichard Henderson left &= ~CPUINFO_ZBB; 118b86c6ba6SRichard Henderson } 119b86c6ba6SRichard Henderson 120b86c6ba6SRichard Henderson if (left & CPUINFO_ZICOND) { 121b86c6ba6SRichard Henderson /* Probe for Zicond: czero.eqz zero,zero,zero. */ 122b86c6ba6SRichard Henderson got_sigill = 0; 123b86c6ba6SRichard Henderson asm volatile(".insn r 0x33, 5, 0x07, zero, zero, zero" 124b86c6ba6SRichard Henderson : : : "memory"); 125b86c6ba6SRichard Henderson info |= got_sigill ? 0 : CPUINFO_ZICOND; 126b86c6ba6SRichard Henderson left &= ~CPUINFO_ZICOND; 127b86c6ba6SRichard Henderson } 128b86c6ba6SRichard Henderson 129b86c6ba6SRichard Henderson sigaction(SIGILL, &sa_old, NULL); 130b86c6ba6SRichard Henderson assert(left == 0); 131b86c6ba6SRichard Henderson } 132b86c6ba6SRichard Henderson 133*f7230e09STANG Tiancheng if (info & CPUINFO_ZVE64X) { 134*f7230e09STANG Tiancheng /* 135*f7230e09STANG Tiancheng * We are guaranteed by RVV-1.0 that VLEN is a power of 2. 136*f7230e09STANG Tiancheng * We are guaranteed by Zve64x that VLEN >= 64, and that 137*f7230e09STANG Tiancheng * EEW of {8,16,32,64} are supported. 138*f7230e09STANG Tiancheng */ 139*f7230e09STANG Tiancheng unsigned long vlenb; 140*f7230e09STANG Tiancheng /* csrr %0, vlenb */ 141*f7230e09STANG Tiancheng asm volatile(".insn i 0x73, 0x2, %0, zero, -990" : "=r"(vlenb)); 142*f7230e09STANG Tiancheng assert(vlenb >= 8); 143*f7230e09STANG Tiancheng assert(is_power_of_2(vlenb)); 144*f7230e09STANG Tiancheng /* Cache VLEN in a convenient form. */ 145*f7230e09STANG Tiancheng riscv_lg2_vlenb = ctz32(vlenb); 146*f7230e09STANG Tiancheng } 147*f7230e09STANG Tiancheng 148b86c6ba6SRichard Henderson info |= CPUINFO_ALWAYS; 149b86c6ba6SRichard Henderson cpuinfo = info; 150b86c6ba6SRichard Henderson return info; 151b86c6ba6SRichard Henderson } 152