riscv(support,linux): use HWPROBE for ISE detection

Current SIGILL handler appears to have weird issues with libluajit on
some platform. Considering 6.6 kernel is becoming more common, switch
to HWPROBE for better compatibility.
This commit is contained in:
gns 2024-08-21 16:39:26 +08:00 committed by gns
parent 23b5c55e1e
commit bedd0cf1e1
2 changed files with 67 additions and 41 deletions

View File

@ -632,23 +632,26 @@ JIT_PARAMDEF(JIT_PARAMINIT)
#endif
#if LJ_TARGET_RISCV64 && LJ_TARGET_POSIX
#include <setjmp.h>
#include <signal.h>
static sigjmp_buf sigbuf = {0};
static void detect_sigill(int sig)
{
siglongjmp(sigbuf, 1);
}
#if LJ_TARGET_LINUX
#include <unistd.h>
struct riscv_hwprobe hwprobe_requests[] = {
{RISCV_HWPROBE_KEY_IMA_EXT_0}
};
const uint64_t *hwprobe_ext = &hwprobe_requests[0].value;
int hwprobe_ret = 0;
#endif
static int riscv_compressed()
{
#if defined(__riscv_c) || defined(__riscv_compressed)
/* Don't bother checking for RVC -- would crash before getting here. */
return 1;
#elif defined(__GNUC__)
/* c.nop; c.nop; */
__asm__(".4byte 0x00010001");
return 1;
#elif LJ_TARGET_LINUX
return (hwprobe_ret == 0 && ((*hwprobe_ext) & RISCV_HWPROBE_IMA_C)) ? 1 : 0;
#else
return 0;
#endif
@ -659,11 +662,8 @@ static int riscv_zba()
#if defined(__riscv_b) || defined(__riscv_zba)
/* Don't bother checking for Zba -- would crash before getting here. */
return 1;
#elif defined(__GNUC__)
/* Don't bother verifying the result, just check if the instruction exists. */
/* add.uw zero, zero, zero */
__asm__(".4byte 0x0800003b");
return 1;
#elif LJ_TARGET_LINUX
return (hwprobe_ret == 0 && ((*hwprobe_ext) & RISCV_HWPROBE_EXT_ZBA)) ? 1 : 0;
#else
return 0;
#endif
@ -674,11 +674,8 @@ static int riscv_zbb()
#if defined(__riscv_b) || defined(__riscv_zbb)
/* Don't bother checking for Zbb -- would crash before getting here. */
return 1;
#elif defined(__GNUC__)
register int t asm ("a0");
/* addi a0, zero, 255; sext.b a0, a0; */
__asm__("addi a0, zero, 255\n\t.4byte 0x60451513");
return t < 0;
#elif LJ_TARGET_LINUX
return (hwprobe_ret == 0 && ((*hwprobe_ext) & RISCV_HWPROBE_EXT_ZBB)) ? 1 : 0;
#else
return 0;
#endif
@ -689,10 +686,8 @@ static int riscv_zicond()
#if defined(__riscv_zicond)
/* Don't bother checking for Zicond -- would crash before getting here. */
return 1;
#elif defined(__GNUC__)
/* czero.eqz zero, zero, zero; */
__asm__(".4byte 0x0e005033");
return 1;
#elif LJ_TARGET_LINUX
return (hwprobe_ret == 0 && ((*hwprobe_ext) & RISCV_HWPROBE_EXT_ZICOND)) ? 1 : 0;
#else
return 0;
#endif
@ -703,6 +698,8 @@ static int riscv_zfa()
#if defined(__riscv_zfa)
/* Don't bother checking for Zfa -- would crash before getting here. */
return 1;
#elif LJ_TARGET_LINUX
return (hwprobe_ret == 0 && ((*hwprobe_ext) & RISCV_HWPROBE_EXT_ZFA)) ? 1 : 0;
#else
return 0;
#endif
@ -716,23 +713,19 @@ static int riscv_xthead()
&& defined(__riscv_xtheadmac))
/* Don't bother checking for XThead -- would crash before getting here. */
return 1;
#elif defined(__GNUC__)
register int t asm ("a0");
/* C906 & C910 & C908 all have "xtheadc", XTheadBb subset "xtheadc". */
/* Therefore assume XThead* are present if XTheadBb is present. */
/* addi a0, zero, 255; th.ext a0, a0, 7, 0; */
__asm__("addi a0, zero, 255\n\t.4byte 0x1c05250b");
return t == -1; /* In case of collision with other vendor extensions. */
#else
return 0;
/*
** Hardcoded as there's no easy way of detection:
** - SIGILL have some trouble with libluajit as we speak
** - Checking mvendorid looks good, but might not be reliable.
*/
return 0;
#endif
}
static uint32_t riscv_probe(int (*func)(void), uint32_t flag)
{
if (sigsetjmp(sigbuf, 1) == 0) {
return func() ? flag : 0;
} else return 0;
return func() ? flag : 0;
}
#endif
@ -809,17 +802,21 @@ static uint32_t jit_cpudetect(void)
#elif LJ_TARGET_RISCV64
#if LJ_HASJIT
/* SIGILL-based detection of RVC, Zba, Zbb and XThead. Welcome to the future. */
struct sigaction old = {0}, act = {0};
act.sa_handler = detect_sigill;
sigaction(SIGILL, &act, &old);
#if LJ_TARGET_LINUX
/* HWPROBE-based detection of RVC, Zba, Zbb and Zicond. */
hwprobe_ret = syscall(__NR_riscv_hwprobe, &hwprobe_requests,
sizeof(hwprobe_requests) / sizeof(struct riscv_hwprobe), 0,
NULL, 0);
flags |= riscv_probe(riscv_compressed, JIT_F_RVC);
flags |= riscv_probe(riscv_zba, JIT_F_RVZba);
flags |= riscv_probe(riscv_zbb, JIT_F_RVZbb);
flags |= riscv_probe(riscv_zicond, JIT_F_RVZicond);
flags |= riscv_probe(riscv_zfa, JIT_F_RVZfa);
flags |= riscv_probe(riscv_xthead, JIT_F_RVXThead);
sigaction(SIGILL, &old, NULL);
#endif
/* Detect V/P? */
/* V have no hardware available, P not ratified yet. */

View File

@ -78,6 +78,35 @@
#define JIT_F_CPUSTRING "\003RVC\003Zba\003Zbb\006Zicond\003Zfa\006XThead"
#if LJ_TARGET_LINUX
#include <sys/syscall.h>
#ifndef __NR_riscv_hwprobe
#ifndef __NR_arch_specific_syscall
#define __NR_arch_specific_syscall 244
#endif
#define __NR_riscv_hwprobe (__NR_arch_specific_syscall + 14)
#endif
struct riscv_hwprobe {
int64_t key;
uint64_t value;
};
#define RISCV_HWPROBE_KEY_MVENDORID 0
#define RISCV_HWPROBE_KEY_MARCHID 1
#define RISCV_HWPROBE_KEY_MIMPID 2
#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
#define RISCV_HWPROBE_IMA_C (1 << 1)
#define RISCV_HWPROBE_EXT_ZBA (1 << 3)
#define RISCV_HWPROBE_EXT_ZBB (1 << 4)
#define RISCV_HWPROBE_EXT_ZFA (1ULL << 32)
#define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35)
#endif
#else
#define JIT_F_CPUSTRING ""