| //=== cpu_model/riscv.c - Update RISC-V Feature Bits Structure -*- C -*-======// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "cpu_model.h" |
| |
| #define RISCV_FEATURE_BITS_LENGTH 2 |
| struct { |
| unsigned length; |
| unsigned long long features[RISCV_FEATURE_BITS_LENGTH]; |
| } __riscv_feature_bits __attribute__((visibility("hidden"), nocommon)); |
| |
| struct { |
| unsigned mvendorid; |
| unsigned long long marchid; |
| unsigned long long mimpid; |
| } __riscv_cpu_model __attribute__((visibility("hidden"), nocommon)); |
| |
| // NOTE: Should sync-up with RISCVFeatures.td |
| // TODO: Maybe generate a header from tablegen then include it. |
| #define A_GROUPID 0 |
| #define A_BITMASK (1ULL << 0) |
| #define B_GROUPID 0 |
| #define B_BITMASK (1ULL << 1) |
| #define C_GROUPID 0 |
| #define C_BITMASK (1ULL << 2) |
| #define D_GROUPID 0 |
| #define D_BITMASK (1ULL << 3) |
| #define E_GROUPID 0 |
| #define E_BITMASK (1ULL << 4) |
| #define F_GROUPID 0 |
| #define F_BITMASK (1ULL << 5) |
| #define H_GROUPID 0 |
| #define H_BITMASK (1ULL << 7) |
| #define I_GROUPID 0 |
| #define I_BITMASK (1ULL << 8) |
| #define M_GROUPID 0 |
| #define M_BITMASK (1ULL << 12) |
| #define Q_GROUPID 0 |
| #define Q_BITMASK (1ULL << 16) |
| #define V_GROUPID 0 |
| #define V_BITMASK (1ULL << 21) |
| #define ZACAS_GROUPID 0 |
| #define ZACAS_BITMASK (1ULL << 26) |
| #define ZBA_GROUPID 0 |
| #define ZBA_BITMASK (1ULL << 27) |
| #define ZBB_GROUPID 0 |
| #define ZBB_BITMASK (1ULL << 28) |
| #define ZBC_GROUPID 0 |
| #define ZBC_BITMASK (1ULL << 29) |
| #define ZBKB_GROUPID 0 |
| #define ZBKB_BITMASK (1ULL << 30) |
| #define ZBKC_GROUPID 0 |
| #define ZBKC_BITMASK (1ULL << 31) |
| #define ZBKX_GROUPID 0 |
| #define ZBKX_BITMASK (1ULL << 32) |
| #define ZBS_GROUPID 0 |
| #define ZBS_BITMASK (1ULL << 33) |
| #define ZFA_GROUPID 0 |
| #define ZFA_BITMASK (1ULL << 34) |
| #define ZFH_GROUPID 0 |
| #define ZFH_BITMASK (1ULL << 35) |
| #define ZFHMIN_GROUPID 0 |
| #define ZFHMIN_BITMASK (1ULL << 36) |
| #define ZICBOZ_GROUPID 0 |
| #define ZICBOZ_BITMASK (1ULL << 37) |
| #define ZICOND_GROUPID 0 |
| #define ZICOND_BITMASK (1ULL << 38) |
| #define ZIHINTNTL_GROUPID 0 |
| #define ZIHINTNTL_BITMASK (1ULL << 39) |
| #define ZIHINTPAUSE_GROUPID 0 |
| #define ZIHINTPAUSE_BITMASK (1ULL << 40) |
| #define ZKND_GROUPID 0 |
| #define ZKND_BITMASK (1ULL << 41) |
| #define ZKNE_GROUPID 0 |
| #define ZKNE_BITMASK (1ULL << 42) |
| #define ZKNH_GROUPID 0 |
| #define ZKNH_BITMASK (1ULL << 43) |
| #define ZKSED_GROUPID 0 |
| #define ZKSED_BITMASK (1ULL << 44) |
| #define ZKSH_GROUPID 0 |
| #define ZKSH_BITMASK (1ULL << 45) |
| #define ZKT_GROUPID 0 |
| #define ZKT_BITMASK (1ULL << 46) |
| #define ZTSO_GROUPID 0 |
| #define ZTSO_BITMASK (1ULL << 47) |
| #define ZVBB_GROUPID 0 |
| #define ZVBB_BITMASK (1ULL << 48) |
| #define ZVBC_GROUPID 0 |
| #define ZVBC_BITMASK (1ULL << 49) |
| #define ZVFH_GROUPID 0 |
| #define ZVFH_BITMASK (1ULL << 50) |
| #define ZVFHMIN_GROUPID 0 |
| #define ZVFHMIN_BITMASK (1ULL << 51) |
| #define ZVKB_GROUPID 0 |
| #define ZVKB_BITMASK (1ULL << 52) |
| #define ZVKG_GROUPID 0 |
| #define ZVKG_BITMASK (1ULL << 53) |
| #define ZVKNED_GROUPID 0 |
| #define ZVKNED_BITMASK (1ULL << 54) |
| #define ZVKNHA_GROUPID 0 |
| #define ZVKNHA_BITMASK (1ULL << 55) |
| #define ZVKNHB_GROUPID 0 |
| #define ZVKNHB_BITMASK (1ULL << 56) |
| #define ZVKSED_GROUPID 0 |
| #define ZVKSED_BITMASK (1ULL << 57) |
| #define ZVKSH_GROUPID 0 |
| #define ZVKSH_BITMASK (1ULL << 58) |
| #define ZVKT_GROUPID 0 |
| #define ZVKT_BITMASK (1ULL << 59) |
| #define ZVE32X_GROUPID 0 |
| #define ZVE32X_BITMASK (1ULL << 60) |
| #define ZVE32F_GROUPID 0 |
| #define ZVE32F_BITMASK (1ULL << 61) |
| #define ZVE64X_GROUPID 0 |
| #define ZVE64X_BITMASK (1ULL << 62) |
| #define ZVE64F_GROUPID 0 |
| #define ZVE64F_BITMASK (1ULL << 63) |
| #define ZVE64D_GROUPID 1 |
| #define ZVE64D_BITMASK (1ULL << 0) |
| #define ZIMOP_GROUPID 1 |
| #define ZIMOP_BITMASK (1ULL << 1) |
| #define ZCA_GROUPID 1 |
| #define ZCA_BITMASK (1ULL << 2) |
| #define ZCB_GROUPID 1 |
| #define ZCB_BITMASK (1ULL << 3) |
| #define ZCD_GROUPID 1 |
| #define ZCD_BITMASK (1ULL << 4) |
| #define ZCF_GROUPID 1 |
| #define ZCF_BITMASK (1ULL << 5) |
| #define ZCMOP_GROUPID 1 |
| #define ZCMOP_BITMASK (1ULL << 6) |
| #define ZAWRS_GROUPID 1 |
| #define ZAWRS_BITMASK (1ULL << 7) |
| #define ZILSD_GROUPID 1 |
| #define ZILSD_BITMASK (1ULL << 8) |
| #define ZCLSD_GROUPID 1 |
| #define ZCLSD_BITMASK (1ULL << 9) |
| #define ZCMP_GROUPID 1 |
| #define ZCMP_BITMASK (1ULL << 10) |
| |
| #if defined(__linux__) |
| |
| // The RISC-V hwprobe interface is documented here: |
| // <https://docs.kernel.org/arch/riscv/hwprobe.html>. |
| |
| static long syscall_impl_5_args(long number, long arg1, long arg2, long arg3, |
| long arg4, long arg5) { |
| register long a7 __asm__("a7") = number; |
| register long a0 __asm__("a0") = arg1; |
| register long a1 __asm__("a1") = arg2; |
| register long a2 __asm__("a2") = arg3; |
| register long a3 __asm__("a3") = arg4; |
| register long a4 __asm__("a4") = arg5; |
| __asm__ __volatile__("ecall\n\t" |
| : "=r"(a0) |
| : "r"(a7), "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4) |
| : "memory"); |
| return a0; |
| } |
| |
| #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_BASE_BEHAVIOR_IMA (1ULL << 0) |
| #define RISCV_HWPROBE_KEY_IMA_EXT_0 4 |
| #define RISCV_HWPROBE_IMA_FD (1ULL << 0) |
| #define RISCV_HWPROBE_IMA_C (1ULL << 1) |
| #define RISCV_HWPROBE_IMA_V (1ULL << 2) |
| #define RISCV_HWPROBE_EXT_ZBA (1ULL << 3) |
| #define RISCV_HWPROBE_EXT_ZBB (1ULL << 4) |
| #define RISCV_HWPROBE_EXT_ZBS (1ULL << 5) |
| #define RISCV_HWPROBE_EXT_ZICBOZ (1ULL << 6) |
| #define RISCV_HWPROBE_EXT_ZBC (1ULL << 7) |
| #define RISCV_HWPROBE_EXT_ZBKB (1ULL << 8) |
| #define RISCV_HWPROBE_EXT_ZBKC (1ULL << 9) |
| #define RISCV_HWPROBE_EXT_ZBKX (1ULL << 10) |
| #define RISCV_HWPROBE_EXT_ZKND (1ULL << 11) |
| #define RISCV_HWPROBE_EXT_ZKNE (1ULL << 12) |
| #define RISCV_HWPROBE_EXT_ZKNH (1ULL << 13) |
| #define RISCV_HWPROBE_EXT_ZKSED (1ULL << 14) |
| #define RISCV_HWPROBE_EXT_ZKSH (1ULL << 15) |
| #define RISCV_HWPROBE_EXT_ZKT (1ULL << 16) |
| #define RISCV_HWPROBE_EXT_ZVBB (1ULL << 17) |
| #define RISCV_HWPROBE_EXT_ZVBC (1ULL << 18) |
| #define RISCV_HWPROBE_EXT_ZVKB (1ULL << 19) |
| #define RISCV_HWPROBE_EXT_ZVKG (1ULL << 20) |
| #define RISCV_HWPROBE_EXT_ZVKNED (1ULL << 21) |
| #define RISCV_HWPROBE_EXT_ZVKNHA (1ULL << 22) |
| #define RISCV_HWPROBE_EXT_ZVKNHB (1ULL << 23) |
| #define RISCV_HWPROBE_EXT_ZVKSED (1ULL << 24) |
| #define RISCV_HWPROBE_EXT_ZVKSH (1ULL << 25) |
| #define RISCV_HWPROBE_EXT_ZVKT (1ULL << 26) |
| #define RISCV_HWPROBE_EXT_ZFH (1ULL << 27) |
| #define RISCV_HWPROBE_EXT_ZFHMIN (1ULL << 28) |
| #define RISCV_HWPROBE_EXT_ZIHINTNTL (1ULL << 29) |
| #define RISCV_HWPROBE_EXT_ZVFH (1ULL << 30) |
| #define RISCV_HWPROBE_EXT_ZVFHMIN (1ULL << 31) |
| #define RISCV_HWPROBE_EXT_ZFA (1ULL << 32) |
| #define RISCV_HWPROBE_EXT_ZTSO (1ULL << 33) |
| #define RISCV_HWPROBE_EXT_ZACAS (1ULL << 34) |
| #define RISCV_HWPROBE_EXT_ZICOND (1ULL << 35) |
| #define RISCV_HWPROBE_EXT_ZIHINTPAUSE (1ULL << 36) |
| #define RISCV_HWPROBE_EXT_ZVE32X (1ULL << 37) |
| #define RISCV_HWPROBE_EXT_ZVE32F (1ULL << 38) |
| #define RISCV_HWPROBE_EXT_ZVE64X (1ULL << 39) |
| #define RISCV_HWPROBE_EXT_ZVE64F (1ULL << 40) |
| #define RISCV_HWPROBE_EXT_ZVE64D (1ULL << 41) |
| #define RISCV_HWPROBE_EXT_ZIMOP (1ULL << 42) |
| #define RISCV_HWPROBE_EXT_ZCA (1ULL << 43) |
| #define RISCV_HWPROBE_EXT_ZCB (1ULL << 44) |
| #define RISCV_HWPROBE_EXT_ZCD (1ULL << 45) |
| #define RISCV_HWPROBE_EXT_ZCF (1ULL << 46) |
| #define RISCV_HWPROBE_EXT_ZCMOP (1ULL << 47) |
| #define RISCV_HWPROBE_EXT_ZAWRS (1ULL << 48) |
| #define RISCV_HWPROBE_KEY_CPUPERF_0 5 |
| #define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0) |
| #define RISCV_HWPROBE_MISALIGNED_EMULATED (1ULL << 0) |
| #define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0) |
| #define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0) |
| #define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0) |
| #define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0) |
| #define RISCV_HWPROBE_KEY_ZICBOZ_BLOCK_SIZE 6 |
| /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ |
| |
| struct riscv_hwprobe { |
| long long key; |
| unsigned long long value; |
| }; |
| |
| #define __NR_riscv_hwprobe 258 |
| static long initHwProbe(struct riscv_hwprobe *Hwprobes, int len) { |
| return syscall_impl_5_args(__NR_riscv_hwprobe, (long)Hwprobes, len, 0, 0, 0); |
| } |
| |
| #define SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(EXTNAME) \ |
| SET_SINGLE_IMAEXT_RISCV_FEATURE(RISCV_HWPROBE_EXT_##EXTNAME, EXTNAME) |
| |
| #define SET_SINGLE_IMAEXT_RISCV_FEATURE(HWPROBE_BITMASK, EXT) \ |
| SET_SINGLE_RISCV_FEATURE(IMAEXT0Value &HWPROBE_BITMASK, EXT) |
| |
| #define SET_SINGLE_RISCV_FEATURE(COND, EXT) \ |
| if (COND) { \ |
| SET_RISCV_FEATURE(EXT); \ |
| } |
| |
| #define SET_RISCV_FEATURE(EXT) features[EXT##_GROUPID] |= EXT##_BITMASK |
| |
| static void initRISCVFeature(struct riscv_hwprobe Hwprobes[]) { |
| |
| // Note: If a hwprobe key is unknown to the kernel, its key field |
| // will be cleared to -1, and its value set to 0. |
| // This unsets all extension bitmask bits. |
| |
| // Init VendorID, ArchID, ImplID |
| __riscv_cpu_model.mvendorid = Hwprobes[2].value; |
| __riscv_cpu_model.marchid = Hwprobes[3].value; |
| __riscv_cpu_model.mimpid = Hwprobes[4].value; |
| |
| // Init standard extension |
| // TODO: Maybe Extension implied generate from tablegen? |
| |
| unsigned long long features[RISCV_FEATURE_BITS_LENGTH]; |
| int i; |
| |
| for (i = 0; i < RISCV_FEATURE_BITS_LENGTH; i++) |
| features[i] = 0; |
| |
| // Check RISCV_HWPROBE_KEY_BASE_BEHAVIOR |
| unsigned long long BaseValue = Hwprobes[0].value; |
| if (BaseValue & RISCV_HWPROBE_BASE_BEHAVIOR_IMA) { |
| SET_RISCV_FEATURE(I); |
| SET_RISCV_FEATURE(M); |
| SET_RISCV_FEATURE(A); |
| } |
| |
| // Check RISCV_HWPROBE_KEY_IMA_EXT_0 |
| unsigned long long IMAEXT0Value = Hwprobes[1].value; |
| if (IMAEXT0Value & RISCV_HWPROBE_IMA_FD) { |
| SET_RISCV_FEATURE(F); |
| SET_RISCV_FEATURE(D); |
| } |
| |
| SET_SINGLE_IMAEXT_RISCV_FEATURE(RISCV_HWPROBE_IMA_C, C); |
| SET_SINGLE_IMAEXT_RISCV_FEATURE(RISCV_HWPROBE_IMA_V, V); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBA); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBB); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBS); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZICBOZ); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBC); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBKB); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBKC); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZBKX); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKND); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKNE); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKNH); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKSED); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKSH); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZKT); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVBB); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVBC); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKB); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKG); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKNED); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKNHA); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKNHB); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKSED); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKSH); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVKT); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZFH); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZFHMIN); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZIHINTNTL); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZIHINTPAUSE); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVFH); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVFHMIN); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZFA); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZTSO); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZACAS); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZICOND); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVE32X); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVE32F); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVE64X); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVE64F); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZVE64D); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZIMOP); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZCA); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZCB); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZCD); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZCF); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZCMOP); |
| SET_RISCV_HWPROBE_EXT_SINGLE_RISCV_FEATURE(ZAWRS); |
| |
| for (i = 0; i < RISCV_FEATURE_BITS_LENGTH; i++) |
| __riscv_feature_bits.features[i] = features[i]; |
| } |
| |
| #endif // defined(__linux__) |
| |
| static int FeaturesBitCached = 0; |
| |
| void __init_riscv_feature_bits(void *); |
| static void __init_riscv_feature_bits_ctor(void) CONSTRUCTOR_ATTRIBUTE; |
| |
| // A constructor function that sets __riscv_feature_bits |
| // to the right values. This needs to run only once. This constructor is given |
| // the highest priority and it should run before constructors without the |
| // priority set. However, it still runs after ifunc initializers and needs to |
| // be called explicitly there. |
| |
| static void CONSTRUCTOR_ATTRIBUTE __init_riscv_feature_bits_ctor(void) { |
| __init_riscv_feature_bits(0); |
| } |
| |
| // PlatformArgs allows the platform to provide pre-computed data and access it |
| // without extra effort. For example, Linux could pass the vDSO object to avoid |
| // an extra system call. |
| void __init_riscv_feature_bits(void *PlatformArgs) { |
| |
| if (FeaturesBitCached) |
| return; |
| |
| __riscv_feature_bits.length = RISCV_FEATURE_BITS_LENGTH; |
| |
| #if defined(__linux__) |
| struct riscv_hwprobe Hwprobes[] = { |
| {RISCV_HWPROBE_KEY_BASE_BEHAVIOR, 0}, {RISCV_HWPROBE_KEY_IMA_EXT_0, 0}, |
| {RISCV_HWPROBE_KEY_MVENDORID, 0}, {RISCV_HWPROBE_KEY_MARCHID, 0}, |
| {RISCV_HWPROBE_KEY_MIMPID, 0}, |
| }; |
| if (initHwProbe(Hwprobes, sizeof(Hwprobes) / sizeof(Hwprobes[0]))) |
| return; |
| |
| initRISCVFeature(Hwprobes); |
| #endif // defined(__linux__) |
| |
| FeaturesBitCached = 1; |
| } |