2 * SPDX-License-Identifier: GPL-2.0-or-later
3 * Host specific cpu identification for RISC-V.
6 #include "qemu/osdep.h"
7 #include "host/cpuinfo.h"
9 #ifdef CONFIG_ASM_HWPROBE_H
10 #include <asm/hwprobe.h>
11 #include <sys/syscall.h>
15 static volatile sig_atomic_t got_sigill
;
17 static void sigill_handler(int signo
, siginfo_t
*si
, void *data
)
19 /* Skip the faulty instruction */
20 ucontext_t
*uc
= (ucontext_t
*)data
;
23 uc
->uc_mcontext
.__gregs
[REG_PC
] += 4;
24 #elif defined(__OpenBSD__)
27 # error Unsupported OS
33 /* Called both as constructor and (possibly) via other constructors. */
34 unsigned __attribute__((constructor
)) cpuinfo_init(void)
36 unsigned left
= CPUINFO_ZBA
| CPUINFO_ZBB
| CPUINFO_ZICOND
;
37 unsigned info
= cpuinfo
;
43 /* Test for compile-time settings. */
44 #if defined(__riscv_arch_test) && defined(__riscv_zba)
47 #if defined(__riscv_arch_test) && defined(__riscv_zbb)
50 #if defined(__riscv_arch_test) && defined(__riscv_zicond)
51 info
|= CPUINFO_ZICOND
;
55 #ifdef CONFIG_ASM_HWPROBE_H
58 * TODO: glibc 2.40 will introduce <sys/hwprobe.h>, which
59 * provides __riscv_hwprobe and __riscv_hwprobe_one,
60 * which is a slightly cleaner interface.
62 struct riscv_hwprobe pair
= { .key
= RISCV_HWPROBE_KEY_IMA_EXT_0
};
63 if (syscall(__NR_riscv_hwprobe
, &pair
, 1, 0, NULL
, 0) == 0
65 info
|= pair
.value
& RISCV_HWPROBE_EXT_ZBA
? CPUINFO_ZBA
: 0;
66 info
|= pair
.value
& RISCV_HWPROBE_EXT_ZBB
? CPUINFO_ZBB
: 0;
67 left
&= ~(CPUINFO_ZBA
| CPUINFO_ZBB
);
68 #ifdef RISCV_HWPROBE_EXT_ZICOND
69 info
|= pair
.value
& RISCV_HWPROBE_EXT_ZICOND
? CPUINFO_ZICOND
: 0;
70 left
&= ~CPUINFO_ZICOND
;
74 #endif /* CONFIG_ASM_HWPROBE_H */
77 struct sigaction sa_old
, sa_new
;
79 memset(&sa_new
, 0, sizeof(sa_new
));
80 sa_new
.sa_flags
= SA_SIGINFO
;
81 sa_new
.sa_sigaction
= sigill_handler
;
82 sigaction(SIGILL
, &sa_new
, &sa_old
);
84 if (left
& CPUINFO_ZBA
) {
85 /* Probe for Zba: add.uw zero,zero,zero. */
87 asm volatile(".insn r 0x3b, 0, 0x04, zero, zero, zero"
89 info
|= got_sigill
? 0 : CPUINFO_ZBA
;
93 if (left
& CPUINFO_ZBB
) {
94 /* Probe for Zbb: andn zero,zero,zero. */
96 asm volatile(".insn r 0x33, 7, 0x20, zero, zero, zero"
98 info
|= got_sigill
? 0 : CPUINFO_ZBB
;
102 if (left
& CPUINFO_ZICOND
) {
103 /* Probe for Zicond: czero.eqz zero,zero,zero. */
105 asm volatile(".insn r 0x33, 5, 0x07, zero, zero, zero"
107 info
|= got_sigill
? 0 : CPUINFO_ZICOND
;
108 left
&= ~CPUINFO_ZICOND
;
111 sigaction(SIGILL
, &sa_old
, NULL
);
115 info
|= CPUINFO_ALWAYS
;