xref: /openbmc/qemu/util/cpuinfo-riscv.c (revision 6b3756503b00d42f1f506815b44ce83aa23ee322)
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"
7*f7230e09STANG Tiancheng #include "qemu/host-utils.h"
8b86c6ba6SRichard Henderson #include "host/cpuinfo.h"
9b86c6ba6SRichard Henderson 
10e5717308SRichard Henderson #ifdef CONFIG_ASM_HWPROBE_H
11e5717308SRichard Henderson #include <asm/hwprobe.h>
12e5717308SRichard Henderson #include <sys/syscall.h>
13c5757f80SMilan P. Stanić #include <asm/unistd.h>
14e5717308SRichard Henderson #endif
15e5717308SRichard Henderson 
16b86c6ba6SRichard Henderson unsigned cpuinfo;
17*f7230e09STANG Tiancheng unsigned riscv_lg2_vlenb;
18b86c6ba6SRichard Henderson static volatile sig_atomic_t got_sigill;
19b86c6ba6SRichard Henderson 
sigill_handler(int signo,siginfo_t * si,void * data)20b86c6ba6SRichard Henderson static void sigill_handler(int signo, siginfo_t *si, void *data)
21b86c6ba6SRichard Henderson {
22b86c6ba6SRichard Henderson     /* Skip the faulty instruction */
23b86c6ba6SRichard Henderson     ucontext_t *uc = (ucontext_t *)data;
24adc02842SRichard Henderson 
25adc02842SRichard Henderson #ifdef __linux__
26b86c6ba6SRichard Henderson     uc->uc_mcontext.__gregs[REG_PC] += 4;
27adc02842SRichard Henderson #elif defined(__OpenBSD__)
28adc02842SRichard Henderson     uc->sc_sepc += 4;
29adc02842SRichard Henderson #else
30adc02842SRichard Henderson # error Unsupported OS
31adc02842SRichard Henderson #endif
32b86c6ba6SRichard Henderson 
33b86c6ba6SRichard Henderson     got_sigill = 1;
34b86c6ba6SRichard Henderson }
35b86c6ba6SRichard Henderson 
36b86c6ba6SRichard Henderson /* Called both as constructor and (possibly) via other constructors. */
cpuinfo_init(void)37b86c6ba6SRichard Henderson unsigned __attribute__((constructor)) cpuinfo_init(void)
38b86c6ba6SRichard Henderson {
39*f7230e09STANG Tiancheng     unsigned left = CPUINFO_ZBA | CPUINFO_ZBB | CPUINFO_ZICOND | CPUINFO_ZVE64X;
40b86c6ba6SRichard Henderson     unsigned info = cpuinfo;
41b86c6ba6SRichard Henderson 
42b86c6ba6SRichard Henderson     if (info) {
43b86c6ba6SRichard Henderson         return info;
44b86c6ba6SRichard Henderson     }
45b86c6ba6SRichard Henderson 
46b86c6ba6SRichard Henderson     /* Test for compile-time settings. */
47b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zba)
48b86c6ba6SRichard Henderson     info |= CPUINFO_ZBA;
49b86c6ba6SRichard Henderson #endif
50b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zbb)
51b86c6ba6SRichard Henderson     info |= CPUINFO_ZBB;
52b86c6ba6SRichard Henderson #endif
53b86c6ba6SRichard Henderson #if defined(__riscv_arch_test) && defined(__riscv_zicond)
54b86c6ba6SRichard Henderson     info |= CPUINFO_ZICOND;
55b86c6ba6SRichard Henderson #endif
56*f7230e09STANG Tiancheng #if defined(__riscv_arch_test) && \
57*f7230e09STANG Tiancheng     (defined(__riscv_vector) || defined(__riscv_zve64x))
58*f7230e09STANG Tiancheng     info |= CPUINFO_ZVE64X;
59*f7230e09STANG Tiancheng #endif
60b86c6ba6SRichard Henderson     left &= ~info;
61b86c6ba6SRichard Henderson 
62e5717308SRichard Henderson #ifdef CONFIG_ASM_HWPROBE_H
63e5717308SRichard Henderson     if (left) {
64e5717308SRichard Henderson         /*
65e5717308SRichard Henderson          * TODO: glibc 2.40 will introduce <sys/hwprobe.h>, which
66e5717308SRichard Henderson          * provides __riscv_hwprobe and __riscv_hwprobe_one,
67e5717308SRichard Henderson          * which is a slightly cleaner interface.
68e5717308SRichard Henderson          */
69e5717308SRichard Henderson         struct riscv_hwprobe pair = { .key = RISCV_HWPROBE_KEY_IMA_EXT_0 };
70e5717308SRichard Henderson         if (syscall(__NR_riscv_hwprobe, &pair, 1, 0, NULL, 0) == 0
71e5717308SRichard Henderson             && pair.key >= 0) {
72e5717308SRichard Henderson             info |= pair.value & RISCV_HWPROBE_EXT_ZBA ? CPUINFO_ZBA : 0;
73e5717308SRichard Henderson             info |= pair.value & RISCV_HWPROBE_EXT_ZBB ? CPUINFO_ZBB : 0;
74e5717308SRichard Henderson             left &= ~(CPUINFO_ZBA | CPUINFO_ZBB);
75e5717308SRichard Henderson #ifdef RISCV_HWPROBE_EXT_ZICOND
76e5717308SRichard Henderson             info |= pair.value & RISCV_HWPROBE_EXT_ZICOND ? CPUINFO_ZICOND : 0;
77e5717308SRichard Henderson             left &= ~CPUINFO_ZICOND;
78e5717308SRichard Henderson #endif
79*f7230e09STANG Tiancheng             /* For rv64, V is Zve64d, a superset of Zve64x. */
80*f7230e09STANG Tiancheng             info |= pair.value & RISCV_HWPROBE_IMA_V ? CPUINFO_ZVE64X : 0;
81*f7230e09STANG Tiancheng #ifdef RISCV_HWPROBE_EXT_ZVE64X
82*f7230e09STANG Tiancheng             info |= pair.value & RISCV_HWPROBE_EXT_ZVE64X ? CPUINFO_ZVE64X : 0;
83*f7230e09STANG Tiancheng #endif
84e5717308SRichard Henderson         }
85e5717308SRichard Henderson     }
86e5717308SRichard Henderson #endif /* CONFIG_ASM_HWPROBE_H */
87e5717308SRichard Henderson 
88*f7230e09STANG Tiancheng     /*
89*f7230e09STANG Tiancheng      * We only detect support for vectors with hwprobe.  All kernels with
90*f7230e09STANG Tiancheng      * support for vectors in userspace also support the hwprobe syscall.
91*f7230e09STANG Tiancheng      */
92*f7230e09STANG Tiancheng     left &= ~CPUINFO_ZVE64X;
93*f7230e09STANG Tiancheng 
94b86c6ba6SRichard Henderson     if (left) {
95b86c6ba6SRichard Henderson         struct sigaction sa_old, sa_new;
96b86c6ba6SRichard Henderson 
97b86c6ba6SRichard Henderson         memset(&sa_new, 0, sizeof(sa_new));
98b86c6ba6SRichard Henderson         sa_new.sa_flags = SA_SIGINFO;
99b86c6ba6SRichard Henderson         sa_new.sa_sigaction = sigill_handler;
100b86c6ba6SRichard Henderson         sigaction(SIGILL, &sa_new, &sa_old);
101b86c6ba6SRichard Henderson 
102b86c6ba6SRichard Henderson         if (left & CPUINFO_ZBA) {
103b86c6ba6SRichard Henderson             /* Probe for Zba: add.uw zero,zero,zero. */
104b86c6ba6SRichard Henderson             got_sigill = 0;
105b86c6ba6SRichard Henderson             asm volatile(".insn r 0x3b, 0, 0x04, zero, zero, zero"
106b86c6ba6SRichard Henderson                          : : : "memory");
107b86c6ba6SRichard Henderson             info |= got_sigill ? 0 : CPUINFO_ZBA;
108b86c6ba6SRichard Henderson             left &= ~CPUINFO_ZBA;
109b86c6ba6SRichard Henderson         }
110b86c6ba6SRichard Henderson 
111b86c6ba6SRichard Henderson         if (left & CPUINFO_ZBB) {
112b86c6ba6SRichard Henderson             /* Probe for Zbb: andn zero,zero,zero. */
113b86c6ba6SRichard Henderson             got_sigill = 0;
114b86c6ba6SRichard Henderson             asm volatile(".insn r 0x33, 7, 0x20, zero, zero, zero"
115b86c6ba6SRichard Henderson                          : : : "memory");
116b86c6ba6SRichard Henderson             info |= got_sigill ? 0 : CPUINFO_ZBB;
117b86c6ba6SRichard Henderson             left &= ~CPUINFO_ZBB;
118b86c6ba6SRichard Henderson         }
119b86c6ba6SRichard Henderson 
120b86c6ba6SRichard Henderson         if (left & CPUINFO_ZICOND) {
121b86c6ba6SRichard Henderson             /* Probe for Zicond: czero.eqz zero,zero,zero. */
122b86c6ba6SRichard Henderson             got_sigill = 0;
123b86c6ba6SRichard Henderson             asm volatile(".insn r 0x33, 5, 0x07, zero, zero, zero"
124b86c6ba6SRichard Henderson                          : : : "memory");
125b86c6ba6SRichard Henderson             info |= got_sigill ? 0 : CPUINFO_ZICOND;
126b86c6ba6SRichard Henderson             left &= ~CPUINFO_ZICOND;
127b86c6ba6SRichard Henderson         }
128b86c6ba6SRichard Henderson 
129b86c6ba6SRichard Henderson         sigaction(SIGILL, &sa_old, NULL);
130b86c6ba6SRichard Henderson         assert(left == 0);
131b86c6ba6SRichard Henderson     }
132b86c6ba6SRichard Henderson 
133*f7230e09STANG Tiancheng     if (info & CPUINFO_ZVE64X) {
134*f7230e09STANG Tiancheng         /*
135*f7230e09STANG Tiancheng          * We are guaranteed by RVV-1.0 that VLEN is a power of 2.
136*f7230e09STANG Tiancheng          * We are guaranteed by Zve64x that VLEN >= 64, and that
137*f7230e09STANG Tiancheng          * EEW of {8,16,32,64} are supported.
138*f7230e09STANG Tiancheng          */
139*f7230e09STANG Tiancheng         unsigned long vlenb;
140*f7230e09STANG Tiancheng         /* csrr %0, vlenb */
141*f7230e09STANG Tiancheng         asm volatile(".insn i 0x73, 0x2, %0, zero, -990" : "=r"(vlenb));
142*f7230e09STANG Tiancheng         assert(vlenb >= 8);
143*f7230e09STANG Tiancheng         assert(is_power_of_2(vlenb));
144*f7230e09STANG Tiancheng         /* Cache VLEN in a convenient form. */
145*f7230e09STANG Tiancheng         riscv_lg2_vlenb = ctz32(vlenb);
146*f7230e09STANG Tiancheng     }
147*f7230e09STANG Tiancheng 
148b86c6ba6SRichard Henderson     info |= CPUINFO_ALWAYS;
149b86c6ba6SRichard Henderson     cpuinfo = info;
150b86c6ba6SRichard Henderson     return info;
151b86c6ba6SRichard Henderson }
152