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" 7b86c6ba6SRichard Henderson #include "host/cpuinfo.h" 8b86c6ba6SRichard Henderson 9e5717308SRichard Henderson #ifdef CONFIG_ASM_HWPROBE_H 10e5717308SRichard Henderson #include <asm/hwprobe.h> 11e5717308SRichard Henderson #include <sys/syscall.h> 12*c5757f80SMilan P. Stanić #include <asm/unistd.h> 13e5717308SRichard Henderson #endif 14e5717308SRichard Henderson 15b86c6ba6SRichard Henderson unsigned cpuinfo; 16b86c6ba6SRichard Henderson static volatile sig_atomic_t got_sigill; 17b86c6ba6SRichard Henderson 18b86c6ba6SRichard Henderson static void sigill_handler(int signo, siginfo_t *si, void *data) 19b86c6ba6SRichard Henderson { 20b86c6ba6SRichard Henderson /* Skip the faulty instruction */ 21b86c6ba6SRichard Henderson ucontext_t *uc = (ucontext_t *)data; 22adc02842SRichard Henderson 23adc02842SRichard Henderson #ifdef __linux__ 24b86c6ba6SRichard Henderson uc->uc_mcontext.__gregs[REG_PC] += 4; 25adc02842SRichard Henderson #elif defined(__OpenBSD__) 26adc02842SRichard Henderson uc->sc_sepc += 4; 27adc02842SRichard Henderson #else 28adc02842SRichard Henderson # error Unsupported OS 29adc02842SRichard Henderson #endif 30b86c6ba6SRichard Henderson 31b86c6ba6SRichard Henderson got_sigill = 1; 32b86c6ba6SRichard Henderson } 33b86c6ba6SRichard Henderson 34b86c6ba6SRichard Henderson /* Called both as constructor and (possibly) via other constructors. */ 35b86c6ba6SRichard Henderson unsigned __attribute__((constructor)) cpuinfo_init(void) 36b86c6ba6SRichard Henderson { 37b86c6ba6SRichard Henderson unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZICOND; 38b86c6ba6SRichard Henderson unsigned info = cpuinfo; 39b86c6ba6SRichard Henderson 40b86c6ba6SRichard Henderson if (info) { 41b86c6ba6SRichard Henderson return info; 42b86c6ba6SRichard Henderson } 43b86c6ba6SRichard Henderson 44b86c6ba6SRichard Henderson /* Test for compile-time settings. */ 45b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zba) 46b86c6ba6SRichard Henderson info |= CPUINFO_ZBA; 47b86c6ba6SRichard Henderson #endif 48b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zbb) 49b86c6ba6SRichard Henderson info |= CPUINFO_ZBB; 50b86c6ba6SRichard Henderson #endif 51b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zicond) 52b86c6ba6SRichard Henderson info |= CPUINFO_ZICOND; 53b86c6ba6SRichard Henderson #endif 54b86c6ba6SRichard Henderson left &= ~info; 55b86c6ba6SRichard Henderson 56e5717308SRichard Henderson #ifdef CONFIG_ASM_HWPROBE_H 57e5717308SRichard Henderson if (left) { 58e5717308SRichard Henderson /* 59e5717308SRichard Henderson * TODO: glibc 2.40 will introduce <sys/hwprobe.h>, which 60e5717308SRichard Henderson * provides __riscv_hwprobe and __riscv_hwprobe_one, 61e5717308SRichard Henderson * which is a slightly cleaner interface. 62e5717308SRichard Henderson */ 63e5717308SRichard Henderson struct riscv_hwprobe pair = { .key = RISCV_HWPROBE_KEY_IMA_EXT_0 }; 64e5717308SRichard Henderson if (syscall(__NR_riscv_hwprobe, &pair, 1, 0, NULL, 0) == 0 65e5717308SRichard Henderson && pair.key >= 0) { 66e5717308SRichard Henderson info |= pair.value & RISCV_HWPROBE_EXT_ZBA ? CPUINFO_ZBA : 0; 67e5717308SRichard Henderson info |= pair.value & RISCV_HWPROBE_EXT_ZBB ? CPUINFO_ZBB : 0; 68e5717308SRichard Henderson left &= ~(CPUINFO_ZBA | CPUINFO_ZBB); 69e5717308SRichard Henderson #ifdef RISCV_HWPROBE_EXT_ZICOND 70e5717308SRichard Henderson info |= pair.value & RISCV_HWPROBE_EXT_ZICOND ? CPUINFO_ZICOND : 0; 71e5717308SRichard Henderson left &= ~CPUINFO_ZICOND; 72e5717308SRichard Henderson #endif 73e5717308SRichard Henderson } 74e5717308SRichard Henderson } 75e5717308SRichard Henderson #endif /* CONFIG_ASM_HWPROBE_H */ 76e5717308SRichard Henderson 77b86c6ba6SRichard Henderson if (left) { 78b86c6ba6SRichard Henderson struct sigaction sa_old, sa_new; 79b86c6ba6SRichard Henderson 80b86c6ba6SRichard Henderson memset(&sa_new, 0, sizeof(sa_new)); 81b86c6ba6SRichard Henderson sa_new.sa_flags = SA_SIGINFO; 82b86c6ba6SRichard Henderson sa_new.sa_sigaction = sigill_handler; 83b86c6ba6SRichard Henderson sigaction(SIGILL, &sa_new, &sa_old); 84b86c6ba6SRichard Henderson 85b86c6ba6SRichard Henderson if (left & CPUINFO_ZBA) { 86b86c6ba6SRichard Henderson /* Probe for Zba: add.uw zero,zero,zero. */ 87b86c6ba6SRichard Henderson got_sigill = 0; 88b86c6ba6SRichard Henderson asm volatile(".insn r 0x3b, 0, 0x04, zero, zero, zero" 89b86c6ba6SRichard Henderson : : : "memory"); 90b86c6ba6SRichard Henderson info |= got_sigill ? 0 : CPUINFO_ZBA; 91b86c6ba6SRichard Henderson left &= ~CPUINFO_ZBA; 92b86c6ba6SRichard Henderson } 93b86c6ba6SRichard Henderson 94b86c6ba6SRichard Henderson if (left & CPUINFO_ZBB) { 95b86c6ba6SRichard Henderson /* Probe for Zbb: andn zero,zero,zero. */ 96b86c6ba6SRichard Henderson got_sigill = 0; 97b86c6ba6SRichard Henderson asm volatile(".insn r 0x33, 7, 0x20, zero, zero, zero" 98b86c6ba6SRichard Henderson : : : "memory"); 99b86c6ba6SRichard Henderson info |= got_sigill ? 0 : CPUINFO_ZBB; 100b86c6ba6SRichard Henderson left &= ~CPUINFO_ZBB; 101b86c6ba6SRichard Henderson } 102b86c6ba6SRichard Henderson 103b86c6ba6SRichard Henderson if (left & CPUINFO_ZICOND) { 104b86c6ba6SRichard Henderson /* Probe for Zicond: czero.eqz zero,zero,zero. */ 105b86c6ba6SRichard Henderson got_sigill = 0; 106b86c6ba6SRichard Henderson asm volatile(".insn r 0x33, 5, 0x07, zero, zero, zero" 107b86c6ba6SRichard Henderson : : : "memory"); 108b86c6ba6SRichard Henderson info |= got_sigill ? 0 : CPUINFO_ZICOND; 109b86c6ba6SRichard Henderson left &= ~CPUINFO_ZICOND; 110b86c6ba6SRichard Henderson } 111b86c6ba6SRichard Henderson 112b86c6ba6SRichard Henderson sigaction(SIGILL, &sa_old, NULL); 113b86c6ba6SRichard Henderson assert(left == 0); 114b86c6ba6SRichard Henderson } 115b86c6ba6SRichard Henderson 116b86c6ba6SRichard Henderson info |= CPUINFO_ALWAYS; 117b86c6ba6SRichard Henderson cpuinfo = info; 118b86c6ba6SRichard Henderson return info; 119b86c6ba6SRichard Henderson } 120