1 /* 2 * SPDX-License-Identifier: GPL-2.0-or-later 3 * Host specific cpu identification for RISC-V. 4 */ 5 6 #include "qemu/osdep.h" 7 #include "host/cpuinfo.h" 8 9 unsigned cpuinfo; 10 static volatile sig_atomic_t got_sigill; 11 12 static void sigill_handler(int signo, siginfo_t *si, void *data) 13 { 14 /* Skip the faulty instruction */ 15 ucontext_t *uc = (ucontext_t *)data; 16 uc->uc_mcontext.__gregs[REG_PC] += 4; 17 18 got_sigill = 1; 19 } 20 21 /* Called both as constructor and (possibly) via other constructors. */ 22 unsigned __attribute__((constructor)) cpuinfo_init(void) 23 { 24 unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZICOND; 25 unsigned info = cpuinfo; 26 27 if (info) { 28 return info; 29 } 30 31 /* Test for compile-time settings. */ 32 #if defined(__riscv_arch_test) && defined(__riscv_zba) 33 info |= CPUINFO_ZBA; 34 #endif 35 #if defined(__riscv_arch_test) && defined(__riscv_zbb) 36 info |= CPUINFO_ZBB; 37 #endif 38 #if defined(__riscv_arch_test) && defined(__riscv_zicond) 39 info |= CPUINFO_ZICOND; 40 #endif 41 left &= ~info; 42 43 if (left) { 44 struct sigaction sa_old, sa_new; 45 46 memset(&sa_new, 0, sizeof(sa_new)); 47 sa_new.sa_flags = SA_SIGINFO; 48 sa_new.sa_sigaction = sigill_handler; 49 sigaction(SIGILL, &sa_new, &sa_old); 50 51 if (left & CPUINFO_ZBA) { 52 /* Probe for Zba: add.uw zero,zero,zero. */ 53 got_sigill = 0; 54 asm volatile(".insn r 0x3b, 0, 0x04, zero, zero, zero" 55 : : : "memory"); 56 info |= got_sigill ? 0 : CPUINFO_ZBA; 57 left &= ~CPUINFO_ZBA; 58 } 59 60 if (left & CPUINFO_ZBB) { 61 /* Probe for Zbb: andn zero,zero,zero. */ 62 got_sigill = 0; 63 asm volatile(".insn r 0x33, 7, 0x20, zero, zero, zero" 64 : : : "memory"); 65 info |= got_sigill ? 0 : CPUINFO_ZBB; 66 left &= ~CPUINFO_ZBB; 67 } 68 69 if (left & CPUINFO_ZICOND) { 70 /* Probe for Zicond: czero.eqz zero,zero,zero. */ 71 got_sigill = 0; 72 asm volatile(".insn r 0x33, 5, 0x07, zero, zero, zero" 73 : : : "memory"); 74 info |= got_sigill ? 0 : CPUINFO_ZICOND; 75 left &= ~CPUINFO_ZICOND; 76 } 77 78 sigaction(SIGILL, &sa_old, NULL); 79 assert(left == 0); 80 } 81 82 info |= CPUINFO_ALWAYS; 83 cpuinfo = info; 84 return info; 85 } 86