[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v3 03/19] target/riscv: move riscv_cpu_validate_set_extension
From: |
Alistair Francis |
Subject: |
Re: [PATCH v3 03/19] target/riscv: move riscv_cpu_validate_set_extensions() to tcg-cpu.c |
Date: |
Fri, 22 Sep 2023 15:32:48 +1000 |
On Wed, Sep 20, 2023 at 10:25 PM Daniel Henrique Barboza
<dbarboza@ventanamicro.com> wrote:
>
> This function is the core of the RISC-V validations for TCG CPUs, and it
> has a lot going on.
>
> Functions in cpu.c were made public to allow them to be used by the KVM
> accelerator class later on. 'cpu_cfg_ext_get_min_version()' is notably
> hard to move it to another file due to its dependency with isa_edata_arr[]
> array, thus make it public and use it as is for now.
>
> riscv_cpu_validate_set_extensions() is kept public because it's used by
> csr.c in write_misa().
>
> Signed-off-by: Daniel Henrique Barboza <dbarboza@ventanamicro.com>
> Reviewed-by: Andrew Jones <ajones@ventanamicro.com>
> Reviewed-by: LIU Zhiwei <zhiwei_liu@linux.alibaba.com>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Alistair
> ---
> target/riscv/cpu.c | 361 +------------------------------------
> target/riscv/cpu.h | 8 +-
> target/riscv/csr.c | 1 +
> target/riscv/tcg/tcg-cpu.c | 357 ++++++++++++++++++++++++++++++++++++
> target/riscv/tcg/tcg-cpu.h | 27 +++
> 5 files changed, 397 insertions(+), 357 deletions(-)
> create mode 100644 target/riscv/tcg/tcg-cpu.h
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 030629294f..7215a29324 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -163,22 +163,21 @@ static const struct isa_ext_data isa_edata_arr[] = {
> /* Hash that stores user set extensions */
> static GHashTable *multi_ext_user_opts;
>
> -static bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset)
> +bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset)
> {
> bool *ext_enabled = (void *)&cpu->cfg + ext_offset;
>
> return *ext_enabled;
> }
>
> -static void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset,
> - bool en)
> +void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en)
> {
> bool *ext_enabled = (void *)&cpu->cfg + ext_offset;
>
> *ext_enabled = en;
> }
>
> -static int cpu_cfg_ext_get_min_version(uint32_t ext_offset)
> +int cpu_cfg_ext_get_min_version(uint32_t ext_offset)
> {
> int i;
>
> @@ -193,38 +192,12 @@ static int cpu_cfg_ext_get_min_version(uint32_t
> ext_offset)
> g_assert_not_reached();
> }
>
> -static bool cpu_cfg_ext_is_user_set(uint32_t ext_offset)
> +bool cpu_cfg_ext_is_user_set(uint32_t ext_offset)
> {
> return g_hash_table_contains(multi_ext_user_opts,
> GUINT_TO_POINTER(ext_offset));
> }
>
> -static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset,
> - bool value)
> -{
> - CPURISCVState *env = &cpu->env;
> - bool prev_val = isa_ext_is_enabled(cpu, ext_offset);
> - int min_version;
> -
> - if (prev_val == value) {
> - return;
> - }
> -
> - if (cpu_cfg_ext_is_user_set(ext_offset)) {
> - return;
> - }
> -
> - if (value && env->priv_ver != PRIV_VERSION_LATEST) {
> - /* Do not enable it if priv_ver is older than min_version */
> - min_version = cpu_cfg_ext_get_min_version(ext_offset);
> - if (env->priv_ver < min_version) {
> - return;
> - }
> - }
> -
> - isa_ext_update_enabled(cpu, ext_offset, value);
> -}
> -
> const char * const riscv_int_regnames[] = {
> "x0/zero", "x1/ra", "x2/sp", "x3/gp", "x4/tp", "x5/t0", "x6/t1",
> "x7/t2", "x8/s0", "x9/s1", "x10/a0", "x11/a1", "x12/a2", "x13/a3",
> @@ -1023,46 +996,7 @@ static void riscv_cpu_disas_set_info(CPUState *s,
> disassemble_info *info)
> }
> }
>
> -static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg,
> - Error **errp)
> -{
> - if (!is_power_of_2(cfg->vlen)) {
> - error_setg(errp, "Vector extension VLEN must be power of 2");
> - return;
> - }
> - if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) {
> - error_setg(errp,
> - "Vector extension implementation only supports VLEN "
> - "in the range [128, %d]", RV_VLEN_MAX);
> - return;
> - }
> - if (!is_power_of_2(cfg->elen)) {
> - error_setg(errp, "Vector extension ELEN must be power of 2");
> - return;
> - }
> - if (cfg->elen > 64 || cfg->elen < 8) {
> - error_setg(errp,
> - "Vector extension implementation only supports ELEN "
> - "in the range [8, 64]");
> - return;
> - }
> - if (cfg->vext_spec) {
> - if (!g_strcmp0(cfg->vext_spec, "v1.0")) {
> - env->vext_ver = VEXT_VERSION_1_00_0;
> - } else {
> - error_setg(errp, "Unsupported vector spec version '%s'",
> - cfg->vext_spec);
> - return;
> - }
> - } else if (env->vext_ver == 0) {
> - qemu_log("vector version is not specified, "
> - "use the default value v1.0\n");
> -
> - env->vext_ver = VEXT_VERSION_1_00_0;
> - }
> -}
> -
> -static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu)
> +void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu)
> {
> CPURISCVState *env = &cpu->env;
> int i;
> @@ -1086,291 +1020,6 @@ static void
> riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu)
> }
> }
>
> -/*
> - * Check consistency between chosen extensions while setting
> - * cpu->cfg accordingly.
> - */
> -void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
> -{
> - CPURISCVState *env = &cpu->env;
> - Error *local_err = NULL;
> -
> - /* Do some ISA extension error checking */
> - if (riscv_has_ext(env, RVG) &&
> - !(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) &&
> - riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) &&
> - riscv_has_ext(env, RVD) &&
> - cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) {
> -
> - if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_icsr)) &&
> - !cpu->cfg.ext_icsr) {
> - error_setg(errp, "RVG requires Zicsr but user set Zicsr to
> false");
> - return;
> - }
> -
> - if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_ifencei)) &&
> - !cpu->cfg.ext_ifencei) {
> - error_setg(errp, "RVG requires Zifencei but user set "
> - "Zifencei to false");
> - return;
> - }
> -
> - warn_report("Setting G will also set IMAFD_Zicsr_Zifencei");
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true);
> -
> - env->misa_ext |= RVI | RVM | RVA | RVF | RVD;
> - env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD;
> - }
> -
> - if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) {
> - error_setg(errp,
> - "I and E extensions are incompatible");
> - return;
> - }
> -
> - if (!riscv_has_ext(env, RVI) && !riscv_has_ext(env, RVE)) {
> - error_setg(errp,
> - "Either I or E extension must be set");
> - return;
> - }
> -
> - if (riscv_has_ext(env, RVS) && !riscv_has_ext(env, RVU)) {
> - error_setg(errp,
> - "Setting S extension without U extension is illegal");
> - return;
> - }
> -
> - if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVI)) {
> - error_setg(errp,
> - "H depends on an I base integer ISA with 32 x registers");
> - return;
> - }
> -
> - if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVS)) {
> - error_setg(errp, "H extension implicitly requires S-mode");
> - return;
> - }
> -
> - if (riscv_has_ext(env, RVF) && !cpu->cfg.ext_icsr) {
> - error_setg(errp, "F extension requires Zicsr");
> - return;
> - }
> -
> - if ((cpu->cfg.ext_zawrs) && !riscv_has_ext(env, RVA)) {
> - error_setg(errp, "Zawrs extension requires A extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zfa && !riscv_has_ext(env, RVF)) {
> - error_setg(errp, "Zfa extension requires F extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zfh) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zfhmin), true);
> - }
> -
> - if (cpu->cfg.ext_zfhmin && !riscv_has_ext(env, RVF)) {
> - error_setg(errp, "Zfh/Zfhmin extensions require F extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zfbfmin && !riscv_has_ext(env, RVF)) {
> - error_setg(errp, "Zfbfmin extension depends on F extension");
> - return;
> - }
> -
> - if (riscv_has_ext(env, RVD) && !riscv_has_ext(env, RVF)) {
> - error_setg(errp, "D extension requires F extension");
> - return;
> - }
> -
> - if (riscv_has_ext(env, RVV)) {
> - riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
> - if (local_err != NULL) {
> - error_propagate(errp, local_err);
> - return;
> - }
> -
> - /* The V vector extension depends on the Zve64d extension */
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64d), true);
> - }
> -
> - /* The Zve64d extension depends on the Zve64f extension */
> - if (cpu->cfg.ext_zve64d) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true);
> - }
> -
> - /* The Zve64f extension depends on the Zve32f extension */
> - if (cpu->cfg.ext_zve64f) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32f), true);
> - }
> -
> - if (cpu->cfg.ext_zve64d && !riscv_has_ext(env, RVD)) {
> - error_setg(errp, "Zve64d/V extensions require D extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zve32f && !riscv_has_ext(env, RVF)) {
> - error_setg(errp, "Zve32f/Zve64f extensions require F extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zvfh) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvfhmin), true);
> - }
> -
> - if (cpu->cfg.ext_zvfhmin && !cpu->cfg.ext_zve32f) {
> - error_setg(errp, "Zvfh/Zvfhmin extensions require Zve32f extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zvfh && !cpu->cfg.ext_zfhmin) {
> - error_setg(errp, "Zvfh extensions requires Zfhmin extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zfbfmin) {
> - error_setg(errp, "Zvfbfmin extension depends on Zfbfmin extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zve32f) {
> - error_setg(errp, "Zvfbfmin extension depends on Zve32f extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zvfbfwma && !cpu->cfg.ext_zvfbfmin) {
> - error_setg(errp, "Zvfbfwma extension depends on Zvfbfmin extension");
> - return;
> - }
> -
> - /* Set the ISA extensions, checks should have happened above */
> - if (cpu->cfg.ext_zhinx) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
> - }
> -
> - if ((cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinxmin) &&
> !cpu->cfg.ext_zfinx) {
> - error_setg(errp, "Zdinx/Zhinx/Zhinxmin extensions require Zfinx");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zfinx) {
> - if (!cpu->cfg.ext_icsr) {
> - error_setg(errp, "Zfinx extension requires Zicsr");
> - return;
> - }
> - if (riscv_has_ext(env, RVF)) {
> - error_setg(errp,
> - "Zfinx cannot be supported together with F
> extension");
> - return;
> - }
> - }
> -
> - if (cpu->cfg.ext_zce) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true);
> - if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true);
> - }
> - }
> -
> - /* zca, zcd and zcf has a PRIV 1.12.0 restriction */
> - if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
> - if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true);
> - }
> - if (riscv_has_ext(env, RVD)) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcd), true);
> - }
> - }
> -
> - if (env->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) {
> - error_setg(errp, "Zcf extension is only relevant to RV32");
> - return;
> - }
> -
> - if (!riscv_has_ext(env, RVF) && cpu->cfg.ext_zcf) {
> - error_setg(errp, "Zcf extension requires F extension");
> - return;
> - }
> -
> - if (!riscv_has_ext(env, RVD) && cpu->cfg.ext_zcd) {
> - error_setg(errp, "Zcd extension requires D extension");
> - return;
> - }
> -
> - if ((cpu->cfg.ext_zcf || cpu->cfg.ext_zcd || cpu->cfg.ext_zcb ||
> - cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt) && !cpu->cfg.ext_zca) {
> - error_setg(errp, "Zcf/Zcd/Zcb/Zcmp/Zcmt extensions require Zca "
> - "extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zcd && (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt)) {
> - error_setg(errp, "Zcmp/Zcmt extensions are incompatible with "
> - "Zcd extension");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zcmt && !cpu->cfg.ext_icsr) {
> - error_setg(errp, "Zcmt extension requires Zicsr extension");
> - return;
> - }
> -
> - /*
> - * In principle Zve*x would also suffice here, were they supported
> - * in qemu
> - */
> - if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned ||
> - cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || cpu->cfg.ext_zvksh) &&
> - !cpu->cfg.ext_zve32f) {
> - error_setg(errp,
> - "Vector crypto extensions require V or Zve* extensions");
> - return;
> - }
> -
> - if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) {
> - error_setg(
> - errp,
> - "Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions");
> - return;
> - }
> -
> - if (cpu->cfg.ext_zk) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkn), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkr), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkt), true);
> - }
> -
> - if (cpu->cfg.ext_zkn) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkne), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknd), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknh), true);
> - }
> -
> - if (cpu->cfg.ext_zks) {
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksed), true);
> - cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksh), true);
> - }
> -
> - /*
> - * Disable isa extensions based on priv spec after we
> - * validated and set everything we need.
> - */
> - riscv_cpu_disable_priv_spec_isa_exts(cpu);
> -}
> -
> #ifndef CONFIG_USER_ONLY
> static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
> {
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 16a2dfa8c7..409d198635 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -445,7 +445,6 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int
> size,
> bool probe, uintptr_t retaddr);
> char *riscv_isa_string(RISCVCPU *cpu);
> void riscv_cpu_list(void);
> -void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
>
> #define cpu_list riscv_cpu_list
> #define cpu_mmu_index riscv_cpu_mmu_index
> @@ -711,6 +710,13 @@ enum riscv_pmu_event_idx {
> #include "hw/core/tcg-cpu-ops.h"
> extern const struct TCGCPUOps riscv_tcg_ops;
>
> +/* used by tcg/tcg-cpu.c*/
> +void isa_ext_update_enabled(RISCVCPU *cpu, uint32_t ext_offset, bool en);
> +bool cpu_cfg_ext_is_user_set(uint32_t ext_offset);
> +bool isa_ext_is_enabled(RISCVCPU *cpu, uint32_t ext_offset);
> +int cpu_cfg_ext_get_min_version(uint32_t ext_offset);
> +void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu);
> +
> /* CSR function table */
> extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
>
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index 85a31dc420..4b4ab56c40 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -21,6 +21,7 @@
> #include "qemu/log.h"
> #include "qemu/timer.h"
> #include "cpu.h"
> +#include "tcg/tcg-cpu.h"
> #include "pmu.h"
> #include "time_helper.h"
> #include "exec/exec-all.h"
> diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
> index f47dc2064f..d86172f725 100644
> --- a/target/riscv/tcg/tcg-cpu.c
> +++ b/target/riscv/tcg/tcg-cpu.c
> @@ -19,14 +19,43 @@
>
> #include "qemu/osdep.h"
> #include "exec/exec-all.h"
> +#include "tcg-cpu.h"
> #include "cpu.h"
> #include "pmu.h"
> #include "time_helper.h"
> #include "qapi/error.h"
> #include "qemu/accel.h"
> +#include "qemu/error-report.h"
> +#include "qemu/log.h"
> #include "hw/core/accel-cpu.h"
>
>
> +static void cpu_cfg_ext_auto_update(RISCVCPU *cpu, uint32_t ext_offset,
> + bool value)
> +{
> + CPURISCVState *env = &cpu->env;
> + bool prev_val = isa_ext_is_enabled(cpu, ext_offset);
> + int min_version;
> +
> + if (prev_val == value) {
> + return;
> + }
> +
> + if (cpu_cfg_ext_is_user_set(ext_offset)) {
> + return;
> + }
> +
> + if (value && env->priv_ver != PRIV_VERSION_LATEST) {
> + /* Do not enable it if priv_ver is older than min_version */
> + min_version = cpu_cfg_ext_get_min_version(ext_offset);
> + if (env->priv_ver < min_version) {
> + return;
> + }
> + }
> +
> + isa_ext_update_enabled(cpu, ext_offset, value);
> +}
> +
> static void riscv_cpu_validate_misa_priv(CPURISCVState *env, Error **errp)
> {
> if (riscv_has_ext(env, RVH) && env->priv_ver < PRIV_VERSION_1_12_0) {
> @@ -85,6 +114,334 @@ static void riscv_cpu_validate_priv_spec(RISCVCPU *cpu,
> Error **errp)
> }
> }
>
> +static void riscv_cpu_validate_v(CPURISCVState *env, RISCVCPUConfig *cfg,
> + Error **errp)
> +{
> + if (!is_power_of_2(cfg->vlen)) {
> + error_setg(errp, "Vector extension VLEN must be power of 2");
> + return;
> + }
> +
> + if (cfg->vlen > RV_VLEN_MAX || cfg->vlen < 128) {
> + error_setg(errp,
> + "Vector extension implementation only supports VLEN "
> + "in the range [128, %d]", RV_VLEN_MAX);
> + return;
> + }
> +
> + if (!is_power_of_2(cfg->elen)) {
> + error_setg(errp, "Vector extension ELEN must be power of 2");
> + return;
> + }
> +
> + if (cfg->elen > 64 || cfg->elen < 8) {
> + error_setg(errp,
> + "Vector extension implementation only supports ELEN "
> + "in the range [8, 64]");
> + return;
> + }
> +
> + if (cfg->vext_spec) {
> + if (!g_strcmp0(cfg->vext_spec, "v1.0")) {
> + env->vext_ver = VEXT_VERSION_1_00_0;
> + } else {
> + error_setg(errp, "Unsupported vector spec version '%s'",
> + cfg->vext_spec);
> + return;
> + }
> + } else if (env->vext_ver == 0) {
> + qemu_log("vector version is not specified, "
> + "use the default value v1.0\n");
> +
> + env->vext_ver = VEXT_VERSION_1_00_0;
> + }
> +}
> +
> +/*
> + * Check consistency between chosen extensions while setting
> + * cpu->cfg accordingly.
> + */
> +void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
> +{
> + CPURISCVState *env = &cpu->env;
> + Error *local_err = NULL;
> +
> + /* Do some ISA extension error checking */
> + if (riscv_has_ext(env, RVG) &&
> + !(riscv_has_ext(env, RVI) && riscv_has_ext(env, RVM) &&
> + riscv_has_ext(env, RVA) && riscv_has_ext(env, RVF) &&
> + riscv_has_ext(env, RVD) &&
> + cpu->cfg.ext_icsr && cpu->cfg.ext_ifencei)) {
> +
> + if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_icsr)) &&
> + !cpu->cfg.ext_icsr) {
> + error_setg(errp, "RVG requires Zicsr but user set Zicsr to
> false");
> + return;
> + }
> +
> + if (cpu_cfg_ext_is_user_set(CPU_CFG_OFFSET(ext_ifencei)) &&
> + !cpu->cfg.ext_ifencei) {
> + error_setg(errp, "RVG requires Zifencei but user set "
> + "Zifencei to false");
> + return;
> + }
> +
> + warn_report("Setting G will also set IMAFD_Zicsr_Zifencei");
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_icsr), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_ifencei), true);
> +
> + env->misa_ext |= RVI | RVM | RVA | RVF | RVD;
> + env->misa_ext_mask |= RVI | RVM | RVA | RVF | RVD;
> + }
> +
> + if (riscv_has_ext(env, RVI) && riscv_has_ext(env, RVE)) {
> + error_setg(errp,
> + "I and E extensions are incompatible");
> + return;
> + }
> +
> + if (!riscv_has_ext(env, RVI) && !riscv_has_ext(env, RVE)) {
> + error_setg(errp,
> + "Either I or E extension must be set");
> + return;
> + }
> +
> + if (riscv_has_ext(env, RVS) && !riscv_has_ext(env, RVU)) {
> + error_setg(errp,
> + "Setting S extension without U extension is illegal");
> + return;
> + }
> +
> + if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVI)) {
> + error_setg(errp,
> + "H depends on an I base integer ISA with 32 x registers");
> + return;
> + }
> +
> + if (riscv_has_ext(env, RVH) && !riscv_has_ext(env, RVS)) {
> + error_setg(errp, "H extension implicitly requires S-mode");
> + return;
> + }
> +
> + if (riscv_has_ext(env, RVF) && !cpu->cfg.ext_icsr) {
> + error_setg(errp, "F extension requires Zicsr");
> + return;
> + }
> +
> + if ((cpu->cfg.ext_zawrs) && !riscv_has_ext(env, RVA)) {
> + error_setg(errp, "Zawrs extension requires A extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zfa && !riscv_has_ext(env, RVF)) {
> + error_setg(errp, "Zfa extension requires F extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zfh) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zfhmin), true);
> + }
> +
> + if (cpu->cfg.ext_zfhmin && !riscv_has_ext(env, RVF)) {
> + error_setg(errp, "Zfh/Zfhmin extensions require F extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zfbfmin && !riscv_has_ext(env, RVF)) {
> + error_setg(errp, "Zfbfmin extension depends on F extension");
> + return;
> + }
> +
> + if (riscv_has_ext(env, RVD) && !riscv_has_ext(env, RVF)) {
> + error_setg(errp, "D extension requires F extension");
> + return;
> + }
> +
> + if (riscv_has_ext(env, RVV)) {
> + riscv_cpu_validate_v(env, &cpu->cfg, &local_err);
> + if (local_err != NULL) {
> + error_propagate(errp, local_err);
> + return;
> + }
> +
> + /* The V vector extension depends on the Zve64d extension */
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64d), true);
> + }
> +
> + /* The Zve64d extension depends on the Zve64f extension */
> + if (cpu->cfg.ext_zve64d) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true);
> + }
> +
> + /* The Zve64f extension depends on the Zve32f extension */
> + if (cpu->cfg.ext_zve64f) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32f), true);
> + }
> +
> + if (cpu->cfg.ext_zve64d && !riscv_has_ext(env, RVD)) {
> + error_setg(errp, "Zve64d/V extensions require D extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zve32f && !riscv_has_ext(env, RVF)) {
> + error_setg(errp, "Zve32f/Zve64f extensions require F extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zvfh) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvfhmin), true);
> + }
> +
> + if (cpu->cfg.ext_zvfhmin && !cpu->cfg.ext_zve32f) {
> + error_setg(errp, "Zvfh/Zvfhmin extensions require Zve32f extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zvfh && !cpu->cfg.ext_zfhmin) {
> + error_setg(errp, "Zvfh extensions requires Zfhmin extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zfbfmin) {
> + error_setg(errp, "Zvfbfmin extension depends on Zfbfmin extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zvfbfmin && !cpu->cfg.ext_zve32f) {
> + error_setg(errp, "Zvfbfmin extension depends on Zve32f extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zvfbfwma && !cpu->cfg.ext_zvfbfmin) {
> + error_setg(errp, "Zvfbfwma extension depends on Zvfbfmin extension");
> + return;
> + }
> +
> + /* Set the ISA extensions, checks should have happened above */
> + if (cpu->cfg.ext_zhinx) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
> + }
> +
> + if ((cpu->cfg.ext_zdinx || cpu->cfg.ext_zhinxmin) &&
> !cpu->cfg.ext_zfinx) {
> + error_setg(errp, "Zdinx/Zhinx/Zhinxmin extensions require Zfinx");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zfinx) {
> + if (!cpu->cfg.ext_icsr) {
> + error_setg(errp, "Zfinx extension requires Zicsr");
> + return;
> + }
> + if (riscv_has_ext(env, RVF)) {
> + error_setg(errp,
> + "Zfinx cannot be supported together with F
> extension");
> + return;
> + }
> + }
> +
> + if (cpu->cfg.ext_zce) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcb), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmp), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcmt), true);
> + if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true);
> + }
> + }
> +
> + /* zca, zcd and zcf has a PRIV 1.12.0 restriction */
> + if (riscv_has_ext(env, RVC) && env->priv_ver >= PRIV_VERSION_1_12_0) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zca), true);
> + if (riscv_has_ext(env, RVF) && env->misa_mxl_max == MXL_RV32) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcf), true);
> + }
> + if (riscv_has_ext(env, RVD)) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zcd), true);
> + }
> + }
> +
> + if (env->misa_mxl_max != MXL_RV32 && cpu->cfg.ext_zcf) {
> + error_setg(errp, "Zcf extension is only relevant to RV32");
> + return;
> + }
> +
> + if (!riscv_has_ext(env, RVF) && cpu->cfg.ext_zcf) {
> + error_setg(errp, "Zcf extension requires F extension");
> + return;
> + }
> +
> + if (!riscv_has_ext(env, RVD) && cpu->cfg.ext_zcd) {
> + error_setg(errp, "Zcd extension requires D extension");
> + return;
> + }
> +
> + if ((cpu->cfg.ext_zcf || cpu->cfg.ext_zcd || cpu->cfg.ext_zcb ||
> + cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt) && !cpu->cfg.ext_zca) {
> + error_setg(errp, "Zcf/Zcd/Zcb/Zcmp/Zcmt extensions require Zca "
> + "extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zcd && (cpu->cfg.ext_zcmp || cpu->cfg.ext_zcmt)) {
> + error_setg(errp, "Zcmp/Zcmt extensions are incompatible with "
> + "Zcd extension");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zcmt && !cpu->cfg.ext_icsr) {
> + error_setg(errp, "Zcmt extension requires Zicsr extension");
> + return;
> + }
> +
> + /*
> + * In principle Zve*x would also suffice here, were they supported
> + * in qemu
> + */
> + if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned ||
> + cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || cpu->cfg.ext_zvksh) &&
> + !cpu->cfg.ext_zve32f) {
> + error_setg(errp,
> + "Vector crypto extensions require V or Zve* extensions");
> + return;
> + }
> +
> + if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) {
> + error_setg(
> + errp,
> + "Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions");
> + return;
> + }
> +
> + if (cpu->cfg.ext_zk) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkn), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkr), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkt), true);
> + }
> +
> + if (cpu->cfg.ext_zkn) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zkne), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknd), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zknh), true);
> + }
> +
> + if (cpu->cfg.ext_zks) {
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkb), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkc), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zbkx), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksed), true);
> + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zksh), true);
> + }
> +
> + /*
> + * Disable isa extensions based on priv spec after we
> + * validated and set everything we need.
> + */
> + riscv_cpu_disable_priv_spec_isa_exts(cpu);
> +}
> +
> /*
> * We'll get here via the following path:
> *
> diff --git a/target/riscv/tcg/tcg-cpu.h b/target/riscv/tcg/tcg-cpu.h
> new file mode 100644
> index 0000000000..630184759d
> --- /dev/null
> +++ b/target/riscv/tcg/tcg-cpu.h
> @@ -0,0 +1,27 @@
> +/*
> + * riscv TCG cpu class initialization
> + *
> + * Copyright (c) 2023 Ventana Micro Systems Inc.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see
> <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef RISCV_TCG_CPU_H
> +#define RISCV_TCG_CPU_H
> +
> +#include "cpu.h"
> +
> +void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp);
> +
> +#endif
> --
> 2.41.0
>
>
- [PATCH v3 00/19] riscv: split TCG/KVM accelerators from cpu.c, Daniel Henrique Barboza, 2023/09/20
- [PATCH v3 03/19] target/riscv: move riscv_cpu_validate_set_extensions() to tcg-cpu.c, Daniel Henrique Barboza, 2023/09/20
- Re: [PATCH v3 03/19] target/riscv: move riscv_cpu_validate_set_extensions() to tcg-cpu.c,
Alistair Francis <=
- [PATCH v3 04/19] target/riscv: move riscv_tcg_ops to tcg-cpu.c, Daniel Henrique Barboza, 2023/09/20
- [PATCH v3 05/19] target/riscv/cpu.c: add .instance_post_init(), Daniel Henrique Barboza, 2023/09/20
- [PATCH v3 06/19] target/riscv: move 'host' CPU declaration to kvm.c, Daniel Henrique Barboza, 2023/09/20
- [PATCH v3 07/19] target/riscv/cpu.c: mark extensions arrays as 'const', Daniel Henrique Barboza, 2023/09/20
- [PATCH v3 08/19] target/riscv: move riscv_cpu_add_kvm_properties() to kvm.c, Daniel Henrique Barboza, 2023/09/20