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