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