xref: /openbmc/qemu/util/cpuinfo-riscv.c (revision adc028428a6da5ea8d6a688085966a33be4c97c7)
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 
9b86c6ba6SRichard Henderson unsigned cpuinfo;
10b86c6ba6SRichard Henderson static volatile sig_atomic_t got_sigill;
11b86c6ba6SRichard Henderson 
12b86c6ba6SRichard Henderson static void sigill_handler(int signo, siginfo_t *si, void *data)
13b86c6ba6SRichard Henderson {
14b86c6ba6SRichard Henderson     /* Skip the faulty instruction */
15b86c6ba6SRichard Henderson     ucontext_t *uc = (ucontext_t *)data;
16*adc02842SRichard Henderson 
17*adc02842SRichard Henderson #ifdef __linux__
18b86c6ba6SRichard Henderson     uc->uc_mcontext.__gregs[REG_PC] += 4;
19*adc02842SRichard Henderson #elif defined(__OpenBSD__)
20*adc02842SRichard Henderson     uc->sc_sepc += 4;
21*adc02842SRichard Henderson #else
22*adc02842SRichard Henderson # error Unsupported OS
23*adc02842SRichard Henderson #endif
24b86c6ba6SRichard Henderson 
25b86c6ba6SRichard Henderson     got_sigill = 1;
26b86c6ba6SRichard Henderson }
27b86c6ba6SRichard Henderson 
28b86c6ba6SRichard Henderson /* Called both as constructor and (possibly) via other constructors. */
29b86c6ba6SRichard Henderson unsigned __attribute__((constructor)) cpuinfo_init(void)
30b86c6ba6SRichard Henderson {
31b86c6ba6SRichard Henderson     unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZICOND;
32b86c6ba6SRichard Henderson     unsigned info = cpuinfo;
33b86c6ba6SRichard Henderson 
34b86c6ba6SRichard Henderson     if (info) {
35b86c6ba6SRichard Henderson         return info;
36b86c6ba6SRichard Henderson     }
37b86c6ba6SRichard Henderson 
38b86c6ba6SRichard Henderson     /* Test for compile-time settings. */
39b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zba)
40b86c6ba6SRichard Henderson     info |= CPUINFO_ZBA;
41b86c6ba6SRichard Henderson #endif
42b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zbb)
43b86c6ba6SRichard Henderson     info |= CPUINFO_ZBB;
44b86c6ba6SRichard Henderson #endif
45b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zicond)
46b86c6ba6SRichard Henderson     info |= CPUINFO_ZICOND;
47b86c6ba6SRichard Henderson #endif
48b86c6ba6SRichard Henderson     left &= ~info;
49b86c6ba6SRichard Henderson 
50b86c6ba6SRichard Henderson     if (left) {
51b86c6ba6SRichard Henderson         struct sigaction sa_old, sa_new;
52b86c6ba6SRichard Henderson 
53b86c6ba6SRichard Henderson         memset(&sa_new, 0, sizeof(sa_new));
54b86c6ba6SRichard Henderson         sa_new.sa_flags = SA_SIGINFO;
55b86c6ba6SRichard Henderson         sa_new.sa_sigaction = sigill_handler;
56b86c6ba6SRichard Henderson         sigaction(SIGILL, &sa_new, &sa_old);
57b86c6ba6SRichard Henderson 
58b86c6ba6SRichard Henderson         if (left & CPUINFO_ZBA) {
59b86c6ba6SRichard Henderson             /* Probe for Zba: add.uw zero,zero,zero. */
60b86c6ba6SRichard Henderson             got_sigill = 0;
61b86c6ba6SRichard Henderson             asm volatile(".insn r 0x3b, 0, 0x04, zero, zero, zero"
62b86c6ba6SRichard Henderson                          : : : "memory");
63b86c6ba6SRichard Henderson             info |= got_sigill ? 0 : CPUINFO_ZBA;
64b86c6ba6SRichard Henderson             left &= ~CPUINFO_ZBA;
65b86c6ba6SRichard Henderson         }
66b86c6ba6SRichard Henderson 
67b86c6ba6SRichard Henderson         if (left & CPUINFO_ZBB) {
68b86c6ba6SRichard Henderson             /* Probe for Zbb: andn zero,zero,zero. */
69b86c6ba6SRichard Henderson             got_sigill = 0;
70b86c6ba6SRichard Henderson             asm volatile(".insn r 0x33, 7, 0x20, zero, zero, zero"
71b86c6ba6SRichard Henderson                          : : : "memory");
72b86c6ba6SRichard Henderson             info |= got_sigill ? 0 : CPUINFO_ZBB;
73b86c6ba6SRichard Henderson             left &= ~CPUINFO_ZBB;
74b86c6ba6SRichard Henderson         }
75b86c6ba6SRichard Henderson 
76b86c6ba6SRichard Henderson         if (left & CPUINFO_ZICOND) {
77b86c6ba6SRichard Henderson             /* Probe for Zicond: czero.eqz zero,zero,zero. */
78b86c6ba6SRichard Henderson             got_sigill = 0;
79b86c6ba6SRichard Henderson             asm volatile(".insn r 0x33, 5, 0x07, zero, zero, zero"
80b86c6ba6SRichard Henderson                          : : : "memory");
81b86c6ba6SRichard Henderson             info |= got_sigill ? 0 : CPUINFO_ZICOND;
82b86c6ba6SRichard Henderson             left &= ~CPUINFO_ZICOND;
83b86c6ba6SRichard Henderson         }
84b86c6ba6SRichard Henderson 
85b86c6ba6SRichard Henderson         sigaction(SIGILL, &sa_old, NULL);
86b86c6ba6SRichard Henderson         assert(left == 0);
87b86c6ba6SRichard Henderson     }
88b86c6ba6SRichard Henderson 
89b86c6ba6SRichard Henderson     info |= CPUINFO_ALWAYS;
90b86c6ba6SRichard Henderson     cpuinfo = info;
91b86c6ba6SRichard Henderson     return info;
92b86c6ba6SRichard Henderson }
93