Skip to content

Instantly share code, notes, and snippets.

@luhenry
Created October 17, 2022 13:37
Show Gist options
  • Save luhenry/fd6f44f98582755d56f73b08dd10e7dd to your computer and use it in GitHub Desktop.
Save luhenry/fd6f44f98582755d56f73b08dd10e7dd to your computer and use it in GitHub Desktop.
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 4d0c178479..f559026e2c 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -74,6 +74,8 @@ static const struct isa_ext_data isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(h, false, PRIV_VERSION_1_12_0, ext_h),
ISA_EXT_DATA_ENTRY(v, false, PRIV_VERSION_1_12_0, ext_v),
ISA_EXT_DATA_ENTRY(zicsr, true, PRIV_VERSION_1_10_0, ext_icsr),
+ ISA_EXT_DATA_ENTRY(zicbom, true, PRIV_VERSION_1_10_0, ext_icbom),
+ ISA_EXT_DATA_ENTRY(zicboz, true, PRIV_VERSION_1_10_0, ext_icboz),
ISA_EXT_DATA_ENTRY(zifencei, true, PRIV_VERSION_1_10_0, ext_ifencei),
ISA_EXT_DATA_ENTRY(zihintpause, true, PRIV_VERSION_1_10_0, ext_zihintpause),
ISA_EXT_DATA_ENTRY(zfh, true, PRIV_VERSION_1_12_0, ext_zfh),
@@ -1039,6 +1041,9 @@ static Property riscv_cpu_extensions[] = {
DEFINE_PROP_BOOL("sscofpmf", RISCVCPU, cfg.ext_sscofpmf, false),
DEFINE_PROP_BOOL("Zifencei", RISCVCPU, cfg.ext_ifencei, true),
DEFINE_PROP_BOOL("Zicsr", RISCVCPU, cfg.ext_icsr, true),
+ DEFINE_PROP_BOOL("Zicbom", RISCVCPU, cfg.ext_icbom, true),
+ DEFINE_PROP_BOOL("Zicboz", RISCVCPU, cfg.ext_icboz, true),
+ DEFINE_PROP_UINT16("cbozlen", RISCVCPU, cfg.cbozlen, 64),
DEFINE_PROP_BOOL("Zihintpause", RISCVCPU, cfg.ext_zihintpause, true),
DEFINE_PROP_BOOL("Zfh", RISCVCPU, cfg.ext_zfh, false),
DEFINE_PROP_BOOL("Zfhmin", RISCVCPU, cfg.ext_zfhmin, false),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 8079e17cfb..ef2dac9b8e 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -464,6 +464,8 @@ struct RISCVCPUConfig {
bool ext_zkt;
bool ext_ifencei;
bool ext_icsr;
+ bool ext_icbom;
+ bool ext_icboz;
bool ext_zihintpause;
bool ext_sstc;
bool ext_svinval;
@@ -499,6 +501,7 @@ struct RISCVCPUConfig {
char *vext_spec;
uint16_t vlen;
uint16_t elen;
+ uint16_t cbozlen;
bool mmu;
bool pmp;
bool epmp;
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index f760b3bb56..ea7d3d2b5c 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -97,6 +97,11 @@ DEF_HELPER_FLAGS_2(fcvt_h_l, TCG_CALL_NO_RWG, i64, env, tl)
DEF_HELPER_FLAGS_2(fcvt_h_lu, TCG_CALL_NO_RWG, i64, env, tl)
DEF_HELPER_FLAGS_2(fclass_h, TCG_CALL_NO_RWG_SE, tl, env, i64)
+/* Cache-block operations */
+DEF_HELPER_2(cbo_clean_flush, void, env, tl)
+DEF_HELPER_2(cbo_inval, void, env, tl)
+DEF_HELPER_2(cbo_zero, void, env, tl)
+
/* Special functions */
DEF_HELPER_2(csrr, tl, env, int)
DEF_HELPER_3(csrw, void, env, int, tl)
diff --git a/target/riscv/insn32.decode b/target/riscv/insn32.decode
index 595fdcdad8..d53cbbc44c 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -177,9 +177,22 @@ sllw 0000000 ..... ..... 001 ..... 0111011 @r
srlw 0000000 ..... ..... 101 ..... 0111011 @r
sraw 0100000 ..... ..... 101 ..... 0111011 @r
+{
+ lq ............ ..... 010 ..... 0001111 @i
+
+ # *** RV32 Zicbom Standard Extension ***
+ cbo_inval 0000000 00000 ..... 010 00000 0001111 @sfence_vm
+ cbo_clean 0000000 00001 ..... 010 00000 0001111 @sfence_vm
+ cbo_flush 0000000 00010 ..... 010 00000 0001111 @sfence_vm
+
+ # *** RV32 Zicboz Standard Extension ***
+ cbo_zero 0000000 01000 ..... 010 00000 0001111 @sfence_vm
+
+ # cbo.prefetch_{i,r,m} instructions are ori with rd=x0 and not decoded.
+}
+
# *** RV128I Base Instruction Set (in addition to RV64I) ***
ldu ............ ..... 111 ..... 0000011 @i
-lq ............ ..... 010 ..... 0001111 @i
sq ............ ..... 100 ..... 0100011 @s
addid ............ ..... 000 ..... 1011011 @i
sllid 000000 ...... ..... 001 ..... 1011011 @sh6
diff --git a/target/riscv/insn_trans/trans_rvzicbo.c.inc b/target/riscv/insn_trans/trans_rvzicbo.c.inc
new file mode 100644
index 0000000000..35c277261f
--- /dev/null
+++ b/target/riscv/insn_trans/trans_rvzicbo.c.inc
@@ -0,0 +1,57 @@
+/*
+ * RISC-V translation routines for the RISC-V CBO Extension.
+ *
+ * Copyright (c) 2021 Philipp Tomsich, philipp.tomsich@vrull.eu
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#define REQUIRE_ZICBOM(ctx) do { \
+ if (!RISCV_CPU(ctx->cs)->cfg.ext_icbom) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_ZICBOZ(ctx) do { \
+ if (!RISCV_CPU(ctx->cs)->cfg.ext_icboz) { \
+ return false; \
+ } \
+} while (0)
+
+static bool trans_cbo_clean(DisasContext *ctx, arg_cbo_clean *a)
+{
+ REQUIRE_ZICBOM(ctx);
+ gen_helper_cbo_clean_flush(cpu_env, cpu_gpr[a->rs1]);
+ return true;
+}
+
+static bool trans_cbo_flush(DisasContext *ctx, arg_cbo_flush *a)
+{
+ REQUIRE_ZICBOM(ctx);
+ gen_helper_cbo_clean_flush(cpu_env, cpu_gpr[a->rs1]);
+ return true;
+}
+
+static bool trans_cbo_inval(DisasContext *ctx, arg_cbo_inval *a)
+{
+ REQUIRE_ZICBOM(ctx);
+ gen_helper_cbo_inval(cpu_env, cpu_gpr[a->rs1]);
+ return true;
+}
+
+static bool trans_cbo_zero(DisasContext *ctx, arg_cbo_zero *a)
+{
+ REQUIRE_ZICBOZ(ctx);
+ gen_helper_cbo_zero(cpu_env, cpu_gpr[a->rs1]);
+ return true;
+}
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 452125c4ab..ec11923be8 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -123,6 +123,99 @@ target_ulong helper_csrrw_i128(CPURISCVState *env, int csr,
return int128_getlo(rv);
}
+/* helper_zicbo_envcfg
+ *
+ * Raise virtual exceptions and illegal instruction exceptions for
+ * Zicbo[mz] instructions based on the settings of [mhs]envcfg as
+ * specified in section 2.5.1 of the CMO specification.
+ */
+static void helper_zicbo_envcfg(CPURISCVState *env, target_ulong envbits,
+ uintptr_t ra)
+{
+#ifndef CONFIG_USER_ONLY
+ /* Check for virtual instruction exceptions first, as we don't see
+ * VU and VS reflected in env->priv (these are just the translated
+ * U and S stated with virtualisation enabled.
+ */
+ if (riscv_cpu_virt_enabled(env) &&
+ (((env->priv < PRV_H) && !get_field(env->henvcfg, envbits)) ||
+ ((env->priv < PRV_S) && !get_field(env->senvcfg, envbits)))) {
+ riscv_raise_exception(env, RISCV_EXCP_VIRT_INSTRUCTION_FAULT, ra);
+ }
+
+ if (((env->priv < PRV_M) && !get_field(env->menvcfg, envbits)) ||
+ ((env->priv < PRV_S) && !get_field(env->senvcfg, envbits))) {
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, ra);
+ }
+#endif
+}
+
+/* helper_zicbom_access
+ *
+ * Check access permissions (LOAD, STORE or FETCH as specified in section
+ * 2.5.2 of the CMO specification) for Zicbom, raising either store
+ * page-fault (non-virtualised) or store guest-page fault (virtualised).
+ */
+static void helper_zicbom_access(CPURISCVState *env, target_ulong address,
+ uintptr_t ra)
+{
+ void* phost;
+ int ret = TLB_INVALID_MASK;
+ MMUAccessType access_type = MMU_DATA_LOAD;
+
+ while (ret == TLB_INVALID_MASK && access_type <= MMU_INST_FETCH) {
+ ret = probe_access_flags(env, address, access_type++,
+ cpu_mmu_index(env, false),
+ true, &phost, ra);
+ }
+
+ if (ret == TLB_INVALID_MASK) {
+ uint32_t exc = RISCV_EXCP_STORE_PAGE_FAULT;
+
+#ifndef CONFIG_USER_ONLY
+ /* User-mode emulation does not have virtualisation. */
+ if (riscv_cpu_virt_enabled(env)) {
+ exc = RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT;
+ }
+#endif
+ riscv_raise_exception(env, exc, ra);
+ }
+}
+
+void helper_cbo_clean_flush(CPURISCVState *env, target_ulong address)
+{
+ uintptr_t ra = GETPC();
+ helper_zicbo_envcfg(env, MENVCFG_CBCFE, ra);
+ helper_zicbom_access(env, address, ra);
+}
+
+void helper_cbo_inval(CPURISCVState *env, target_ulong address)
+{
+ uintptr_t ra = GETPC();
+ helper_zicbo_envcfg(env, MENVCFG_CBIE, ra);
+ helper_zicbom_access(env, address, ra);
+}
+
+void helper_cbo_zero(CPURISCVState *env, target_ulong address)
+{
+ uintptr_t ra = GETPC();
+ helper_zicbo_envcfg(env, MENVCFG_CBZE, ra);
+
+ /* Get the size of the cache block for zero instructions. */
+ RISCVCPU *cpu = env_archcpu(env);
+ uint16_t cbozlen = cpu->cfg.cbozlen;
+
+ /* Mask off low-bits to align-down to the cache-block. */
+ address &= ~(cbozlen - 1);
+
+ void* mem = probe_access(env, address, cbozlen, MMU_DATA_STORE,
+ cpu_mmu_index(env, false), GETPC());
+
+ /* Zero the block */
+ memset(mem, 0, cbozlen);
+}
+
+
#ifndef CONFIG_USER_ONLY
static target_ulong check_rcode_privilege_intercept(CPURISCVState *env,
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index dd9c916652..ee15f63174 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -1032,6 +1032,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
#include "insn_trans/trans_rvv.c.inc"
#include "insn_trans/trans_rvb.c.inc"
#include "insn_trans/trans_rvzfh.c.inc"
+#include "insn_trans/trans_rvzicbo.c.inc"
#include "insn_trans/trans_rvk.c.inc"
#include "insn_trans/trans_privileged.c.inc"
#include "insn_trans/trans_svinval.c.inc"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment