diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst index c420a8349bc681..9b901bf8bab9af 100644 --- a/Documentation/arch/riscv/hwprobe.rst +++ b/Documentation/arch/riscv/hwprobe.rst @@ -67,6 +67,14 @@ The following keys are defined: programs (it may still be executed in userspace via a kernel-controlled mechanism such as the vDSO). + * :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64`: Support for all mandatory + extensions of RVA23U64, as defined in the RISC-V Profiles specification + starting from commit 0273f3c921b6 ("rva23/rvb23 ratified"). + + The RVA23U64 base is based upon the IMA base and therefore IMA extension + keys (e.g. :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`:) may be used to probe + optional extensions. + * :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`: A bitmask containing extensions that are compatible with the :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior. @@ -289,6 +297,10 @@ The following keys are defined: defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating load/store pair for RV32 with the main manual") of the riscv-isa-manual. + * :c:macro:`RISCV_HWPROBE_EXT_ZICCLSM`: The Zicclsm extension is supported, + as defined in the RISC-V Profiles specification starting from commit + b1d80660 ("Updated to ratified state.") + * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated. Returns similar values to :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was mistakenly classified as a bitmask rather than a value. @@ -358,7 +370,7 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XTHEADVECTOR`: The xtheadvector vendor extension is supported in the T-Head ISA extensions spec starting from - commit a18c801634 ("Add T-Head VECTOR vendor extension. "). + commit a18c801634 ("Add T-Head VECTOR vendor extension. "). * :c:macro:`RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE`: An unsigned int which represents the size of the Zicbom block in bytes. @@ -371,19 +383,19 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCDOD`: The Xsfqmaccdod vendor extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication - Extensions Specification. + Extensions Specification. * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCQOQ`: The Xsfqmaccqoq vendor extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication - Instruction Extensions Specification. + Instruction Extensions Specification. * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFNRCLIPXFQF`: The Xsfvfnrclipxfqf vendor extension is supported in version 1.0 of SiFive FP32-to-int8 Ranged - Clip Instructions Extensions Specification. + Clip Instructions Extensions Specification. * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFWMACCQQQ`: The Xsfvfwmaccqqq vendor extension is supported in version 1.0 of Matrix Multiply Accumulate - Instruction Extensions Specification. + Instruction Extensions Specification. * :c:macro:`RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE`: An unsigned int which represents the size of the Zicbop block in bytes. @@ -391,3 +403,27 @@ The following keys are defined: * :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_1`: A bitmask containing additional extensions that are compatible with the :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior. + + * :c:macro:`RISCV_HWPROBE_EXT_ZICFISS`: The Zicfiss extension is supported, + as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI) + extensions specification, ratified 2024-07. + + * :c:macro:`RISCV_HWPROBE_EXT_ZICCAMOA`: The Ziccamoa extension is supported, + as defined in the RISC-V Profiles specification starting from commit + b1d80660 ("Updated to ratified state.") + + * :c:macro:`RISCV_HWPROBE_EXT_ZICCIF`: The Ziccif extension is supported, + as defined in the RISC-V Profiles specification starting from commit + b1d80660 ("Updated to ratified state.") + + * :c:macro:`RISCV_HWPROBE_EXT_ZICCRSE`: The Ziccrse extension is supported, + as defined in the RISC-V Profiles specification starting from commit + b1d80660 ("Updated to ratified state.") + + * :c:macro:`RISCV_HWPROBE_EXT_ZA64RS`: The Za64rs extension is supported, + as defined in the RISC-V Profiles specification starting from commit + b1d80660 ("Updated to ratified state.") + + * :c:macro:`RISCV_HWPROBE_EXT_B`: The B extension is supported, as defined + in version 1.0 of the Bit-Manipulation ISA extensions, and implies the + presence of the Zba, Zbb, and Zbs sub-extensions. diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h index 739fcc84bf7b28..facc31b2960c6f 100644 --- a/arch/riscv/include/asm/cpufeature.h +++ b/arch/riscv/include/asm/cpufeature.h @@ -25,10 +25,24 @@ struct riscv_cpuinfo { unsigned long mimpid; }; +enum { + RISCV_ISA_BASE_IMA, + RISCV_ISA_BASE_RVA23U64, + RISCV_NR_ISA_BASES, +}; + +/** + * struct riscv_isainfo - per-hart ISA state + * @isa: bitmap of ISA extensions this hart implements + * @isa_bases: bitmap of profile bases this hart conforms to + */ struct riscv_isainfo { DECLARE_BITMAP(isa, RISCV_ISA_EXT_MAX); + DECLARE_BITMAP(isa_bases, RISCV_NR_ISA_BASES); }; +extern unsigned long riscv_isa_bases[BITS_TO_LONGS(RISCV_NR_ISA_BASES)]; + DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo); extern const struct seq_operations cpuinfo_op; diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h index 7ef8e5f55c8dcf..58523b3a1998aa 100644 --- a/arch/riscv/include/asm/hwcap.h +++ b/arch/riscv/include/asm/hwcap.h @@ -10,15 +10,16 @@ #include -#define RISCV_ISA_EXT_a ('a' - 'a') -#define RISCV_ISA_EXT_c ('c' - 'a') -#define RISCV_ISA_EXT_d ('d' - 'a') -#define RISCV_ISA_EXT_f ('f' - 'a') -#define RISCV_ISA_EXT_h ('h' - 'a') -#define RISCV_ISA_EXT_i ('i' - 'a') -#define RISCV_ISA_EXT_m ('m' - 'a') -#define RISCV_ISA_EXT_q ('q' - 'a') -#define RISCV_ISA_EXT_v ('v' - 'a') +#define RISCV_ISA_EXT_A ('a' - 'a') +#define RISCV_ISA_EXT_B ('b' - 'a') +#define RISCV_ISA_EXT_C ('c' - 'a') +#define RISCV_ISA_EXT_D ('d' - 'a') +#define RISCV_ISA_EXT_F ('f' - 'a') +#define RISCV_ISA_EXT_H ('h' - 'a') +#define RISCV_ISA_EXT_I ('i' - 'a') +#define RISCV_ISA_EXT_M ('m' - 'a') +#define RISCV_ISA_EXT_Q ('q' - 'a') +#define RISCV_ISA_EXT_V ('v' - 'a') /* * These macros represent the logical IDs of each multi-letter RISC-V ISA @@ -112,6 +113,10 @@ #define RISCV_ISA_EXT_ZCLSD 103 #define RISCV_ISA_EXT_ZICFILP 104 #define RISCV_ISA_EXT_ZICFISS 105 +#define RISCV_ISA_EXT_ZICCLSM 106 +#define RISCV_ISA_EXT_ZICCAMOA 107 +#define RISCV_ISA_EXT_ZICCIF 108 +#define RISCV_ISA_EXT_ZA64RS 109 #define RISCV_ISA_EXT_XLINUXENVCFG 127 diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h index 812517b2cec135..febf51e127f70a 100644 --- a/arch/riscv/include/asm/processor.h +++ b/arch/riscv/include/asm/processor.h @@ -214,6 +214,10 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg); long get_tagged_addr_ctrl(struct task_struct *task); #define SET_TAGGED_ADDR_CTRL(arg) set_tagged_addr_ctrl(current, arg) #define GET_TAGGED_ADDR_CTRL() get_tagged_addr_ctrl(current) + +bool riscv_have_user_pmlen(u8 len); +#else +static inline bool riscv_have_user_pmlen(u8 len) { return false; } #endif #endif /* __ASSEMBLER__ */ diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h index 0e71eb82f920ca..ff35a4d04f85a3 100644 --- a/arch/riscv/include/asm/switch_to.h +++ b/arch/riscv/include/asm/switch_to.h @@ -60,8 +60,8 @@ static inline void __switch_to_fpu(struct task_struct *prev, static __always_inline bool has_fpu(void) { - return riscv_has_extension_likely(RISCV_ISA_EXT_f) || - riscv_has_extension_likely(RISCV_ISA_EXT_d); + return riscv_has_extension_likely(RISCV_ISA_EXT_F) || + riscv_has_extension_likely(RISCV_ISA_EXT_D); } #else static __always_inline bool has_fpu(void) { return false; } diff --git a/arch/riscv/include/uapi/asm/hwcap.h b/arch/riscv/include/uapi/asm/hwcap.h index c52bb7bbbabe93..96b7cf854e090b 100644 --- a/arch/riscv/include/uapi/asm/hwcap.h +++ b/arch/riscv/include/uapi/asm/hwcap.h @@ -21,6 +21,7 @@ #define COMPAT_HWCAP_ISA_F (1 << ('F' - 'A')) #define COMPAT_HWCAP_ISA_D (1 << ('D' - 'A')) #define COMPAT_HWCAP_ISA_C (1 << ('C' - 'A')) +#define COMPAT_HWCAP_ISA_B (1 << ('B' - 'A')) #define COMPAT_HWCAP_ISA_V (1 << ('V' - 'A')) #endif /* _UAPI_ASM_RISCV_HWCAP_H */ diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h index 9139edba0aecbf..d940ba4f6a1e81 100644 --- a/arch/riscv/include/uapi/asm/hwprobe.h +++ b/arch/riscv/include/uapi/asm/hwprobe.h @@ -21,7 +21,8 @@ struct riscv_hwprobe { #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 (1 << 0) +#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0) +#define RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64 (1 << 1) #define RISCV_HWPROBE_KEY_IMA_EXT_0 4 #define RISCV_HWPROBE_IMA_FD (1 << 0) #define RISCV_HWPROBE_IMA_C (1 << 1) @@ -116,6 +117,12 @@ struct riscv_hwprobe { #define RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE 15 #define RISCV_HWPROBE_KEY_IMA_EXT_1 16 #define RISCV_HWPROBE_EXT_ZICFISS (1ULL << 0) +#define RISCV_HWPROBE_EXT_ZICCLSM (1ULL << 1) +#define RISCV_HWPROBE_EXT_ZICCAMOA (1ULL << 2) +#define RISCV_HWPROBE_EXT_ZICCIF (1ULL << 3) +#define RISCV_HWPROBE_EXT_ZICCRSE (1ULL << 4) +#define RISCV_HWPROBE_EXT_ZA64RS (1ULL << 5) +#define RISCV_HWPROBE_EXT_B (1ULL << 6) /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */ diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c index 3dbc8cc557dd1d..31e2857dcdcf1e 100644 --- a/arch/riscv/kernel/cpu.c +++ b/arch/riscv/kernel/cpu.c @@ -305,6 +305,26 @@ static void print_mmu(struct seq_file *f) seq_printf(f, "mmu\t\t: %s\n", sv_type); } +static const char * const riscv_isa_base_names[] = { +#ifdef CONFIG_32BIT + [RISCV_ISA_BASE_IMA] = "rv32ima", +#else + [RISCV_ISA_BASE_IMA] = "rv64ima", +#endif + [RISCV_ISA_BASE_RVA23U64] = "rva23u64", +}; + +static void print_isa_bases(struct seq_file *m, const unsigned long *isa_bases) +{ + unsigned int i; + + for (i = 0; i < RISCV_NR_ISA_BASES; i++) { + if (test_bit(i, isa_bases)) + seq_printf(m, " %s", riscv_isa_base_names[i]); + } + seq_puts(m, "\n"); +} + static void *c_start(struct seq_file *m, loff_t *pos) { if (*pos == nr_cpu_ids) @@ -336,6 +356,9 @@ static int c_show(struct seq_file *m, void *v) seq_printf(m, "processor\t: %lu\n", cpu_id); seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id)); + seq_puts(m, "isa bases\t:"); + print_isa_bases(m, riscv_isa_bases); + /* * For historical raisins, the isa: line is limited to the lowest common * denominator of extensions supported across all harts. A true list of @@ -360,6 +383,9 @@ static int c_show(struct seq_file *m, void *v) seq_printf(m, "marchid\t\t: 0x%lx\n", ci->marchid); seq_printf(m, "mimpid\t\t: 0x%lx\n", ci->mimpid); + seq_puts(m, "hart isa bases\t:"); + print_isa_bases(m, hart_isa[cpu_id].isa_bases); + /* * Print the ISA extensions specific to this hart, which may show * additional extensions not present across all harts. diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 1734f9a4c2fd70..6e8dd33aa38889 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -41,6 +41,9 @@ unsigned long elf_hwcap __read_mostly; /* Host ISA bitmap */ static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly; +/* Host ISA bases bitmap */ +DECLARE_BITMAP(riscv_isa_bases, RISCV_NR_ISA_BASES) __read_mostly; + /* Per-cpu ISA extensions. */ struct riscv_isainfo hart_isa[NR_CPUS]; @@ -84,7 +87,25 @@ EXPORT_SYMBOL_GPL(__riscv_isa_extension_available); static int riscv_ext_f_depends(const struct riscv_isa_ext_data *data, const unsigned long *isa_bitmap) { - if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_f)) + if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_F)) + return 0; + + return -EPROBE_DEFER; +} + +static int riscv_ext_zaamo_depends(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) +{ + if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZAAMO)) + return 0; + + return -EPROBE_DEFER; +} + +static int riscv_ext_zalrsc_depends(const struct riscv_isa_ext_data *data, + const unsigned long *isa_bitmap) +{ + if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZALRSC)) return 0; return -EPROBE_DEFER; @@ -146,7 +167,7 @@ static int riscv_ext_f_validate(const struct riscv_isa_ext_data *data, * Due to extension ordering, d is checked before f, so no deferral * is required. */ - if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d)) { + if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D)) { pr_warn_once("This kernel does not support systems with F but not D\n"); return -EINVAL; } @@ -189,7 +210,7 @@ static int riscv_ext_vector_float_validate(const struct riscv_isa_ext_data *data * Since this function validates vector only, and v/Zve* are probed * after f/d, there's no need for a deferral here. */ - if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d)) + if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D)) return -EINVAL; return 0; @@ -224,7 +245,7 @@ static int riscv_ext_zcd_validate(const struct riscv_isa_ext_data *data, const unsigned long *isa_bitmap) { if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA) && - __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d)) + __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D)) return 0; return -EPROBE_DEFER; @@ -237,7 +258,7 @@ static int riscv_ext_zcf_validate(const struct riscv_isa_ext_data *data, return -EINVAL; if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA) && - __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_f)) + __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_F)) return 0; return -EPROBE_DEFER; @@ -450,6 +471,12 @@ static const unsigned int riscv_c_exts[] = { RISCV_ISA_EXT_ZCD, }; +static const unsigned int riscv_b_exts[] = { + RISCV_ISA_EXT_ZBA, + RISCV_ISA_EXT_ZBB, + RISCV_ISA_EXT_ZBS, +}; + /* * The canonical order of ISA extension names in the ISA string is defined in * chapter 27 of the unprivileged specification. @@ -490,18 +517,22 @@ static const unsigned int riscv_c_exts[] = { * New entries to this struct should follow the ordering rules described above. */ const struct riscv_isa_ext_data riscv_isa_ext[] = { - __RISCV_ISA_EXT_DATA(i, RISCV_ISA_EXT_i), - __RISCV_ISA_EXT_DATA(m, RISCV_ISA_EXT_m), - __RISCV_ISA_EXT_SUPERSET(a, RISCV_ISA_EXT_a, riscv_a_exts), - __RISCV_ISA_EXT_DATA_VALIDATE(f, RISCV_ISA_EXT_f, riscv_ext_f_validate), - __RISCV_ISA_EXT_DATA_VALIDATE(d, RISCV_ISA_EXT_d, riscv_ext_d_validate), - __RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q), - __RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_c, riscv_c_exts), - __RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_v, riscv_v_exts, riscv_ext_vector_float_validate), - __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h), + __RISCV_ISA_EXT_DATA(i, RISCV_ISA_EXT_I), + __RISCV_ISA_EXT_DATA(m, RISCV_ISA_EXT_M), + __RISCV_ISA_EXT_SUPERSET(a, RISCV_ISA_EXT_A, riscv_a_exts), + __RISCV_ISA_EXT_DATA_VALIDATE(f, RISCV_ISA_EXT_F, riscv_ext_f_validate), + __RISCV_ISA_EXT_DATA_VALIDATE(d, RISCV_ISA_EXT_D, riscv_ext_d_validate), + __RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_Q), + __RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_C, riscv_c_exts), + __RISCV_ISA_EXT_SUPERSET(b, RISCV_ISA_EXT_B, riscv_b_exts), + __RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_V, riscv_v_exts, riscv_ext_vector_float_validate), + __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_H), __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate), __RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate), __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate), + __RISCV_ISA_EXT_DATA_VALIDATE(ziccamoa, RISCV_ISA_EXT_ZICCAMOA, riscv_ext_zaamo_depends), + __RISCV_ISA_EXT_DATA(ziccif, RISCV_ISA_EXT_ZICCIF), + __RISCV_ISA_EXT_DATA(zicclsm, RISCV_ISA_EXT_ZICCLSM), __RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE), __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicfilp, RISCV_ISA_EXT_ZICFILP, riscv_xlinuxenvcfg_exts, riscv_cfilp_validate), @@ -515,6 +546,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = { __RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE), __RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM), __RISCV_ISA_EXT_DATA(zimop, RISCV_ISA_EXT_ZIMOP), + __RISCV_ISA_EXT_DATA_VALIDATE(za64rs, RISCV_ISA_EXT_ZA64RS, riscv_ext_zalrsc_depends), __RISCV_ISA_EXT_DATA(zaamo, RISCV_ISA_EXT_ZAAMO), __RISCV_ISA_EXT_DATA(zabha, RISCV_ISA_EXT_ZABHA), __RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS), @@ -897,8 +929,8 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap) * marchid. */ if (acpi_disabled && boot_vendorid == THEAD_VENDOR_ID && boot_archid == 0x0) { - this_hwcap &= ~isa2hwcap[RISCV_ISA_EXT_v]; - clear_bit(RISCV_ISA_EXT_v, source_isa); + this_hwcap &= ~isa2hwcap[RISCV_ISA_EXT_V]; + clear_bit(RISCV_ISA_EXT_V, source_isa); } riscv_resolve_isa(source_isa, isainfo->isa, &this_hwcap, isa2hwcap); @@ -1113,6 +1145,7 @@ void __init riscv_fill_hwcap(void) isa2hwcap['f' - 'a'] = COMPAT_HWCAP_ISA_F; isa2hwcap['d' - 'a'] = COMPAT_HWCAP_ISA_D; isa2hwcap['c' - 'a'] = COMPAT_HWCAP_ISA_C; + isa2hwcap['b' - 'a'] = COMPAT_HWCAP_ISA_B; isa2hwcap['v' - 'a'] = COMPAT_HWCAP_ISA_V; if (!acpi_disabled) { @@ -1275,3 +1308,92 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin, } } #endif + +/* + * Compute the set of profile bases (IMA, RVA23U64, ...) a hart + * conforms to, given its resolved ISA bitmap. + * + * If @isa_bitmap is NULL, the host ISA bitmap (the AND across all harts) is + * used. + */ +static void riscv_set_isa_bases(unsigned long *bases, const unsigned long *isa_bitmap) +{ + const unsigned long *isa = isa_bitmap ? isa_bitmap : riscv_isa; + DECLARE_BITMAP(ext_mask, RISCV_ISA_EXT_MAX) = { 0 }; + DECLARE_BITMAP(tmp, RISCV_ISA_EXT_MAX); + + /* IMA */ + set_bit(RISCV_ISA_EXT_I, ext_mask); + set_bit(RISCV_ISA_EXT_M, ext_mask); + set_bit(RISCV_ISA_EXT_A, ext_mask); + + if (bitmap_andnot(tmp, ext_mask, isa, RISCV_ISA_EXT_MAX)) + return; + + set_bit(RISCV_ISA_BASE_IMA, bases); + + /* RVA23U64 */ + + /* Zic64b and Supm with PMLEN=7 */ + if (riscv_cbom_block_size != 64 || + riscv_cbop_block_size != 64 || + riscv_cboz_block_size != 64 || + !riscv_have_user_pmlen(7)) + return; + + set_bit(RISCV_ISA_EXT_F, ext_mask); + set_bit(RISCV_ISA_EXT_D, ext_mask); + set_bit(RISCV_ISA_EXT_C, ext_mask); + set_bit(RISCV_ISA_EXT_B, ext_mask); + set_bit(RISCV_ISA_EXT_ZICSR, ext_mask); + set_bit(RISCV_ISA_EXT_ZICNTR, ext_mask); + set_bit(RISCV_ISA_EXT_ZIHPM, ext_mask); + set_bit(RISCV_ISA_EXT_ZICCIF, ext_mask); + set_bit(RISCV_ISA_EXT_ZICCRSE, ext_mask); + set_bit(RISCV_ISA_EXT_ZICCAMOA, ext_mask); + set_bit(RISCV_ISA_EXT_ZICCLSM, ext_mask); + set_bit(RISCV_ISA_EXT_ZA64RS, ext_mask); + set_bit(RISCV_ISA_EXT_ZIHINTPAUSE, ext_mask); + set_bit(RISCV_ISA_EXT_ZICBOM, ext_mask); + set_bit(RISCV_ISA_EXT_ZICBOP, ext_mask); + set_bit(RISCV_ISA_EXT_ZICBOZ, ext_mask); + set_bit(RISCV_ISA_EXT_ZFHMIN, ext_mask); + set_bit(RISCV_ISA_EXT_ZKT, ext_mask); + set_bit(RISCV_ISA_EXT_V, ext_mask); + set_bit(RISCV_ISA_EXT_ZVFHMIN, ext_mask); + set_bit(RISCV_ISA_EXT_ZVBB, ext_mask); + set_bit(RISCV_ISA_EXT_ZVKT, ext_mask); + set_bit(RISCV_ISA_EXT_ZIHINTNTL, ext_mask); + set_bit(RISCV_ISA_EXT_ZICOND, ext_mask); + set_bit(RISCV_ISA_EXT_ZIMOP, ext_mask); + set_bit(RISCV_ISA_EXT_ZCMOP, ext_mask); + set_bit(RISCV_ISA_EXT_ZCB, ext_mask); + set_bit(RISCV_ISA_EXT_ZFA, ext_mask); + set_bit(RISCV_ISA_EXT_ZAWRS, ext_mask); + set_bit(RISCV_ISA_EXT_SUPM, ext_mask); + + if (bitmap_andnot(tmp, ext_mask, isa, RISCV_ISA_EXT_MAX)) + return; + + set_bit(RISCV_ISA_BASE_RVA23U64, bases); +} + +/* + * Populate the host ISA bases bitmap (riscv_isa_bases) and each + * hart's per-cpu isa_bases. + */ +static int __init riscv_init_isa_bases(void) +{ + int cpu; + + for_each_possible_cpu(cpu) + riscv_set_isa_bases(hart_isa[cpu].isa_bases, hart_isa[cpu].isa); + + riscv_set_isa_bases(riscv_isa_bases, NULL); + return 0; +} +/* + * Registered as subsys_initcall so it runs after + * core_initcall(tagged_addr_init) populates have_user_pmlen_*. + */ +subsys_initcall(riscv_init_isa_bases); diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c index b2df7f72241a5f..5d9cb108a6232c 100644 --- a/arch/riscv/kernel/process.c +++ b/arch/riscv/kernel/process.c @@ -302,6 +302,18 @@ enum { static bool have_user_pmlen_7; static bool have_user_pmlen_16; +bool riscv_have_user_pmlen(u8 len) +{ + switch (len) { + case PMLEN_7: + return have_user_pmlen_7; + case PMLEN_16: + return have_user_pmlen_16; + default: + return false; + } +} + /* * Control the relaxed ABI allowing tagged user addresses into the kernel. */ diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c index 1659d31fd288fc..c43fcad737b738 100644 --- a/arch/riscv/kernel/sys_hwprobe.c +++ b/arch/riscv/kernel/sys_hwprobe.c @@ -88,10 +88,10 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair, if (has_fpu()) pair->value |= RISCV_HWPROBE_IMA_FD; - if (riscv_isa_extension_available(NULL, c)) + if (riscv_isa_extension_available(NULL, C)) pair->value |= RISCV_HWPROBE_IMA_C; - if (has_vector() && riscv_isa_extension_available(NULL, v)) + if (has_vector() && riscv_isa_extension_available(NULL, V)) pair->value |= RISCV_HWPROBE_IMA_V; /* @@ -205,6 +205,12 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair, * in the hart_isa bitmap, are made. */ EXT_KEY(isainfo->isa, ZICFISS, pair->value, missing); + EXT_KEY(isainfo->isa, ZICCLSM, pair->value, missing); + EXT_KEY(isainfo->isa, ZICCAMOA, pair->value, missing); + EXT_KEY(isainfo->isa, ZICCIF, pair->value, missing); + EXT_KEY(isainfo->isa, ZICCRSE, pair->value, missing); + EXT_KEY(isainfo->isa, ZA64RS, pair->value, missing); + EXT_KEY(isainfo->isa, B, pair->value, missing); } /* Now turn off reporting features if any CPU is missing it. */ @@ -219,6 +225,17 @@ static bool hwprobe_ext0_has(const struct cpumask *cpus, u64 ext) return (pair.value & ext); } +static bool hwprobe_has_isa_base(const struct cpumask *cpus, unsigned int base) +{ + int cpu; + + for_each_cpu(cpu, cpus) { + if (!test_bit(base, hart_isa[cpu].isa_bases)) + return false; + } + return true; +} + #if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS) static u64 hwprobe_misaligned(const struct cpumask *cpus) { @@ -301,14 +318,12 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair, case RISCV_HWPROBE_KEY_MIMPID: hwprobe_arch_id(pair, cpus); break; - /* - * The kernel already assumes that the base single-letter ISA - * extensions are supported on all harts, and only supports the - * IMA base, so just cheat a bit here and tell that to - * userspace. - */ case RISCV_HWPROBE_KEY_BASE_BEHAVIOR: - pair->value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA; + pair->value = 0; + if (hwprobe_has_isa_base(cpus, RISCV_ISA_BASE_IMA)) + pair->value |= RISCV_HWPROBE_BASE_BEHAVIOR_IMA; + if (hwprobe_has_isa_base(cpus, RISCV_ISA_BASE_RVA23U64)) + pair->value |= RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64; break; case RISCV_HWPROBE_KEY_IMA_EXT_0: diff --git a/arch/riscv/kvm/isa.c b/arch/riscv/kvm/isa.c index 1132d909cc25cd..94077117d11363 100644 --- a/arch/riscv/kvm/isa.c +++ b/arch/riscv/kvm/isa.c @@ -17,14 +17,14 @@ /* Mapping between KVM ISA Extension ID & guest ISA extension ID */ static const unsigned long kvm_isa_ext_arr[] = { /* Single letter extensions (alphabetically sorted) */ - [KVM_RISCV_ISA_EXT_A] = RISCV_ISA_EXT_a, - [KVM_RISCV_ISA_EXT_C] = RISCV_ISA_EXT_c, - [KVM_RISCV_ISA_EXT_D] = RISCV_ISA_EXT_d, - [KVM_RISCV_ISA_EXT_F] = RISCV_ISA_EXT_f, - [KVM_RISCV_ISA_EXT_H] = RISCV_ISA_EXT_h, - [KVM_RISCV_ISA_EXT_I] = RISCV_ISA_EXT_i, - [KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m, - [KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v, + KVM_ISA_EXT_ARR(A), + KVM_ISA_EXT_ARR(C), + KVM_ISA_EXT_ARR(D), + KVM_ISA_EXT_ARR(F), + KVM_ISA_EXT_ARR(H), + KVM_ISA_EXT_ARR(I), + KVM_ISA_EXT_ARR(M), + KVM_ISA_EXT_ARR(V), /* Multi letter extensions (alphabetically sorted) */ KVM_ISA_EXT_ARR(SMNPM), KVM_ISA_EXT_ARR(SMSTATEEN), diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c index cb8a65273c1f04..70640701310c8f 100644 --- a/arch/riscv/kvm/main.c +++ b/arch/riscv/kvm/main.c @@ -85,7 +85,7 @@ static int __init riscv_kvm_init(void) char slist[64]; const char *str; - if (!riscv_isa_extension_available(NULL, h)) { + if (!riscv_isa_extension_available(NULL, H)) { kvm_info("hypervisor extension not available\n"); return -ENODEV; } diff --git a/arch/riscv/kvm/vcpu_fp.c b/arch/riscv/kvm/vcpu_fp.c index 6ad6df26a2fd42..bb11e6757d3498 100644 --- a/arch/riscv/kvm/vcpu_fp.c +++ b/arch/riscv/kvm/vcpu_fp.c @@ -21,8 +21,8 @@ void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu) struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; cntx->sstatus &= ~SR_FS; - if (riscv_isa_extension_available(vcpu->arch.isa, f) || - riscv_isa_extension_available(vcpu->arch.isa, d)) + if (riscv_isa_extension_available(vcpu->arch.isa, F) || + riscv_isa_extension_available(vcpu->arch.isa, D)) cntx->sstatus |= SR_FS_INITIAL; else cntx->sstatus |= SR_FS_OFF; @@ -38,9 +38,9 @@ void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx, const unsigned long *isa) { if ((cntx->sstatus & SR_FS) == SR_FS_DIRTY) { - if (riscv_isa_extension_available(isa, d)) + if (riscv_isa_extension_available(isa, D)) __kvm_riscv_fp_d_save(cntx); - else if (riscv_isa_extension_available(isa, f)) + else if (riscv_isa_extension_available(isa, F)) __kvm_riscv_fp_f_save(cntx); kvm_riscv_vcpu_fp_clean(cntx); } @@ -50,9 +50,9 @@ void kvm_riscv_vcpu_guest_fp_restore(struct kvm_cpu_context *cntx, const unsigned long *isa) { if ((cntx->sstatus & SR_FS) != SR_FS_OFF) { - if (riscv_isa_extension_available(isa, d)) + if (riscv_isa_extension_available(isa, D)) __kvm_riscv_fp_d_restore(cntx); - else if (riscv_isa_extension_available(isa, f)) + else if (riscv_isa_extension_available(isa, F)) __kvm_riscv_fp_f_restore(cntx); kvm_riscv_vcpu_fp_clean(cntx); } @@ -89,7 +89,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu, void *reg_val; if ((rtype == KVM_REG_RISCV_FP_F) && - riscv_isa_extension_available(vcpu->arch.isa, f)) { + riscv_isa_extension_available(vcpu->arch.isa, F)) { if (KVM_REG_SIZE(reg->id) != sizeof(u32)) return -EINVAL; if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr)) @@ -102,7 +102,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu, } else return -ENOENT; } else if ((rtype == KVM_REG_RISCV_FP_D) && - riscv_isa_extension_available(vcpu->arch.isa, d)) { + riscv_isa_extension_available(vcpu->arch.isa, D)) { if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) { if (KVM_REG_SIZE(reg->id) != sizeof(u32)) return -EINVAL; @@ -138,7 +138,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu, void *reg_val; if ((rtype == KVM_REG_RISCV_FP_F) && - riscv_isa_extension_available(vcpu->arch.isa, f)) { + riscv_isa_extension_available(vcpu->arch.isa, F)) { if (KVM_REG_SIZE(reg->id) != sizeof(u32)) return -EINVAL; if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr)) @@ -151,7 +151,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu, } else return -ENOENT; } else if ((rtype == KVM_REG_RISCV_FP_D) && - riscv_isa_extension_available(vcpu->arch.isa, d)) { + riscv_isa_extension_available(vcpu->arch.isa, D)) { if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) { if (KVM_REG_SIZE(reg->id) != sizeof(u32)) return -EINVAL; diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c index bb920e8923c930..5cc7ddd4aa2760 100644 --- a/arch/riscv/kvm/vcpu_onereg.c +++ b/arch/riscv/kvm/vcpu_onereg.c @@ -770,7 +770,7 @@ static inline unsigned long num_fp_f_regs(const struct kvm_vcpu *vcpu) { const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; - if (riscv_isa_extension_available(vcpu->arch.isa, f)) + if (riscv_isa_extension_available(vcpu->arch.isa, F)) return sizeof(cntx->fp.f) / sizeof(u32); else return 0; @@ -799,7 +799,7 @@ static inline unsigned long num_fp_d_regs(const struct kvm_vcpu *vcpu) { const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; - if (riscv_isa_extension_available(vcpu->arch.isa, d)) + if (riscv_isa_extension_available(vcpu->arch.isa, D)) return sizeof(cntx->fp.d.f) / sizeof(u64) + 1; else return 0; @@ -878,7 +878,7 @@ static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu) static inline unsigned long num_vector_regs(const struct kvm_vcpu *vcpu) { - if (!riscv_isa_extension_available(vcpu->arch.isa, v)) + if (!riscv_isa_extension_available(vcpu->arch.isa, V)) return 0; /* vstart, vl, vtype, vcsr, vlenb and 32 vector regs */ diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c index 62d2fb77bb9b93..f26108a4e601ea 100644 --- a/arch/riscv/kvm/vcpu_vector.c +++ b/arch/riscv/kvm/vcpu_vector.c @@ -26,7 +26,7 @@ void kvm_riscv_vcpu_vector_reset(struct kvm_vcpu *vcpu) cntx->vector.vlenb = riscv_v_vsize / 32; - if (riscv_isa_extension_available(isa, v)) { + if (riscv_isa_extension_available(isa, V)) { cntx->sstatus |= SR_VS_INITIAL; WARN_ON(!cntx->vector.datap); memset(cntx->vector.datap, 0, riscv_v_vsize); @@ -45,7 +45,7 @@ void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx, unsigned long *isa) { if ((cntx->sstatus & SR_VS) == SR_VS_DIRTY) { - if (riscv_isa_extension_available(isa, v)) + if (riscv_isa_extension_available(isa, V)) __kvm_riscv_vector_save(cntx); kvm_riscv_vcpu_vector_clean(cntx); } @@ -55,7 +55,7 @@ void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx, unsigned long *isa) { if ((cntx->sstatus & SR_VS) != SR_VS_OFF) { - if (riscv_isa_extension_available(isa, v)) + if (riscv_isa_extension_available(isa, V)) __kvm_riscv_vector_restore(cntx); kvm_riscv_vcpu_vector_clean(cntx); } @@ -154,7 +154,7 @@ int kvm_riscv_vcpu_get_reg_vector(struct kvm_vcpu *vcpu, void *reg_addr; int rc; - if (!riscv_isa_extension_available(isa, v)) + if (!riscv_isa_extension_available(isa, V)) return -ENOENT; rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, ®_addr); @@ -180,7 +180,7 @@ int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu, void *reg_addr; int rc; - if (!riscv_isa_extension_available(isa, v)) + if (!riscv_isa_extension_available(isa, V)) return -ENOENT; if (reg_num == KVM_REG_RISCV_VECTOR_CSR_REG(vlenb)) { diff --git a/tools/testing/selftests/riscv/hwprobe/which-cpus.c b/tools/testing/selftests/riscv/hwprobe/which-cpus.c index 587feb198c049e..f8c797b1d0fd98 100644 --- a/tools/testing/selftests/riscv/hwprobe/which-cpus.c +++ b/tools/testing/selftests/riscv/hwprobe/which-cpus.c @@ -105,7 +105,7 @@ int main(int argc, char **argv) pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, }; rc = riscv_hwprobe(pairs, 1, 0, NULL, 0); assert(rc == 0 && pairs[0].key == RISCV_HWPROBE_KEY_BASE_BEHAVIOR && - pairs[0].value == RISCV_HWPROBE_BASE_BEHAVIOR_IMA); + (pairs[0].value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA)); pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, }; rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);