xref: /openbmc/qemu/util/cpuinfo-riscv.c (revision b86c6ba689662256ea32f3e27927524ccb13f81d)
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