xref: /openbmc/qemu/util/cpuinfo-riscv.c (revision c5757f808bd74db7ef1a90ee28334f3b5afb8179)
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 
9e5717308SRichard Henderson #ifdef CONFIG_ASM_HWPROBE_H
10e5717308SRichard Henderson #include <asm/hwprobe.h>
11e5717308SRichard Henderson #include <sys/syscall.h>
12*c5757f80SMilan P. Stanić #include <asm/unistd.h>
13e5717308SRichard Henderson #endif
14e5717308SRichard Henderson 
15b86c6ba6SRichard Henderson unsigned cpuinfo;
16b86c6ba6SRichard Henderson static volatile sig_atomic_t got_sigill;
17b86c6ba6SRichard Henderson 
18b86c6ba6SRichard Henderson static void sigill_handler(int signo, siginfo_t *si, void *data)
19b86c6ba6SRichard Henderson {
20b86c6ba6SRichard Henderson     /* Skip the faulty instruction */
21b86c6ba6SRichard Henderson     ucontext_t *uc = (ucontext_t *)data;
22adc02842SRichard Henderson 
23adc02842SRichard Henderson #ifdef __linux__
24b86c6ba6SRichard Henderson     uc->uc_mcontext.__gregs[REG_PC] += 4;
25adc02842SRichard Henderson #elif defined(__OpenBSD__)
26adc02842SRichard Henderson     uc->sc_sepc += 4;
27adc02842SRichard Henderson #else
28adc02842SRichard Henderson # error Unsupported OS
29adc02842SRichard Henderson #endif
30b86c6ba6SRichard Henderson 
31b86c6ba6SRichard Henderson     got_sigill = 1;
32b86c6ba6SRichard Henderson }
33b86c6ba6SRichard Henderson 
34b86c6ba6SRichard Henderson /* Called both as constructor and (possibly) via other constructors. */
35b86c6ba6SRichard Henderson unsigned __attribute__((constructor)) cpuinfo_init(void)
36b86c6ba6SRichard Henderson {
37b86c6ba6SRichard Henderson     unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZICOND;
38b86c6ba6SRichard Henderson     unsigned info = cpuinfo;
39b86c6ba6SRichard Henderson 
40b86c6ba6SRichard Henderson     if (info) {
41b86c6ba6SRichard Henderson         return info;
42b86c6ba6SRichard Henderson     }
43b86c6ba6SRichard Henderson 
44b86c6ba6SRichard Henderson     /* Test for compile-time settings. */
45b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zba)
46b86c6ba6SRichard Henderson     info |= CPUINFO_ZBA;
47b86c6ba6SRichard Henderson #endif
48b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zbb)
49b86c6ba6SRichard Henderson     info |= CPUINFO_ZBB;
50b86c6ba6SRichard Henderson #endif
51b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zicond)
52b86c6ba6SRichard Henderson     info |= CPUINFO_ZICOND;
53b86c6ba6SRichard Henderson #endif
54b86c6ba6SRichard Henderson     left &= ~info;
55b86c6ba6SRichard Henderson 
56e5717308SRichard Henderson #ifdef CONFIG_ASM_HWPROBE_H
57e5717308SRichard Henderson     if (left) {
58e5717308SRichard Henderson         /*
59e5717308SRichard Henderson          * TODO: glibc 2.40 will introduce <sys/hwprobe.h>, which
60e5717308SRichard Henderson          * provides __riscv_hwprobe and __riscv_hwprobe_one,
61e5717308SRichard Henderson          * which is a slightly cleaner interface.
62e5717308SRichard Henderson          */
63e5717308SRichard Henderson         struct riscv_hwprobe pair = { .key = RISCV_HWPROBE_KEY_IMA_EXT_0 };
64e5717308SRichard Henderson         if (syscall(__NR_riscv_hwprobe, &pair, 1, 0, NULL, 0) == 0
65e5717308SRichard Henderson             && pair.key >= 0) {
66e5717308SRichard Henderson             info |= pair.value & RISCV_HWPROBE_EXT_ZBA ? CPUINFO_ZBA : 0;
67e5717308SRichard Henderson             info |= pair.value & RISCV_HWPROBE_EXT_ZBB ? CPUINFO_ZBB : 0;
68e5717308SRichard Henderson             left &= ~(CPUINFO_ZBA | CPUINFO_ZBB);
69e5717308SRichard Henderson #ifdef RISCV_HWPROBE_EXT_ZICOND
70e5717308SRichard Henderson             info |= pair.value & RISCV_HWPROBE_EXT_ZICOND ? CPUINFO_ZICOND : 0;
71e5717308SRichard Henderson             left &= ~CPUINFO_ZICOND;
72e5717308SRichard Henderson #endif
73e5717308SRichard Henderson         }
74e5717308SRichard Henderson     }
75e5717308SRichard Henderson #endif /* CONFIG_ASM_HWPROBE_H */
76e5717308SRichard Henderson 
77b86c6ba6SRichard Henderson     if (left) {
78b86c6ba6SRichard Henderson         struct sigaction sa_old, sa_new;
79b86c6ba6SRichard Henderson 
80b86c6ba6SRichard Henderson         memset(&sa_new, 0, sizeof(sa_new));
81b86c6ba6SRichard Henderson         sa_new.sa_flags = SA_SIGINFO;
82b86c6ba6SRichard Henderson         sa_new.sa_sigaction = sigill_handler;
83b86c6ba6SRichard Henderson         sigaction(SIGILL, &sa_new, &sa_old);
84b86c6ba6SRichard Henderson 
85b86c6ba6SRichard Henderson         if (left & CPUINFO_ZBA) {
86b86c6ba6SRichard Henderson             /* Probe for Zba: add.uw zero,zero,zero. */
87b86c6ba6SRichard Henderson             got_sigill = 0;
88b86c6ba6SRichard Henderson             asm volatile(".insn r 0x3b, 0, 0x04, zero, zero, zero"
89b86c6ba6SRichard Henderson                          : : : "memory");
90b86c6ba6SRichard Henderson             info |= got_sigill ? 0 : CPUINFO_ZBA;
91b86c6ba6SRichard Henderson             left &= ~CPUINFO_ZBA;
92b86c6ba6SRichard Henderson         }
93b86c6ba6SRichard Henderson 
94b86c6ba6SRichard Henderson         if (left & CPUINFO_ZBB) {
95b86c6ba6SRichard Henderson             /* Probe for Zbb: andn zero,zero,zero. */
96b86c6ba6SRichard Henderson             got_sigill = 0;
97b86c6ba6SRichard Henderson             asm volatile(".insn r 0x33, 7, 0x20, zero, zero, zero"
98b86c6ba6SRichard Henderson                          : : : "memory");
99b86c6ba6SRichard Henderson             info |= got_sigill ? 0 : CPUINFO_ZBB;
100b86c6ba6SRichard Henderson             left &= ~CPUINFO_ZBB;
101b86c6ba6SRichard Henderson         }
102b86c6ba6SRichard Henderson 
103b86c6ba6SRichard Henderson         if (left & CPUINFO_ZICOND) {
104b86c6ba6SRichard Henderson             /* Probe for Zicond: czero.eqz zero,zero,zero. */
105b86c6ba6SRichard Henderson             got_sigill = 0;
106b86c6ba6SRichard Henderson             asm volatile(".insn r 0x33, 5, 0x07, zero, zero, zero"
107b86c6ba6SRichard Henderson                          : : : "memory");
108b86c6ba6SRichard Henderson             info |= got_sigill ? 0 : CPUINFO_ZICOND;
109b86c6ba6SRichard Henderson             left &= ~CPUINFO_ZICOND;
110b86c6ba6SRichard Henderson         }
111b86c6ba6SRichard Henderson 
112b86c6ba6SRichard Henderson         sigaction(SIGILL, &sa_old, NULL);
113b86c6ba6SRichard Henderson         assert(left == 0);
114b86c6ba6SRichard Henderson     }
115b86c6ba6SRichard Henderson 
116b86c6ba6SRichard Henderson     info |= CPUINFO_ALWAYS;
117b86c6ba6SRichard Henderson     cpuinfo = info;
118b86c6ba6SRichard Henderson     return info;
119b86c6ba6SRichard Henderson }
120