aboutsummaryrefslogtreecommitdiff
path: root/target/riscv
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2023-03-07 12:53:00 +0000
committerPeter Maydell <peter.maydell@linaro.org>2023-03-07 12:53:00 +0000
commit9832009d9dd2386664c15cc70f6e6bfe062be8bd (patch)
treeea3821c795d341ac30bd0e8e762a2ccdbdcbb058 /target/riscv
parentc29a2f40cd5d1fdad4632b48343cd968db041a44 (diff)
parent47fc340010335bc2549bc1f07e5fd85d86a2b9f9 (diff)
downloadqemu-9832009d9dd2386664c15cc70f6e6bfe062be8bd.zip
qemu-9832009d9dd2386664c15cc70f6e6bfe062be8bd.tar.gz
qemu-9832009d9dd2386664c15cc70f6e6bfe062be8bd.tar.bz2
Merge tag 'pull-riscv-to-apply-20230306' of https://gitlab.com/palmer-dabbelt/qemu into staging
Sixth RISC-V PR for 8.0 * Support for the Zicbiom, ZCicboz, and Zicbop extensions. * OpenSBI has been updated to version 1.2, see <https://github.com/riscv-software-src/opensbi/releases/tag/v1.2> for the release notes. * Support for setting the virtual address width (ie, sv39/sv48/sv57) on the command line. * Support for ACPI on RISC-V. # -----BEGIN PGP SIGNATURE----- # # iQJHBAABCAAxFiEEKzw3R0RoQ7JKlDp6LhMZ81+7GIkFAmQGYGgTHHBhbG1lckBk # YWJiZWx0LmNvbQAKCRAuExnzX7sYidmyEAC6FEMbbFM5D++qR6w6xM6hXgzcrev6 # s1kyRRNVa45uSA78ti/Zi0hsDLNf7ZsNPndF0OIkkO5iAE0OVm3LU7tV1TqKcT82 # Dd9VXxe93zEmfnuJazHrMa54SXPhhnNdWHtKlZ6vBfZpbxgx0FFs50xkCsrM5LQZ # hYHxQUqPWQTvF2MdDHrxCuLcdKl+Wg3ysCcgRh2d049KUBrIu6vNaHC2+AGRjCbj # BkrGCkB82fTmVJjzAcVWQxLoAV12pCbJS4og1GtP8hA7WevtB39tbPin9siBKRZp # QBeiIsg0nebkpmZGrb+xWVwlIBNe9yYwJa0KmveQk8v7L5RIzjM1mtDL91VrVljC # KC2tfT570m0Iq2NoFMb3wd/kESHFzVDM/g+XYqRd4KSoiCNP/RbqYNQBwbMc31Tr # E27xfA1D8w2vem0Rk20x3KgPf1Z5OmGXjq6YObTpnAzG8cZlA37qKBP+ortt5aHX # GZSg3CAwknHHVajd4aaegkPsHxm1tRvoTfh38MwkPSNxaA9GD0nz0k9xaYDmeZ2L # olfanNsaQEwcVUId31+7sAENg1TZU0fnj879/nxkMUCazVTdL8/mz+IoTTx0QCST # 3+9ATWcyJUlmjbDKIs7kr1L+wJdvvHEJggPAbbPI8ekpXaLZvUYOT6ObzYKNAmwY # wELQBn8QKXcLVA== # =5gAt # -----END PGP SIGNATURE----- # gpg: Signature made Mon 06 Mar 2023 21:51:36 GMT # gpg: using RSA key 2B3C3747446843B24A943A7A2E1319F35FBB1889 # gpg: issuer "palmer@dabbelt.com" # gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" [unknown] # gpg: aka "Palmer Dabbelt <palmerdabbelt@google.com>" [unknown] # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 00CE 76D1 8349 60DF CE88 6DF8 EF4C A150 2CCB AB41 # Subkey fingerprint: 2B3C 3747 4468 43B2 4A94 3A7A 2E13 19F3 5FBB 1889 * tag 'pull-riscv-to-apply-20230306' of https://gitlab.com/palmer-dabbelt/qemu: (22 commits) MAINTAINERS: Add entry for RISC-V ACPI hw/riscv/virt.c: Initialize the ACPI tables hw/riscv/virt: virt-acpi-build.c: Add RHCT Table hw/riscv/virt: virt-acpi-build.c: Add RINTC in MADT hw/riscv/virt: Enable basic ACPI infrastructure hw/riscv/virt: Add memmap pointer to RiscVVirtState hw/riscv/virt: Add a switch to disable ACPI hw/riscv/virt: Add OEM_ID and OEM_TABLE_ID fields riscv: Correctly set the device-tree entry 'mmu-type' riscv: Introduce satp mode hw capabilities riscv: Allow user to set the satp mode riscv: Change type of valid_vm_1_10_[32|64] to bool riscv: Pass Object to register_cpu_props instead of DeviceState roms/opensbi: Upgrade from v1.1 to v1.2 gitlab/opensbi: Move to docker:stable hw: intc: Use cpu_by_arch_id to fetch CPU state target/riscv: cpu: Implement get_arch_id callback disas/riscv Fix ctzw disassemble hw/riscv/virt.c: add cbo[mz]-block-size fdt properties target/riscv: add Zicbop cbo.prefetch{i, r, m} placeholder ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target/riscv')
-rw-r--r--target/riscv/cpu.c303
-rw-r--r--target/riscv/cpu.h29
-rw-r--r--target/riscv/csr.c29
-rw-r--r--target/riscv/helper.h5
-rw-r--r--target/riscv/insn32.decode16
-rw-r--r--target/riscv/insn_trans/trans_rvzicbo.c.inc57
-rw-r--r--target/riscv/op_helper.c135
-rw-r--r--target/riscv/translate.c1
8 files changed, 545 insertions, 30 deletions
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 5bc0005..1e97473 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -28,6 +28,7 @@
#include "time_helper.h"
#include "exec/exec-all.h"
#include "qapi/error.h"
+#include "qapi/visitor.h"
#include "qemu/error-report.h"
#include "hw/qdev-properties.h"
#include "migration/vmstate.h"
@@ -75,6 +76,8 @@ struct isa_ext_data {
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_10_0, ext_v),
+ ISA_EXT_DATA_ENTRY(zicbom, true, PRIV_VERSION_1_12_0, ext_icbom),
+ ISA_EXT_DATA_ENTRY(zicboz, true, PRIV_VERSION_1_12_0, ext_icboz),
ISA_EXT_DATA_ENTRY(zicond, true, PRIV_VERSION_1_12_0, ext_zicond),
ISA_EXT_DATA_ENTRY(zicsr, true, PRIV_VERSION_1_10_0, ext_icsr),
ISA_EXT_DATA_ENTRY(zifencei, true, PRIV_VERSION_1_10_0, ext_ifencei),
@@ -218,7 +221,7 @@ static const char * const riscv_intr_names[] = {
"reserved"
};
-static void register_cpu_props(DeviceState *dev);
+static void register_cpu_props(Object *obj);
const char *riscv_cpu_get_trap_name(target_ulong cause, bool async)
{
@@ -247,6 +250,89 @@ static void set_vext_version(CPURISCVState *env, int vext_ver)
env->vext_ver = vext_ver;
}
+#ifndef CONFIG_USER_ONLY
+static uint8_t satp_mode_from_str(const char *satp_mode_str)
+{
+ if (!strncmp(satp_mode_str, "mbare", 5)) {
+ return VM_1_10_MBARE;
+ }
+
+ if (!strncmp(satp_mode_str, "sv32", 4)) {
+ return VM_1_10_SV32;
+ }
+
+ if (!strncmp(satp_mode_str, "sv39", 4)) {
+ return VM_1_10_SV39;
+ }
+
+ if (!strncmp(satp_mode_str, "sv48", 4)) {
+ return VM_1_10_SV48;
+ }
+
+ if (!strncmp(satp_mode_str, "sv57", 4)) {
+ return VM_1_10_SV57;
+ }
+
+ if (!strncmp(satp_mode_str, "sv64", 4)) {
+ return VM_1_10_SV64;
+ }
+
+ g_assert_not_reached();
+}
+
+uint8_t satp_mode_max_from_map(uint32_t map)
+{
+ /* map here has at least one bit set, so no problem with clz */
+ return 31 - __builtin_clz(map);
+}
+
+const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit)
+{
+ if (is_32_bit) {
+ switch (satp_mode) {
+ case VM_1_10_SV32:
+ return "sv32";
+ case VM_1_10_MBARE:
+ return "none";
+ }
+ } else {
+ switch (satp_mode) {
+ case VM_1_10_SV64:
+ return "sv64";
+ case VM_1_10_SV57:
+ return "sv57";
+ case VM_1_10_SV48:
+ return "sv48";
+ case VM_1_10_SV39:
+ return "sv39";
+ case VM_1_10_MBARE:
+ return "none";
+ }
+ }
+
+ g_assert_not_reached();
+}
+
+static void set_satp_mode_max_supported(RISCVCPU *cpu,
+ uint8_t satp_mode)
+{
+ bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
+ const bool *valid_vm = rv32 ? valid_vm_1_10_32 : valid_vm_1_10_64;
+
+ for (int i = 0; i <= satp_mode; ++i) {
+ if (valid_vm[i]) {
+ cpu->cfg.satp_mode.supported |= (1 << i);
+ }
+ }
+}
+
+/* Set the satp mode to the max supported */
+static void set_satp_mode_default_map(RISCVCPU *cpu)
+{
+ cpu->cfg.satp_mode.map = cpu->cfg.satp_mode.supported;
+}
+#endif
+
static void riscv_any_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
@@ -255,8 +341,15 @@ static void riscv_any_cpu_init(Object *obj)
#elif defined(TARGET_RISCV64)
set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVU);
#endif
+
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(RISCV_CPU(obj),
+ riscv_cpu_mxl(&RISCV_CPU(obj)->env) == MXL_RV32 ?
+ VM_1_10_SV32 : VM_1_10_SV57);
+#endif
+
set_priv_version(env, PRIV_VERSION_1_12_0);
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
}
#if defined(TARGET_RISCV64)
@@ -265,17 +358,23 @@ static void rv64_base_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, MXL_RV64, 0);
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
/* Set latest version of privileged specification */
set_priv_version(env, PRIV_VERSION_1_12_0);
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57);
+#endif
}
static void rv64_sifive_u_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, MXL_RV64, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV39);
+#endif
}
static void rv64_sifive_e_cpu_init(Object *obj)
@@ -284,9 +383,12 @@ static void rv64_sifive_e_cpu_init(Object *obj)
RISCVCPU *cpu = RISCV_CPU(obj);
set_misa(env, MXL_RV64, RVI | RVM | RVA | RVC | RVU);
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
cpu->cfg.mmu = false;
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
+#endif
}
static void rv64_thead_c906_cpu_init(Object *obj)
@@ -316,6 +418,9 @@ static void rv64_thead_c906_cpu_init(Object *obj)
cpu->cfg.ext_xtheadsync = true;
cpu->cfg.mvendorid = THEAD_VENDOR_ID;
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(cpu, VM_1_10_SV39);
+#endif
}
static void rv128_base_cpu_init(Object *obj)
@@ -329,9 +434,12 @@ static void rv128_base_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, MXL_RV128, 0);
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
/* Set latest version of privileged specification */
set_priv_version(env, PRIV_VERSION_1_12_0);
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV57);
+#endif
}
#else
static void rv32_base_cpu_init(Object *obj)
@@ -339,17 +447,23 @@ static void rv32_base_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */
set_misa(env, MXL_RV32, 0);
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
/* Set latest version of privileged specification */
set_priv_version(env, PRIV_VERSION_1_12_0);
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32);
+#endif
}
static void rv32_sifive_u_cpu_init(Object *obj)
{
CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(RISCV_CPU(obj), VM_1_10_SV32);
+#endif
}
static void rv32_sifive_e_cpu_init(Object *obj)
@@ -358,9 +472,12 @@ static void rv32_sifive_e_cpu_init(Object *obj)
RISCVCPU *cpu = RISCV_CPU(obj);
set_misa(env, MXL_RV32, RVI | RVM | RVA | RVC | RVU);
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
cpu->cfg.mmu = false;
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
+#endif
}
static void rv32_ibex_cpu_init(Object *obj)
@@ -369,9 +486,12 @@ static void rv32_ibex_cpu_init(Object *obj)
RISCVCPU *cpu = RISCV_CPU(obj);
set_misa(env, MXL_RV32, RVI | RVM | RVC | RVU);
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_11_0);
cpu->cfg.mmu = false;
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
+#endif
cpu->cfg.epmp = true;
}
@@ -381,9 +501,12 @@ static void rv32_imafcu_nommu_cpu_init(Object *obj)
RISCVCPU *cpu = RISCV_CPU(obj);
set_misa(env, MXL_RV32, RVI | RVM | RVA | RVF | RVC | RVU);
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
set_priv_version(env, PRIV_VERSION_1_10_0);
cpu->cfg.mmu = false;
+#ifndef CONFIG_USER_ONLY
+ set_satp_mode_max_supported(cpu, VM_1_10_MBARE);
+#endif
}
#endif
@@ -396,7 +519,7 @@ static void riscv_host_cpu_init(Object *obj)
#elif defined(TARGET_RISCV64)
set_misa(env, MXL_RV64, 0);
#endif
- register_cpu_props(DEVICE(obj));
+ register_cpu_props(obj);
}
#endif
@@ -916,6 +1039,88 @@ static void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
set_misa(env, env->misa_mxl, ext);
}
+#ifndef CONFIG_USER_ONLY
+static void riscv_cpu_satp_mode_finalize(RISCVCPU *cpu, Error **errp)
+{
+ bool rv32 = riscv_cpu_mxl(&cpu->env) == MXL_RV32;
+ uint8_t satp_mode_map_max;
+ uint8_t satp_mode_supported_max =
+ satp_mode_max_from_map(cpu->cfg.satp_mode.supported);
+
+ if (cpu->cfg.satp_mode.map == 0) {
+ if (cpu->cfg.satp_mode.init == 0) {
+ /* If unset by the user, we fallback to the default satp mode. */
+ set_satp_mode_default_map(cpu);
+ } else {
+ /*
+ * Find the lowest level that was disabled and then enable the
+ * first valid level below which can be found in
+ * valid_vm_1_10_32/64.
+ */
+ for (int i = 1; i < 16; ++i) {
+ if ((cpu->cfg.satp_mode.init & (1 << i)) &&
+ (cpu->cfg.satp_mode.supported & (1 << i))) {
+ for (int j = i - 1; j >= 0; --j) {
+ if (cpu->cfg.satp_mode.supported & (1 << j)) {
+ cpu->cfg.satp_mode.map |= (1 << j);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ satp_mode_map_max = satp_mode_max_from_map(cpu->cfg.satp_mode.map);
+
+ /* Make sure the user asked for a supported configuration (HW and qemu) */
+ if (satp_mode_map_max > satp_mode_supported_max) {
+ error_setg(errp, "satp_mode %s is higher than hw max capability %s",
+ satp_mode_str(satp_mode_map_max, rv32),
+ satp_mode_str(satp_mode_supported_max, rv32));
+ return;
+ }
+
+ /*
+ * Make sure the user did not ask for an invalid configuration as per
+ * the specification.
+ */
+ if (!rv32) {
+ for (int i = satp_mode_map_max - 1; i >= 0; --i) {
+ if (!(cpu->cfg.satp_mode.map & (1 << i)) &&
+ (cpu->cfg.satp_mode.init & (1 << i)) &&
+ (cpu->cfg.satp_mode.supported & (1 << i))) {
+ error_setg(errp, "cannot disable %s satp mode if %s "
+ "is enabled", satp_mode_str(i, false),
+ satp_mode_str(satp_mode_map_max, false));
+ return;
+ }
+ }
+ }
+
+ /* Finally expand the map so that all valid modes are set */
+ for (int i = satp_mode_map_max - 1; i >= 0; --i) {
+ if (cpu->cfg.satp_mode.supported & (1 << i)) {
+ cpu->cfg.satp_mode.map |= (1 << i);
+ }
+ }
+}
+#endif
+
+static void riscv_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
+{
+#ifndef CONFIG_USER_ONLY
+ Error *local_err = NULL;
+
+ riscv_cpu_satp_mode_finalize(cpu, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+#endif
+}
+
static void riscv_cpu_realize(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
@@ -1015,6 +1220,12 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
}
#endif
+ riscv_cpu_finalize_features(cpu, &local_err);
+ if (local_err != NULL) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
riscv_cpu_register_gdb_regs_for_features(cs);
qemu_init_vcpu(cs);
@@ -1024,6 +1235,52 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
}
#ifndef CONFIG_USER_ONLY
+static void cpu_riscv_get_satp(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ RISCVSATPMap *satp_map = opaque;
+ uint8_t satp = satp_mode_from_str(name);
+ bool value;
+
+ value = satp_map->map & (1 << satp);
+
+ visit_type_bool(v, name, &value, errp);
+}
+
+static void cpu_riscv_set_satp(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ RISCVSATPMap *satp_map = opaque;
+ uint8_t satp = satp_mode_from_str(name);
+ bool value;
+
+ if (!visit_type_bool(v, name, &value, errp)) {
+ return;
+ }
+
+ satp_map->map = deposit32(satp_map->map, satp, 1, value);
+ satp_map->init |= 1 << satp;
+}
+
+static void riscv_add_satp_mode_properties(Object *obj)
+{
+ RISCVCPU *cpu = RISCV_CPU(obj);
+
+ if (cpu->env.misa_mxl == MXL_RV32) {
+ object_property_add(obj, "sv32", "bool", cpu_riscv_get_satp,
+ cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode);
+ } else {
+ object_property_add(obj, "sv39", "bool", cpu_riscv_get_satp,
+ cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode);
+ object_property_add(obj, "sv48", "bool", cpu_riscv_get_satp,
+ cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode);
+ object_property_add(obj, "sv57", "bool", cpu_riscv_get_satp,
+ cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode);
+ object_property_add(obj, "sv64", "bool", cpu_riscv_get_satp,
+ cpu_riscv_set_satp, NULL, &cpu->cfg.satp_mode);
+ }
+}
+
static void riscv_cpu_set_irq(void *opaque, int irq, int level)
{
RISCVCPU *cpu = RISCV_CPU(opaque);
@@ -1167,6 +1424,11 @@ static Property riscv_cpu_extensions[] = {
DEFINE_PROP_BOOL("zhinx", RISCVCPU, cfg.ext_zhinx, false),
DEFINE_PROP_BOOL("zhinxmin", RISCVCPU, cfg.ext_zhinxmin, false),
+ DEFINE_PROP_BOOL("zicbom", RISCVCPU, cfg.ext_icbom, true),
+ DEFINE_PROP_UINT16("cbom_blocksize", RISCVCPU, cfg.cbom_blocksize, 64),
+ DEFINE_PROP_BOOL("zicboz", RISCVCPU, cfg.ext_icboz, true),
+ DEFINE_PROP_UINT16("cboz_blocksize", RISCVCPU, cfg.cboz_blocksize, 64),
+
DEFINE_PROP_BOOL("zmmul", RISCVCPU, cfg.ext_zmmul, false),
/* Vendor-specific custom extensions */
@@ -1203,11 +1465,12 @@ static Property riscv_cpu_extensions[] = {
* properties and leave. env.misa_ext = 0 means that we want
* all the default properties to be registered.
*/
-static void register_cpu_props(DeviceState *dev)
+static void register_cpu_props(Object *obj)
{
- RISCVCPU *cpu = RISCV_CPU(OBJECT(dev));
+ RISCVCPU *cpu = RISCV_CPU(obj);
uint32_t misa_ext = cpu->env.misa_ext;
Property *prop;
+ DeviceState *dev = DEVICE(obj);
/*
* If misa_ext is not zero, set cfg properties now to
@@ -1238,6 +1501,10 @@ static void register_cpu_props(DeviceState *dev)
for (prop = riscv_cpu_extensions; prop && prop->name; prop++) {
qdev_property_add_static(dev, prop);
}
+
+#ifndef CONFIG_USER_ONLY
+ riscv_add_satp_mode_properties(obj);
+#endif
}
static Property riscv_cpu_properties[] = {
@@ -1294,6 +1561,13 @@ static const char *riscv_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname)
}
#ifndef CONFIG_USER_ONLY
+static int64_t riscv_get_arch_id(CPUState *cs)
+{
+ RISCVCPU *cpu = RISCV_CPU(cs);
+
+ return cpu->env.mhartid;
+}
+
#include "hw/core/sysemu-cpu-ops.h"
static const struct SysemuCPUOps riscv_sysemu_ops = {
@@ -1348,6 +1622,7 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
cc->disas_set_info = riscv_cpu_disas_set_info;
#ifndef CONFIG_USER_ONLY
cc->sysemu_ops = &riscv_sysemu_ops;
+ cc->get_arch_id = riscv_get_arch_id;
#endif
cc->gdb_arch_name = riscv_gdb_arch_name;
cc->gdb_get_dynamic_xml = riscv_gdb_get_dynamic_xml;
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 665b4c6..638e47c 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -27,6 +27,7 @@
#include "qom/object.h"
#include "qemu/int128.h"
#include "cpu_bits.h"
+#include "qapi/qapi-types-common.h"
#define TCG_GUEST_DEFAULT_MO 0
@@ -401,6 +402,21 @@ struct RISCVCPUClass {
ResettablePhases parent_phases;
};
+/*
+ * map is a 16-bit bitmap: the most significant set bit in map is the maximum
+ * satp mode that is supported. It may be chosen by the user and must respect
+ * what qemu implements (valid_1_10_32/64) and what the hw is capable of
+ * (supported bitmap below).
+ *
+ * init is a 16-bit bitmap used to make sure the user selected a correct
+ * configuration as per the specification.
+ *
+ * supported is a 16-bit bitmap used to reflect the hw capabilities.
+ */
+typedef struct {
+ uint16_t map, init, supported;
+} RISCVSATPMap;
+
struct RISCVCPUConfig {
bool ext_i;
bool ext_e;
@@ -434,6 +450,8 @@ struct RISCVCPUConfig {
bool ext_zkt;
bool ext_ifencei;
bool ext_icsr;
+ bool ext_icbom;
+ bool ext_icboz;
bool ext_zicond;
bool ext_zihintpause;
bool ext_smstateen;
@@ -486,6 +504,8 @@ struct RISCVCPUConfig {
char *vext_spec;
uint16_t vlen;
uint16_t elen;
+ uint16_t cbom_blocksize;
+ uint16_t cboz_blocksize;
bool mmu;
bool pmp;
bool epmp;
@@ -493,6 +513,10 @@ struct RISCVCPUConfig {
bool misa_w;
bool short_isa_string;
+
+#ifndef CONFIG_USER_ONLY
+ RISCVSATPMap satp_mode;
+#endif
};
typedef struct RISCVCPUConfig RISCVCPUConfig;
@@ -794,9 +818,14 @@ enum riscv_pmu_event_idx {
/* CSR function table */
extern riscv_csr_operations csr_ops[CSR_TABLE_SIZE];
+extern const bool valid_vm_1_10_32[], valid_vm_1_10_64[];
+
void riscv_get_csr_ops(int csrno, riscv_csr_operations *ops);
void riscv_set_csr_ops(int csrno, riscv_csr_operations *ops);
void riscv_cpu_register_gdb_regs_for_features(CPUState *cs);
+uint8_t satp_mode_max_from_map(uint32_t map);
+const char *satp_mode_str(uint8_t satp_mode, bool is_32_bit);
+
#endif /* RISCV_CPU_H */
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 3106f96..ab56663 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1141,16 +1141,16 @@ static const target_ulong hip_writable_mask = MIP_VSSIP;
static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
static const target_ulong vsip_writable_mask = MIP_VSSIP;
-static const char valid_vm_1_10_32[16] = {
- [VM_1_10_MBARE] = 1,
- [VM_1_10_SV32] = 1
+const bool valid_vm_1_10_32[16] = {
+ [VM_1_10_MBARE] = true,
+ [VM_1_10_SV32] = true
};
-static const char valid_vm_1_10_64[16] = {
- [VM_1_10_MBARE] = 1,
- [VM_1_10_SV39] = 1,
- [VM_1_10_SV48] = 1,
- [VM_1_10_SV57] = 1
+const bool valid_vm_1_10_64[16] = {
+ [VM_1_10_MBARE] = true,
+ [VM_1_10_SV39] = true,
+ [VM_1_10_SV48] = true,
+ [VM_1_10_SV57] = true
};
/* Machine Information Registers */
@@ -1230,13 +1230,11 @@ static RISCVException read_mstatus(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
-static int validate_vm(CPURISCVState *env, target_ulong vm)
+static bool validate_vm(CPURISCVState *env, target_ulong vm)
{
- if (riscv_cpu_mxl(env) == MXL_RV32) {
- return valid_vm_1_10_32[vm & 0xf];
- } else {
- return valid_vm_1_10_64[vm & 0xf];
- }
+ RISCVCPU *cpu = RISCV_CPU(env_cpu(env));
+
+ return (vm & 0xf) <= satp_mode_max_from_map(cpu->cfg.satp_mode.map);
}
static RISCVException write_mstatus(CPURISCVState *env, int csrno,
@@ -2669,7 +2667,8 @@ static RISCVException read_satp(CPURISCVState *env, int csrno,
static RISCVException write_satp(CPURISCVState *env, int csrno,
target_ulong val)
{
- target_ulong vm, mask;
+ target_ulong mask;
+ bool vm;
if (!riscv_cpu_cfg(env)->mmu) {
return RISCV_EXCP_NONE;
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 0497370..37b54e0 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 fb537e9..73d5d1b 100644
--- a/target/riscv/insn32.decode
+++ b/target/riscv/insn32.decode
@@ -134,6 +134,7 @@ addi ............ ..... 000 ..... 0010011 @i
slti ............ ..... 010 ..... 0010011 @i
sltiu ............ ..... 011 ..... 0010011 @i
xori ............ ..... 100 ..... 0010011 @i
+# cbo.prefetch_{i,r,m} instructions are ori with rd=x0 and not decoded.
ori ............ ..... 110 ..... 0010011 @i
andi ............ ..... 111 ..... 0010011 @i
slli 00000. ...... ..... 001 ..... 0010011 @sh
@@ -179,7 +180,20 @@ sraw 0100000 ..... ..... 101 ..... 0111011 @r
# *** RV128I Base Instruction Set (in addition to RV64I) ***
ldu ............ ..... 111 ..... 0000011 @i
-lq ............ ..... 010 ..... 0001111 @i
+{
+ [
+ # *** RV32 Zicbom Standard Extension ***
+ cbo_clean 0000000 00001 ..... 010 00000 0001111 @sfence_vm
+ cbo_flush 0000000 00010 ..... 010 00000 0001111 @sfence_vm
+ cbo_inval 0000000 00000 ..... 010 00000 0001111 @sfence_vm
+
+ # *** RV32 Zicboz Standard Extension ***
+ cbo_zero 0000000 00100 ..... 010 00000 0001111 @sfence_vm
+ ]
+
+ # *** RVI128 lq ***
+ 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 0000000..7df9c30
--- /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 (!ctx->cfg_ptr->ext_icbom) { \
+ return false; \
+ } \
+} while (0)
+
+#define REQUIRE_ZICBOZ(ctx) do { \
+ if (!ctx->cfg_ptr->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 9c0b91c..84ee018 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2016-2017 Sagar Karandikar, sagark@eecs.berkeley.edu
* Copyright (c) 2017-2018 SiFive, Inc.
+ * Copyright (c) 2022 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,
@@ -123,6 +124,140 @@ target_ulong helper_csrrw_i128(CPURISCVState *env, int csr,
return int128_getlo(rv);
}
+
+/*
+ * check_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 check_zicbo_envcfg(CPURISCVState *env, target_ulong envbits,
+ uintptr_t ra)
+{
+#ifndef CONFIG_USER_ONLY
+ if ((env->priv < PRV_M) && !get_field(env->menvcfg, envbits)) {
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, ra);
+ }
+
+ 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_S) && !get_field(env->senvcfg, envbits)) {
+ riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, ra);
+ }
+#endif
+}
+
+void helper_cbo_zero(CPURISCVState *env, target_ulong address)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+ uint16_t cbozlen = cpu->cfg.cboz_blocksize;
+ int mmu_idx = cpu_mmu_index(env, false);
+ uintptr_t ra = GETPC();
+ void *mem;
+
+ check_zicbo_envcfg(env, MENVCFG_CBZE, ra);
+
+ /* Mask off low-bits to align-down to the cache-block. */
+ address &= ~(cbozlen - 1);
+
+ /*
+ * cbo.zero requires MMU_DATA_STORE access. Do a probe_write()
+ * to raise any exceptions, including PMP.
+ */
+ mem = probe_write(env, address, cbozlen, mmu_idx, ra);
+
+ if (likely(mem)) {
+ memset(mem, 0, cbozlen);
+ } else {
+ /*
+ * This means that we're dealing with an I/O page. Section 4.2
+ * of cmobase v1.0.1 says:
+ *
+ * "Cache-block zero instructions store zeros independently
+ * of whether data from the underlying memory locations are
+ * cacheable."
+ *
+ * Write zeros in address + cbozlen regardless of not being
+ * a RAM page.
+ */
+ for (int i = 0; i < cbozlen; i++) {
+ cpu_stb_mmuidx_ra(env, address + i, 0, mmu_idx, ra);
+ }
+ }
+}
+
+/*
+ * check_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-virtualized) or store guest-page
+ * fault (virtualized).
+ */
+static void check_zicbom_access(CPURISCVState *env,
+ target_ulong address,
+ uintptr_t ra)
+{
+ RISCVCPU *cpu = env_archcpu(env);
+ int mmu_idx = cpu_mmu_index(env, false);
+ uint16_t cbomlen = cpu->cfg.cbom_blocksize;
+ void *phost;
+ int ret;
+
+ /* Mask off low-bits to align-down to the cache-block. */
+ address &= ~(cbomlen - 1);
+
+ /*
+ * Section 2.5.2 of cmobase v1.0.1:
+ *
+ * "A cache-block management instruction is permitted to
+ * access the specified cache block whenever a load instruction
+ * or store instruction is permitted to access the corresponding
+ * physical addresses. If neither a load instruction nor store
+ * instruction is permitted to access the physical addresses,
+ * but an instruction fetch is permitted to access the physical
+ * addresses, whether a cache-block management instruction is
+ * permitted to access the cache block is UNSPECIFIED."
+ */
+ ret = probe_access_flags(env, address, cbomlen, MMU_DATA_LOAD,
+ mmu_idx, true, &phost, ra);
+ if (ret != TLB_INVALID_MASK) {
+ /* Success: readable */
+ return;
+ }
+
+ /*
+ * Since not readable, must be writable. On failure, store
+ * fault/store guest amo fault will be raised by
+ * riscv_cpu_tlb_fill(). PMP exceptions will be caught
+ * there as well.
+ */
+ probe_write(env, address, cbomlen, mmu_idx, ra);
+}
+
+void helper_cbo_clean_flush(CPURISCVState *env, target_ulong address)
+{
+ uintptr_t ra = GETPC();
+ check_zicbo_envcfg(env, MENVCFG_CBCFE, ra);
+ check_zicbom_access(env, address, ra);
+
+ /* We don't emulate the cache-hierarchy, so we're done. */
+}
+
+void helper_cbo_inval(CPURISCVState *env, target_ulong address)
+{
+ uintptr_t ra = GETPC();
+ check_zicbo_envcfg(env, MENVCFG_CBIE, ra);
+ check_zicbom_access(env, address, ra);
+
+ /* We don't emulate the cache-hierarchy, so we're done. */
+}
+
#ifndef CONFIG_USER_ONLY
target_ulong helper_sret(CPURISCVState *env)
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index 9390920..0ee8ee1 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -1080,6 +1080,7 @@ static uint32_t opcode_at(DisasContextBase *dcbase, target_ulong pc)
#include "insn_trans/trans_rvb.c.inc"
#include "insn_trans/trans_rvzicond.c.inc"
#include "insn_trans/trans_rvzawrs.c.inc"
+#include "insn_trans/trans_rvzicbo.c.inc"
#include "insn_trans/trans_rvzfh.c.inc"
#include "insn_trans/trans_rvk.c.inc"
#include "insn_trans/trans_privileged.c.inc"