From 672cb29d1e811180bf1aeefbcb0936ecd5bd3853 Mon Sep 17 00:00:00 2001 From: Santiago Monserrat Campanello Date: Wed, 5 Mar 2025 11:26:32 +0100 Subject: [PATCH 01/10] docs/about/emulation: Fix broken link semihosting link to risc-v changed Signed-off-by: Santiago Monserrat Campanello Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2717 Reviewed-by: Alistair Francis Reviewed-by: Thomas Huth Message-ID: <20250305102632.91376-1-santimonserr@gmail.com> Signed-off-by: Alistair Francis --- docs/about/emulation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/about/emulation.rst b/docs/about/emulation.rst index 3bc3579434..a72591ee4d 100644 --- a/docs/about/emulation.rst +++ b/docs/about/emulation.rst @@ -171,7 +171,7 @@ for that architecture. - Unified Hosting Interface (MD01069) * - RISC-V - System and User-mode - - https://github.com/riscv/riscv-semihosting-spec/blob/main/riscv-semihosting-spec.adoc + - https://github.com/riscv-non-isa/riscv-semihosting/blob/main/riscv-semihosting.adoc * - Xtensa - System - Tensilica ISS SIMCALL From 17288e38bebf20121c4aa20b264e661a7fa50ed8 Mon Sep 17 00:00:00 2001 From: Paolo Savini Date: Fri, 21 Feb 2025 15:53:20 +0000 Subject: [PATCH 02/10] optimize the memory probing for vector fault-only-first loads. Fault-only-first loads in the RISC-V vector extension need to update the vl with the element index that causes an exception. In order to ensure this the emulation of this instruction used to probe the memory covered by the load operation with a loop that iterated over each element so that when a flag was raised it was possible to set the vl to the corresponding element index. This loop was executed every time whether an exception happened or not. This commit removes the per element memory probing from the main execution path and adds a broad memory probing first. If this probing raises any flag that is not a watchpoint flag (that per standard is allowed by this instruction) we proceed with the per element probing to find the index of the element causing the exception and set vl to such index. Signed-off-by: Paolo Savini Reviewed-by: Daniel Henrique Barboza Message-ID: <20250221155320.59159-2-paolo.savini@embecosm.com> Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 97 ++++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 42 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 7773df6a7c..71b823d5d4 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -633,47 +633,69 @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, uint32_t esz = 1 << log2_esz; uint32_t msize = nf * esz; uint32_t vma = vext_vma(desc); - target_ulong addr, offset, remain, page_split, elems; + target_ulong addr, addr_probe, addr_i, offset, remain, page_split, elems; int mmu_index = riscv_env_mmu_index(env, false); + int flags; + void *host; VSTART_CHECK_EARLY_EXIT(env); - /* probe every access */ - for (i = env->vstart; i < env->vl; i++) { - if (!vm && !vext_elem_mask(v0, i)) { - continue; - } - addr = adjust_addr(env, base + i * (nf << log2_esz)); - if (i == 0) { - /* Allow fault on first element. */ - probe_pages(env, addr, nf << log2_esz, ra, MMU_DATA_LOAD); - } else { - remain = nf << log2_esz; - while (remain > 0) { - void *host; - int flags; + addr = base + ((env->vstart * nf) << log2_esz); + page_split = -(addr | TARGET_PAGE_MASK); + /* Get number of elements */ + elems = page_split / msize; + if (unlikely(env->vstart + elems >= env->vl)) { + elems = env->vl - env->vstart; + } - offset = -(addr | TARGET_PAGE_MASK); + /* Check page permission/pmp/watchpoint/etc. */ + flags = probe_access_flags(env, adjust_addr(env, addr), elems * msize, + MMU_DATA_LOAD, mmu_index, true, &host, ra); - /* Probe nonfault on subsequent elements. */ - flags = probe_access_flags(env, addr, offset, MMU_DATA_LOAD, - mmu_index, true, &host, 0); + /* If we are crossing a page check also the second page. */ + if (env->vl > elems) { + addr_probe = addr + (elems << log2_esz); + flags |= probe_access_flags(env, adjust_addr(env, addr_probe), + elems * msize, MMU_DATA_LOAD, mmu_index, + true, &host, ra); + } - /* - * Stop if invalid (unmapped) or mmio (transaction may fail). - * Do not stop if watchpoint, as the spec says that - * first-fault should continue to access the same - * elements regardless of any watchpoint. - */ - if (flags & ~TLB_WATCHPOINT) { - vl = i; - goto ProbeSuccess; + if (flags & ~TLB_WATCHPOINT) { + /* probe every access */ + for (i = env->vstart; i < env->vl; i++) { + if (!vm && !vext_elem_mask(v0, i)) { + continue; + } + addr_i = adjust_addr(env, base + i * (nf << log2_esz)); + if (i == 0) { + /* Allow fault on first element. */ + probe_pages(env, addr_i, nf << log2_esz, ra, MMU_DATA_LOAD); + } else { + remain = nf << log2_esz; + while (remain > 0) { + offset = -(addr_i | TARGET_PAGE_MASK); + + /* Probe nonfault on subsequent elements. */ + flags = probe_access_flags(env, addr_i, offset, + MMU_DATA_LOAD, mmu_index, true, + &host, 0); + + /* + * Stop if invalid (unmapped) or mmio (transaction may + * fail). Do not stop if watchpoint, as the spec says that + * first-fault should continue to access the same + * elements regardless of any watchpoint. + */ + if (flags & ~TLB_WATCHPOINT) { + vl = i; + goto ProbeSuccess; + } + if (remain <= offset) { + break; + } + remain -= offset; + addr_i = adjust_addr(env, addr_i + offset); } - if (remain <= offset) { - break; - } - remain -= offset; - addr = adjust_addr(env, addr + offset); } } } @@ -685,15 +707,6 @@ ProbeSuccess: if (env->vstart < env->vl) { if (vm) { - /* Calculate the page range of first page */ - addr = base + ((env->vstart * nf) << log2_esz); - page_split = -(addr | TARGET_PAGE_MASK); - /* Get number of elements */ - elems = page_split / msize; - if (unlikely(env->vstart + elems >= env->vl)) { - elems = env->vl - env->vstart; - } - /* Load/store elements in the first page */ if (likely(elems)) { vext_page_ldst_us(env, vd, addr, elems, nf, max_elems, From 86c78b280607fcff787866a03374047c65037a90 Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Wed, 5 Mar 2025 22:46:35 -0800 Subject: [PATCH 03/10] target/riscv: fix access permission checks for CSR_SSP Commit:8205bc1 ("target/riscv: introduce ssp and enabling controls for zicfiss") introduced CSR_SSP but it mis-interpreted the spec on access to CSR_SSP in M-mode. Gated to CSR_SSP is not gated via `xSSE`. But rather rules clearly specified in section "22.2.1. Shadow Stack Pointer (ssp) CSR access contr" in the priv spec. Fixes: 8205bc127a83 ("target/riscv: introduce ssp and enabling controls for zicfiss". Thanks to Adam Zabrocki for bringing this to attention. Reported-by: Adam Zabrocki Signed-off-by: Deepak Gupta Reviewed-by: Alistair Francis Message-ID: <20250306064636.452396-1-debug@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 49566d3c08..8225e9bb4b 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -192,6 +192,11 @@ static RISCVException cfi_ss(CPURISCVState *env, int csrno) return RISCV_EXCP_ILLEGAL_INST; } + /* If ext implemented, M-mode always have access to SSP CSR */ + if (env->priv == PRV_M) { + return RISCV_EXCP_NONE; + } + /* if bcfi not active for current env, access to csr is illegal */ if (!cpu_get_bcfien(env)) { #if !defined(CONFIG_USER_ONLY) From d2c5759c8dd4c00195d4ebecc7d009e41df6baef Mon Sep 17 00:00:00 2001 From: Deepak Gupta Date: Wed, 5 Mar 2025 22:46:36 -0800 Subject: [PATCH 04/10] target/riscv: fixes a bug against `ssamoswap` behavior in M-mode Commit f06bfe3dc38c ("target/riscv: implement zicfiss instructions") adds `ssamoswap` instruction. `ssamoswap` takes the code-point from existing reserved encoding (and not a zimop like other shadow stack instructions). If shadow stack is not enabled (via xenvcfg.SSE) and effective priv is less than M then `ssamoswap` must result in an illegal instruction exception. However if effective priv is M, then `ssamoswap` results in store/AMO access fault. See Section "22.2.3. Shadow Stack Memory Protection" of priv spec. Fixes: f06bfe3dc38c ("target/riscv: implement zicfiss instructions") Reported-by: Ved Shanbhogue Signed-off-by: Deepak Gupta Reviewed-by: Alistair Francis Message-ID: <20250306064636.452396-2-debug@rivosinc.com> Signed-off-by: Alistair Francis --- target/riscv/insn_trans/trans_rvzicfiss.c.inc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/target/riscv/insn_trans/trans_rvzicfiss.c.inc b/target/riscv/insn_trans/trans_rvzicfiss.c.inc index e3ebc4977c..b0096adcd0 100644 --- a/target/riscv/insn_trans/trans_rvzicfiss.c.inc +++ b/target/riscv/insn_trans/trans_rvzicfiss.c.inc @@ -15,6 +15,13 @@ * You should have received a copy of the GNU General Public License along with * this program. If not, see . */ + +#define REQUIRE_ZICFISS(ctx) do { \ + if (!ctx->cfg_ptr->ext_zicfiss) { \ + return false; \ + } \ +} while (0) + static bool trans_sspopchk(DisasContext *ctx, arg_sspopchk *a) { if (!ctx->bcfi_enabled) { @@ -77,6 +84,11 @@ static bool trans_ssrdp(DisasContext *ctx, arg_ssrdp *a) static bool trans_ssamoswap_w(DisasContext *ctx, arg_amoswap_w *a) { REQUIRE_A_OR_ZAAMO(ctx); + REQUIRE_ZICFISS(ctx); + if (ctx->priv == PRV_M) { + generate_exception(ctx, RISCV_EXCP_STORE_AMO_ACCESS_FAULT); + } + if (!ctx->bcfi_enabled) { return false; } @@ -97,6 +109,11 @@ static bool trans_ssamoswap_d(DisasContext *ctx, arg_amoswap_w *a) { REQUIRE_64BIT(ctx); REQUIRE_A_OR_ZAAMO(ctx); + REQUIRE_ZICFISS(ctx); + if (ctx->priv == PRV_M) { + generate_exception(ctx, RISCV_EXCP_STORE_AMO_ACCESS_FAULT); + } + if (!ctx->bcfi_enabled) { return false; } From 3ea8fb521d6161a64879b6f43fac46b4d80d2e39 Mon Sep 17 00:00:00 2001 From: Jason Chien Date: Sun, 2 Mar 2025 01:37:51 +0800 Subject: [PATCH 05/10] hw/riscv/riscv-iommu: Fix process directory table walk The PPN field in a non-leaf PDT entry is positioned differently from that in a leaf PDT entry. The original implementation incorrectly used the leaf entry's PPN mask to extract the PPN from a non-leaf entry, leading to an erroneous page table walk. This commit introduces new macros to properly define the fields for non-leaf PDT entries and corrects the page table walk. Signed-off-by: Jason Chien Reviewed-by: Daniel Henrique Barboza Message-ID: <20250301173751.9446-1-jason.chien@sifive.com> Signed-off-by: Alistair Francis --- hw/riscv/riscv-iommu-bits.h | 6 +++++- hw/riscv/riscv-iommu.c | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/riscv/riscv-iommu-bits.h b/hw/riscv/riscv-iommu-bits.h index b7cb1bc736..1017d73fc6 100644 --- a/hw/riscv/riscv-iommu-bits.h +++ b/hw/riscv/riscv-iommu-bits.h @@ -415,12 +415,16 @@ enum riscv_iommu_fq_causes { #define RISCV_IOMMU_DC_MSIPTP_MODE_OFF 0 #define RISCV_IOMMU_DC_MSIPTP_MODE_FLAT 1 +/* 2.2 Process Directory Table */ +#define RISCV_IOMMU_PDTE_VALID BIT_ULL(0) +#define RISCV_IOMMU_PDTE_PPN RISCV_IOMMU_PPN_FIELD + /* Translation attributes fields */ #define RISCV_IOMMU_PC_TA_V BIT_ULL(0) #define RISCV_IOMMU_PC_TA_RESERVED GENMASK_ULL(63, 32) /* First stage context fields */ -#define RISCV_IOMMU_PC_FSC_PPN GENMASK_ULL(43, 0) +#define RISCV_IOMMU_PC_FSC_PPN RISCV_IOMMU_ATP_PPN_FIELD #define RISCV_IOMMU_PC_FSC_RESERVED GENMASK_ULL(59, 44) enum riscv_iommu_fq_ttypes { diff --git a/hw/riscv/riscv-iommu.c b/hw/riscv/riscv-iommu.c index d46beb2d64..76e0fcd873 100644 --- a/hw/riscv/riscv-iommu.c +++ b/hw/riscv/riscv-iommu.c @@ -1042,10 +1042,10 @@ static int riscv_iommu_ctx_fetch(RISCVIOMMUState *s, RISCVIOMMUContext *ctx) return RISCV_IOMMU_FQ_CAUSE_PDT_LOAD_FAULT; } le64_to_cpus(&de); - if (!(de & RISCV_IOMMU_PC_TA_V)) { + if (!(de & RISCV_IOMMU_PDTE_VALID)) { return RISCV_IOMMU_FQ_CAUSE_PDT_INVALID; } - addr = PPN_PHYS(get_field(de, RISCV_IOMMU_PC_FSC_PPN)); + addr = PPN_PHYS(get_field(de, RISCV_IOMMU_PDTE_PPN)); } riscv_iommu_hpm_incr_ctr(s, ctx, RISCV_IOMMU_HPMEVENT_PD_WALK); From ec6411a5251de3479d44c6e539d0e9596c68909b Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Fri, 7 Mar 2025 09:46:02 -0300 Subject: [PATCH 06/10] target/riscv/csr.c: fix OVERFLOW_BEFORE_WIDEN in rmw_sctrdepth() Coverity found the following issue: >>> CID 1593156: Integer handling issues (OVERFLOW_BEFORE_WIDEN) >>> Potentially overflowing expression "0x10 << depth" with type "int" (32 bits, signed) is evaluated using 32-bit arithmetic, and then used in a context that expects an expression of type "uint64_t" (64 bits, unsigned). 4299 depth = 16 << depth; Fix it by forcing the expression to be 64 bits wide by using '16ULL'. Resolves: Coverity CID 1593156 Fixes: c48bd18eae ("target/riscv: Add support for Control Transfer Records extension CSRs.") Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20250307124602.1905754-1-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- target/riscv/csr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 8225e9bb4b..7948188356 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -4302,7 +4302,7 @@ static RISCVException rmw_sctrdepth(CPURISCVState *env, int csrno, } /* Update sctrstatus.WRPTR with a legal value */ - depth = 16 << depth; + depth = 16ULL << depth; env->sctrstatus = env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1)); } From e83845316abcea9024eb5402a6c5eb8b092c79d5 Mon Sep 17 00:00:00 2001 From: Chao Liu Date: Mon, 10 Mar 2025 10:35:24 +0800 Subject: [PATCH 07/10] target/riscv: refactor VSTART_CHECK_EARLY_EXIT() to accept vl as a parameter Some vector instructions are special, such as the vlm.v instruction, where setting its vl actually sets evl = (vl + 7) >> 3. To improve maintainability, we will uniformly use VSTART_CHECK_EARLY_EXIT() to check for the condition vstart >= vl. This function will also handle cases involving evl. Fixes: df4252b2ec ("target/riscv/vector_helpers: do early exit when vstart >= vl") Signed-off-by: Chao Liu Reviewed-by: Daniel Henrique Barboza Message-ID: Signed-off-by: Alistair Francis --- target/riscv/vcrypto_helper.c | 32 +++++++-------- target/riscv/vector_helper.c | 69 ++++++++++++++++----------------- target/riscv/vector_internals.c | 4 +- target/riscv/vector_internals.h | 12 +++--- 4 files changed, 57 insertions(+), 60 deletions(-) diff --git a/target/riscv/vcrypto_helper.c b/target/riscv/vcrypto_helper.c index f7423df226..1526de96f5 100644 --- a/target/riscv/vcrypto_helper.c +++ b/target/riscv/vcrypto_helper.c @@ -222,7 +222,7 @@ static inline void xor_round_key(AESState *round_state, AESState *round_key) uint32_t total_elems = vext_get_total_elems(env, desc, 4); \ uint32_t vta = vext_vta(desc); \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { \ AESState round_key; \ @@ -248,7 +248,7 @@ static inline void xor_round_key(AESState *round_state, AESState *round_key) uint32_t total_elems = vext_get_total_elems(env, desc, 4); \ uint32_t vta = vext_vta(desc); \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { \ AESState round_key; \ @@ -309,7 +309,7 @@ void HELPER(vaeskf1_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm, uint32_t total_elems = vext_get_total_elems(env, desc, 4); uint32_t vta = vext_vta(desc); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, vl); uimm &= 0b1111; if (uimm > 10 || uimm == 0) { @@ -357,7 +357,7 @@ void HELPER(vaeskf2_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm, uint32_t total_elems = vext_get_total_elems(env, desc, 4); uint32_t vta = vext_vta(desc); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, vl); uimm &= 0b1111; if (uimm > 14 || uimm < 2) { @@ -465,7 +465,7 @@ void HELPER(vsha2ms_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env, uint32_t total_elems; uint32_t vta = vext_vta(desc); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { if (sew == MO_32) { @@ -582,7 +582,7 @@ void HELPER(vsha2ch32_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env, uint32_t total_elems; uint32_t vta = vext_vta(desc); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { vsha2c_32(((uint32_t *)vs2) + 4 * i, ((uint32_t *)vd) + 4 * i, @@ -602,7 +602,7 @@ void HELPER(vsha2ch64_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env, uint32_t total_elems; uint32_t vta = vext_vta(desc); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { vsha2c_64(((uint64_t *)vs2) + 4 * i, ((uint64_t *)vd) + 4 * i, @@ -622,7 +622,7 @@ void HELPER(vsha2cl32_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env, uint32_t total_elems; uint32_t vta = vext_vta(desc); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { vsha2c_32(((uint32_t *)vs2) + 4 * i, ((uint32_t *)vd) + 4 * i, @@ -642,7 +642,7 @@ void HELPER(vsha2cl64_vv)(void *vd, void *vs1, void *vs2, CPURISCVState *env, uint32_t total_elems; uint32_t vta = vext_vta(desc); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { vsha2c_64(((uint64_t *)vs2) + 4 * i, ((uint64_t *)vd) + 4 * i, @@ -676,7 +676,7 @@ void HELPER(vsm3me_vv)(void *vd_vptr, void *vs1_vptr, void *vs2_vptr, uint32_t *vs1 = vs1_vptr; uint32_t *vs2 = vs2_vptr; - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (int i = env->vstart / 8; i < env->vl / 8; i++) { uint32_t w[24]; @@ -777,7 +777,7 @@ void HELPER(vsm3c_vi)(void *vd_vptr, void *vs2_vptr, uint32_t uimm, uint32_t *vs2 = vs2_vptr; uint32_t v1[8], v2[8], v3[8]; - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (int i = env->vstart / 8; i < env->vl / 8; i++) { for (int k = 0; k < 8; k++) { @@ -802,7 +802,7 @@ void HELPER(vghsh_vv)(void *vd_vptr, void *vs1_vptr, void *vs2_vptr, uint32_t vta = vext_vta(desc); uint32_t total_elems = vext_get_total_elems(env, desc, 4); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { uint64_t Y[2] = {vd[i * 2 + 0], vd[i * 2 + 1]}; @@ -841,7 +841,7 @@ void HELPER(vgmul_vv)(void *vd_vptr, void *vs2_vptr, CPURISCVState *env, uint32_t vta = vext_vta(desc); uint32_t total_elems = vext_get_total_elems(env, desc, 4); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (uint32_t i = env->vstart / 4; i < env->vl / 4; i++) { uint64_t Y[2] = {brev8(vd[i * 2 + 0]), brev8(vd[i * 2 + 1])}; @@ -879,7 +879,7 @@ void HELPER(vsm4k_vi)(void *vd, void *vs2, uint32_t uimm5, CPURISCVState *env, uint32_t esz = sizeof(uint32_t); uint32_t total_elems = vext_get_total_elems(env, desc, esz); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (uint32_t i = group_start; i < group_end; ++i) { uint32_t vstart = i * egs; @@ -937,7 +937,7 @@ void HELPER(vsm4r_vv)(void *vd, void *vs2, CPURISCVState *env, uint32_t desc) uint32_t esz = sizeof(uint32_t); uint32_t total_elems = vext_get_total_elems(env, desc, esz); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (uint32_t i = group_start; i < group_end; ++i) { uint32_t vstart = i * egs; @@ -973,7 +973,7 @@ void HELPER(vsm4r_vs)(void *vd, void *vs2, CPURISCVState *env, uint32_t desc) uint32_t esz = sizeof(uint32_t); uint32_t total_elems = vext_get_total_elems(env, desc, esz); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (uint32_t i = group_start; i < group_end; ++i) { uint32_t vstart = i * egs; diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 71b823d5d4..217d2f60a5 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -260,7 +260,7 @@ vext_ldst_stride(void *vd, void *v0, target_ulong base, target_ulong stride, uint32_t esz = 1 << log2_esz; uint32_t vma = vext_vma(desc); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); for (i = env->vstart; i < env->vl; env->vstart = ++i) { k = 0; @@ -383,10 +383,7 @@ vext_ldst_us(void *vd, target_ulong base, CPURISCVState *env, uint32_t desc, uint32_t msize = nf * esz; int mmu_index = riscv_env_mmu_index(env, false); - if (env->vstart >= evl) { - env->vstart = 0; - return; - } + VSTART_CHECK_EARLY_EXIT(env, evl); #if defined(CONFIG_USER_ONLY) /* @@ -544,7 +541,7 @@ vext_ldst_index(void *vd, void *v0, target_ulong base, uint32_t esz = 1 << log2_esz; uint32_t vma = vext_vma(desc); - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); /* load bytes from guest memory */ for (i = env->vstart; i < env->vl; env->vstart = ++i) { @@ -638,7 +635,7 @@ vext_ldff(void *vd, void *v0, target_ulong base, CPURISCVState *env, int flags; void *host; - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, env->vl); addr = base + ((env->vstart * nf) << log2_esz); page_split = -(addr | TARGET_PAGE_MASK); @@ -1116,7 +1113,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ @@ -1150,7 +1147,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ @@ -1187,7 +1184,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ @@ -1227,7 +1224,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ uint32_t vta_all_1s = vext_vta_all_1s(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ @@ -1325,7 +1322,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -1374,7 +1371,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -1438,7 +1435,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ @@ -1505,7 +1502,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ @@ -2054,7 +2051,7 @@ void HELPER(NAME)(void *vd, void *vs1, CPURISCVState *env, \ uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ @@ -2080,7 +2077,7 @@ void HELPER(NAME)(void *vd, uint64_t s1, CPURISCVState *env, \ uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ *((ETYPE *)vd + H(i)) = (ETYPE)s1; \ @@ -2105,7 +2102,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE *vt = (!vext_elem_mask(v0, i) ? vs2 : vs1); \ @@ -2131,7 +2128,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, \ uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ @@ -2178,7 +2175,7 @@ vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2, uint32_t vl, uint32_t vm, int vxrm, opivv2_rm_fn *fn, uint32_t vma, uint32_t esz) { - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, vl); for (uint32_t i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { @@ -2305,7 +2302,7 @@ vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2, uint32_t vl, uint32_t vm, int vxrm, opivx2_rm_fn *fn, uint32_t vma, uint32_t esz) { - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, vl); for (uint32_t i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { @@ -3104,7 +3101,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -3149,7 +3146,7 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -3737,7 +3734,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ if (vl == 0) { \ return; \ @@ -4260,7 +4257,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s1 = *((ETYPE *)vs1 + H(i)); \ @@ -4302,7 +4299,7 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ @@ -4497,7 +4494,7 @@ void HELPER(NAME)(void *vd, void *v0, uint64_t s1, void *vs2, \ uint32_t vta = vext_vta(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ ETYPE s2 = *((ETYPE *)vs2 + H(i)); \ @@ -4827,7 +4824,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ uint32_t i; \ int a, b; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ a = vext_elem_mask(vs1, i); \ @@ -5022,7 +5019,7 @@ void HELPER(NAME)(void *vd, void *v0, CPURISCVState *env, uint32_t desc) \ uint32_t vma = vext_vma(desc); \ int i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -5059,7 +5056,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vma = vext_vma(desc); \ target_ulong offset = s1, i_min, i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ i_min = MAX(env->vstart, offset); \ for (i = i_min; i < vl; i++) { \ @@ -5094,7 +5091,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint32_t vma = vext_vma(desc); \ target_ulong i_max, i_min, i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ i_min = MIN(s1 < vlmax ? vlmax - s1 : 0, vl); \ i_max = MAX(i_min, env->vstart); \ @@ -5138,7 +5135,7 @@ static void vslide1up_##BITWIDTH(void *vd, void *v0, uint64_t s1, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -5189,7 +5186,7 @@ static void vslide1down_##BITWIDTH(void *vd, void *v0, uint64_t s1, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -5266,7 +5263,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint64_t index; \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -5311,7 +5308,7 @@ void HELPER(NAME)(void *vd, void *v0, target_ulong s1, void *vs2, \ uint64_t index = s1; \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -5407,7 +5404,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ diff --git a/target/riscv/vector_internals.c b/target/riscv/vector_internals.c index 05b2d01e58..b490b1d398 100644 --- a/target/riscv/vector_internals.c +++ b/target/riscv/vector_internals.c @@ -66,7 +66,7 @@ void do_vext_vv(void *vd, void *v0, void *vs1, void *vs2, uint32_t vma = vext_vma(desc); uint32_t i; - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, vl); for (i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { @@ -92,7 +92,7 @@ void do_vext_vx(void *vd, void *v0, target_long s1, void *vs2, uint32_t vma = vext_vma(desc); uint32_t i; - VSTART_CHECK_EARLY_EXIT(env); + VSTART_CHECK_EARLY_EXIT(env, vl); for (i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { diff --git a/target/riscv/vector_internals.h b/target/riscv/vector_internals.h index a11cc8366d..8eee7e5c31 100644 --- a/target/riscv/vector_internals.h +++ b/target/riscv/vector_internals.h @@ -25,11 +25,11 @@ #include "tcg/tcg-gvec-desc.h" #include "internals.h" -#define VSTART_CHECK_EARLY_EXIT(env) do { \ - if (env->vstart >= env->vl) { \ - env->vstart = 0; \ - return; \ - } \ +#define VSTART_CHECK_EARLY_EXIT(env, vl) do { \ + if (env->vstart >= vl) { \ + env->vstart = 0; \ + return; \ + } \ } while (0) static inline uint32_t vext_nf(uint32_t desc) @@ -159,7 +159,7 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, \ uint32_t vma = vext_vma(desc); \ uint32_t i; \ \ - VSTART_CHECK_EARLY_EXIT(env); \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ From 4e9e2478dfd26480bbf50367a67b9be0edafef2b Mon Sep 17 00:00:00 2001 From: Chao Liu Date: Mon, 10 Mar 2025 10:35:25 +0800 Subject: [PATCH 08/10] target/riscv: fix handling of nop for vstart >= vl in some vector instruction Recently, when I was writing a RISCV test, I found that when VL is set to 0, the instruction should be nop, but when I tested it, I found that QEMU will treat all elements as tail elements, and in the case of VTA=1, write all elements to 1. After troubleshooting, it was found that the vext_vx_rm_1 function was called in the vext_vx_rm_2, and then the vext_set_elems_1s function was called to process the tail element, but only VSTART >= vl was checked in the vext_vx_rm_1 function, which caused the tail element to still be processed even if it was returned in advance. So I've made the following change: Put VSTART_CHECK_EARLY_EXIT(env) at the beginning of the vext_vx_rm_2 function, so that the VSTART register is checked correctly. Fixes: df4252b2ec ("target/riscv/vector_helpers: do early exit when vstart >= vl") Signed-off-by: Chao Liu Reviewed-by: Daniel Henrique Barboza Message-ID: Signed-off-by: Alistair Francis --- target/riscv/vector_helper.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c index 217d2f60a5..67b3bafebb 100644 --- a/target/riscv/vector_helper.c +++ b/target/riscv/vector_helper.c @@ -2175,8 +2175,6 @@ vext_vv_rm_1(void *vd, void *v0, void *vs1, void *vs2, uint32_t vl, uint32_t vm, int vxrm, opivv2_rm_fn *fn, uint32_t vma, uint32_t esz) { - VSTART_CHECK_EARLY_EXIT(env, vl); - for (uint32_t i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { /* set masked-off elements to 1s */ @@ -2200,6 +2198,8 @@ vext_vv_rm_2(void *vd, void *v0, void *vs1, void *vs2, uint32_t vta = vext_vta(desc); uint32_t vma = vext_vma(desc); + VSTART_CHECK_EARLY_EXIT(env, vl); + switch (env->vxrm) { case 0: /* rnu */ vext_vv_rm_1(vd, v0, vs1, vs2, @@ -2302,8 +2302,6 @@ vext_vx_rm_1(void *vd, void *v0, target_long s1, void *vs2, uint32_t vl, uint32_t vm, int vxrm, opivx2_rm_fn *fn, uint32_t vma, uint32_t esz) { - VSTART_CHECK_EARLY_EXIT(env, vl); - for (uint32_t i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { /* set masked-off elements to 1s */ @@ -2327,6 +2325,8 @@ vext_vx_rm_2(void *vd, void *v0, target_long s1, void *vs2, uint32_t vta = vext_vta(desc); uint32_t vma = vext_vma(desc); + VSTART_CHECK_EARLY_EXIT(env, vl); + switch (env->vxrm) { case 0: /* rnu */ vext_vx_rm_1(vd, v0, s1, vs2, @@ -4662,6 +4662,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ uint32_t i; \ TD s1 = *((TD *)vs1 + HD(0)); \ \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ + \ for (i = env->vstart; i < vl; i++) { \ TS2 s2 = *((TS2 *)vs2 + HS2(i)); \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -4750,6 +4752,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, \ uint32_t i; \ TD s1 = *((TD *)vs1 + HD(0)); \ \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ + \ for (i = env->vstart; i < vl; i++) { \ TS2 s2 = *((TS2 *)vs2 + HS2(i)); \ if (!vm && !vext_elem_mask(v0, i)) { \ @@ -4914,6 +4918,8 @@ static void vmsetm(void *vd, void *v0, void *vs2, CPURISCVState *env, int i; bool first_mask_bit = false; + VSTART_CHECK_EARLY_EXIT(env, vl); + for (i = env->vstart; i < vl; i++) { if (!vm && !vext_elem_mask(v0, i)) { /* set masked-off elements to 1s */ @@ -4986,6 +4992,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs2, CPURISCVState *env, \ uint32_t sum = 0; \ int i; \ \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ + \ for (i = env->vstart; i < vl; i++) { \ if (!vm && !vext_elem_mask(v0, i)) { \ /* set masked-off elements to 1s */ \ @@ -5344,6 +5352,8 @@ void HELPER(NAME)(void *vd, void *v0, void *vs1, void *vs2, \ uint32_t vta = vext_vta(desc); \ uint32_t num = 0, i; \ \ + VSTART_CHECK_EARLY_EXIT(env, vl); \ + \ for (i = env->vstart; i < vl; i++) { \ if (!vext_elem_mask(vs1, i)) { \ continue; \ From 1a010d22b7adecf0fb1c069e1e535af1aa51e9cf Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Sat, 8 Mar 2025 14:58:40 -0800 Subject: [PATCH 09/10] linux-user/riscv: Fix handling of cpu mask in riscv_hwprobe syscall The third argument of the syscall contains the size of the cpu mask in bytes, not bits. Nor is the size rounded up to a multiple of sizeof(abi_ulong). Cc: qemu-stable@nongnu.org Reported-by: Andreas Schwab Fixes: 9e1c7d982d7 ("linux-user/riscv: Add syscall riscv_hwprobe") Signed-off-by: Richard Henderson Reviewed-by: Alistair Francis Message-ID: <20250308225902.1208237-3-richard.henderson@linaro.org> Signed-off-by: Alistair Francis --- linux-user/syscall.c | 55 +++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b32de763f7..8bfe4912e1 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -9119,35 +9119,38 @@ static void risc_hwprobe_fill_pairs(CPURISCVState *env, } } -static int cpu_set_valid(abi_long arg3, abi_long arg4) +/* + * If the cpumask_t of (target_cpus, cpusetsize) cannot be read: -EFAULT. + * If the cpumast_t has no bits set: -EINVAL. + * Otherwise the cpumask_t contains some bit set: 0. + * Unlike the kernel, we do not mask cpumask_t by the set of online cpus, + * nor bound the search by cpumask_size(). + */ +static int nonempty_cpu_set(abi_ulong cpusetsize, abi_ptr target_cpus) { - int ret, i, tmp; - size_t host_mask_size, target_mask_size; - unsigned long *host_mask; + unsigned char *p = lock_user(VERIFY_READ, target_cpus, cpusetsize, 1); + int ret = -TARGET_EFAULT; - /* - * cpu_set_t represent CPU masks as bit masks of type unsigned long *. - * arg3 contains the cpu count. - */ - tmp = (8 * sizeof(abi_ulong)); - target_mask_size = ((arg3 + tmp - 1) / tmp) * sizeof(abi_ulong); - host_mask_size = (target_mask_size + (sizeof(*host_mask) - 1)) & - ~(sizeof(*host_mask) - 1); - - host_mask = alloca(host_mask_size); - - ret = target_to_host_cpu_mask(host_mask, host_mask_size, - arg4, target_mask_size); - if (ret != 0) { - return ret; - } - - for (i = 0 ; i < host_mask_size / sizeof(*host_mask); i++) { - if (host_mask[i] != 0) { - return 0; + if (p) { + ret = -TARGET_EINVAL; + /* + * Since we only care about the empty/non-empty state of the cpumask_t + * not the individual bits, we do not need to repartition the bits + * from target abi_ulong to host unsigned long. + * + * Note that the kernel does not round up cpusetsize to a multiple of + * sizeof(abi_ulong). After bounding cpusetsize by cpumask_size(), + * it copies exactly cpusetsize bytes into a zeroed buffer. + */ + for (abi_ulong i = 0; i < cpusetsize; ++i) { + if (p[i]) { + ret = 0; + break; + } } + unlock_user(p, target_cpus, 0); } - return -TARGET_EINVAL; + return ret; } static abi_long do_riscv_hwprobe(CPUArchState *cpu_env, abi_long arg1, @@ -9164,7 +9167,7 @@ static abi_long do_riscv_hwprobe(CPUArchState *cpu_env, abi_long arg1, /* check cpu_set */ if (arg3 != 0) { - ret = cpu_set_valid(arg3, arg4); + ret = nonempty_cpu_set(arg3, arg4); if (ret != 0) { return ret; } From ffe4db11f8aed79c7ec7d3ebd92674a1cfab4fe7 Mon Sep 17 00:00:00 2001 From: Yu-Ming Chang Date: Thu, 13 Mar 2025 14:07:58 +0800 Subject: [PATCH 10/10] target/riscv: Add check for 16-bit aligned PC for different priv versions. For privilege version 1.12 or newer, C always implies Zca. We can only check ext_zca to allow 16-bit aligned PC addresses. For older privilege versions, we only check C. Signed-off-by: Yu-Ming Chang Reviewed-by: Alistair Francis Message-ID: <174184718265.10540.10120024221661781046-0@git.sr.ht> Signed-off-by: Alistair Francis --- target/riscv/cpu.h | 12 ++++++++++++ target/riscv/insn_trans/trans_rvi.c.inc | 8 ++++++-- target/riscv/op_helper.c | 8 ++++++-- target/riscv/translate.c | 4 +++- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index 7de19b4183..51e49e03de 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -765,6 +765,18 @@ static inline RISCVMXL riscv_cpu_sxl(CPURISCVState *env) } #endif +static inline bool riscv_cpu_allow_16bit_insn(const RISCVCPUConfig *cfg, + target_long priv_ver, + uint32_t misa_ext) +{ + /* In priv spec version 1.12 or newer, C always implies Zca */ + if (priv_ver >= PRIV_VERSION_1_12_0) { + return cfg->ext_zca; + } else { + return misa_ext & RVC; + } +} + /* * Encode LMUL to lmul as follows: * LMUL vlmul lmul diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc index b55f56a5eb..b9c7160468 100644 --- a/target/riscv/insn_trans/trans_rvi.c.inc +++ b/target/riscv/insn_trans/trans_rvi.c.inc @@ -151,7 +151,9 @@ static bool trans_jalr(DisasContext *ctx, arg_jalr *a) tcg_gen_ext32s_tl(target_pc, target_pc); } - if (!has_ext(ctx, RVC) && !ctx->cfg_ptr->ext_zca) { + if (!riscv_cpu_allow_16bit_insn(ctx->cfg_ptr, + ctx->priv_ver, + ctx->misa_ext)) { TCGv t0 = tcg_temp_new(); misaligned = gen_new_label(); @@ -300,7 +302,9 @@ static bool gen_branch(DisasContext *ctx, arg_b *a, TCGCond cond) gen_set_label(l); /* branch taken */ - if (!has_ext(ctx, RVC) && !ctx->cfg_ptr->ext_zca && + if (!riscv_cpu_allow_16bit_insn(ctx->cfg_ptr, + ctx->priv_ver, + ctx->misa_ext) && (a->imm & 0x3)) { /* misaligned */ TCGv target_pc = tcg_temp_new(); diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c index 0d4220ba93..72dc48e58d 100644 --- a/target/riscv/op_helper.c +++ b/target/riscv/op_helper.c @@ -279,7 +279,9 @@ target_ulong helper_sret(CPURISCVState *env) } target_ulong retpc = env->sepc; - if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) { + if (!riscv_cpu_allow_16bit_insn(&env_archcpu(env)->cfg, + env->priv_ver, + env->misa_ext) && (retpc & 0x3)) { riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC()); } @@ -357,7 +359,9 @@ static void check_ret_from_m_mode(CPURISCVState *env, target_ulong retpc, riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC()); } - if (!riscv_has_ext(env, RVC) && (retpc & 0x3)) { + if (!riscv_cpu_allow_16bit_insn(&env_archcpu(env)->cfg, + env->priv_ver, + env->misa_ext) && (retpc & 0x3)) { riscv_raise_exception(env, RISCV_EXCP_INST_ADDR_MIS, GETPC()); } diff --git a/target/riscv/translate.c b/target/riscv/translate.c index eaa5d86eae..d6651f244f 100644 --- a/target/riscv/translate.c +++ b/target/riscv/translate.c @@ -606,7 +606,9 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm) TCGv succ_pc = dest_gpr(ctx, rd); /* check misaligned: */ - if (!has_ext(ctx, RVC) && !ctx->cfg_ptr->ext_zca) { + if (!riscv_cpu_allow_16bit_insn(ctx->cfg_ptr, + ctx->priv_ver, + ctx->misa_ext)) { if ((imm & 0x3) != 0) { TCGv target_pc = tcg_temp_new(); gen_pc_plus_diff(target_pc, ctx, imm);