From c76b121840c6ca79dc6305a5f4bcf17c72217d9c Mon Sep 17 00:00:00 2001 From: "yang.zhang" Date: Tue, 9 Apr 2024 09:44:45 +0800 Subject: [PATCH 01/27] hw/intc/riscv_aplic: APLICs should add child earlier than realize Since only root APLICs can have hw IRQ lines, aplic->parent should be initialized first. Fixes: e8f79343cf ("hw/intc: Add RISC-V AIA APLIC device emulation") Reviewed-by: Daniel Henrique Barboza Signed-off-by: yang.zhang Cc: qemu-stable Message-ID: <20240409014445.278-1-gaoshanliukou@163.com> Signed-off-by: Alistair Francis --- hw/intc/riscv_aplic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index fc5df0d598..32edd6d07b 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -1000,16 +1000,16 @@ DeviceState *riscv_aplic_create(hwaddr addr, hwaddr size, qdev_prop_set_bit(dev, "msimode", msimode); qdev_prop_set_bit(dev, "mmode", mmode); + if (parent) { + riscv_aplic_add_child(parent, dev); + } + sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); if (!is_kvm_aia(msimode)) { sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); } - if (parent) { - riscv_aplic_add_child(parent, dev); - } - if (!msimode) { for (i = 0; i < num_harts; i++) { CPUState *cpu = cpu_by_arch_id(hartid_base + i); From 86997772fa807f3961e5aeed97af7738adec1b43 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Mon, 22 Apr 2024 15:46:06 +0200 Subject: [PATCH 02/27] target/riscv/kvm: Fix exposure of Zkr The Zkr extension may only be exposed to KVM guests if the VMM implements the SEED CSR. Use the same implementation as TCG. Without this patch, running with a KVM which does not forward the SEED CSR access to QEMU will result in an ILL exception being injected into the guest (this results in Linux guests crashing on boot). And, when running with a KVM which does forward the access, QEMU will crash, since QEMU doesn't know what to do with the exit. Fixes: 3108e2f1c69d ("target/riscv/kvm: update KVM exts to Linux 6.8") Signed-off-by: Andrew Jones Reviewed-by: Daniel Henrique Barboza Cc: qemu-stable Message-ID: <20240422134605.534207-2-ajones@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 3 +++ target/riscv/csr.c | 18 ++++++++++++++---- target/riscv/kvm/kvm-cpu.c | 25 +++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 2d0c02c35b..746efd099a 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -819,6 +819,9 @@ void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops); void riscv_cpu_register_gdb_regs_for_features(CPUState *cs); +target_ulong riscv_new_csr_seed(target_ulong new_value, + target_ulong write_mask); + uint8_t satp_mode_max_from_map(uint32_t map); const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit); diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 726096444f..829d8346ed 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -4267,10 +4267,8 @@ static RISCVException write_upmbase(CPURISCVState *env, int csrno, #endif /* Crypto Extension */ -static RISCVException rmw_seed(CPURISCVState *env, int csrno, - target_ulong *ret_value, - target_ulong new_value, - target_ulong write_mask) +target_ulong riscv_new_csr_seed(target_ulong new_value, + target_ulong write_mask) { uint16_t random_v; Error *random_e = NULL; @@ -4294,6 +4292,18 @@ static RISCVException rmw_seed(CPURISCVState *env, int csrno, rval = random_v | SEED_OPST_ES16; } + return rval; +} + +static RISCVException rmw_seed(CPURISCVState *env, int csrno, + target_ulong *ret_value, + target_ulong new_value, + target_ulong write_mask) +{ + target_ulong rval; + + rval = riscv_new_csr_seed(new_value, write_mask); + if (ret_value) { *ret_value = rval; } diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index eaa36121c7..b8136c7ef8 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -1418,6 +1418,28 @@ static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run) return ret; } +static int kvm_riscv_handle_csr(CPUState *cs, struct kvm_run *run) +{ + target_ulong csr_num = run->riscv_csr.csr_num; + target_ulong new_value = run->riscv_csr.new_value; + target_ulong write_mask = run->riscv_csr.write_mask; + int ret = 0; + + switch (csr_num) { + case CSR_SEED: + run->riscv_csr.ret_value = riscv_new_csr_seed(new_value, write_mask); + break; + default: + qemu_log_mask(LOG_UNIMP, + "%s: un-handled CSR EXIT for CSR %lx\n", + __func__, csr_num); + ret = -1; + break; + } + + return ret; +} + int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) { int ret = 0; @@ -1425,6 +1447,9 @@ int kvm_arch_handle_exit(CPUState *cs, struct kvm_run *run) case KVM_EXIT_RISCV_SBI: ret = kvm_riscv_handle_sbi(cs, run); break; + case KVM_EXIT_RISCV_CSR: + ret = kvm_riscv_handle_csr(cs, run); + break; default: qemu_log_mask(LOG_UNIMP, "%s: un-handled exit reason %d\n", __func__, run->exit_reason); From b62e0ce76098d53c875f0aff70776f08418ccb58 Mon Sep 17 00:00:00 2001 From: Andrew Jones Date: Wed, 24 Apr 2024 16:28:09 +0200 Subject: [PATCH 03/27] target/riscv: Raise exceptions on wrs.nto MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implementing wrs.nto to always just return is consistent with the specification, as the instruction is permitted to terminate the stall for any reason, but it's not useful for virtualization, where we'd like the guest to trap to the hypervisor in order to allow scheduling of the lock holding VCPU. Change to always immediately raise exceptions when the appropriate conditions are present, otherwise continue to just return. Note, immediately raising exceptions is also consistent with the specification since the time limit that should expire prior to the exception is implementation-specific. Signed-off-by: Andrew Jones Reviewed-by: Christoph Müllner Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20240424142808.62936-2-ajones@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/helper.h | 1 + target/riscv/insn_trans/trans_rvzawrs.c.inc | 29 ++++++++++++++------- target/riscv/op_helper.c | 11 ++++++++ 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/target/riscv/helper.h b/target/riscv/helper.h index 8a63523851..451261ce5a 100644 --- a/target/riscv/helper.h +++ b/target/riscv/helper.h @@ -132,6 +132,7 @@ DEF_HELPER_6(csrrw_i128, tl, env, int, tl, tl, tl, tl) DEF_HELPER_1(sret, tl, env) DEF_HELPER_1(mret, tl, env) DEF_HELPER_1(wfi, void, env) +DEF_HELPER_1(wrs_nto, void, env) DEF_HELPER_1(tlb_flush, void, env) DEF_HELPER_1(tlb_flush_all, void, env) /* Native Debug */ diff --git a/target/riscv/insn_trans/trans_rvzawrs.c.inc b/target/riscv/insn_trans/trans_rvzawrs.c.inc index 32efbff4d5..0eef033838 100644 --- a/target/riscv/insn_trans/trans_rvzawrs.c.inc +++ b/target/riscv/insn_trans/trans_rvzawrs.c.inc @@ -16,7 +16,7 @@ * this program. If not, see . */ -static bool trans_wrs(DisasContext *ctx) +static bool trans_wrs_sto(DisasContext *ctx, arg_wrs_sto *a) { if (!ctx->cfg_ptr->ext_zawrs) { return false; @@ -40,12 +40,23 @@ static bool trans_wrs(DisasContext *ctx) return true; } -#define GEN_TRANS_WRS(insn) \ -static bool trans_ ## insn(DisasContext *ctx, arg_ ## insn *a) \ -{ \ - (void)a; \ - return trans_wrs(ctx); \ -} +static bool trans_wrs_nto(DisasContext *ctx, arg_wrs_nto *a) +{ + if (!ctx->cfg_ptr->ext_zawrs) { + return false; + } -GEN_TRANS_WRS(wrs_nto) -GEN_TRANS_WRS(wrs_sto) + /* + * Depending on the mode of execution, mstatus.TW and hstatus.VTW, wrs.nto + * should raise an exception when the implementation-specific bounded time + * limit has expired. Our time limit is zero, so we either return + * immediately, as does our implementation of wrs.sto, or raise an + * exception, as handled by the wrs.nto helper. + */ +#ifndef CONFIG_USER_ONLY + gen_helper_wrs_nto(tcg_env); +#endif + + /* We only get here when helper_wrs_nto() doesn't raise an exception. */ + return trans_wrs_sto(ctx, NULL); +} diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index f414aaebdb..2baf5bc3ca 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -380,6 +380,17 @@ void helper_wfi(CPURISCVState *env) } } +void helper_wrs_nto(CPURISCVState *env) +{ + if (env->virt_enabled && (env->priv == PRV_S || env->priv == PRV_U) && + get_field(env->hstatus, HSTATUS_VTW) && + !get_field(env->mstatus, MSTATUS_TW)) { + riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, GETPC()); + } else if (env->priv != PRV_M && get_field(env->mstatus, MSTATUS_TW)) { + riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); + } +} + void helper_tlb_flush(CPURISCVState *env) { CPUState *cs = env_cpu(env); From a6b53378f537a51355a49826b7d119698c74ffba Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Thu, 25 Apr 2024 12:50:12 -0300 Subject: [PATCH 04/27] target/riscv/kvm: implement SBI debug console (DBCN) calls SBI defines a Debug Console extension "DBCN" that will, in time, replace the legacy console putchar and getchar SBI extensions. The appeal of the DBCN extension is that it allows multiple bytes to be read/written in the SBI console in a single SBI call. As far as KVM goes, the DBCN calls are forwarded by an in-kernel KVM module to userspace. But this will only happens if the KVM module actually supports this SBI extension and we activate it. We'll check for DBCN support during init time, checking if get-reg-list is advertising KVM_RISCV_SBI_EXT_DBCN. In that case, we'll enable it via kvm_set_one_reg() during kvm_arch_init_vcpu(). Finally, change kvm_riscv_handle_sbi() to handle the incoming calls for SBI_EXT_DBCN, reading and writing as required. A simple KVM guest with 'earlycon=sbi', running in an emulated RISC-V host, takes around 20 seconds to boot without using DBCN. With this patch we're taking around 14 seconds to boot due to the speed-up in the terminal output. There's no change in boot time if the guest isn't using earlycon. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Message-ID: <20240425155012.581366-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 111 +++++++++++++++++++++++++++++ target/riscv/sbi_ecall_interface.h | 17 +++++ 2 files changed, 128 insertions(+) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index b8136c7ef8..d2491d84e2 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -409,6 +409,12 @@ static KVMCPUConfig kvm_v_vlenb = { KVM_REG_RISCV_VECTOR_CSR_REG(vlenb) }; +static KVMCPUConfig kvm_sbi_dbcn = { + .name = "sbi_dbcn", + .kvm_reg_id = KVM_REG_RISCV | KVM_REG_SIZE_U64 | + KVM_REG_RISCV_SBI_EXT | KVM_RISCV_SBI_EXT_DBCN +}; + static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) { CPURISCVState *env = &cpu->env; @@ -1037,6 +1043,20 @@ static int uint64_cmp(const void *a, const void *b) return 0; } +static void kvm_riscv_check_sbi_dbcn_support(RISCVCPU *cpu, + KVMScratchCPU *kvmcpu, + struct kvm_reg_list *reglist) +{ + struct kvm_reg_list *reg_search; + + reg_search = bsearch(&kvm_sbi_dbcn.kvm_reg_id, reglist->reg, reglist->n, + sizeof(uint64_t), uint64_cmp); + + if (reg_search) { + kvm_sbi_dbcn.supported = true; + } +} + static void kvm_riscv_read_vlenb(RISCVCPU *cpu, KVMScratchCPU *kvmcpu, struct kvm_reg_list *reglist) { @@ -1142,6 +1162,8 @@ static void kvm_riscv_init_multiext_cfg(RISCVCPU *cpu, KVMScratchCPU *kvmcpu) if (riscv_has_ext(&cpu->env, RVV)) { kvm_riscv_read_vlenb(cpu, kvmcpu, reglist); } + + kvm_riscv_check_sbi_dbcn_support(cpu, kvmcpu, reglist); } static void riscv_init_kvm_registers(Object *cpu_obj) @@ -1316,6 +1338,17 @@ static int kvm_vcpu_set_machine_ids(RISCVCPU *cpu, CPUState *cs) return ret; } +static int kvm_vcpu_enable_sbi_dbcn(RISCVCPU *cpu, CPUState *cs) +{ + target_ulong reg = 1; + + if (!kvm_sbi_dbcn.supported) { + return 0; + } + + return kvm_set_one_reg(cs, kvm_sbi_dbcn.kvm_reg_id, ®); +} + int kvm_arch_init_vcpu(CPUState *cs) { int ret = 0; @@ -1333,6 +1366,8 @@ int kvm_arch_init_vcpu(CPUState *cs) kvm_riscv_update_cpu_misa_ext(cpu, cs); kvm_riscv_update_cpu_cfg_isa_ext(cpu, cs); + ret = kvm_vcpu_enable_sbi_dbcn(cpu, cs); + return ret; } @@ -1390,6 +1425,79 @@ bool kvm_arch_stop_on_emulation_error(CPUState *cs) return true; } +static void kvm_riscv_handle_sbi_dbcn(CPUState *cs, struct kvm_run *run) +{ + g_autofree uint8_t *buf = NULL; + RISCVCPU *cpu = RISCV_CPU(cs); + target_ulong num_bytes; + uint64_t addr; + unsigned char ch; + int ret; + + switch (run->riscv_sbi.function_id) { + case SBI_EXT_DBCN_CONSOLE_READ: + case SBI_EXT_DBCN_CONSOLE_WRITE: + num_bytes = run->riscv_sbi.args[0]; + + if (num_bytes == 0) { + run->riscv_sbi.ret[0] = SBI_SUCCESS; + run->riscv_sbi.ret[1] = 0; + break; + } + + addr = run->riscv_sbi.args[1]; + + /* + * Handle the case where a 32 bit CPU is running in a + * 64 bit addressing env. + */ + if (riscv_cpu_mxl(&cpu->env) == MXL_RV32) { + addr |= (uint64_t)run->riscv_sbi.args[2] << 32; + } + + buf = g_malloc0(num_bytes); + + if (run->riscv_sbi.function_id == SBI_EXT_DBCN_CONSOLE_READ) { + ret = qemu_chr_fe_read_all(serial_hd(0)->be, buf, num_bytes); + if (ret < 0) { + error_report("SBI_EXT_DBCN_CONSOLE_READ: error when " + "reading chardev"); + exit(1); + } + + cpu_physical_memory_write(addr, buf, ret); + } else { + cpu_physical_memory_read(addr, buf, num_bytes); + + ret = qemu_chr_fe_write_all(serial_hd(0)->be, buf, num_bytes); + if (ret < 0) { + error_report("SBI_EXT_DBCN_CONSOLE_WRITE: error when " + "writing chardev"); + exit(1); + } + } + + run->riscv_sbi.ret[0] = SBI_SUCCESS; + run->riscv_sbi.ret[1] = ret; + break; + case SBI_EXT_DBCN_CONSOLE_WRITE_BYTE: + ch = run->riscv_sbi.args[0]; + ret = qemu_chr_fe_write(serial_hd(0)->be, &ch, sizeof(ch)); + + if (ret < 0) { + error_report("SBI_EXT_DBCN_CONSOLE_WRITE_BYTE: error when " + "writing chardev"); + exit(1); + } + + run->riscv_sbi.ret[0] = SBI_SUCCESS; + run->riscv_sbi.ret[1] = 0; + break; + default: + run->riscv_sbi.ret[0] = SBI_ERR_NOT_SUPPORTED; + } +} + static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run) { int ret = 0; @@ -1408,6 +1516,9 @@ static int kvm_riscv_handle_sbi(CPUState *cs, struct kvm_run *run) } ret = 0; break; + case SBI_EXT_DBCN: + kvm_riscv_handle_sbi_dbcn(cs, run); + break; default: qemu_log_mask(LOG_UNIMP, "%s: un-handled SBI EXIT, specific reasons is %lu\n", diff --git a/target/riscv/sbi_ecall_interface.h b/target/riscv/sbi_ecall_interface.h index 43899d08f6..7dfe5f72c6 100644 --- a/target/riscv/sbi_ecall_interface.h +++ b/target/riscv/sbi_ecall_interface.h @@ -12,6 +12,17 @@ /* clang-format off */ +#define SBI_SUCCESS 0 +#define SBI_ERR_FAILED -1 +#define SBI_ERR_NOT_SUPPORTED -2 +#define SBI_ERR_INVALID_PARAM -3 +#define SBI_ERR_DENIED -4 +#define SBI_ERR_INVALID_ADDRESS -5 +#define SBI_ERR_ALREADY_AVAILABLE -6 +#define SBI_ERR_ALREADY_STARTED -7 +#define SBI_ERR_ALREADY_STOPPED -8 +#define SBI_ERR_NO_SHMEM -9 + /* SBI Extension IDs */ #define SBI_EXT_0_1_SET_TIMER 0x0 #define SBI_EXT_0_1_CONSOLE_PUTCHAR 0x1 @@ -27,6 +38,7 @@ #define SBI_EXT_IPI 0x735049 #define SBI_EXT_RFENCE 0x52464E43 #define SBI_EXT_HSM 0x48534D +#define SBI_EXT_DBCN 0x4442434E /* SBI function IDs for BASE extension */ #define SBI_EXT_BASE_GET_SPEC_VERSION 0x0 @@ -57,6 +69,11 @@ #define SBI_EXT_HSM_HART_STOP 0x1 #define SBI_EXT_HSM_HART_GET_STATUS 0x2 +/* SBI function IDs for DBCN extension */ +#define SBI_EXT_DBCN_CONSOLE_WRITE 0x0 +#define SBI_EXT_DBCN_CONSOLE_READ 0x1 +#define SBI_EXT_DBCN_CONSOLE_WRITE_BYTE 0x2 + #define SBI_HSM_HART_STATUS_STARTED 0x0 #define SBI_HSM_HART_STATUS_STOPPED 0x1 #define SBI_HSM_HART_STATUS_START_PENDING 0x2 From 039003995047b2f7911142c7c5cfb845fda044fd Mon Sep 17 00:00:00 2001 From: Cheng Yang Date: Mon, 1 Apr 2024 15:51:22 +0800 Subject: [PATCH 05/27] hw/riscv/boot.c: Support 64-bit address for initrd Use qemu_fdt_setprop_u64() instead of qemu_fdt_setprop_cell() to set the address of initrd in FDT to support 64-bit address. Signed-off-by: Cheng Yang Reviewed-by: Alistair Francis Message-ID: Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 09878e722c..47281ca853 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -209,8 +209,8 @@ static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) /* Some RISC-V machines (e.g. opentitan) don't have a fdt. */ if (fdt) { end = start + size; - qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-start", start); - qemu_fdt_setprop_cell(fdt, "/chosen", "linux,initrd-end", end); + qemu_fdt_setprop_u64(fdt, "/chosen", "linux,initrd-start", start); + qemu_fdt_setprop_u64(fdt, "/chosen", "linux,initrd-end", end); } } From ba7a1c52975a4068573deea4471535567393c366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20L=C3=A9ger?= Date: Mon, 22 Apr 2024 15:58:36 +0200 Subject: [PATCH 06/27] target/riscv: change RISCV_EXCP_SEMIHOST exception number to 63 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current semihost exception number (16) is a reserved number (range [16-17]). The upcoming double trap specification uses that number for the double trap exception. Since the privileged spec (Table 22) defines ranges for custom uses change the semihosting exception number to 63 which belongs to the range [48-63] in order to avoid any future collisions with reserved exception. Signed-off-by: Clément Léger Reviewed-by: Alistair Francis Message-ID: <20240422135840.1959967-1-cleger@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_bits.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h index fc2068ee4d..74318a925c 100644 --- a/target/riscv/cpu_bits.h +++ b/target/riscv/cpu_bits.h @@ -670,11 +670,11 @@ typedef enum RISCVException { RISCV_EXCP_INST_PAGE_FAULT = 0xc, /* since: priv-1.10.0 */ RISCV_EXCP_LOAD_PAGE_FAULT = 0xd, /* since: priv-1.10.0 */ RISCV_EXCP_STORE_PAGE_FAULT = 0xf, /* since: priv-1.10.0 */ - RISCV_EXCP_SEMIHOST = 0x10, RISCV_EXCP_INST_GUEST_PAGE_FAULT = 0x14, RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT = 0x15, RISCV_EXCP_VIRT_INSTRUCTION_FAULT = 0x16, RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT = 0x17, + RISCV_EXCP_SEMIHOST = 0x3f, } RISCVException; #define RISCV_EXCP_INT_FLAG 0x80000000 From 1215d45b2aa97512a2867e401aa59f3d0c23cb23 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Mon, 22 Apr 2024 14:14:25 -0300 Subject: [PATCH 07/27] target/riscv/kvm: tolerate KVM disable ext errors Running a KVM guest using a 6.9-rc3 kernel, in a 6.8 host that has zkr enabled, will fail with a kernel oops SIGILL right at the start. The reason is that we can't expose zkr without implementing the SEED CSR. Disabling zkr in the guest would be a workaround, but if the KVM doesn't allow it we'll error out and never boot. In hindsight this is too strict. If we keep proceeding, despite not disabling the extension in the KVM vcpu, we'll not add the extension in the riscv,isa. The guest kernel will be unaware of the extension, i.e. it doesn't matter if the KVM vcpu has it enabled underneath or not. So it's ok to keep booting in this case. Change our current logic to not error out if we fail to disable an extension in kvm_set_one_reg(), but show a warning and keep booting. It is important to throw a warning because we must make the user aware that the extension is still available in the vcpu, meaning that an ill-behaved guest can ignore the riscv,isa settings and use the extension. The case we're handling happens with an EINVAL error code. If we fail to disable the extension in KVM for any other reason, error out. We'll also keep erroring out when we fail to enable an extension in KVM, since adding the extension in riscv,isa at this point will cause a guest malfunction because the extension isn't enabled in the vcpu. Suggested-by: Andrew Jones Signed-off-by: Daniel Henrique Barboza Reviewed-by: Andrew Jones Cc: qemu-stable Message-ID: <20240422171425.333037-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index d2491d84e2..473416649f 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -433,10 +433,14 @@ static void kvm_riscv_update_cpu_cfg_isa_ext(RISCVCPU *cpu, CPUState *cs) reg = kvm_cpu_cfg_get(cpu, multi_ext_cfg); ret = kvm_set_one_reg(cs, id, ®); if (ret != 0) { - error_report("Unable to %s extension %s in KVM, error %d", - reg ? "enable" : "disable", - multi_ext_cfg->name, ret); - exit(EXIT_FAILURE); + if (!reg && ret == -EINVAL) { + warn_report("KVM cannot disable extension %s", + multi_ext_cfg->name); + } else { + error_report("Unable to enable extension %s in KVM, error %d", + multi_ext_cfg->name, ret); + exit(EXIT_FAILURE); + } } } } From 0099f6053410f5611796213b723e908cfc8055eb Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 16 Apr 2024 20:04:36 -0300 Subject: [PATCH 08/27] target/riscv/debug: set tval=pc in breakpoint exceptions We're not setting (s/m)tval when triggering breakpoints of type 2 (mcontrol) and 6 (mcontrol6). According to the debug spec section 5.7.12, "Match Control Type 6": "The Privileged Spec says that breakpoint exceptions that occur on instruction fetches, loads, or stores update the tval CSR with either zero or the faulting virtual address. The faulting virtual address for an mcontrol6 trigger with action = 0 is the address being accessed and which caused that trigger to fire." A similar text is also found in the Debug spec section 5.7.11 w.r.t. mcontrol. Note that what we're doing ATM is not violating the spec, but it's simple enough to set mtval/stval and it makes life easier for any software that relies on this info. Given that we always use action = 0, save the faulting address for the mcontrol and mcontrol6 trigger breakpoints into env->badaddr, which is used as as scratch area for traps with address information. 'tval' is then set during riscv_cpu_do_interrupt(). Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: LIU Zhiwei Message-ID: <20240416230437.1869024-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 1 + target/riscv/debug.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 8ad546a45a..179cf3d1a1 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1718,6 +1718,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) tval = env->bins; break; case RISCV_EXCP_BREAKPOINT: + tval = env->badaddr; if (cs->watchpoint_hit) { tval = cs->watchpoint_hit->hitaddr; cs->watchpoint_hit = NULL; diff --git a/target/riscv/debug.c b/target/riscv/debug.c index e30d99cc2f..b110370ea6 100644 --- a/target/riscv/debug.c +++ b/target/riscv/debug.c @@ -798,6 +798,7 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs) if ((ctrl & TYPE2_EXEC) && (bp->pc == pc)) { /* check U/S/M bit against current privilege level */ if ((ctrl >> 3) & BIT(env->priv)) { + env->badaddr = pc; return true; } } @@ -810,11 +811,13 @@ bool riscv_cpu_debug_check_breakpoint(CPUState *cs) if (env->virt_enabled) { /* check VU/VS bit against current privilege level */ if ((ctrl >> 23) & BIT(env->priv)) { + env->badaddr = pc; return true; } } else { /* check U/S/M bit against current privilege level */ if ((ctrl >> 3) & BIT(env->priv)) { + env->badaddr = pc; return true; } } From f15af01740efb95d1dccdac763011dcba144c1fe Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 16 Apr 2024 20:04:37 -0300 Subject: [PATCH 09/27] trans_privileged.c.inc: set (m|s)tval on ebreak breakpoint Privileged spec section 4.1.9 mentions: "When a trap is taken into S-mode, stval is written with exception-specific information to assist software in handling the trap. (...) If stval is written with a nonzero value when a breakpoint, address-misaligned, access-fault, or page-fault exception occurs on an instruction fetch, load, or store, then stval will contain the faulting virtual address." A similar text is found for mtval in section 3.1.16. Setting mtval/stval in this scenario is optional, but some softwares read these regs when handling ebreaks. Write 'badaddr' in all ebreak breakpoints to write the appropriate 'tval' during riscv_do_cpu_interrrupt(). Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Reviewed-by: LIU Zhiwei Reviewed-by: Richard Henderson Message-ID: <20240416230437.1869024-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_privileged.c.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/target/riscv/insn_trans/trans_privileged.c.inc b/target/riscv/insn_trans/trans_privileged.c.inc index 620ab54eb0..bc5263a4e0 100644 --- a/target/riscv/insn_trans/trans_privileged.c.inc +++ b/target/riscv/insn_trans/trans_privileged.c.inc @@ -62,6 +62,8 @@ static bool trans_ebreak(DisasContext *ctx, arg_ebreak *a) if (pre == 0x01f01013 && ebreak == 0x00100073 && post == 0x40705013) { generate_exception(ctx, RISCV_EXCP_SEMIHOST); } else { + tcg_gen_st_tl(tcg_constant_tl(ebreak_addr), tcg_env, + offsetof(CPURISCVState, badaddr)); generate_exception(ctx, RISCV_EXCP_BREAKPOINT); } return true; From 9fb41a4418efb6008bce218d9510db830fd744ab Mon Sep 17 00:00:00 2001 From: Jason Chien Date: Thu, 28 Mar 2024 10:23:10 +0800 Subject: [PATCH 10/27] target/riscv: Add support for Zve32x extension Add support for Zve32x extension and replace some checks for Zve32f with Zve32x, since Zve32f depends on Zve32x. Signed-off-by: Jason Chien Reviewed-by: Frank Chang Reviewed-by: Max Chou Reviewed-by: Daniel Henrique Barboza Message-ID: <20240328022343.6871-2-jason.chien@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ target/riscv/cpu_cfg.h | 1 + target/riscv/cpu_helper.c | 2 +- target/riscv/csr.c | 2 +- target/riscv/insn_trans/trans_rvv.c.inc | 4 ++-- target/riscv/tcg/tcg-cpu.c | 16 ++++++++-------- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index eb1a2e7d6d..d744594cc4 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -153,6 +153,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zvbb, PRIV_VERSION_1_12_0, ext_zvbb), ISA_EXT_DATA_ENTRY(zvbc, PRIV_VERSION_1_12_0, ext_zvbc), ISA_EXT_DATA_ENTRY(zve32f, PRIV_VERSION_1_10_0, ext_zve32f), + ISA_EXT_DATA_ENTRY(zve32x, PRIV_VERSION_1_10_0, ext_zve32x), ISA_EXT_DATA_ENTRY(zve64f, PRIV_VERSION_1_10_0, ext_zve64f), ISA_EXT_DATA_ENTRY(zve64d, PRIV_VERSION_1_10_0, ext_zve64d), ISA_EXT_DATA_ENTRY(zvfbfmin, PRIV_VERSION_1_12_0, ext_zvfbfmin), @@ -1472,6 +1473,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zfh", ext_zfh, false), MULTI_EXT_CFG_BOOL("zfhmin", ext_zfhmin, false), MULTI_EXT_CFG_BOOL("zve32f", ext_zve32f, false), + MULTI_EXT_CFG_BOOL("zve32x", ext_zve32x, false), MULTI_EXT_CFG_BOOL("zve64f", ext_zve64f, false), MULTI_EXT_CFG_BOOL("zve64d", ext_zve64d, false), MULTI_EXT_CFG_BOOL("zvfbfmin", ext_zvfbfmin, false), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index cb750154bd..dce49050c0 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -91,6 +91,7 @@ struct RISCVCPUConfig { bool ext_zhinx; bool ext_zhinxmin; bool ext_zve32f; + bool ext_zve32x; bool ext_zve64f; bool ext_zve64d; bool ext_zvbb; diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 179cf3d1a1..d71245a8cb 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -73,7 +73,7 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, vaddr *pc, *pc = env->xl == MXL_RV32 ? env->pc & UINT32_MAX : env->pc; *cs_base = 0; - if (cpu->cfg.ext_zve32f) { + if (cpu->cfg.ext_zve32x) { /* * If env->vl equals to VLMAX, we can use generic vector operation * expanders (GVEC) to accerlate the vector operations. diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 829d8346ed..58ef7079dc 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -93,7 +93,7 @@ static RISCVException fs(CPURISCVState *env, int csrno) static RISCVException vs(CPURISCVState *env, int csrno) { - if (riscv_cpu_cfg(env)->ext_zve32f) { + if (riscv_cpu_cfg(env)->ext_zve32x) { #if !defined(CONFIG_USER_ONLY) if (!env->debugger && !riscv_cpu_vector_enabled(env)) { return RISCV_EXCP_ILLEGAL_INST; diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 7d84e7d812..eec2939e23 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -149,7 +149,7 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2) { TCGv s1, dst; - if (!require_rvv(s) || !s->cfg_ptr->ext_zve32f) { + if (!require_rvv(s) || !s->cfg_ptr->ext_zve32x) { return false; } @@ -179,7 +179,7 @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2) { TCGv dst; - if (!require_rvv(s) || !s->cfg_ptr->ext_zve32f) { + if (!require_rvv(s) || !s->cfg_ptr->ext_zve32x) { return false; } diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index 40054a391a..e2cf5f429d 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -511,9 +511,13 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) return; } - if (cpu->cfg.ext_zve32f && !riscv_has_ext(env, RVF)) { - error_setg(errp, "Zve32f/Zve64f extensions require F extension"); - return; + /* The Zve32f extension depends on the Zve32x extension */ + if (cpu->cfg.ext_zve32f) { + if (!riscv_has_ext(env, RVF)) { + error_setg(errp, "Zve32f/Zve64f extensions require F extension"); + return; + } + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32x), true); } if (cpu->cfg.ext_zvfh) { @@ -658,13 +662,9 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zvbc), true); } - /* - * In principle Zve*x would also suffice here, were they supported - * in qemu - */ if ((cpu->cfg.ext_zvbb || cpu->cfg.ext_zvkb || cpu->cfg.ext_zvkg || cpu->cfg.ext_zvkned || cpu->cfg.ext_zvknha || cpu->cfg.ext_zvksed || - cpu->cfg.ext_zvksh) && !cpu->cfg.ext_zve32f) { + cpu->cfg.ext_zvksh) && !cpu->cfg.ext_zve32x) { error_setg(errp, "Vector crypto extensions require V or Zve* extensions"); return; From e7dc5e160f69678432c24827b522baf82b73688a Mon Sep 17 00:00:00 2001 From: Jason Chien Date: Thu, 28 Mar 2024 10:23:11 +0800 Subject: [PATCH 11/27] target/riscv: Add support for Zve64x extension Add support for Zve64x extension. Enabling Zve64f enables Zve64x and enabling Zve64x enables Zve32x according to their dependency. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2107 Signed-off-by: Jason Chien Reviewed-by: Frank Chang Reviewed-by: Max Chou Reviewed-by: Daniel Henrique Barboza Message-ID: <20240328022343.6871-3-jason.chien@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 ++ target/riscv/cpu_cfg.h | 1 + target/riscv/tcg/tcg-cpu.c | 17 +++++++++++------ 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index d744594cc4..a74f0eb29c 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -156,6 +156,7 @@ const RISCVIsaExtData isa_edata_arr[] = { ISA_EXT_DATA_ENTRY(zve32x, PRIV_VERSION_1_10_0, ext_zve32x), ISA_EXT_DATA_ENTRY(zve64f, PRIV_VERSION_1_10_0, ext_zve64f), ISA_EXT_DATA_ENTRY(zve64d, PRIV_VERSION_1_10_0, ext_zve64d), + ISA_EXT_DATA_ENTRY(zve64x, PRIV_VERSION_1_10_0, ext_zve64x), ISA_EXT_DATA_ENTRY(zvfbfmin, PRIV_VERSION_1_12_0, ext_zvfbfmin), ISA_EXT_DATA_ENTRY(zvfbfwma, PRIV_VERSION_1_12_0, ext_zvfbfwma), ISA_EXT_DATA_ENTRY(zvfh, PRIV_VERSION_1_12_0, ext_zvfh), @@ -1476,6 +1477,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { MULTI_EXT_CFG_BOOL("zve32x", ext_zve32x, false), MULTI_EXT_CFG_BOOL("zve64f", ext_zve64f, false), MULTI_EXT_CFG_BOOL("zve64d", ext_zve64d, false), + MULTI_EXT_CFG_BOOL("zve64x", ext_zve64x, false), MULTI_EXT_CFG_BOOL("zvfbfmin", ext_zvfbfmin, false), MULTI_EXT_CFG_BOOL("zvfbfwma", ext_zvfbfwma, false), MULTI_EXT_CFG_BOOL("zvfh", ext_zvfh, false), diff --git a/target/riscv/cpu_cfg.h b/target/riscv/cpu_cfg.h index dce49050c0..e1e4f32698 100644 --- a/target/riscv/cpu_cfg.h +++ b/target/riscv/cpu_cfg.h @@ -94,6 +94,7 @@ struct RISCVCPUConfig { bool ext_zve32x; bool ext_zve64f; bool ext_zve64d; + bool ext_zve64x; bool ext_zvbb; bool ext_zvbc; bool ext_zvkb; diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index e2cf5f429d..fedc035313 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -498,17 +498,22 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) /* The Zve64d extension depends on the Zve64f extension */ if (cpu->cfg.ext_zve64d) { + if (!riscv_has_ext(env, RVD)) { + error_setg(errp, "Zve64d/V extensions require D extension"); + return; + } cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64f), true); } - /* The Zve64f extension depends on the Zve32f extension */ + /* The Zve64f extension depends on the Zve64x and Zve32f extensions */ if (cpu->cfg.ext_zve64f) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve64x), true); 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; + /* The Zve64x extension depends on the Zve32x extension */ + if (cpu->cfg.ext_zve64x) { + cpu_cfg_ext_auto_update(cpu, CPU_CFG_OFFSET(ext_zve32x), true); } /* The Zve32f extension depends on the Zve32x extension */ @@ -670,10 +675,10 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp) return; } - if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64f) { + if ((cpu->cfg.ext_zvbc || cpu->cfg.ext_zvknhb) && !cpu->cfg.ext_zve64x) { error_setg( errp, - "Zvbc and Zvknhb extensions require V or Zve64{f,d} extensions"); + "Zvbc and Zvknhb extensions require V or Zve64x extensions"); return; } From 4a90991234f003d8fe55919e84bf3ec7d542830e Mon Sep 17 00:00:00 2001 From: Jason Chien Date: Thu, 28 Mar 2024 10:23:12 +0800 Subject: [PATCH 12/27] target/riscv: Relax vector register check in RISCV gdbstub In current implementation, the gdbstub allows reading vector registers only if V extension is supported. However, all vector extensions and vector crypto extensions have the vector registers and they all depend on Zve32x. The gdbstub should check for Zve32x instead. Signed-off-by: Jason Chien Reviewed-by: Frank Chang Reviewed-by: Max Chou Message-ID: <20240328022343.6871-4-jason.chien@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/gdbstub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index be7a02cd90..d0cc5762c2 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -338,7 +338,7 @@ void riscv_cpu_register_gdb_regs_for_features(CPUState *cs) gdb_find_static_feature("riscv-32bit-fpu.xml"), 0); } - if (env->misa_ext & RVV) { + if (cpu->cfg.ext_zve32x) { gdb_register_coprocessor(cs, riscv_gdb_get_vector, riscv_gdb_set_vector, ricsv_gen_dynamic_vector_feature(cs, cs->gdb_num_regs), From 75115d880c6d396f8a2d56aab8c12236d85a90e0 Mon Sep 17 00:00:00 2001 From: Huang Tao Date: Mon, 25 Mar 2024 10:16:54 +0800 Subject: [PATCH 13/27] target/riscv: Fix the element agnostic function problem In RVV and vcrypto instructions, the masked and tail elements are set to 1s using vext_set_elems_1s function if the vma/vta bit is set. It is the element agnostic policy. However, this function can't deal the big endian situation. This patch fixes the problem by adding handling of such case. Signed-off-by: Huang Tao Suggested-by: Richard Henderson Reviewed-by: LIU Zhiwei Cc: qemu-stable Message-ID: <20240325021654.6594-1-eric.huang@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/vector_internals.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/target/riscv/vector_internals.c b/target/riscv/vector_internals.c index 996c21eb31..05b2d01e58 100644 --- a/target/riscv/vector_internals.c +++ b/target/riscv/vector_internals.c @@ -30,6 +30,28 @@ void vext_set_elems_1s(void *base, uint32_t is_agnostic, uint32_t cnt, if (tot - cnt == 0) { return ; } + + if (HOST_BIG_ENDIAN) { + /* + * Deal the situation when the elements are insdie + * only one uint64 block including setting the + * masked-off element. + */ + if (((tot - 1) ^ cnt) < 8) { + memset(base + H1(tot - 1), -1, tot - cnt); + return; + } + /* + * Otherwise, at least cross two uint64_t blocks. + * Set first unaligned block. + */ + if (cnt % 8 != 0) { + uint32_t j = ROUND_UP(cnt, 8); + memset(base + H1(j - 1), -1, j - cnt); + cnt = j; + } + /* Set other 64bit aligend blocks */ + } memset(base + cnt, -1, tot - cnt); } From ff33b7a9699e977a050a1014c617a89da1bf8295 Mon Sep 17 00:00:00 2001 From: Yangyu Chen Date: Sat, 11 May 2024 19:26:48 +0800 Subject: [PATCH 14/27] target/riscv/cpu.c: fix Zvkb extension config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This code has a typo that writes zvkb to zvkg, causing users can't enable zvkb through the config. This patch gets this fixed. Signed-off-by: Yangyu Chen Fixes: ea61ef7097d0 ("target/riscv: Move vector crypto extensions to riscv_cpu_extensions") Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Reviewed-by: Max Chou Reviewed-by:  Weiwei Li Message-ID: Cc: qemu-stable Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index a74f0eb29c..0d6fb9b4ba 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1539,7 +1539,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = { /* Vector cryptography extensions */ MULTI_EXT_CFG_BOOL("zvbb", ext_zvbb, false), MULTI_EXT_CFG_BOOL("zvbc", ext_zvbc, false), - MULTI_EXT_CFG_BOOL("zvkb", ext_zvkg, false), + MULTI_EXT_CFG_BOOL("zvkb", ext_zvkb, false), MULTI_EXT_CFG_BOOL("zvkg", ext_zvkg, false), MULTI_EXT_CFG_BOOL("zvkned", ext_zvkned, false), MULTI_EXT_CFG_BOOL("zvknha", ext_zvknha, false), From 8c8a7cd647c53cd620e702243914820b6eae70f1 Mon Sep 17 00:00:00 2001 From: Huang Tao Date: Mon, 6 May 2024 10:36:07 +0800 Subject: [PATCH 15/27] target/riscv: Implement dynamic establishment of custom decoder In this patch, we modify the decoder to be a freely composable data structure instead of a hardcoded one. It can be dynamically builded up according to the extensions. This approach has several benefits: 1. Provides support for heterogeneous cpu architectures. As we add decoder in RISCVCPU, each cpu can have their own decoder, and the decoders can be different due to cpu's features. 2. Improve the decoding efficiency. We run the guard_func to see if the decoder can be added to the dynamic_decoder when building up the decoder. Therefore, there is no need to run the guard_func when decoding each instruction. It can improve the decoding efficiency 3. For vendor or dynamic cpus, it allows them to customize their own decoder functions to improve decoding efficiency, especially when vendor-defined instruction sets increase. Because of dynamic building up, it can skip the other decoder guard functions when decoding. 4. Pre patch for allowing adding a vendor decoder before decode_insn32() with minimal overhead for users that don't need this particular vendor decoder. Signed-off-by: Huang Tao Suggested-by: Christoph Muellner Co-authored-by: LIU Zhiwei Reviewed-by: Richard Henderson Reviewed-by: Alistair Francis Message-ID: <20240506023607.29544-1-eric.huang@linux.alibaba.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 1 + target/riscv/cpu.h | 1 + target/riscv/tcg/tcg-cpu.c | 15 +++++++++++++++ target/riscv/tcg/tcg-cpu.h | 15 +++++++++++++++ target/riscv/translate.c | 31 +++++++++++++++---------------- 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 0d6fb9b4ba..abeb50369c 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1134,6 +1134,7 @@ void riscv_cpu_finalize_features(RISCVCPU *cpu, Error **errp) error_propagate(errp, local_err); return; } + riscv_tcg_cpu_finalize_dynamic_decoder(cpu); } else if (kvm_enabled()) { riscv_kvm_cpu_finalize_features(cpu, &local_err); if (local_err != NULL) { diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 746efd099a..04ab0f153a 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -455,6 +455,7 @@ struct ArchCPU { uint32_t pmu_avail_ctrs; /* Mapping of events to counters */ GHashTable *pmu_event_ctr_map; + const GPtrArray *decoders; }; /** diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index fedc035313..f59b5d7f2d 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -863,6 +863,21 @@ void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp) } } +void riscv_tcg_cpu_finalize_dynamic_decoder(RISCVCPU *cpu) +{ + GPtrArray *dynamic_decoders; + dynamic_decoders = g_ptr_array_sized_new(decoder_table_size); + for (size_t i = 0; i < decoder_table_size; ++i) { + if (decoder_table[i].guard_func && + decoder_table[i].guard_func(&cpu->cfg)) { + g_ptr_array_add(dynamic_decoders, + (gpointer)decoder_table[i].riscv_cpu_decode_fn); + } + } + + cpu->decoders = dynamic_decoders; +} + bool riscv_cpu_tcg_compatible(RISCVCPU *cpu) { return object_dynamic_cast(OBJECT(cpu), TYPE_RISCV_CPU_HOST) == NULL; diff --git a/target/riscv/tcg/tcg-cpu.h b/target/riscv/tcg/tcg-cpu.h index f7b32417f8..ce94253fe4 100644 --- a/target/riscv/tcg/tcg-cpu.h +++ b/target/riscv/tcg/tcg-cpu.h @@ -26,4 +26,19 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp); void riscv_tcg_cpu_finalize_features(RISCVCPU *cpu, Error **errp); bool riscv_cpu_tcg_compatible(RISCVCPU *cpu); +struct DisasContext; +struct RISCVCPUConfig; +typedef struct RISCVDecoder { + bool (*guard_func)(const struct RISCVCPUConfig *); + bool (*riscv_cpu_decode_fn)(struct DisasContext *, uint32_t); +} RISCVDecoder; + +typedef bool (*riscv_cpu_decode_fn)(struct DisasContext *, uint32_t); + +extern const size_t decoder_table_size; + +extern const RISCVDecoder decoder_table[]; + +void riscv_tcg_cpu_finalize_dynamic_decoder(RISCVCPU *cpu); + #endif diff --git a/target/riscv/translate.c b/target/riscv/translate.c index 2c27fd4ce1..4cd6480558 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -35,6 +35,8 @@ #include "exec/helper-info.c.inc" #undef HELPER_H +#include "tcg/tcg-cpu.h" + /* global register indices */ static TCGv cpu_gpr[32], cpu_gprh[32], cpu_pc, cpu_vl, cpu_vstart; static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */ @@ -114,6 +116,7 @@ typedef struct DisasContext { /* FRM is known to contain a valid value. */ bool frm_valid; bool insn_start_updated; + const GPtrArray *decoders; } DisasContext; static inline bool has_ext(DisasContext *ctx, uint32_t ext) @@ -1123,21 +1126,16 @@ static inline int insn_len(uint16_t first_word) return (first_word & 3) == 3 ? 4 : 2; } +const RISCVDecoder decoder_table[] = { + { always_true_p, decode_insn32 }, + { has_xthead_p, decode_xthead}, + { has_XVentanaCondOps_p, decode_XVentanaCodeOps}, +}; + +const size_t decoder_table_size = ARRAY_SIZE(decoder_table); + static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) { - /* - * A table with predicate (i.e., guard) functions and decoder functions - * that are tested in-order until a decoder matches onto the opcode. - */ - static const struct { - bool (*guard_func)(const RISCVCPUConfig *); - bool (*decode_func)(DisasContext *, uint32_t); - } decoders[] = { - { always_true_p, decode_insn32 }, - { has_xthead_p, decode_xthead }, - { has_XVentanaCondOps_p, decode_XVentanaCodeOps }, - }; - ctx->virt_inst_excp = false; ctx->cur_insn_len = insn_len(opcode); /* Check for compressed insn */ @@ -1158,9 +1156,9 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode) ctx->base.pc_next + 2)); ctx->opcode = opcode32; - for (size_t i = 0; i < ARRAY_SIZE(decoders); ++i) { - if (decoders[i].guard_func(ctx->cfg_ptr) && - decoders[i].decode_func(ctx, opcode32)) { + for (guint i = 0; i < ctx->decoders->len; ++i) { + riscv_cpu_decode_fn func = g_ptr_array_index(ctx->decoders, i); + if (func(ctx, opcode32)) { return; } } @@ -1205,6 +1203,7 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs) ctx->itrigger = FIELD_EX32(tb_flags, TB_FLAGS, ITRIGGER); ctx->zero = tcg_constant_tl(0); ctx->virt_inst_excp = false; + ctx->decoders = cpu->decoders; } static void riscv_tr_tb_start(DisasContextBase *db, CPUState *cpu) From fd53ee268d43a0c16814a2c0d4c7ebcf688cfe09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20M=C3=BCllner?= Date: Mon, 29 Apr 2024 09:36:56 +0200 Subject: [PATCH 16/27] riscv: thead: Add th.sxstatus CSR emulation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The th.sxstatus CSR can be used to identify available custom extension on T-Head CPUs. The CSR is documented here: https://github.com/T-head-Semi/thead-extension-spec/blob/master/xtheadsxstatus.adoc An important property of this patch is, that the th.sxstatus MAEE field is not set (indicating that XTheadMae is not available). XTheadMae is a memory attribute extension (similar to Svpbmt) which is implemented in many T-Head CPUs (C906, C910, etc.) and utilizes bits in PTEs that are marked as reserved. QEMU maintainers prefer to not implement XTheadMae, so we need give kernels a mechanism to identify if XTheadMae is available in a system or not. And this patch introduces this mechanism in QEMU in a way that's compatible with real HW (i.e., probing the th.sxstatus.MAEE bit). Further context can be found on the list: https://lists.gnu.org/archive/html/qemu-devel/2024-02/msg00775.html Reviewed-by: LIU Zhiwei Reviewed-by: Alistair Francis Signed-off-by: Christoph Müllner Message-ID: <20240429073656.2486732-1-christoph.muellner@vrull.eu> Signed-off-by: Alistair Francis --- MAINTAINERS | 1 + target/riscv/cpu.c | 1 + target/riscv/cpu.h | 3 ++ target/riscv/meson.build | 1 + target/riscv/th_csr.c | 79 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+) create mode 100644 target/riscv/th_csr.c diff --git a/MAINTAINERS b/MAINTAINERS index 448dc951c5..e9d861e8ef 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -343,6 +343,7 @@ L: qemu-riscv@nongnu.org S: Supported F: target/riscv/insn_trans/trans_xthead.c.inc F: target/riscv/xthead*.decode +F: target/riscv/th_* F: disas/riscv-xthead* RISC-V XVentanaCondOps extension diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index abeb50369c..2946ac298a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -547,6 +547,7 @@ static void rv64_thead_c906_cpu_init(Object *obj) cpu->cfg.mvendorid = THEAD_VENDOR_ID; #ifndef CONFIG_USER_ONLY set_satp_mode_max_supported(cpu, VM_1_10_SV39); + th_register_custom_csrs(cpu); #endif /* inherited from parent obj via riscv_cpu_init() */ diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 04ab0f153a..12d8b5344a 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -826,4 +826,7 @@ target_ulong riscv_new_csr_seed(target_ulong new_value, uint8_t satp_mode_max_from_map(uint32_t map); const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit); +/* Implemented in th_csr.c */ +void th_register_custom_csrs(RISCVCPU *cpu); + #endif /* RISCV_CPU_H */ diff --git a/target/riscv/meson.build b/target/riscv/meson.build index a5e0734e7f..a4bd61e52a 100644 --- a/target/riscv/meson.build +++ b/target/riscv/meson.build @@ -33,6 +33,7 @@ riscv_system_ss.add(files( 'monitor.c', 'machine.c', 'pmu.c', + 'th_csr.c', 'time_helper.c', 'riscv-qmp-cmds.c', )) diff --git a/target/riscv/th_csr.c b/target/riscv/th_csr.c new file mode 100644 index 0000000000..6c970d4e81 --- /dev/null +++ b/target/riscv/th_csr.c @@ -0,0 +1,79 @@ +/* + * T-Head-specific CSRs. + * + * Copyright (c) 2024 VRULL GmbH + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2 or later, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "cpu_vendorid.h" + +#define CSR_TH_SXSTATUS 0x5c0 + +/* TH_SXSTATUS bits */ +#define TH_SXSTATUS_UCME BIT(16) +#define TH_SXSTATUS_MAEE BIT(21) +#define TH_SXSTATUS_THEADISAEE BIT(22) + +typedef struct { + int csrno; + int (*insertion_test)(RISCVCPU *cpu); + riscv_csr_operations csr_ops; +} riscv_csr; + +static RISCVException smode(CPURISCVState *env, int csrno) +{ + if (riscv_has_ext(env, RVS)) { + return RISCV_EXCP_NONE; + } + + return RISCV_EXCP_ILLEGAL_INST; +} + +static int test_thead_mvendorid(RISCVCPU *cpu) +{ + if (cpu->cfg.mvendorid != THEAD_VENDOR_ID) { + return -1; + } + + return 0; +} + +static RISCVException read_th_sxstatus(CPURISCVState *env, int csrno, + target_ulong *val) +{ + /* We don't set MAEE here, because QEMU does not implement MAEE. */ + *val = TH_SXSTATUS_UCME | TH_SXSTATUS_THEADISAEE; + return RISCV_EXCP_NONE; +} + +static riscv_csr th_csr_list[] = { + { + .csrno = CSR_TH_SXSTATUS, + .insertion_test = test_thead_mvendorid, + .csr_ops = { "th.sxstatus", smode, read_th_sxstatus } + } +}; + +void th_register_custom_csrs(RISCVCPU *cpu) +{ + for (size_t i = 0; i < ARRAY_SIZE(th_csr_list); i++) { + int csrno = th_csr_list[i].csrno; + riscv_csr_operations *csr_ops = &th_csr_list[i].csr_ops; + if (!th_csr_list[i].insertion_test(cpu)) { + riscv_set_csr_ops(csrno, csr_ops); + } + } +} From 17b713c0806e72cd8edc6c2ddd8acc5be0475df6 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Fri, 22 Mar 2024 17:25:55 +0800 Subject: [PATCH 17/27] target/riscv: rvv: Fix Zvfhmin checking for vfwcvt.f.f.v and vfncvt.f.f.w instructions According v spec 18.4, only the vfwcvt.f.f.v and vfncvt.f.f.w instructions will be affected by Zvfhmin extension. And the vfwcvt.f.f.v and vfncvt.f.f.w instructions only support the conversions of * From 1*SEW(16/32) to 2*SEW(32/64) * From 2*SEW(32/64) to 1*SEW(16/32) Signed-off-by: Max Chou Reviewed-by: Daniel Henrique Barboza Cc: qemu-stable Message-ID: <20240322092600.1198921-2-max.chou@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index eec2939e23..678b34b759 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -50,6 +50,22 @@ static bool require_rvf(DisasContext *s) } } +static bool require_rvfmin(DisasContext *s) +{ + if (s->mstatus_fs == EXT_STATUS_DISABLED) { + return false; + } + + switch (s->sew) { + case MO_16: + return s->cfg_ptr->ext_zvfhmin; + case MO_32: + return s->cfg_ptr->ext_zve32f; + default: + return false; + } +} + static bool require_scale_rvf(DisasContext *s) { if (s->mstatus_fs == EXT_STATUS_DISABLED) { @@ -75,8 +91,6 @@ static bool require_scale_rvfmin(DisasContext *s) } switch (s->sew) { - case MO_8: - return s->cfg_ptr->ext_zvfhmin; case MO_16: return s->cfg_ptr->ext_zve32f; case MO_32: @@ -2685,6 +2699,7 @@ static bool opxfv_widen_check(DisasContext *s, arg_rmr *a) static bool opffv_widen_check(DisasContext *s, arg_rmr *a) { return opfv_widen_check(s, a) && + require_rvfmin(s) && require_scale_rvfmin(s) && (s->sew != MO_8); } @@ -2790,6 +2805,7 @@ static bool opfxv_narrow_check(DisasContext *s, arg_rmr *a) static bool opffv_narrow_check(DisasContext *s, arg_rmr *a) { return opfv_narrow_check(s, a) && + require_rvfmin(s) && require_scale_rvfmin(s) && (s->sew != MO_8); } From 7a999d4dd704aa71fe6416871ada69438b56b1e5 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Fri, 22 Mar 2024 17:25:56 +0800 Subject: [PATCH 18/27] target/riscv: rvv: Check single width operator for vector fp widen instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The require_scale_rvf function only checks the double width operator for the vector floating point widen instructions, so most of the widen checking functions need to add require_rvf for single width operator. The vfwcvt.f.x.v and vfwcvt.f.xu.v instructions convert single width integer to double width float, so the opfxv_widen_check function doesn’t need require_rvf for the single width operator(integer). Signed-off-by: Max Chou Reviewed-by: Daniel Henrique Barboza Cc: qemu-stable Message-ID: <20240322092600.1198921-3-max.chou@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index 678b34b759..a7217aed4e 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -2331,6 +2331,7 @@ GEN_OPFVF_TRANS(vfrsub_vf, opfvf_check) static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && + require_rvf(s) && require_scale_rvf(s) && (s->sew != MO_8) && vext_check_isa_ill(s) && @@ -2370,6 +2371,7 @@ GEN_OPFVV_WIDEN_TRANS(vfwsub_vv, opfvv_widen_check) static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && + require_rvf(s) && require_scale_rvf(s) && (s->sew != MO_8) && vext_check_isa_ill(s) && @@ -2402,6 +2404,7 @@ GEN_OPFVF_WIDEN_TRANS(vfwsub_vf) static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && + require_rvf(s) && require_scale_rvf(s) && (s->sew != MO_8) && vext_check_isa_ill(s) && @@ -2441,6 +2444,7 @@ GEN_OPFWV_WIDEN_TRANS(vfwsub_wv) static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) { return require_rvv(s) && + require_rvf(s) && require_scale_rvf(s) && (s->sew != MO_8) && vext_check_isa_ill(s) && @@ -2941,6 +2945,7 @@ GEN_OPFVV_TRANS(vfredmin_vs, freduction_check) static bool freduction_widen_check(DisasContext *s, arg_rmrr *a) { return reduction_widen_check(s, a) && + require_rvf(s) && require_scale_rvf(s) && (s->sew != MO_8); } From 692f33a3abcaae789b08623e7cbdffcd2c738c89 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Fri, 22 Mar 2024 17:25:57 +0800 Subject: [PATCH 19/27] target/riscv: rvv: Check single width operator for vfncvt.rod.f.f.w The opfv_narrow_check needs to check the single width float operator by require_rvf. Signed-off-by: Max Chou Reviewed-by: Daniel Henrique Barboza Cc: qemu-stable Message-ID: <20240322092600.1198921-4-max.chou@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index a7217aed4e..c3af38af80 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -2817,6 +2817,7 @@ static bool opffv_narrow_check(DisasContext *s, arg_rmr *a) static bool opffv_rod_narrow_check(DisasContext *s, arg_rmr *a) { return opfv_narrow_check(s, a) && + require_rvf(s) && require_scale_rvf(s) && (s->sew != MO_8); } From 93cb52b7a3ccc64e8d28813324818edae07e21d5 Mon Sep 17 00:00:00 2001 From: Max Chou Date: Fri, 22 Mar 2024 17:25:58 +0800 Subject: [PATCH 20/27] target/riscv: rvv: Remove redudant SEW checking for vector fp narrow/widen instructions If the checking functions check both the single and double width operators at the same time, then the single width operator checking functions (require_rvf[min]) will check whether the SEW is 8. Signed-off-by: Max Chou Reviewed-by: Daniel Henrique Barboza Cc: qemu-stable Message-ID: <20240322092600.1198921-5-max.chou@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvv.c.inc | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc index c3af38af80..3a3896ba06 100644 --- a/target/riscv/insn_trans/trans_rvv.c.inc +++ b/target/riscv/insn_trans/trans_rvv.c.inc @@ -2333,7 +2333,6 @@ static bool opfvv_widen_check(DisasContext *s, arg_rmrr *a) return require_rvv(s) && require_rvf(s) && require_scale_rvf(s) && - (s->sew != MO_8) && vext_check_isa_ill(s) && vext_check_dss(s, a->rd, a->rs1, a->rs2, a->vm); } @@ -2373,7 +2372,6 @@ static bool opfvf_widen_check(DisasContext *s, arg_rmrr *a) return require_rvv(s) && require_rvf(s) && require_scale_rvf(s) && - (s->sew != MO_8) && vext_check_isa_ill(s) && vext_check_ds(s, a->rd, a->rs2, a->vm); } @@ -2406,7 +2404,6 @@ static bool opfwv_widen_check(DisasContext *s, arg_rmrr *a) return require_rvv(s) && require_rvf(s) && require_scale_rvf(s) && - (s->sew != MO_8) && vext_check_isa_ill(s) && vext_check_dds(s, a->rd, a->rs1, a->rs2, a->vm); } @@ -2446,7 +2443,6 @@ static bool opfwf_widen_check(DisasContext *s, arg_rmrr *a) return require_rvv(s) && require_rvf(s) && require_scale_rvf(s) && - (s->sew != MO_8) && vext_check_isa_ill(s) && vext_check_dd(s, a->rd, a->rs2, a->vm); } @@ -2704,8 +2700,7 @@ static bool opffv_widen_check(DisasContext *s, arg_rmr *a) { return opfv_widen_check(s, a) && require_rvfmin(s) && - require_scale_rvfmin(s) && - (s->sew != MO_8); + require_scale_rvfmin(s); } #define GEN_OPFV_WIDEN_TRANS(NAME, CHECK, HELPER, FRM) \ @@ -2810,16 +2805,14 @@ static bool opffv_narrow_check(DisasContext *s, arg_rmr *a) { return opfv_narrow_check(s, a) && require_rvfmin(s) && - require_scale_rvfmin(s) && - (s->sew != MO_8); + require_scale_rvfmin(s); } static bool opffv_rod_narrow_check(DisasContext *s, arg_rmr *a) { return opfv_narrow_check(s, a) && require_rvf(s) && - require_scale_rvf(s) && - (s->sew != MO_8); + require_scale_rvf(s); } #define GEN_OPFV_NARROW_TRANS(NAME, CHECK, HELPER, FRM) \ @@ -2947,8 +2940,7 @@ static bool freduction_widen_check(DisasContext *s, arg_rmrr *a) { return reduction_widen_check(s, a) && require_rvf(s) && - require_scale_rvf(s) && - (s->sew != MO_8); + require_scale_rvf(s); } GEN_OPFVV_WIDEN_TRANS(vfwredusum_vs, freduction_widen_check) From 68e7c86927afa240fa450578cb3a4f18926153e4 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Sat, 13 Apr 2024 13:59:28 +0300 Subject: [PATCH 21/27] target/riscv: prioritize pmp errors in raise_mmu_exception() raise_mmu_exception(), as is today, is prioritizing guest page faults by checking first if virt_enabled && !first_stage, and then considering the regular inst/load/store faults. There's no mention in the spec about guest page fault being a higher priority that PMP faults. In fact, privileged spec section 3.7.1 says: "Attempting to fetch an instruction from a PMP region that does not have execute permissions raises an instruction access-fault exception. Attempting to execute a load or load-reserved instruction which accesses a physical address within a PMP region without read permissions raises a load access-fault exception. Attempting to execute a store, store-conditional, or AMO instruction which accesses a physical address within a PMP region without write permissions raises a store access-fault exception." So, in fact, we're doing it wrong - PMP faults should always be thrown, regardless of also being a first or second stage fault. The way riscv_cpu_tlb_fill() and get_physical_address() work is adequate: a TRANSLATE_PMP_FAIL error is immediately reported and reflected in the 'pmp_violation' flag. What we need is to change raise_mmu_exception() to prioritize it. Reported-by: Joseph Chan Fixes: 82d53adfbb ("target/riscv/cpu_helper.c: Invalid exception on MMU translation stage") Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20240413105929.7030-1-alexei.filippov@syntacore.com> Cc: qemu-stable Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index d71245a8cb..574886a694 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1177,28 +1177,30 @@ static void raise_mmu_exception(CPURISCVState *env, target_ulong address, switch (access_type) { case MMU_INST_FETCH: - if (env->virt_enabled && !first_stage) { + if (pmp_violation) { + cs->exception_index = RISCV_EXCP_INST_ACCESS_FAULT; + } else if (env->virt_enabled && !first_stage) { cs->exception_index = RISCV_EXCP_INST_GUEST_PAGE_FAULT; } else { - cs->exception_index = pmp_violation ? - RISCV_EXCP_INST_ACCESS_FAULT : RISCV_EXCP_INST_PAGE_FAULT; + cs->exception_index = RISCV_EXCP_INST_PAGE_FAULT; } break; case MMU_DATA_LOAD: - if (two_stage && !first_stage) { + if (pmp_violation) { + cs->exception_index = RISCV_EXCP_LOAD_ACCESS_FAULT; + } else if (two_stage && !first_stage) { cs->exception_index = RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT; } else { - cs->exception_index = pmp_violation ? - RISCV_EXCP_LOAD_ACCESS_FAULT : RISCV_EXCP_LOAD_PAGE_FAULT; + cs->exception_index = RISCV_EXCP_LOAD_PAGE_FAULT; } break; case MMU_DATA_STORE: - if (two_stage && !first_stage) { + if (pmp_violation) { + cs->exception_index = RISCV_EXCP_STORE_AMO_ACCESS_FAULT; + } else if (two_stage && !first_stage) { cs->exception_index = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT; } else { - cs->exception_index = pmp_violation ? - RISCV_EXCP_STORE_AMO_ACCESS_FAULT : - RISCV_EXCP_STORE_PAGE_FAULT; + cs->exception_index = RISCV_EXCP_STORE_PAGE_FAULT; } break; default: From 6c9a344247132ac6c3d0eb9670db45149a29c88f Mon Sep 17 00:00:00 2001 From: Alexei Filippov Date: Fri, 3 May 2024 13:30:52 +0300 Subject: [PATCH 22/27] target/riscv: do not set mtval2 for non guest-page faults Previous patch fixed the PMP priority in raise_mmu_exception() but we're still setting mtval2 incorrectly. In riscv_cpu_tlb_fill(), after pmp check in 2 stage translation part, mtval2 will be set in case of successes 2 stage translation but failed pmp check. In this case we gonna set mtval2 via env->guest_phys_fault_addr in context of riscv_cpu_tlb_fill(), as this was a guest-page-fault, but it didn't and mtval2 should be zero, according to RISCV privileged spec sect. 9.4.4: When a guest page-fault is taken into M-mode, mtval2 is written with either zero or guest physical address that faulted, shifted by 2 bits. *For other traps, mtval2 is set to zero...* Signed-off-by: Alexei Filippov Reviewed-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20240503103052.6819-1-alexei.filippov@syntacore.com> Cc: qemu-stable Signed-off-by: Alistair Francis --- target/riscv/cpu_helper.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 574886a694..a02497d778 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -1376,17 +1376,17 @@ bool riscv_cpu_tlb_fill(CPUState *cs, vaddr address, int size, __func__, pa, ret, prot_pmp, tlb_size); prot &= prot_pmp; - } - - if (ret != TRANSLATE_SUCCESS) { + } else { /* * Guest physical address translation failed, this is a HS * level exception */ first_stage_error = false; - env->guest_phys_fault_addr = (im_address | - (address & - (TARGET_PAGE_SIZE - 1))) >> 2; + if (ret != TRANSLATE_PMP_FAIL) { + env->guest_phys_fault_addr = (im_address | + (address & + (TARGET_PAGE_SIZE - 1))) >> 2; + } } } } else { From 73ef14b1277d4c9d79bfe7cb080c09ddba18044f Mon Sep 17 00:00:00 2001 From: Rob Bradford Date: Tue, 14 May 2024 12:02:17 +0100 Subject: [PATCH 23/27] target/riscv: Remove experimental prefix from "B" extension This extension has now been ratified: https://jira.riscv.org/browse/RVS-2006 so the "x-" prefix can be removed. Since this is now a ratified extension add it to the list of extensions included in the "max" CPU variant. Signed-off-by: Rob Bradford Reviewed-by: Andrew Jones Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Reviewed-by: LIU Zhiwei Message-ID: <20240514110217.22516-1-rbradford@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/cpu.c | 2 +- target/riscv/tcg/tcg-cpu.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index 2946ac298a..cee6fc4a9a 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -1400,7 +1400,7 @@ static const MISAExtInfo misa_ext_info_arr[] = { MISA_EXT_INFO(RVJ, "x-j", "Dynamic translated languages"), MISA_EXT_INFO(RVV, "v", "Vector operations"), MISA_EXT_INFO(RVG, "g", "General purpose (IMAFD_Zicsr_Zifencei)"), - MISA_EXT_INFO(RVB, "x-b", "Bit manipulation (Zba_Zbb_Zbs)") + MISA_EXT_INFO(RVB, "b", "Bit manipulation (Zba_Zbb_Zbs)") }; static void riscv_cpu_validate_misa_mxl(RISCVCPUClass *mcc) diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c index f59b5d7f2d..683f604d9f 100644 --- a/target/riscv/tcg/tcg-cpu.c +++ b/target/riscv/tcg/tcg-cpu.c @@ -1301,7 +1301,7 @@ static void riscv_init_max_cpu_extensions(Object *obj) const RISCVCPUMultiExtConfig *prop; /* Enable RVG, RVJ and RVV that are disabled by default */ - riscv_cpu_set_misa_ext(env, env->misa_ext | RVG | RVJ | RVV); + riscv_cpu_set_misa_ext(env, env->misa_ext | RVB | RVG | RVJ | RVV); for (prop = riscv_cpu_extensions; prop && prop->name; prop++) { isa_ext_update_enabled(cpu, prop->offset, true); From c5eb8d6336741dbcb98efcc347f8265bf60bc9d1 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 14 May 2024 12:39:10 +1000 Subject: [PATCH 24/27] target/riscv: rvzicbo: Fixup CBO extension register calculation When running the instruction ``` cbo.flush 0(x0) ``` QEMU would segfault. The issue was in cpu_gpr[a->rs1] as QEMU does not have cpu_gpr[0] allocated. In order to fix this let's use the existing get_address() helper. This also has the benefit of performing pointer mask calculations on the address specified in rs1. The pointer masking specificiation specifically states: """ Cache Management Operations: All instructions in Zicbom, Zicbop and Zicboz """ So this is the correct behaviour and we previously have been incorrectly not masking the address. Signed-off-by: Alistair Francis Reported-by: Fabian Thomas Fixes: e05da09b7cfd ("target/riscv: implement Zicbom extension") Reviewed-by: Richard Henderson Cc: qemu-stable Message-ID: <20240514023910.301766-1-alistair.francis@wdc.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvzicbo.c.inc | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/target/riscv/insn_trans/trans_rvzicbo.c.inc b/target/riscv/insn_trans/trans_rvzicbo.c.inc index d5d7095903..15711c3140 100644 --- a/target/riscv/insn_trans/trans_rvzicbo.c.inc +++ b/target/riscv/insn_trans/trans_rvzicbo.c.inc @@ -31,27 +31,35 @@ static bool trans_cbo_clean(DisasContext *ctx, arg_cbo_clean *a) { REQUIRE_ZICBOM(ctx); - gen_helper_cbo_clean_flush(tcg_env, cpu_gpr[a->rs1]); + TCGv src = get_address(ctx, a->rs1, 0); + + gen_helper_cbo_clean_flush(tcg_env, src); return true; } static bool trans_cbo_flush(DisasContext *ctx, arg_cbo_flush *a) { REQUIRE_ZICBOM(ctx); - gen_helper_cbo_clean_flush(tcg_env, cpu_gpr[a->rs1]); + TCGv src = get_address(ctx, a->rs1, 0); + + gen_helper_cbo_clean_flush(tcg_env, src); return true; } static bool trans_cbo_inval(DisasContext *ctx, arg_cbo_inval *a) { REQUIRE_ZICBOM(ctx); - gen_helper_cbo_inval(tcg_env, cpu_gpr[a->rs1]); + TCGv src = get_address(ctx, a->rs1, 0); + + gen_helper_cbo_inval(tcg_env, src); return true; } static bool trans_cbo_zero(DisasContext *ctx, arg_cbo_zero *a) { REQUIRE_ZICBOZ(ctx); - gen_helper_cbo_zero(tcg_env, cpu_gpr[a->rs1]); + TCGv src = get_address(ctx, a->rs1, 0); + + gen_helper_cbo_zero(tcg_env, src); return true; } From 190b867f28cb5781f3cd01a3deb371e4211595b1 Mon Sep 17 00:00:00 2001 From: Yong-Xuan Wang Date: Wed, 15 May 2024 17:11:28 +0800 Subject: [PATCH 25/27] target/riscv/kvm.c: Fix the hart bit setting of AIA In AIA spec, each hart (or each hart within a group) has a unique hart number to locate the memory pages of interrupt files in the address space. The number of bits required to represent any hart number is equal to ceil(log2(hmax + 1)), where hmax is the largest hart number among groups. However, if the largest hart number among groups is a power of 2, QEMU will pass an inaccurate hart-index-bit setting to Linux. For example, when the guest OS has 4 harts, only ceil(log2(3 + 1)) = 2 bits are sufficient to represent 4 harts, but we passes 3 to Linux. The code needs to be updated to ensure accurate hart-index-bit settings. Additionally, a Linux patch[1] is necessary to correctly recover the hart index when the guest OS has only 1 hart, where the hart-index-bit is 0. [1] https://lore.kernel.org/lkml/20240415064905.25184-1-yongxuan.wang@sifive.com/t/ Signed-off-by: Yong-Xuan Wang Reviewed-by: Andrew Jones Cc: qemu-stable Message-ID: <20240515091129.28116-1-yongxuan.wang@sifive.com> Signed-off-by: Alistair Francis --- target/riscv/kvm/kvm-cpu.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c index 473416649f..235e2cdaca 100644 --- a/target/riscv/kvm/kvm-cpu.c +++ b/target/riscv/kvm/kvm-cpu.c @@ -1777,7 +1777,14 @@ void kvm_riscv_aia_create(MachineState *machine, uint64_t group_shift, } } - hart_bits = find_last_bit(&max_hart_per_socket, BITS_PER_LONG) + 1; + + if (max_hart_per_socket > 1) { + max_hart_per_socket--; + hart_bits = find_last_bit(&max_hart_per_socket, BITS_PER_LONG) + 1; + } else { + hart_bits = 0; + } + ret = kvm_device_access(aia_fd, KVM_DEV_RISCV_AIA_GRP_CONFIG, KVM_DEV_RISCV_AIA_CONFIG_HART_BITS, &hart_bits, true, NULL); From 583edc4efb7f4075212bdee281f336edfa532e3f Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 17 May 2024 17:30:54 -0300 Subject: [PATCH 26/27] riscv, gdbstub.c: fix reg_width in ricsv_gen_dynamic_vector_feature() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 33a24910ae changed 'reg_width' to use 'vlenb', i.e. vector length in bytes, when in this context we want 'reg_width' as the length in bits. Fix 'reg_width' back to the value in bits like 7cb59921c05a ("target/riscv/gdbstub.c: use 'vlenb' instead of shifting 'vlen'") set beforehand. While we're at it, rename 'reg_width' to 'bitsize' to provide a bit more clarity about what the variable represents. 'bitsize' is also used in riscv_gen_dynamic_csr_feature() with the same purpose, i.e. as an input to gdb_feature_builder_append_reg(). Cc: Akihiko Odaki Cc: Alex Bennée Reported-by: Robin Dapp Fixes: 33a24910ae ("target/riscv: Use GDBFeature for dynamic XML") Signed-off-by: Daniel Henrique Barboza Reviewed-by: LIU Zhiwei Acked-by: Alex Bennée Reviewed-by: Akihiko Odaki Reviewed-by: Alistair Francis Cc: qemu-stable Message-ID: <20240517203054.880861-2-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/gdbstub.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/target/riscv/gdbstub.c b/target/riscv/gdbstub.c index d0cc5762c2..c07df972f1 100644 --- a/target/riscv/gdbstub.c +++ b/target/riscv/gdbstub.c @@ -288,7 +288,7 @@ static GDBFeature *riscv_gen_dynamic_csr_feature(CPUState *cs, int base_reg) static GDBFeature *ricsv_gen_dynamic_vector_feature(CPUState *cs, int base_reg) { RISCVCPU *cpu = RISCV_CPU(cs); - int reg_width = cpu->cfg.vlenb; + int bitsize = cpu->cfg.vlenb << 3; GDBFeatureBuilder builder; int i; @@ -298,7 +298,7 @@ static GDBFeature *ricsv_gen_dynamic_vector_feature(CPUState *cs, int base_reg) /* First define types and totals in a whole VL */ for (i = 0; i < ARRAY_SIZE(vec_lanes); i++) { - int count = reg_width / vec_lanes[i].size; + int count = bitsize / vec_lanes[i].size; gdb_feature_builder_append_tag( &builder, "", vec_lanes[i].id, vec_lanes[i].gdb_type, count); @@ -316,7 +316,7 @@ static GDBFeature *ricsv_gen_dynamic_vector_feature(CPUState *cs, int base_reg) /* Define vector registers */ for (i = 0; i < 32; i++) { gdb_feature_builder_append_reg(&builder, g_strdup_printf("v%d", i), - reg_width, i, "riscv_vector", "vector"); + bitsize, i, "riscv_vector", "vector"); } gdb_feature_builder_end(&builder); From 915758c537b5fe09575291f4acd87e2d377a93de Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 14 May 2024 15:16:15 +1000 Subject: [PATCH 27/27] disas/riscv: Decode all of the pmpcfg and pmpaddr CSRs Previously we only listed a single pmpcfg CSR and the first 16 pmpaddr CSRs. This patch fixes this to list all 16 pmpcfg and all 64 pmpaddr CSRs are part of the disassembly. Reported-by: Eric DeVolder Signed-off-by: Alistair Francis Fixes: ea10325917 ("RISC-V Disassembler") Reviewed-by: Daniel Henrique Barboza Cc: qemu-stable Message-ID: <20240514051615.330979-1-alistair.francis@wdc.com> Signed-off-by: Alistair Francis --- disas/riscv.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/disas/riscv.c b/disas/riscv.c index e236c8b5b7..297cfa2f63 100644 --- a/disas/riscv.c +++ b/disas/riscv.c @@ -2190,7 +2190,22 @@ static const char *csr_name(int csrno) case 0x0383: return "mibound"; case 0x0384: return "mdbase"; case 0x0385: return "mdbound"; - case 0x03a0: return "pmpcfg3"; + case 0x03a0: return "pmpcfg0"; + case 0x03a1: return "pmpcfg1"; + case 0x03a2: return "pmpcfg2"; + case 0x03a3: return "pmpcfg3"; + case 0x03a4: return "pmpcfg4"; + case 0x03a5: return "pmpcfg5"; + case 0x03a6: return "pmpcfg6"; + case 0x03a7: return "pmpcfg7"; + case 0x03a8: return "pmpcfg8"; + case 0x03a9: return "pmpcfg9"; + case 0x03aa: return "pmpcfg10"; + case 0x03ab: return "pmpcfg11"; + case 0x03ac: return "pmpcfg12"; + case 0x03ad: return "pmpcfg13"; + case 0x03ae: return "pmpcfg14"; + case 0x03af: return "pmpcfg15"; case 0x03b0: return "pmpaddr0"; case 0x03b1: return "pmpaddr1"; case 0x03b2: return "pmpaddr2"; @@ -2207,6 +2222,54 @@ static const char *csr_name(int csrno) case 0x03bd: return "pmpaddr13"; case 0x03be: return "pmpaddr14"; case 0x03bf: return "pmpaddr15"; + case 0x03c0: return "pmpaddr16"; + case 0x03c1: return "pmpaddr17"; + case 0x03c2: return "pmpaddr18"; + case 0x03c3: return "pmpaddr19"; + case 0x03c4: return "pmpaddr20"; + case 0x03c5: return "pmpaddr21"; + case 0x03c6: return "pmpaddr22"; + case 0x03c7: return "pmpaddr23"; + case 0x03c8: return "pmpaddr24"; + case 0x03c9: return "pmpaddr25"; + case 0x03ca: return "pmpaddr26"; + case 0x03cb: return "pmpaddr27"; + case 0x03cc: return "pmpaddr28"; + case 0x03cd: return "pmpaddr29"; + case 0x03ce: return "pmpaddr30"; + case 0x03cf: return "pmpaddr31"; + case 0x03d0: return "pmpaddr32"; + case 0x03d1: return "pmpaddr33"; + case 0x03d2: return "pmpaddr34"; + case 0x03d3: return "pmpaddr35"; + case 0x03d4: return "pmpaddr36"; + case 0x03d5: return "pmpaddr37"; + case 0x03d6: return "pmpaddr38"; + case 0x03d7: return "pmpaddr39"; + case 0x03d8: return "pmpaddr40"; + case 0x03d9: return "pmpaddr41"; + case 0x03da: return "pmpaddr42"; + case 0x03db: return "pmpaddr43"; + case 0x03dc: return "pmpaddr44"; + case 0x03dd: return "pmpaddr45"; + case 0x03de: return "pmpaddr46"; + case 0x03df: return "pmpaddr47"; + case 0x03e0: return "pmpaddr48"; + case 0x03e1: return "pmpaddr49"; + case 0x03e2: return "pmpaddr50"; + case 0x03e3: return "pmpaddr51"; + case 0x03e4: return "pmpaddr52"; + case 0x03e5: return "pmpaddr53"; + case 0x03e6: return "pmpaddr54"; + case 0x03e7: return "pmpaddr55"; + case 0x03e8: return "pmpaddr56"; + case 0x03e9: return "pmpaddr57"; + case 0x03ea: return "pmpaddr58"; + case 0x03eb: return "pmpaddr59"; + case 0x03ec: return "pmpaddr60"; + case 0x03ed: return "pmpaddr61"; + case 0x03ee: return "pmpaddr62"; + case 0x03ef: return "pmpaddr63"; case 0x0780: return "mtohost"; case 0x0781: return "mfromhost"; case 0x0782: return "mreset";