aboutsummaryrefslogtreecommitdiff
path: root/target
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2025-07-04 08:58:58 -0400
committerStefan Hajnoczi <stefanha@redhat.com>2025-07-04 08:58:58 -0400
commite240f6cc25917f3138d9e95e0343ae23b63a3f8c (patch)
treeb87fa91997108a3eb6fff736765a4fd7ac113f59 /target
parent989dd906ed5556563a57b32ae7abf9db5e1f38ba (diff)
parentdc8bffc4eb0a93d3266cea1b17f8848dea5b915c (diff)
downloadqemu-master.zip
qemu-master.tar.gz
qemu-master.tar.bz2
Merge tag 'pull-riscv-to-apply-20250704' of https://github.com/alistair23/qemu into stagingHEADstagingmaster
Second RISC-V PR for 10.1 * sstc extension fixes * Fix zama16b order in isa_edata_arr * Profile handling fixes * Extend PMP region up to 64 * Remove capital 'Z' CPU properties * Add missing named features * Support atomic instruction fetch (Ziccif) * Add max_satp_mode from host cpu * Extend and configure PMP region count * Fix PPN field of Translation-reponse register * Use qemu_chr_fe_write_all() in DBCN_CONSOLE_WRITE_BYTE * Fix fcvt.s.bf16 NaN box checking * Avoid infinite delay of async xmit function * Device tree reg cleanups * Add Kunminghu CPU and platform * Fix missing exit TB flow for ldff_trans * Fix migration failure when aia is configured as aplic-imsic * Fix MEPC/SEPC bit masking for IALIGN * Add a property to set vill bit on reserved usage of vsetvli instruction * Add Svrsw60t59b extension support # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCgAdFiEEaukCtqfKh31tZZKWr3yVEwxTgBMFAmhntt4ACgkQr3yVEwxT # gBMaCQ/9E+LeRY59nz3K3XXUw6XLBfaDECXbKzIn0GM1yXeWTX4dB2h2hoGWdu3R # CRPxWHECN7CeJhd2J23eLfOi+fTUeppJBeR7TcGyoXVC+y0knZv/clQ3OvMFYcgV # xjzzu1yipQlXwY+kmDZ6qL5up/Q+faw7tRaePZaJheRGYpVRnjoKUZq5fe4Ug4RU # Xg6Di86eYyk+Jo0g2exvtzy1rX2eBp7Hz200wWiH5Z1B+3NzgMUHrHuJfNAz8zAt # n8uvruvaLGGtWcQJauRXlAELR6k9tmkfq1Mbqf3FK6muaQCtFD7PXXnjL/rU/z20 # hhxj0psOhBJLd0W5wQ3vLnDf6Wve9zmUdTR9kI0Kt3xUUdfeBuzKcU06F/G8wEsZ # 2sIYQqt0mxoJboY2lpje7TO4H9gvAf76WBOV10FV2gWsqWu2rZQ6herdq3YZYkHX # purUTgyjHn4jl2Y3Kzj0Gq1SHo0yaA/sD6xNR8X+JqljSruDxtOFU7wkKBbewoIg # OSfwemjRUVsPQZ958042ntwJt81v1604Oky8JSFr5eCFx/aoLJ1vDYh7BKZAogNH # uB/YigGq9+/MVzqJpZI+kZkd+1nzaizeL0FUPRTq0jFA2u+vc3J3svQ/jNXDH2c+ # 5nGuhbkvT0ptmVMBqFV2vjPh6+ScR8t03wHdQ4PmDoXC3o9zbbU= # =CfRy # -----END PGP SIGNATURE----- # gpg: Signature made Fri 04 Jul 2025 07:11:26 EDT # gpg: using RSA key 6AE902B6A7CA877D6D659296AF7C95130C538013 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [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: 6AE9 02B6 A7CA 877D 6D65 9296 AF7C 9513 0C53 8013 * tag 'pull-riscv-to-apply-20250704' of https://github.com/alistair23/qemu: (40 commits) target: riscv: Add Svrsw60t59b extension support target/riscv: Add a property to set vill bit on reserved usage of vsetvli instruction tests/tcg/riscv64: Add test for MEPC bit masking target/riscv: Fix MEPC/SEPC bit masking for IALIGN migration: Fix migration failure when aia is configured as aplic-imsic target/riscv: rvv: Fix missing exit TB flow for ldff_trans hw/riscv: Initial support for BOSC's Xiangshan Kunminghu FPGA prototype target/riscv: Add BOSC's Xiangshan Kunminghu CPU hw/riscv/virt: Use setprop_sized_cells for pcie hw/riscv/virt: Use setprop_sized_cells for iommu hw/riscv/virt: Use setprop_sized_cells for rtc hw/riscv/virt: Use setprop_sized_cells for uart hw/riscv/virt: Use setprop_sized_cells for reset hw/riscv/virt: Use setprop_sized_cells for virtio hw/riscv/virt: Use setprop_sized_cells for plic hw/riscv/virt: Use setprop_sized_cells for aclint hw/riscv/virt: Use setprop_sized_cells for aplic hw/riscv/virt: Use setprop_sized_cells for memory hw/riscv/virt: Use setprop_sized_cells for clint hw/riscv/virt: Fix clint base address type ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Diffstat (limited to 'target')
-rw-r--r--target/riscv/cpu-qom.h1
-rw-r--r--target/riscv/cpu.c144
-rw-r--r--target/riscv/cpu.h19
-rw-r--r--target/riscv/cpu_bits.h63
-rw-r--r--target/riscv/cpu_cfg_fields.h.inc3
-rw-r--r--target/riscv/cpu_helper.c3
-rw-r--r--target/riscv/csr.c192
-rw-r--r--target/riscv/fpu_helper.c2
-rw-r--r--target/riscv/helper.h2
-rw-r--r--target/riscv/insn_trans/trans_rvv.c.inc10
-rw-r--r--target/riscv/internals.h27
-rw-r--r--target/riscv/kvm/kvm-cpu.c18
-rw-r--r--target/riscv/machine.c3
-rw-r--r--target/riscv/op_helper.c4
-rw-r--r--target/riscv/pmp.c28
-rw-r--r--target/riscv/riscv-qmp-cmds.c2
-rw-r--r--target/riscv/tcg/tcg-cpu.c186
-rw-r--r--target/riscv/time_helper.c65
-rw-r--r--target/riscv/time_helper.h1
-rw-r--r--target/riscv/translate.c46
-rw-r--r--target/riscv/vector_helper.c12
21 files changed, 665 insertions, 166 deletions
diff --git a/target/riscv/cpu-qom.h b/target/riscv/cpu-qom.h
index 1ee05eb..75f4e43 100644
--- a/target/riscv/cpu-qom.h
+++ b/target/riscv/cpu-qom.h
@@ -55,6 +55,7 @@
#define TYPE_RISCV_CPU_VEYRON_V1 RISCV_CPU_TYPE_NAME("veyron-v1")
#define TYPE_RISCV_CPU_TT_ASCALON RISCV_CPU_TYPE_NAME("tt-ascalon")
#define TYPE_RISCV_CPU_XIANGSHAN_NANHU RISCV_CPU_TYPE_NAME("xiangshan-nanhu")
+#define TYPE_RISCV_CPU_XIANGSHAN_KMH RISCV_CPU_TYPE_NAME("xiangshan-kunminghu")
#define TYPE_RISCV_CPU_HOST RISCV_CPU_TYPE_NAME("host")
OBJECT_DECLARE_CPU_TYPE(RISCVCPU, RISCVCPUClass, RISCV_CPU)
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 629ac37..d055ddf 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -127,8 +127,8 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(zaamo, PRIV_VERSION_1_12_0, ext_zaamo),
ISA_EXT_DATA_ENTRY(zabha, PRIV_VERSION_1_13_0, ext_zabha),
ISA_EXT_DATA_ENTRY(zacas, PRIV_VERSION_1_12_0, ext_zacas),
- ISA_EXT_DATA_ENTRY(zama16b, PRIV_VERSION_1_13_0, ext_zama16b),
ISA_EXT_DATA_ENTRY(zalrsc, PRIV_VERSION_1_12_0, ext_zalrsc),
+ ISA_EXT_DATA_ENTRY(zama16b, PRIV_VERSION_1_13_0, ext_zama16b),
ISA_EXT_DATA_ENTRY(zawrs, PRIV_VERSION_1_12_0, ext_zawrs),
ISA_EXT_DATA_ENTRY(zfa, PRIV_VERSION_1_12_0, ext_zfa),
ISA_EXT_DATA_ENTRY(zfbfmin, PRIV_VERSION_1_12_0, ext_zfbfmin),
@@ -189,6 +189,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(zvkt, PRIV_VERSION_1_12_0, ext_zvkt),
ISA_EXT_DATA_ENTRY(zhinx, PRIV_VERSION_1_12_0, ext_zhinx),
ISA_EXT_DATA_ENTRY(zhinxmin, PRIV_VERSION_1_12_0, ext_zhinxmin),
+ ISA_EXT_DATA_ENTRY(sdtrig, PRIV_VERSION_1_12_0, debug),
ISA_EXT_DATA_ENTRY(shcounterenw, PRIV_VERSION_1_12_0, has_priv_1_12),
ISA_EXT_DATA_ENTRY(sha, PRIV_VERSION_1_12_0, ext_sha),
ISA_EXT_DATA_ENTRY(shgatpa, PRIV_VERSION_1_12_0, has_priv_1_12),
@@ -216,6 +217,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(ssnpm, PRIV_VERSION_1_13_0, ext_ssnpm),
ISA_EXT_DATA_ENTRY(sspm, PRIV_VERSION_1_13_0, ext_sspm),
ISA_EXT_DATA_ENTRY(ssstateen, PRIV_VERSION_1_12_0, ext_ssstateen),
+ ISA_EXT_DATA_ENTRY(ssstrict, PRIV_VERSION_1_12_0, has_priv_1_12),
ISA_EXT_DATA_ENTRY(sstc, PRIV_VERSION_1_12_0, ext_sstc),
ISA_EXT_DATA_ENTRY(sstvala, PRIV_VERSION_1_12_0, has_priv_1_12),
ISA_EXT_DATA_ENTRY(sstvecd, PRIV_VERSION_1_12_0, has_priv_1_12),
@@ -228,6 +230,7 @@ const RISCVIsaExtData isa_edata_arr[] = {
ISA_EXT_DATA_ENTRY(svinval, PRIV_VERSION_1_12_0, ext_svinval),
ISA_EXT_DATA_ENTRY(svnapot, PRIV_VERSION_1_12_0, ext_svnapot),
ISA_EXT_DATA_ENTRY(svpbmt, PRIV_VERSION_1_12_0, ext_svpbmt),
+ ISA_EXT_DATA_ENTRY(svrsw60t59b, PRIV_VERSION_1_13_0, ext_svrsw60t59b),
ISA_EXT_DATA_ENTRY(svukte, PRIV_VERSION_1_13_0, ext_svukte),
ISA_EXT_DATA_ENTRY(svvptc, PRIV_VERSION_1_13_0, ext_svvptc),
ISA_EXT_DATA_ENTRY(xtheadba, PRIV_VERSION_1_11_0, ext_xtheadba),
@@ -1117,6 +1120,7 @@ static void riscv_cpu_init(Object *obj)
cpu->cfg.cbom_blocksize = 64;
cpu->cfg.cbop_blocksize = 64;
cpu->cfg.cboz_blocksize = 64;
+ cpu->cfg.pmp_regions = 16;
cpu->env.vext_ver = VEXT_VERSION_1_00_0;
cpu->cfg.max_satp_mode = -1;
@@ -1282,6 +1286,7 @@ const RISCVCPUMultiExtConfig riscv_cpu_extensions[] = {
MULTI_EXT_CFG_BOOL("svinval", ext_svinval, false),
MULTI_EXT_CFG_BOOL("svnapot", ext_svnapot, false),
MULTI_EXT_CFG_BOOL("svpbmt", ext_svpbmt, false),
+ MULTI_EXT_CFG_BOOL("svrsw60t59b", ext_svrsw60t59b, false),
MULTI_EXT_CFG_BOOL("svvptc", ext_svvptc, true),
MULTI_EXT_CFG_BOOL("zicntr", ext_zicntr, true),
@@ -1375,31 +1380,24 @@ const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[] = {
* 'Named features' is the name we give to extensions that we
* don't want to expose to users. They are either immutable
* (always enabled/disable) or they'll vary depending on
- * the resulting CPU state. They have riscv,isa strings
- * and priv_ver like regular extensions.
+ * the resulting CPU state.
+ *
+ * Some of them are always enabled depending on priv version
+ * of the CPU and are declared directly in isa_edata_arr[].
+ * The ones listed here have special checks during finalize()
+ * time and require their own flags like regular extensions.
+ * See riscv_cpu_update_named_features() for more info.
*/
const RISCVCPUMultiExtConfig riscv_cpu_named_features[] = {
MULTI_EXT_CFG_BOOL("zic64b", ext_zic64b, true),
MULTI_EXT_CFG_BOOL("ssstateen", ext_ssstateen, true),
MULTI_EXT_CFG_BOOL("sha", ext_sha, true),
- MULTI_EXT_CFG_BOOL("ziccrse", ext_ziccrse, true),
- { },
-};
-
-/* Deprecated entries marked for future removal */
-const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[] = {
- MULTI_EXT_CFG_BOOL("Zifencei", ext_zifencei, true),
- MULTI_EXT_CFG_BOOL("Zicsr", ext_zicsr, true),
- MULTI_EXT_CFG_BOOL("Zihintntl", ext_zihintntl, true),
- MULTI_EXT_CFG_BOOL("Zihintpause", ext_zihintpause, true),
- MULTI_EXT_CFG_BOOL("Zawrs", ext_zawrs, true),
- MULTI_EXT_CFG_BOOL("Zfa", ext_zfa, true),
- 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("Zve64f", ext_zve64f, false),
- MULTI_EXT_CFG_BOOL("Zve64d", ext_zve64d, false),
+ /*
+ * 'ziccrse' has its own flag because the KVM driver
+ * wants to enable/disable it on its own accord.
+ */
+ MULTI_EXT_CFG_BOOL("ziccrse", ext_ziccrse, true),
{ },
};
@@ -1568,6 +1566,46 @@ static const PropertyInfo prop_pmp = {
.set = prop_pmp_set,
};
+static void prop_num_pmp_regions_set(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ RISCVCPU *cpu = RISCV_CPU(obj);
+ uint8_t value;
+
+ visit_type_uint8(v, name, &value, errp);
+
+ if (cpu->cfg.pmp_regions != value && riscv_cpu_is_vendor(obj)) {
+ cpu_set_prop_err(cpu, name, errp);
+ return;
+ }
+
+ if (cpu->env.priv_ver < PRIV_VERSION_1_12_0 && value > OLD_MAX_RISCV_PMPS) {
+ error_setg(errp, "Number of PMP regions exceeds maximum available");
+ return;
+ } else if (value > MAX_RISCV_PMPS) {
+ error_setg(errp, "Number of PMP regions exceeds maximum available");
+ return;
+ }
+
+ cpu_option_add_user_setting(name, value);
+ cpu->cfg.pmp_regions = value;
+}
+
+static void prop_num_pmp_regions_get(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ uint8_t value = RISCV_CPU(obj)->cfg.pmp_regions;
+
+ visit_type_uint8(v, name, &value, errp);
+}
+
+static const PropertyInfo prop_num_pmp_regions = {
+ .type = "uint8",
+ .description = "num-pmp-regions",
+ .get = prop_num_pmp_regions_get,
+ .set = prop_num_pmp_regions_set,
+};
+
static int priv_spec_from_str(const char *priv_spec_str)
{
int priv_version = -1;
@@ -2567,6 +2605,7 @@ static const Property riscv_cpu_properties[] = {
{.name = "mmu", .info = &prop_mmu},
{.name = "pmp", .info = &prop_pmp},
+ {.name = "num-pmp-regions", .info = &prop_num_pmp_regions},
{.name = "priv_spec", .info = &prop_priv_spec},
{.name = "vext_spec", .info = &prop_vext_spec},
@@ -2595,6 +2634,7 @@ static const Property riscv_cpu_properties[] = {
DEFINE_PROP_BOOL("rvv_ta_all_1s", RISCVCPU, cfg.rvv_ta_all_1s, false),
DEFINE_PROP_BOOL("rvv_ma_all_1s", RISCVCPU, cfg.rvv_ma_all_1s, false),
DEFINE_PROP_BOOL("rvv_vl_half_avl", RISCVCPU, cfg.rvv_vl_half_avl, false),
+ DEFINE_PROP_BOOL("rvv_vsetvl_x0_vill", RISCVCPU, cfg.rvv_vsetvl_x0_vill, false),
/*
* write_misa() is marked as experimental for now so mark
@@ -2937,7 +2977,8 @@ static const TypeInfo riscv_cpu_type_infos[] = {
.cfg.max_satp_mode = VM_1_10_MBARE,
.cfg.ext_zifencei = true,
.cfg.ext_zicsr = true,
- .cfg.pmp = true
+ .cfg.pmp = true,
+ .cfg.pmp_regions = 8
),
DEFINE_ABSTRACT_RISCV_CPU(TYPE_RISCV_CPU_SIFIVE_U, TYPE_RISCV_VENDOR_CPU,
@@ -2948,7 +2989,8 @@ static const TypeInfo riscv_cpu_type_infos[] = {
.cfg.ext_zifencei = true,
.cfg.ext_zicsr = true,
.cfg.mmu = true,
- .cfg.pmp = true
+ .cfg.pmp = true,
+ .cfg.pmp_regions = 8
),
#if defined(TARGET_RISCV32) || \
@@ -3167,6 +3209,64 @@ static const TypeInfo riscv_cpu_type_infos[] = {
.cfg.max_satp_mode = VM_1_10_SV39,
),
+ DEFINE_RISCV_CPU(TYPE_RISCV_CPU_XIANGSHAN_KMH, TYPE_RISCV_VENDOR_CPU,
+ .misa_mxl_max = MXL_RV64,
+ .misa_ext = RVG | RVC | RVB | RVS | RVU | RVH | RVV,
+ .priv_spec = PRIV_VERSION_1_13_0,
+ /*
+ * The RISC-V Instruction Set Manual: Volume I
+ * Unprivileged Architecture
+ */
+ .cfg.ext_zicntr = true,
+ .cfg.ext_zihpm = true,
+ .cfg.ext_zihintntl = true,
+ .cfg.ext_zihintpause = true,
+ .cfg.ext_zimop = true,
+ .cfg.ext_zcmop = true,
+ .cfg.ext_zicond = true,
+ .cfg.ext_zawrs = true,
+ .cfg.ext_zacas = true,
+ .cfg.ext_zfh = true,
+ .cfg.ext_zfa = true,
+ .cfg.ext_zcb = true,
+ .cfg.ext_zbc = true,
+ .cfg.ext_zvfh = true,
+ .cfg.ext_zkn = true,
+ .cfg.ext_zks = true,
+ .cfg.ext_zkt = true,
+ .cfg.ext_zvbb = true,
+ .cfg.ext_zvkt = true,
+ /*
+ * The RISC-V Instruction Set Manual: Volume II
+ * Privileged Architecture
+ */
+ .cfg.ext_smstateen = true,
+ .cfg.ext_smcsrind = true,
+ .cfg.ext_sscsrind = true,
+ .cfg.ext_svnapot = true,
+ .cfg.ext_svpbmt = true,
+ .cfg.ext_svinval = true,
+ .cfg.ext_sstc = true,
+ .cfg.ext_sscofpmf = true,
+ .cfg.ext_ssdbltrp = true,
+ .cfg.ext_ssnpm = true,
+ .cfg.ext_smnpm = true,
+ .cfg.ext_smmpm = true,
+ .cfg.ext_sspm = true,
+ .cfg.ext_supm = true,
+ /* The RISC-V Advanced Interrupt Architecture */
+ .cfg.ext_smaia = true,
+ .cfg.ext_ssaia = true,
+ /* RVA23 Profiles */
+ .cfg.ext_zicbom = true,
+ .cfg.ext_zicbop = true,
+ .cfg.ext_zicboz = true,
+ .cfg.ext_svade = true,
+ .cfg.mmu = true,
+ .cfg.pmp = true,
+ .cfg.max_satp_mode = VM_1_10_SV48,
+ ),
+
#if defined(CONFIG_TCG) && !defined(CONFIG_USER_ONLY)
DEFINE_RISCV_CPU(TYPE_RISCV_CPU_BASE128, TYPE_RISCV_DYNAMIC_CPU,
.cfg.max_satp_mode = VM_1_10_SV57,
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 229ade9..4a862da 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -82,7 +82,22 @@ typedef struct riscv_cpu_profile {
struct riscv_cpu_profile *s_parent;
const char *name;
uint32_t misa_ext;
+ /*
+ * The profile is enabled/disabled via command line or
+ * via cpu_init(). Enabling a profile will add all its
+ * mandatory extensions in the CPU during init().
+ */
bool enabled;
+ /*
+ * The profile is present in the CPU, i.e. the current set of
+ * CPU extensions complies with it. A profile can be enabled
+ * and not present (e.g. the user disabled a mandatory extension)
+ * and the other way around (e.g. all mandatory extensions are
+ * present in a non-profile CPU).
+ *
+ * QMP uses this flag.
+ */
+ bool present;
bool user_set;
int priv_spec;
int satp_mode;
@@ -159,7 +174,8 @@ extern RISCVCPUImpliedExtsRule *riscv_multi_ext_implied_rules[];
#define MMU_USER_IDX 3
-#define MAX_RISCV_PMPS (16)
+#define MAX_RISCV_PMPS (64)
+#define OLD_MAX_RISCV_PMPS (16)
#if !defined(CONFIG_USER_ONLY)
#include "pmp.h"
@@ -936,7 +952,6 @@ extern const RISCVCPUMultiExtConfig riscv_cpu_extensions[];
extern const RISCVCPUMultiExtConfig riscv_cpu_vendor_exts[];
extern const RISCVCPUMultiExtConfig riscv_cpu_experimental_exts[];
extern const RISCVCPUMultiExtConfig riscv_cpu_named_features[];
-extern const RISCVCPUMultiExtConfig riscv_cpu_deprecated_exts[];
typedef struct isa_ext_data {
const char *name;
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index a30317c..b62dd82 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -372,6 +372,18 @@
#define CSR_PMPCFG1 0x3a1
#define CSR_PMPCFG2 0x3a2
#define CSR_PMPCFG3 0x3a3
+#define CSR_PMPCFG4 0x3a4
+#define CSR_PMPCFG5 0x3a5
+#define CSR_PMPCFG6 0x3a6
+#define CSR_PMPCFG7 0x3a7
+#define CSR_PMPCFG8 0x3a8
+#define CSR_PMPCFG9 0x3a9
+#define CSR_PMPCFG10 0x3aa
+#define CSR_PMPCFG11 0x3ab
+#define CSR_PMPCFG12 0x3ac
+#define CSR_PMPCFG13 0x3ad
+#define CSR_PMPCFG14 0x3ae
+#define CSR_PMPCFG15 0x3af
#define CSR_PMPADDR0 0x3b0
#define CSR_PMPADDR1 0x3b1
#define CSR_PMPADDR2 0x3b2
@@ -388,6 +400,54 @@
#define CSR_PMPADDR13 0x3bd
#define CSR_PMPADDR14 0x3be
#define CSR_PMPADDR15 0x3bf
+#define CSR_PMPADDR16 0x3c0
+#define CSR_PMPADDR17 0x3c1
+#define CSR_PMPADDR18 0x3c2
+#define CSR_PMPADDR19 0x3c3
+#define CSR_PMPADDR20 0x3c4
+#define CSR_PMPADDR21 0x3c5
+#define CSR_PMPADDR22 0x3c6
+#define CSR_PMPADDR23 0x3c7
+#define CSR_PMPADDR24 0x3c8
+#define CSR_PMPADDR25 0x3c9
+#define CSR_PMPADDR26 0x3ca
+#define CSR_PMPADDR27 0x3cb
+#define CSR_PMPADDR28 0x3cc
+#define CSR_PMPADDR29 0x3cd
+#define CSR_PMPADDR30 0x3ce
+#define CSR_PMPADDR31 0x3cf
+#define CSR_PMPADDR32 0x3d0
+#define CSR_PMPADDR33 0x3d1
+#define CSR_PMPADDR34 0x3d2
+#define CSR_PMPADDR35 0x3d3
+#define CSR_PMPADDR36 0x3d4
+#define CSR_PMPADDR37 0x3d5
+#define CSR_PMPADDR38 0x3d6
+#define CSR_PMPADDR39 0x3d7
+#define CSR_PMPADDR40 0x3d8
+#define CSR_PMPADDR41 0x3d9
+#define CSR_PMPADDR42 0x3da
+#define CSR_PMPADDR43 0x3db
+#define CSR_PMPADDR44 0x3dc
+#define CSR_PMPADDR45 0x3dd
+#define CSR_PMPADDR46 0x3de
+#define CSR_PMPADDR47 0x3df
+#define CSR_PMPADDR48 0x3e0
+#define CSR_PMPADDR49 0x3e1
+#define CSR_PMPADDR50 0x3e2
+#define CSR_PMPADDR51 0x3e3
+#define CSR_PMPADDR52 0x3e4
+#define CSR_PMPADDR53 0x3e5
+#define CSR_PMPADDR54 0x3e6
+#define CSR_PMPADDR55 0x3e7
+#define CSR_PMPADDR56 0x3e8
+#define CSR_PMPADDR57 0x3e9
+#define CSR_PMPADDR58 0x3ea
+#define CSR_PMPADDR59 0x3eb
+#define CSR_PMPADDR60 0x3ec
+#define CSR_PMPADDR61 0x3ed
+#define CSR_PMPADDR62 0x3ee
+#define CSR_PMPADDR63 0x3ef
/* RNMI */
#define CSR_MNSCRATCH 0x740
@@ -675,7 +735,8 @@ typedef enum {
#define PTE_SOFT 0x300 /* Reserved for Software */
#define PTE_PBMT 0x6000000000000000ULL /* Page-based memory types */
#define PTE_N 0x8000000000000000ULL /* NAPOT translation */
-#define PTE_RESERVED 0x1FC0000000000000ULL /* Reserved bits */
+#define PTE_RESERVED(svrsw60t59b) \
+ (svrsw60t59b ? 0x07C0000000000000ULL : 0x1FC0000000000000ULL) /* Reserved bits */
#define PTE_ATTR (PTE_N | PTE_PBMT) /* All attributes bits */
/* Page table PPN shift amount */
diff --git a/target/riscv/cpu_cfg_fields.h.inc b/target/riscv/cpu_cfg_fields.h.inc
index 59f134a..e2d116f 100644
--- a/target/riscv/cpu_cfg_fields.h.inc
+++ b/target/riscv/cpu_cfg_fields.h.inc
@@ -57,6 +57,7 @@ BOOL_FIELD(ext_svadu)
BOOL_FIELD(ext_svinval)
BOOL_FIELD(ext_svnapot)
BOOL_FIELD(ext_svpbmt)
+BOOL_FIELD(ext_svrsw60t59b)
BOOL_FIELD(ext_svvptc)
BOOL_FIELD(ext_svukte)
BOOL_FIELD(ext_zdinx)
@@ -114,6 +115,7 @@ BOOL_FIELD(ext_supm)
BOOL_FIELD(rvv_ta_all_1s)
BOOL_FIELD(rvv_ma_all_1s)
BOOL_FIELD(rvv_vl_half_avl)
+BOOL_FIELD(rvv_vsetvl_x0_vill)
/* Named features */
BOOL_FIELD(ext_svade)
BOOL_FIELD(ext_zic64b)
@@ -163,6 +165,7 @@ TYPED_FIELD(uint16_t, elen, 0)
TYPED_FIELD(uint16_t, cbom_blocksize, 0)
TYPED_FIELD(uint16_t, cbop_blocksize, 0)
TYPED_FIELD(uint16_t, cboz_blocksize, 0)
+TYPED_FIELD(uint8_t, pmp_regions, 0)
TYPED_FIELD(int8_t, max_satp_mode, -1)
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 2ed69d7..3479a62 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -1309,6 +1309,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
bool svade = riscv_cpu_cfg(env)->ext_svade;
bool svadu = riscv_cpu_cfg(env)->ext_svadu;
bool adue = svadu ? env->menvcfg & MENVCFG_ADUE : !svade;
+ bool svrsw60t59b = riscv_cpu_cfg(env)->ext_svrsw60t59b;
if (first_stage && two_stage && env->virt_enabled) {
pbmte = pbmte && (env->henvcfg & HENVCFG_PBMTE);
@@ -1376,7 +1377,7 @@ static int get_physical_address(CPURISCVState *env, hwaddr *physical,
if (riscv_cpu_sxl(env) == MXL_RV32) {
ppn = pte >> PTE_PPN_SHIFT;
} else {
- if (pte & PTE_RESERVED) {
+ if (pte & PTE_RESERVED(svrsw60t59b)) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: reserved bits set in PTE: "
"addr: 0x%" HWADDR_PRIx " pte: 0x" TARGET_FMT_lx "\n",
__func__, pte_addr, pte);
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index fb14972..8631be9 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -738,7 +738,10 @@ static RISCVException dbltrp_hmode(CPURISCVState *env, int csrno)
static RISCVException pmp(CPURISCVState *env, int csrno)
{
if (riscv_cpu_cfg(env)->pmp) {
- if (csrno <= CSR_PMPCFG3) {
+ int max_pmpcfg = (env->priv_ver >= PRIV_VERSION_1_12_0) ?
++ CSR_PMPCFG15 : CSR_PMPCFG3;
+
+ if (csrno <= max_pmpcfg) {
uint32_t reg_index = csrno - CSR_PMPCFG0;
/* TODO: RV128 restriction check */
@@ -3126,14 +3129,14 @@ static RISCVException write_mscratch(CPURISCVState *env, int csrno,
static RISCVException read_mepc(CPURISCVState *env, int csrno,
target_ulong *val)
{
- *val = env->mepc;
+ *val = env->mepc & get_xepc_mask(env);
return RISCV_EXCP_NONE;
}
static RISCVException write_mepc(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra)
{
- env->mepc = val;
+ env->mepc = val & get_xepc_mask(env);
return RISCV_EXCP_NONE;
}
@@ -3181,6 +3184,7 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
uint64_t mask = MENVCFG_FIOM | MENVCFG_CBIE | MENVCFG_CBCFE |
MENVCFG_CBZE | MENVCFG_CDE;
+ bool stce_changed = false;
if (riscv_cpu_mxl(env) == MXL_RV64) {
mask |= (cfg->ext_svpbmt ? MENVCFG_PBMTE : 0) |
@@ -3206,8 +3210,18 @@ static RISCVException write_menvcfg(CPURISCVState *env, int csrno,
if ((val & MENVCFG_DTE) == 0) {
env->mstatus &= ~MSTATUS_SDT;
}
+
+ if (cfg->ext_sstc &&
+ ((env->menvcfg & MENVCFG_STCE) != (val & MENVCFG_STCE))) {
+ stce_changed = true;
+ }
}
env->menvcfg = (env->menvcfg & ~mask) | (val & mask);
+
+ if (stce_changed) {
+ riscv_timer_stce_changed(env, true, !!(val & MENVCFG_STCE));
+ }
+
return write_henvcfg(env, CSR_HENVCFG, env->henvcfg, ra);
}
@@ -3230,12 +3244,23 @@ static RISCVException write_menvcfgh(CPURISCVState *env, int csrno,
(cfg->ext_smcdeleg ? MENVCFG_CDE : 0) |
(cfg->ext_ssdbltrp ? MENVCFG_DTE : 0);
uint64_t valh = (uint64_t)val << 32;
+ bool stce_changed = false;
+
+ if (cfg->ext_sstc &&
+ ((env->menvcfg & MENVCFG_STCE) != (valh & MENVCFG_STCE))) {
+ stce_changed = true;
+ }
if ((valh & MENVCFG_DTE) == 0) {
env->mstatus &= ~MSTATUS_SDT;
}
env->menvcfg = (env->menvcfg & ~mask) | (valh & mask);
+
+ if (stce_changed) {
+ riscv_timer_stce_changed(env, true, !!(valh & MENVCFG_STCE));
+ }
+
return write_henvcfgh(env, CSR_HENVCFGH, env->henvcfg >> 32, ra);
}
@@ -3313,8 +3338,10 @@ static RISCVException read_henvcfg(CPURISCVState *env, int csrno,
static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra)
{
+ const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
uint64_t mask = HENVCFG_FIOM | HENVCFG_CBIE | HENVCFG_CBCFE | HENVCFG_CBZE;
RISCVException ret;
+ bool stce_changed = false;
ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG);
if (ret != RISCV_EXCP_NONE) {
@@ -3340,6 +3367,11 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
get_field(val, HENVCFG_PMM) != PMM_FIELD_RESERVED) {
mask |= HENVCFG_PMM;
}
+
+ if (cfg->ext_sstc &&
+ ((env->henvcfg & HENVCFG_STCE) != (val & HENVCFG_STCE))) {
+ stce_changed = true;
+ }
}
env->henvcfg = val & mask;
@@ -3347,6 +3379,10 @@ static RISCVException write_henvcfg(CPURISCVState *env, int csrno,
env->vsstatus &= ~MSTATUS_SDT;
}
+ if (stce_changed) {
+ riscv_timer_stce_changed(env, false, !!(val & HENVCFG_STCE));
+ }
+
return RISCV_EXCP_NONE;
}
@@ -3368,19 +3404,32 @@ static RISCVException read_henvcfgh(CPURISCVState *env, int csrno,
static RISCVException write_henvcfgh(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra)
{
+ const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
uint64_t mask = env->menvcfg & (HENVCFG_PBMTE | HENVCFG_STCE |
HENVCFG_ADUE | HENVCFG_DTE);
uint64_t valh = (uint64_t)val << 32;
RISCVException ret;
+ bool stce_changed = false;
ret = smstateen_acc_ok(env, 0, SMSTATEEN0_HSENVCFG);
if (ret != RISCV_EXCP_NONE) {
return ret;
}
+
+ if (cfg->ext_sstc &&
+ ((env->henvcfg & HENVCFG_STCE) != (valh & HENVCFG_STCE))) {
+ stce_changed = true;
+ }
+
env->henvcfg = (env->henvcfg & 0xFFFFFFFF) | (valh & mask);
if ((env->henvcfg & HENVCFG_DTE) == 0) {
env->vsstatus &= ~MSTATUS_SDT;
}
+
+ if (stce_changed) {
+ riscv_timer_stce_changed(env, false, !!(val & HENVCFG_STCE));
+ }
+
return RISCV_EXCP_NONE;
}
@@ -3651,7 +3700,14 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno,
if (riscv_cpu_cfg(env)->ext_sstc && (env->priv == PRV_M) &&
get_field(env->menvcfg, MENVCFG_STCE)) {
/* sstc extension forbids STIP & VSTIP to be writeable in mip */
- mask = mask & ~(MIP_STIP | MIP_VSTIP);
+
+ /* STIP is not writable when menvcfg.STCE is enabled. */
+ mask = mask & ~MIP_STIP;
+
+ /* VSTIP is not writable when both [mh]envcfg.STCE are enabled. */
+ if (get_field(env->henvcfg, HENVCFG_STCE)) {
+ mask = mask & ~MIP_VSTIP;
+ }
}
if (mask) {
@@ -4113,14 +4169,14 @@ static RISCVException write_sscratch(CPURISCVState *env, int csrno,
static RISCVException read_sepc(CPURISCVState *env, int csrno,
target_ulong *val)
{
- *val = env->sepc;
+ *val = env->sepc & get_xepc_mask(env);
return RISCV_EXCP_NONE;
}
static RISCVException write_sepc(CPURISCVState *env, int csrno,
target_ulong val, uintptr_t ra)
{
- env->sepc = val;
+ env->sepc = val & get_xepc_mask(env);
return RISCV_EXCP_NONE;
}
@@ -6111,6 +6167,30 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg },
[CSR_PMPCFG2] = { "pmpcfg2", pmp, read_pmpcfg, write_pmpcfg },
[CSR_PMPCFG3] = { "pmpcfg3", pmp, read_pmpcfg, write_pmpcfg },
+ [CSR_PMPCFG4] = { "pmpcfg4", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG5] = { "pmpcfg5", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG6] = { "pmpcfg6", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG7] = { "pmpcfg7", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG8] = { "pmpcfg8", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG9] = { "pmpcfg9", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG10] = { "pmpcfg10", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG11] = { "pmpcfg11", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG12] = { "pmpcfg12", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG13] = { "pmpcfg13", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG14] = { "pmpcfg14", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPCFG15] = { "pmpcfg15", pmp, read_pmpcfg, write_pmpcfg,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
[CSR_PMPADDR0] = { "pmpaddr0", pmp, read_pmpaddr, write_pmpaddr },
[CSR_PMPADDR1] = { "pmpaddr1", pmp, read_pmpaddr, write_pmpaddr },
[CSR_PMPADDR2] = { "pmpaddr2", pmp, read_pmpaddr, write_pmpaddr },
@@ -6125,8 +6205,104 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_PMPADDR11] = { "pmpaddr11", pmp, read_pmpaddr, write_pmpaddr },
[CSR_PMPADDR12] = { "pmpaddr12", pmp, read_pmpaddr, write_pmpaddr },
[CSR_PMPADDR13] = { "pmpaddr13", pmp, read_pmpaddr, write_pmpaddr },
- [CSR_PMPADDR14] = { "pmpaddr14", pmp, read_pmpaddr, write_pmpaddr },
- [CSR_PMPADDR15] = { "pmpaddr15", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR14] = { "pmpaddr14", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR15] = { "pmpaddr15", pmp, read_pmpaddr, write_pmpaddr },
+ [CSR_PMPADDR16] = { "pmpaddr16", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR17] = { "pmpaddr17", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR18] = { "pmpaddr18", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR19] = { "pmpaddr19", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR20] = { "pmpaddr20", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR21] = { "pmpaddr21", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR22] = { "pmpaddr22", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR23] = { "pmpaddr23", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR24] = { "pmpaddr24", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR25] = { "pmpaddr25", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR26] = { "pmpaddr26", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR27] = { "pmpaddr27", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR28] = { "pmpaddr28", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR29] = { "pmpaddr29", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR30] = { "pmpaddr30", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR31] = { "pmpaddr31", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR32] = { "pmpaddr32", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR33] = { "pmpaddr33", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR34] = { "pmpaddr34", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR35] = { "pmpaddr35", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR36] = { "pmpaddr36", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR37] = { "pmpaddr37", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR38] = { "pmpaddr38", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR39] = { "pmpaddr39", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR40] = { "pmpaddr40", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR41] = { "pmpaddr41", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR42] = { "pmpaddr42", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR43] = { "pmpaddr43", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR44] = { "pmpaddr44", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR45] = { "pmpaddr45", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR46] = { "pmpaddr46", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR47] = { "pmpaddr47", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR48] = { "pmpaddr48", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR49] = { "pmpaddr49", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR50] = { "pmpaddr50", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR51] = { "pmpaddr51", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR52] = { "pmpaddr52", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR53] = { "pmpaddr53", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR54] = { "pmpaddr54", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR55] = { "pmpaddr55", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR56] = { "pmpaddr56", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR57] = { "pmpaddr57", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR58] = { "pmpaddr58", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR59] = { "pmpaddr59", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR60] = { "pmpaddr60", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR61] = { "pmpaddr61", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR62] = { "pmpaddr62", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
+ [CSR_PMPADDR63] = { "pmpaddr63", pmp, read_pmpaddr, write_pmpaddr,
+ .min_priv_ver = PRIV_VERSION_1_12_0 },
/* Debug CSRs */
[CSR_TSELECT] = { "tselect", debug, read_tselect, write_tselect },
diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c
index 706bdfa..af40561 100644
--- a/target/riscv/fpu_helper.c
+++ b/target/riscv/fpu_helper.c
@@ -755,6 +755,6 @@ uint64_t helper_fcvt_bf16_s(CPURISCVState *env, uint64_t rs1)
uint64_t helper_fcvt_s_bf16(CPURISCVState *env, uint64_t rs1)
{
- float16 frs1 = check_nanbox_h(env, rs1);
+ float16 frs1 = check_nanbox_bf16(env, rs1);
return nanbox_s(env, bfloat16_to_float32(frs1, &env->fp_status));
}
diff --git a/target/riscv/helper.h b/target/riscv/helper.h
index 85d73e4..f712b1c 100644
--- a/target/riscv/helper.h
+++ b/target/riscv/helper.h
@@ -159,7 +159,7 @@ DEF_HELPER_FLAGS_3(hyp_hsv_d, TCG_CALL_NO_WG, void, env, tl, tl)
#endif
/* Vector functions */
-DEF_HELPER_3(vsetvl, tl, env, tl, tl)
+DEF_HELPER_4(vsetvl, tl, env, tl, tl, tl)
DEF_HELPER_5(vle8_v, void, ptr, ptr, tl, env, i32)
DEF_HELPER_5(vle16_v, void, ptr, ptr, tl, env, i32)
DEF_HELPER_5(vle32_v, void, ptr, ptr, tl, env, i32)
diff --git a/target/riscv/insn_trans/trans_rvv.c.inc b/target/riscv/insn_trans/trans_rvv.c.inc
index 2b6077a..610bf9f 100644
--- a/target/riscv/insn_trans/trans_rvv.c.inc
+++ b/target/riscv/insn_trans/trans_rvv.c.inc
@@ -202,7 +202,7 @@ static bool do_vsetvl(DisasContext *s, int rd, int rs1, TCGv s2)
s1 = get_gpr(s, rs1, EXT_ZERO);
}
- gen_helper_vsetvl(dst, tcg_env, s1, s2);
+ gen_helper_vsetvl(dst, tcg_env, s1, s2, tcg_constant_tl((int) (rd == 0 && rs1 == 0)));
gen_set_gpr(s, rd, dst);
finalize_rvv_inst(s);
@@ -222,7 +222,7 @@ static bool do_vsetivli(DisasContext *s, int rd, TCGv s1, TCGv s2)
dst = dest_gpr(s, rd);
- gen_helper_vsetvl(dst, tcg_env, s1, s2);
+ gen_helper_vsetvl(dst, tcg_env, s1, s2, tcg_constant_tl(0));
gen_set_gpr(s, rd, dst);
finalize_rvv_inst(s);
gen_update_pc(s, s->cur_insn_len);
@@ -1361,6 +1361,12 @@ static bool ldff_trans(uint32_t vd, uint32_t rs1, uint32_t data,
fn(dest, mask, base, tcg_env, desc);
finalize_rvv_inst(s);
+
+ /* vector unit-stride fault-only-first load may modify vl CSR */
+ gen_update_pc(s, s->cur_insn_len);
+ lookup_and_goto_ptr(s);
+ s->base.is_jmp = DISAS_NORETURN;
+
return true;
}
diff --git a/target/riscv/internals.h b/target/riscv/internals.h
index 4570bd5..172296f 100644
--- a/target/riscv/internals.h
+++ b/target/riscv/internals.h
@@ -142,6 +142,33 @@ static inline float16 check_nanbox_h(CPURISCVState *env, uint64_t f)
}
}
+static inline float16 check_nanbox_bf16(CPURISCVState *env, uint64_t f)
+{
+ /* Disable nanbox check when enable zfinx */
+ if (env_archcpu(env)->cfg.ext_zfinx) {
+ return (uint16_t)f;
+ }
+
+ uint64_t mask = MAKE_64BIT_MASK(16, 48);
+
+ if (likely((f & mask) == mask)) {
+ return (uint16_t)f;
+ } else {
+ return 0x7FC0u; /* default qnan */
+ }
+}
+
+static inline target_ulong get_xepc_mask(CPURISCVState *env)
+{
+ /* When IALIGN=32, both low bits must be zero.
+ * When IALIGN=16 (has C extension), only bit 0 must be zero. */
+ if (riscv_has_ext(env, RVC)) {
+ return ~(target_ulong)1;
+ } else {
+ return ~(target_ulong)3;
+ }
+}
+
#ifndef CONFIG_USER_ONLY
/* Our implementation of SysemuCPUOps::has_work */
bool riscv_cpu_has_work(CPUState *cs);
diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c
index e1a04be..5c19062 100644
--- a/target/riscv/kvm/kvm-cpu.c
+++ b/target/riscv/kvm/kvm-cpu.c
@@ -999,6 +999,19 @@ static void kvm_riscv_destroy_scratch_vcpu(KVMScratchCPU *scratch)
close(scratch->kvmfd);
}
+static void kvm_riscv_init_max_satp_mode(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
+{
+ struct kvm_one_reg reg;
+ int ret;
+
+ reg.id = RISCV_CONFIG_REG(satp_mode);
+ reg.addr = (uint64_t)&cpu->cfg.max_satp_mode;
+ ret = ioctl(kvmcpu->cpufd, KVM_GET_ONE_REG, &reg);
+ if (ret != 0) {
+ error_report("Unable to retrieve satp mode from host, error %d", ret);
+ }
+}
+
static void kvm_riscv_init_machine_ids(RISCVCPU *cpu, KVMScratchCPU *kvmcpu)
{
struct kvm_one_reg reg;
@@ -1302,6 +1315,7 @@ static void riscv_init_kvm_registers(Object *cpu_obj)
kvm_riscv_init_machine_ids(cpu, &kvmcpu);
kvm_riscv_init_misa_ext_mask(cpu, &kvmcpu);
kvm_riscv_init_cfg(cpu, &kvmcpu);
+ kvm_riscv_init_max_satp_mode(cpu, &kvmcpu);
kvm_riscv_destroy_scratch_vcpu(&kvmcpu);
}
@@ -1605,7 +1619,7 @@ static void kvm_riscv_handle_sbi_dbcn(CPUState *cs, struct kvm_run *run)
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));
+ ret = qemu_chr_fe_write_all(serial_hd(0)->be, &ch, sizeof(ch));
if (ret < 0) {
error_report("SBI_EXT_DBCN_CONSOLE_WRITE_BYTE: error when "
@@ -1985,7 +1999,7 @@ static bool kvm_cpu_realize(CPUState *cs, Error **errp)
}
}
- return true;
+ return true;
}
void riscv_kvm_cpu_finalize_features(RISCVCPU *cpu, Error **errp)
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index c97e9ce..1600ec4 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -36,8 +36,9 @@ static int pmp_post_load(void *opaque, int version_id)
RISCVCPU *cpu = opaque;
CPURISCVState *env = &cpu->env;
int i;
+ uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
- for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ for (i = 0; i < pmp_regions; i++) {
pmp_update_rule_addr(env, i);
}
pmp_update_rule_nums(env);
diff --git a/target/riscv/op_helper.c b/target/riscv/op_helper.c
index 557807b..15460bf 100644
--- a/target/riscv/op_helper.c
+++ b/target/riscv/op_helper.c
@@ -280,7 +280,7 @@ target_ulong helper_sret(CPURISCVState *env)
riscv_raise_exception(env, RISCV_EXCP_ILLEGAL_INST, GETPC());
}
- target_ulong retpc = env->sepc;
+ target_ulong retpc = env->sepc & get_xepc_mask(env);
if (!riscv_cpu_allow_16bit_insn(&env_archcpu(env)->cfg,
env->priv_ver,
env->misa_ext) && (retpc & 0x3)) {
@@ -391,7 +391,7 @@ static target_ulong ssdbltrp_mxret(CPURISCVState *env, target_ulong mstatus,
target_ulong helper_mret(CPURISCVState *env)
{
- target_ulong retpc = env->mepc;
+ target_ulong retpc = env->mepc & get_xepc_mask(env);
uint64_t mstatus = env->mstatus;
target_ulong prev_priv = get_field(mstatus, MSTATUS_MPP);
diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c
index 5af295e..3540327 100644
--- a/target/riscv/pmp.c
+++ b/target/riscv/pmp.c
@@ -122,7 +122,9 @@ uint32_t pmp_get_num_rules(CPURISCVState *env)
*/
static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
{
- if (pmp_index < MAX_RISCV_PMPS) {
+ uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
+
+ if (pmp_index < pmp_regions) {
return env->pmp_state.pmp[pmp_index].cfg_reg;
}
@@ -136,7 +138,9 @@ static inline uint8_t pmp_read_cfg(CPURISCVState *env, uint32_t pmp_index)
*/
static bool pmp_write_cfg(CPURISCVState *env, uint32_t pmp_index, uint8_t val)
{
- if (pmp_index < MAX_RISCV_PMPS) {
+ uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
+
+ if (pmp_index < pmp_regions) {
if (env->pmp_state.pmp[pmp_index].cfg_reg == val) {
/* no change */
return false;
@@ -236,9 +240,10 @@ void pmp_update_rule_addr(CPURISCVState *env, uint32_t pmp_index)
void pmp_update_rule_nums(CPURISCVState *env)
{
int i;
+ uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
env->pmp_state.num_rules = 0;
- for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ for (i = 0; i < pmp_regions; i++) {
const uint8_t a_field =
pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg);
if (PMP_AMATCH_OFF != a_field) {
@@ -332,6 +337,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
int pmp_size = 0;
hwaddr s = 0;
hwaddr e = 0;
+ uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
/* Short cut if no rules */
if (0 == pmp_get_num_rules(env)) {
@@ -356,7 +362,7 @@ bool pmp_hart_has_privs(CPURISCVState *env, hwaddr addr,
* 1.10 draft priv spec states there is an implicit order
* from low to high
*/
- for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ for (i = 0; i < pmp_regions; i++) {
s = pmp_is_in_range(env, i, addr);
e = pmp_is_in_range(env, i, addr + pmp_size - 1);
@@ -527,8 +533,9 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
{
trace_pmpaddr_csr_write(env->mhartid, addr_index, val);
bool is_next_cfg_tor = false;
+ uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
- if (addr_index < MAX_RISCV_PMPS) {
+ if (addr_index < pmp_regions) {
if (env->pmp_state.pmp[addr_index].addr_reg == val) {
/* no change */
return;
@@ -538,7 +545,7 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
* In TOR mode, need to check the lock bit of the next pmp
* (if there is a next).
*/
- if (addr_index + 1 < MAX_RISCV_PMPS) {
+ if (addr_index + 1 < pmp_regions) {
uint8_t pmp_cfg = env->pmp_state.pmp[addr_index + 1].cfg_reg;
is_next_cfg_tor = PMP_AMATCH_TOR == pmp_get_a_field(pmp_cfg);
@@ -573,8 +580,9 @@ void pmpaddr_csr_write(CPURISCVState *env, uint32_t addr_index,
target_ulong pmpaddr_csr_read(CPURISCVState *env, uint32_t addr_index)
{
target_ulong val = 0;
+ uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
- if (addr_index < MAX_RISCV_PMPS) {
+ if (addr_index < pmp_regions) {
val = env->pmp_state.pmp[addr_index].addr_reg;
trace_pmpaddr_csr_read(env->mhartid, addr_index, val);
} else {
@@ -592,6 +600,7 @@ void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
{
int i;
uint64_t mask = MSECCFG_MMWP | MSECCFG_MML;
+ uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
/* Update PMM field only if the value is valid according to Zjpm v1.0 */
if (riscv_cpu_cfg(env)->ext_smmpm &&
riscv_cpu_mxl(env) == MXL_RV64 &&
@@ -603,7 +612,7 @@ void mseccfg_csr_write(CPURISCVState *env, target_ulong val)
/* RLB cannot be enabled if it's already 0 and if any regions are locked */
if (!MSECCFG_RLB_ISSET(env)) {
- for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ for (i = 0; i < pmp_regions; i++) {
if (pmp_is_locked(env, i)) {
val &= ~MSECCFG_RLB;
break;
@@ -659,6 +668,7 @@ target_ulong pmp_get_tlb_size(CPURISCVState *env, hwaddr addr)
hwaddr tlb_sa = addr & ~(TARGET_PAGE_SIZE - 1);
hwaddr tlb_ea = tlb_sa + TARGET_PAGE_SIZE - 1;
int i;
+ uint8_t pmp_regions = riscv_cpu_cfg(env)->pmp_regions;
/*
* If PMP is not supported or there are no PMP rules, the TLB page will not
@@ -669,7 +679,7 @@ target_ulong pmp_get_tlb_size(CPURISCVState *env, hwaddr addr)
return TARGET_PAGE_SIZE;
}
- for (i = 0; i < MAX_RISCV_PMPS; i++) {
+ for (i = 0; i < pmp_regions; i++) {
if (pmp_get_a_field(env->pmp_state.pmp[i].cfg_reg) == PMP_AMATCH_OFF) {
continue;
}
diff --git a/target/riscv/riscv-qmp-cmds.c b/target/riscv/riscv-qmp-cmds.c
index 8ba8aa0..8a1856c 100644
--- a/target/riscv/riscv-qmp-cmds.c
+++ b/target/riscv/riscv-qmp-cmds.c
@@ -121,7 +121,7 @@ static void riscv_obj_add_profiles_qdict(Object *obj, QDict *qdict_out)
for (int i = 0; riscv_profiles[i] != NULL; i++) {
profile = riscv_profiles[i];
- value = QOBJECT(qbool_from_bool(profile->enabled));
+ value = QOBJECT(qbool_from_bool(profile->present));
qdict_put_obj(qdict_out, profile->name, value);
}
diff --git a/target/riscv/tcg/tcg-cpu.c b/target/riscv/tcg/tcg-cpu.c
index 55fd9e5..78fb279 100644
--- a/target/riscv/tcg/tcg-cpu.c
+++ b/target/riscv/tcg/tcg-cpu.c
@@ -451,6 +451,15 @@ static void riscv_cpu_disable_priv_spec_isa_exts(RISCVCPU *cpu)
continue;
}
+ /*
+ * cpu.debug = true is marked as 'sdtrig', priv spec 1.12.
+ * Skip this warning since existing CPUs with older priv
+ * spec and debug = true will be impacted.
+ */
+ if (!strcmp(edata->name, "sdtrig")) {
+ continue;
+ }
+
isa_ext_update_enabled(cpu, edata->ext_enable_offset, false);
/*
@@ -830,6 +839,12 @@ void riscv_cpu_validate_set_extensions(RISCVCPU *cpu, Error **errp)
cpu->cfg.ext_ssctr = false;
}
+ if (cpu->cfg.ext_svrsw60t59b &&
+ (!cpu->cfg.mmu || mcc->def->misa_mxl_max == MXL_RV32)) {
+ error_setg(errp, "svrsw60t59b is not supported on RV32 and MMU-less platforms");
+ return;
+ }
+
/*
* Disable isa extensions based on priv spec after we
* validated and set everything we need.
@@ -867,16 +882,11 @@ static void riscv_cpu_check_parent_profile(RISCVCPU *cpu,
RISCVCPUProfile *profile,
RISCVCPUProfile *parent)
{
- const char *parent_name;
- bool parent_enabled;
-
- if (!profile->enabled || !parent) {
+ if (!profile->present || !parent) {
return;
}
- parent_name = parent->name;
- parent_enabled = object_property_get_bool(OBJECT(cpu), parent_name, NULL);
- profile->enabled = parent_enabled;
+ profile->present = parent->present;
}
static void riscv_cpu_validate_profile(RISCVCPU *cpu,
@@ -937,7 +947,7 @@ static void riscv_cpu_validate_profile(RISCVCPU *cpu,
}
}
- profile->enabled = profile_impl;
+ profile->present = profile_impl;
riscv_cpu_check_parent_profile(cpu, profile, profile->u_parent);
riscv_cpu_check_parent_profile(cpu, profile, profile->s_parent);
@@ -1166,6 +1176,70 @@ static bool riscv_cpu_is_generic(Object *cpu_obj)
return object_dynamic_cast(cpu_obj, TYPE_RISCV_DYNAMIC_CPU) != NULL;
}
+static void riscv_cpu_set_profile(RISCVCPU *cpu,
+ RISCVCPUProfile *profile,
+ bool enabled)
+{
+ int i, ext_offset;
+
+ if (profile->u_parent != NULL) {
+ riscv_cpu_set_profile(cpu, profile->u_parent, enabled);
+ }
+
+ if (profile->s_parent != NULL) {
+ riscv_cpu_set_profile(cpu, profile->s_parent, enabled);
+ }
+
+ profile->enabled = enabled;
+
+ if (profile->enabled) {
+ cpu->env.priv_ver = profile->priv_spec;
+
+#ifndef CONFIG_USER_ONLY
+ if (profile->satp_mode != RISCV_PROFILE_ATTR_UNUSED) {
+ object_property_set_bool(OBJECT(cpu), "mmu", true, NULL);
+ const char *satp_prop = satp_mode_str(profile->satp_mode,
+ riscv_cpu_is_32bit(cpu));
+ object_property_set_bool(OBJECT(cpu), satp_prop, true, NULL);
+ }
+#endif
+ }
+
+ for (i = 0; misa_bits[i] != 0; i++) {
+ uint32_t bit = misa_bits[i];
+
+ if (!(profile->misa_ext & bit)) {
+ continue;
+ }
+
+ if (bit == RVI && !profile->enabled) {
+ /*
+ * Disabling profiles will not disable the base
+ * ISA RV64I.
+ */
+ continue;
+ }
+
+ cpu_misa_ext_add_user_opt(bit, profile->enabled);
+ riscv_cpu_write_misa_bit(cpu, bit, profile->enabled);
+ }
+
+ for (i = 0; profile->ext_offsets[i] != RISCV_PROFILE_EXT_LIST_END; i++) {
+ ext_offset = profile->ext_offsets[i];
+
+ if (profile->enabled) {
+ if (cpu_cfg_offset_is_named_feat(ext_offset)) {
+ riscv_cpu_enable_named_feat(cpu, ext_offset);
+ }
+
+ cpu_bump_multi_ext_priv_ver(&cpu->env, ext_offset);
+ }
+
+ cpu_cfg_ext_add_user_opt(ext_offset, profile->enabled);
+ isa_ext_update_enabled(cpu, ext_offset, profile->enabled);
+ }
+}
+
/*
* We'll get here via the following path:
*
@@ -1332,7 +1406,6 @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name,
RISCVCPUProfile *profile = opaque;
RISCVCPU *cpu = RISCV_CPU(obj);
bool value;
- int i, ext_offset;
if (riscv_cpu_is_vendor(obj)) {
error_setg(errp, "Profile %s is not available for vendor CPUs",
@@ -1351,64 +1424,8 @@ static void cpu_set_profile(Object *obj, Visitor *v, const char *name,
}
profile->user_set = true;
- profile->enabled = value;
- if (profile->u_parent != NULL) {
- object_property_set_bool(obj, profile->u_parent->name,
- profile->enabled, NULL);
- }
-
- if (profile->s_parent != NULL) {
- object_property_set_bool(obj, profile->s_parent->name,
- profile->enabled, NULL);
- }
-
- if (profile->enabled) {
- cpu->env.priv_ver = profile->priv_spec;
- }
-
-#ifndef CONFIG_USER_ONLY
- if (profile->satp_mode != RISCV_PROFILE_ATTR_UNUSED) {
- object_property_set_bool(obj, "mmu", true, NULL);
- const char *satp_prop = satp_mode_str(profile->satp_mode,
- riscv_cpu_is_32bit(cpu));
- object_property_set_bool(obj, satp_prop, profile->enabled, NULL);
- }
-#endif
-
- for (i = 0; misa_bits[i] != 0; i++) {
- uint32_t bit = misa_bits[i];
-
- if (!(profile->misa_ext & bit)) {
- continue;
- }
-
- if (bit == RVI && !profile->enabled) {
- /*
- * Disabling profiles will not disable the base
- * ISA RV64I.
- */
- continue;
- }
-
- cpu_misa_ext_add_user_opt(bit, profile->enabled);
- riscv_cpu_write_misa_bit(cpu, bit, profile->enabled);
- }
-
- for (i = 0; profile->ext_offsets[i] != RISCV_PROFILE_EXT_LIST_END; i++) {
- ext_offset = profile->ext_offsets[i];
-
- if (profile->enabled) {
- if (cpu_cfg_offset_is_named_feat(ext_offset)) {
- riscv_cpu_enable_named_feat(cpu, ext_offset);
- }
-
- cpu_bump_multi_ext_priv_ver(&cpu->env, ext_offset);
- }
-
- cpu_cfg_ext_add_user_opt(ext_offset, profile->enabled);
- isa_ext_update_enabled(cpu, ext_offset, profile->enabled);
- }
+ riscv_cpu_set_profile(cpu, profile, value);
}
static void cpu_get_profile(Object *obj, Visitor *v, const char *name,
@@ -1423,7 +1440,7 @@ static void cpu_get_profile(Object *obj, Visitor *v, const char *name,
static void riscv_cpu_add_profiles(Object *cpu_obj)
{
for (int i = 0; riscv_profiles[i] != NULL; i++) {
- const RISCVCPUProfile *profile = riscv_profiles[i];
+ RISCVCPUProfile *profile = riscv_profiles[i];
object_property_add(cpu_obj, profile->name, "bool",
cpu_get_profile, cpu_set_profile,
@@ -1435,30 +1452,11 @@ static void riscv_cpu_add_profiles(Object *cpu_obj)
* case.
*/
if (profile->enabled) {
- object_property_set_bool(cpu_obj, profile->name, true, NULL);
+ riscv_cpu_set_profile(RISCV_CPU(cpu_obj), profile, true);
}
}
}
-static bool cpu_ext_is_deprecated(const char *ext_name)
-{
- return isupper(ext_name[0]);
-}
-
-/*
- * String will be allocated in the heap. Caller is responsible
- * for freeing it.
- */
-static char *cpu_ext_to_lower(const char *ext_name)
-{
- char *ret = g_malloc0(strlen(ext_name) + 1);
-
- strcpy(ret, ext_name);
- ret[0] = tolower(ret[0]);
-
- return ret;
-}
-
static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
@@ -1471,13 +1469,6 @@ static void cpu_set_multi_ext_cfg(Object *obj, Visitor *v, const char *name,
return;
}
- if (cpu_ext_is_deprecated(multi_ext_cfg->name)) {
- g_autofree char *lower = cpu_ext_to_lower(multi_ext_cfg->name);
-
- warn_report("CPU property '%s' is deprecated. Please use '%s' instead",
- multi_ext_cfg->name, lower);
- }
-
cpu_cfg_ext_add_user_opt(multi_ext_cfg->offset, value);
prev_val = isa_ext_is_enabled(cpu, multi_ext_cfg->offset);
@@ -1513,14 +1504,13 @@ static void cpu_add_multi_ext_prop(Object *cpu_obj,
const RISCVCPUMultiExtConfig *multi_cfg)
{
bool generic_cpu = riscv_cpu_is_generic(cpu_obj);
- bool deprecated_ext = cpu_ext_is_deprecated(multi_cfg->name);
object_property_add(cpu_obj, multi_cfg->name, "bool",
cpu_get_multi_ext_cfg,
cpu_set_multi_ext_cfg,
NULL, (void *)multi_cfg);
- if (!generic_cpu || deprecated_ext) {
+ if (!generic_cpu) {
return;
}
@@ -1563,8 +1553,6 @@ static void riscv_cpu_add_user_properties(Object *obj)
riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_vendor_exts);
riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_experimental_exts);
- riscv_cpu_add_multiext_prop_array(obj, riscv_cpu_deprecated_exts);
-
riscv_cpu_add_profiles(obj);
}
@@ -1606,6 +1594,8 @@ static void riscv_init_max_cpu_extensions(Object *obj)
if (env->misa_mxl != MXL_RV32) {
isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_zcf), false);
+ } else {
+ isa_ext_update_enabled(cpu, CPU_CFG_OFFSET(ext_svrsw60t59b), false);
}
/*
diff --git a/target/riscv/time_helper.c b/target/riscv/time_helper.c
index bc0d9a0..400e917 100644
--- a/target/riscv/time_helper.c
+++ b/target/riscv/time_helper.c
@@ -46,8 +46,23 @@ void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer,
{
uint64_t diff, ns_diff, next;
RISCVAclintMTimerState *mtimer = env->rdtime_fn_arg;
- uint32_t timebase_freq = mtimer->timebase_freq;
- uint64_t rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta;
+ uint32_t timebase_freq;
+ uint64_t rtc_r;
+
+ if (!riscv_cpu_cfg(env)->ext_sstc || !env->rdtime_fn ||
+ !env->rdtime_fn_arg || !get_field(env->menvcfg, MENVCFG_STCE)) {
+ /* S/VS Timer IRQ depends on sstc extension, rdtime_fn(), and STCE. */
+ return;
+ }
+
+ if (timer_irq == MIP_VSTIP &&
+ (!riscv_has_ext(env, RVH) || !get_field(env->henvcfg, HENVCFG_STCE))) {
+ /* VS Timer IRQ also depends on RVH and henvcfg.STCE. */
+ return;
+ }
+
+ timebase_freq = mtimer->timebase_freq;
+ rtc_r = env->rdtime_fn(env->rdtime_fn_arg) + delta;
if (timecmp <= rtc_r) {
/*
@@ -125,6 +140,52 @@ void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer,
timer_mod(timer, next);
}
+/*
+ * When disabling xenvcfg.STCE, the S/VS Timer may be disabled at the same time.
+ * It is safe to call this function regardless of whether the timer has been
+ * deleted or not. timer_del() will do nothing if the timer has already
+ * been deleted.
+ */
+static void riscv_timer_disable_timecmp(CPURISCVState *env, QEMUTimer *timer,
+ uint32_t timer_irq)
+{
+ /* Disable S-mode Timer IRQ and HW-based STIP */
+ if ((timer_irq == MIP_STIP) && !get_field(env->menvcfg, MENVCFG_STCE)) {
+ riscv_cpu_update_mip(env, timer_irq, BOOL_TO_MASK(0));
+ timer_del(timer);
+ return;
+ }
+
+ /* Disable VS-mode Timer IRQ and HW-based VSTIP */
+ if ((timer_irq == MIP_VSTIP) &&
+ (!get_field(env->menvcfg, MENVCFG_STCE) ||
+ !get_field(env->henvcfg, HENVCFG_STCE))) {
+ env->vstime_irq = 0;
+ riscv_cpu_update_mip(env, 0, BOOL_TO_MASK(0));
+ timer_del(timer);
+ return;
+ }
+}
+
+/* Enable or disable S/VS-mode Timer when xenvcfg.STCE is changed */
+void riscv_timer_stce_changed(CPURISCVState *env, bool is_m_mode, bool enable)
+{
+ if (enable) {
+ riscv_timer_write_timecmp(env, env->vstimer, env->vstimecmp,
+ env->htimedelta, MIP_VSTIP);
+ } else {
+ riscv_timer_disable_timecmp(env, env->vstimer, MIP_VSTIP);
+ }
+
+ if (is_m_mode) {
+ if (enable) {
+ riscv_timer_write_timecmp(env, env->stimer, env->stimecmp, 0, MIP_STIP);
+ } else {
+ riscv_timer_disable_timecmp(env, env->stimer, MIP_STIP);
+ }
+ }
+}
+
void riscv_timer_init(RISCVCPU *cpu)
{
CPURISCVState *env;
diff --git a/target/riscv/time_helper.h b/target/riscv/time_helper.h
index cacd79b..af1f634 100644
--- a/target/riscv/time_helper.h
+++ b/target/riscv/time_helper.h
@@ -25,6 +25,7 @@
void riscv_timer_write_timecmp(CPURISCVState *env, QEMUTimer *timer,
uint64_t timecmp, uint64_t delta,
uint32_t timer_irq);
+void riscv_timer_stce_changed(CPURISCVState *env, bool is_m_mode, bool enable);
void riscv_timer_init(RISCVCPU *cpu);
#endif
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index d7a6de0..9ddef2d 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -1217,13 +1217,35 @@ const RISCVDecoder decoder_table[] = {
const size_t decoder_table_size = ARRAY_SIZE(decoder_table);
-static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
+static void decode_opc(CPURISCVState *env, DisasContext *ctx)
{
+ uint32_t opcode;
+ bool pc_is_4byte_align = ((ctx->base.pc_next % 4) == 0);
+
ctx->virt_inst_excp = false;
- ctx->cur_insn_len = insn_len(opcode);
+ if (pc_is_4byte_align) {
+ /*
+ * Load 4 bytes at once to make instruction fetch atomically.
+ *
+ * Note: When pc is 4-byte aligned, 4-byte instruction wouldn't be
+ * across pages. We could preload 4 bytes instruction no matter
+ * real one is 2 or 4 bytes. Instruction preload wouldn't trigger
+ * additional page fault.
+ */
+ opcode = translator_ldl(env, &ctx->base, ctx->base.pc_next);
+ } else {
+ /*
+ * For unaligned pc, instruction preload may trigger additional
+ * page fault so we only load 2 bytes here.
+ */
+ opcode = (uint32_t) translator_lduw(env, &ctx->base, ctx->base.pc_next);
+ }
+ ctx->ol = ctx->xl;
+
+ ctx->cur_insn_len = insn_len((uint16_t)opcode);
/* Check for compressed insn */
if (ctx->cur_insn_len == 2) {
- ctx->opcode = opcode;
+ ctx->opcode = (uint16_t)opcode;
/*
* The Zca extension is added as way to refer to instructions in the C
* extension that do not include the floating-point loads and stores
@@ -1233,15 +1255,17 @@ static void decode_opc(CPURISCVState *env, DisasContext *ctx, uint16_t opcode)
return;
}
} else {
- uint32_t opcode32 = opcode;
- opcode32 = deposit32(opcode32, 16, 16,
- translator_lduw(env, &ctx->base,
- ctx->base.pc_next + 2));
- ctx->opcode = opcode32;
+ if (!pc_is_4byte_align) {
+ /* Load last 2 bytes of instruction here */
+ opcode = deposit32(opcode, 16, 16,
+ translator_lduw(env, &ctx->base,
+ ctx->base.pc_next + 2));
+ }
+ ctx->opcode = opcode;
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)) {
+ if (func(ctx, opcode)) {
return;
}
}
@@ -1319,10 +1343,8 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
{
DisasContext *ctx = container_of(dcbase, DisasContext, base);
CPURISCVState *env = cpu_env(cpu);
- uint16_t opcode16 = translator_lduw(env, &ctx->base, ctx->base.pc_next);
- ctx->ol = ctx->xl;
- decode_opc(env, ctx, opcode16);
+ decode_opc(env, ctx);
ctx->base.pc_next += ctx->cur_insn_len;
/*
diff --git a/target/riscv/vector_helper.c b/target/riscv/vector_helper.c
index 5dc1c10..b41c29d 100644
--- a/target/riscv/vector_helper.c
+++ b/target/riscv/vector_helper.c
@@ -35,7 +35,7 @@
#include <math.h>
target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
- target_ulong s2)
+ target_ulong s2, target_ulong x0)
{
int vlmax, vl;
RISCVCPU *cpu = env_archcpu(env);
@@ -83,6 +83,16 @@ target_ulong HELPER(vsetvl)(CPURISCVState *env, target_ulong s1,
} else {
vl = vlmax;
}
+
+ if (cpu->cfg.rvv_vsetvl_x0_vill && x0 && (env->vl != vl)) {
+ /* only set vill bit. */
+ env->vill = 1;
+ env->vtype = 0;
+ env->vl = 0;
+ env->vstart = 0;
+ return 0;
+ }
+
env->vl = vl;
env->vtype = s2;
env->vstart = 0;