aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2021-10-29 10:59:09 -0700
committerRichard Henderson <richard.henderson@linaro.org>2021-10-29 10:59:09 -0700
commit6450ce5634a57e57ee8bb790c080fc7636678f3d (patch)
tree24f52476f9f0bdacc83646f4e3aefe3f230f1807
parenta92cecba2791cd408d2bca04ce181dc2abaf9695 (diff)
parent15161e425ee1bb1180f9cec574cda44fb10c0931 (diff)
downloadqemu-6450ce5634a57e57ee8bb790c080fc7636678f3d.zip
qemu-6450ce5634a57e57ee8bb790c080fc7636678f3d.tar.gz
qemu-6450ce5634a57e57ee8bb790c080fc7636678f3d.tar.bz2
Merge remote-tracking branch 'remotes/alistair23/tags/pull-riscv-to-apply-20211029-1' into staging
Fifth RISC-V PR for QEMU 6.2 - Use a shared PLIC config helper function - Fixup the OpenTitan PLIC configuration - Add support for the experimental J extension - Update the fmin/fmax handling - Fixup VS interrupt forwarding # gpg: Signature made Fri 29 Oct 2021 12:03:47 AM PDT # gpg: using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054 # gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [full] * remotes/alistair23/tags/pull-riscv-to-apply-20211029-1: target/riscv: change the api for RVF/RVD fmin/fmax softfloat: add APIs to handle alternative sNaN propagation for fmax/fmin target/riscv: remove force HS exception target/riscv: fix VS interrupts forwarding to HS target/riscv: Allow experimental J-ext to be turned on target/riscv: Implement address masking functions required for RISC-V Pointer Masking extension target/riscv: Support pointer masking for RISC-V for i/c/f/d/a types of instructions target/riscv: Print new PM CSRs in QEMU logs target/riscv: Add J extension state description target/riscv: Support CSRs required for RISC-V PM extension except for the h-mode target/riscv: Add CSR defines for RISC-V PM extension target/riscv: Add J-extension into RISC-V hw/riscv: opentitan: Fixup the PLIC context addresses hw/riscv: virt: Use the PLIC config helper function hw/riscv: microchip_pfsoc: Use the PLIC config helper function hw/riscv: sifive_u: Use the PLIC config helper function hw/riscv: boot: Add a PLIC config string function hw/riscv: virt: Don't use a macro for the PLIC configuration Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
-rw-r--r--fpu/softfloat-parts.c.inc25
-rw-r--r--fpu/softfloat.c19
-rw-r--r--hw/riscv/boot.c25
-rw-r--r--hw/riscv/microchip_pfsoc.c14
-rw-r--r--hw/riscv/opentitan.c4
-rw-r--r--hw/riscv/sifive_u.c14
-rw-r--r--hw/riscv/virt.c20
-rw-r--r--include/fpu/softfloat.h10
-rw-r--r--include/hw/riscv/boot.h2
-rw-r--r--include/hw/riscv/microchip_pfsoc.h1
-rw-r--r--include/hw/riscv/sifive_u.h1
-rw-r--r--include/hw/riscv/virt.h1
-rw-r--r--target/riscv/cpu.c13
-rw-r--r--target/riscv/cpu.h17
-rw-r--r--target/riscv/cpu_bits.h102
-rw-r--r--target/riscv/cpu_helper.c72
-rw-r--r--target/riscv/csr.c285
-rw-r--r--target/riscv/fpu_helper.c16
-rw-r--r--target/riscv/insn_trans/trans_rva.c.inc3
-rw-r--r--target/riscv/insn_trans/trans_rvd.c.inc2
-rw-r--r--target/riscv/insn_trans/trans_rvf.c.inc2
-rw-r--r--target/riscv/insn_trans/trans_rvi.c.inc2
-rw-r--r--target/riscv/machine.c27
-rw-r--r--target/riscv/translate.c43
24 files changed, 605 insertions, 115 deletions
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
index dddee92..41d4b17 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -1219,14 +1219,35 @@ static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b,
if (unlikely(ab_mask & float_cmask_anynan)) {
/*
- * For minnum/maxnum, if one operand is a QNaN, and the other
+ * For minNum/maxNum (IEEE 754-2008)
+ * or minimumNumber/maximumNumber (IEEE 754-2019),
+ * if one operand is a QNaN, and the other
* operand is numerical, then return numerical argument.
*/
- if ((flags & minmax_isnum)
+ if ((flags & (minmax_isnum | minmax_isnumber))
&& !(ab_mask & float_cmask_snan)
&& (ab_mask & ~float_cmask_qnan)) {
return is_nan(a->cls) ? b : a;
}
+
+ /*
+ * In IEEE 754-2019, minNum, maxNum, minNumMag and maxNumMag
+ * are removed and replaced with minimum, minimumNumber, maximum
+ * and maximumNumber.
+ * minimumNumber/maximumNumber behavior for SNaN is changed to:
+ * If both operands are NaNs, a QNaN is returned.
+ * If either operand is a SNaN,
+ * an invalid operation exception is signaled,
+ * but unless both operands are NaNs,
+ * the SNaN is otherwise ignored and not converted to a QNaN.
+ */
+ if ((flags & minmax_isnumber)
+ && (ab_mask & float_cmask_snan)
+ && (ab_mask & ~float_cmask_anynan)) {
+ float_raise(float_flag_invalid, s);
+ return is_nan(a->cls) ? b : a;
+ }
+
return parts_pick_nan(a, b, s);
}
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 6e769f9..9a28720 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -436,6 +436,11 @@ enum {
minmax_isnum = 2,
/* Set for the IEEE 754-2008 minNumMag() and minNumMag() operations. */
minmax_ismag = 4,
+ /*
+ * Set for the IEEE 754-2019 minimumNumber() and maximumNumber()
+ * operations.
+ */
+ minmax_isnumber = 8,
};
/* Simple helpers for checking if, or what kind of, NaN we have */
@@ -3927,12 +3932,14 @@ static float128 float128_minmax(float128 a, float128 b,
{ return type##_minmax(a, b, s, flags); }
#define MINMAX_2(type) \
- MINMAX_1(type, max, 0) \
- MINMAX_1(type, maxnum, minmax_isnum) \
- MINMAX_1(type, maxnummag, minmax_isnum | minmax_ismag) \
- MINMAX_1(type, min, minmax_ismin) \
- MINMAX_1(type, minnum, minmax_ismin | minmax_isnum) \
- MINMAX_1(type, minnummag, minmax_ismin | minmax_isnum | minmax_ismag)
+ MINMAX_1(type, max, 0) \
+ MINMAX_1(type, maxnum, minmax_isnum) \
+ MINMAX_1(type, maxnummag, minmax_isnum | minmax_ismag) \
+ MINMAX_1(type, maximum_number, minmax_isnumber) \
+ MINMAX_1(type, min, minmax_ismin) \
+ MINMAX_1(type, minnum, minmax_ismin | minmax_isnum) \
+ MINMAX_1(type, minnummag, minmax_ismin | minmax_isnum | minmax_ismag) \
+ MINMAX_1(type, minimum_number, minmax_ismin | minmax_isnumber) \
MINMAX_2(float16)
MINMAX_2(bfloat16)
diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c
index d1ffc7b..519fa45 100644
--- a/hw/riscv/boot.c
+++ b/hw/riscv/boot.c
@@ -38,6 +38,31 @@ bool riscv_is_32bit(RISCVHartArrayState *harts)
return harts->harts[0].env.misa_mxl_max == MXL_RV32;
}
+/*
+ * Return the per-socket PLIC hart topology configuration string
+ * (caller must free with g_free())
+ */
+char *riscv_plic_hart_config_string(int hart_count)
+{
+ g_autofree const char **vals = g_new(const char *, hart_count + 1);
+ int i;
+
+ for (i = 0; i < hart_count; i++) {
+ CPUState *cs = qemu_get_cpu(i);
+ CPURISCVState *env = &RISCV_CPU(cs)->env;
+
+ if (riscv_has_ext(env, RVS)) {
+ vals[i] = "MS";
+ } else {
+ vals[i] = "M";
+ }
+ }
+ vals[i] = NULL;
+
+ /* g_strjoinv() obliges us to cast away const here */
+ return g_strjoinv(",", (char **)vals);
+}
+
target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts,
target_ulong firmware_end_addr) {
if (riscv_is_32bit(harts)) {
diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c
index 3fc8545..57d779f 100644
--- a/hw/riscv/microchip_pfsoc.c
+++ b/hw/riscv/microchip_pfsoc.c
@@ -187,7 +187,6 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
MemoryRegion *envm_data = g_new(MemoryRegion, 1);
MemoryRegion *qspi_xip_mem = g_new(MemoryRegion, 1);
char *plic_hart_config;
- size_t plic_hart_config_len;
NICInfo *nd;
int i;
@@ -262,18 +261,7 @@ static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
l2lim_mem);
/* create PLIC hart topology configuration string */
- plic_hart_config_len = (strlen(MICROCHIP_PFSOC_PLIC_HART_CONFIG) + 1) *
- ms->smp.cpus;
- plic_hart_config = g_malloc0(plic_hart_config_len);
- for (i = 0; i < ms->smp.cpus; i++) {
- if (i != 0) {
- strncat(plic_hart_config, "," MICROCHIP_PFSOC_PLIC_HART_CONFIG,
- plic_hart_config_len);
- } else {
- strncat(plic_hart_config, "M", plic_hart_config_len);
- }
- plic_hart_config_len -= (strlen(MICROCHIP_PFSOC_PLIC_HART_CONFIG) + 1);
- }
+ plic_hart_config = riscv_plic_hart_config_string(ms->smp.cpus);
/* PLIC */
s->plic = sifive_plic_create(memmap[MICROCHIP_PFSOC_PLIC].base,
diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c
index 83e1511..c531450 100644
--- a/hw/riscv/opentitan.c
+++ b/hw/riscv/opentitan.c
@@ -161,8 +161,8 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
qdev_prop_set_uint32(DEVICE(&s->plic), "pending-base", 0x1000);
qdev_prop_set_uint32(DEVICE(&s->plic), "enable-base", 0x2000);
qdev_prop_set_uint32(DEVICE(&s->plic), "enable-stride", 0x18);
- qdev_prop_set_uint32(DEVICE(&s->plic), "context-base", 0x200004);
- qdev_prop_set_uint32(DEVICE(&s->plic), "context-stride", 4);
+ qdev_prop_set_uint32(DEVICE(&s->plic), "context-base", 0x200000);
+ qdev_prop_set_uint32(DEVICE(&s->plic), "context-stride", 8);
qdev_prop_set_uint32(DEVICE(&s->plic), "aperture-size", memmap[IBEX_DEV_PLIC].size);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->plic), errp)) {
diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c
index 0217006..589ae72 100644
--- a/hw/riscv/sifive_u.c
+++ b/hw/riscv/sifive_u.c
@@ -811,7 +811,6 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1);
char *plic_hart_config;
- size_t plic_hart_config_len;
int i, j;
NICInfo *nd = &nd_table[0];
@@ -852,18 +851,7 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
l2lim_mem);
/* create PLIC hart topology configuration string */
- plic_hart_config_len = (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1) *
- ms->smp.cpus;
- plic_hart_config = g_malloc0(plic_hart_config_len);
- for (i = 0; i < ms->smp.cpus; i++) {
- if (i != 0) {
- strncat(plic_hart_config, "," SIFIVE_U_PLIC_HART_CONFIG,
- plic_hart_config_len);
- } else {
- strncat(plic_hart_config, "M", plic_hart_config_len);
- }
- plic_hart_config_len -= (strlen(SIFIVE_U_PLIC_HART_CONFIG) + 1);
- }
+ plic_hart_config = riscv_plic_hart_config_string(ms->smp.cpus);
/* MMIO */
s->plic = sifive_plic_create(memmap[SIFIVE_U_DEV_PLIC].base,
diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index b3b431c..3af0741 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -748,24 +748,6 @@ static FWCfgState *create_fw_cfg(const MachineState *mc)
return fw_cfg;
}
-/*
- * Return the per-socket PLIC hart topology configuration string
- * (caller must free with g_free())
- */
-static char *plic_hart_config_string(int hart_count)
-{
- g_autofree const char **vals = g_new(const char *, hart_count + 1);
- int i;
-
- for (i = 0; i < hart_count; i++) {
- vals[i] = VIRT_PLIC_HART_CONFIG;
- }
- vals[i] = NULL;
-
- /* g_strjoinv() obliges us to cast away const here */
- return g_strjoinv(",", (char **)vals);
-}
-
static void virt_machine_init(MachineState *machine)
{
const MemMapEntry *memmap = virt_memmap;
@@ -839,7 +821,7 @@ static void virt_machine_init(MachineState *machine)
}
/* Per-socket PLIC hart topology configuration string */
- plic_hart_config = plic_hart_config_string(hart_count);
+ plic_hart_config = riscv_plic_hart_config_string(hart_count);
/* Per-socket PLIC */
s->plic[i] = sifive_plic_create(
diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h
index ec7dca0..a249991 100644
--- a/include/fpu/softfloat.h
+++ b/include/fpu/softfloat.h
@@ -243,6 +243,8 @@ float16 float16_minnum(float16, float16, float_status *status);
float16 float16_maxnum(float16, float16, float_status *status);
float16 float16_minnummag(float16, float16, float_status *status);
float16 float16_maxnummag(float16, float16, float_status *status);
+float16 float16_minimum_number(float16, float16, float_status *status);
+float16 float16_maximum_number(float16, float16, float_status *status);
float16 float16_sqrt(float16, float_status *status);
FloatRelation float16_compare(float16, float16, float_status *status);
FloatRelation float16_compare_quiet(float16, float16, float_status *status);
@@ -422,6 +424,8 @@ bfloat16 bfloat16_minnum(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_maxnum(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_minnummag(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_maxnummag(bfloat16, bfloat16, float_status *status);
+bfloat16 bfloat16_minimum_number(bfloat16, bfloat16, float_status *status);
+bfloat16 bfloat16_maximum_number(bfloat16, bfloat16, float_status *status);
bfloat16 bfloat16_sqrt(bfloat16, float_status *status);
FloatRelation bfloat16_compare(bfloat16, bfloat16, float_status *status);
FloatRelation bfloat16_compare_quiet(bfloat16, bfloat16, float_status *status);
@@ -589,6 +593,8 @@ float32 float32_minnum(float32, float32, float_status *status);
float32 float32_maxnum(float32, float32, float_status *status);
float32 float32_minnummag(float32, float32, float_status *status);
float32 float32_maxnummag(float32, float32, float_status *status);
+float32 float32_minimum_number(float32, float32, float_status *status);
+float32 float32_maximum_number(float32, float32, float_status *status);
bool float32_is_quiet_nan(float32, float_status *status);
bool float32_is_signaling_nan(float32, float_status *status);
float32 float32_silence_nan(float32, float_status *status);
@@ -778,6 +784,8 @@ float64 float64_minnum(float64, float64, float_status *status);
float64 float64_maxnum(float64, float64, float_status *status);
float64 float64_minnummag(float64, float64, float_status *status);
float64 float64_maxnummag(float64, float64, float_status *status);
+float64 float64_minimum_number(float64, float64, float_status *status);
+float64 float64_maximum_number(float64, float64, float_status *status);
bool float64_is_quiet_nan(float64 a, float_status *status);
bool float64_is_signaling_nan(float64, float_status *status);
float64 float64_silence_nan(float64, float_status *status);
@@ -1210,6 +1218,8 @@ float128 float128_minnum(float128, float128, float_status *status);
float128 float128_maxnum(float128, float128, float_status *status);
float128 float128_minnummag(float128, float128, float_status *status);
float128 float128_maxnummag(float128, float128, float_status *status);
+float128 float128_minimum_number(float128, float128, float_status *status);
+float128 float128_maximum_number(float128, float128, float_status *status);
bool float128_is_quiet_nan(float128, float_status *status);
bool float128_is_signaling_nan(float128, float_status *status);
float128 float128_silence_nan(float128, float_status *status);
diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h
index 0e89400..baff11d 100644
--- a/include/hw/riscv/boot.h
+++ b/include/hw/riscv/boot.h
@@ -31,6 +31,8 @@
bool riscv_is_32bit(RISCVHartArrayState *harts);
+char *riscv_plic_hart_config_string(int hart_count);
+
target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts,
target_ulong firmware_end_addr);
target_ulong riscv_find_and_load_firmware(MachineState *machine,
diff --git a/include/hw/riscv/microchip_pfsoc.h b/include/hw/riscv/microchip_pfsoc.h
index d30916f..a0673f5 100644
--- a/include/hw/riscv/microchip_pfsoc.h
+++ b/include/hw/riscv/microchip_pfsoc.h
@@ -138,7 +138,6 @@ enum {
#define MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT 1
#define MICROCHIP_PFSOC_COMPUTE_CPU_COUNT 4
-#define MICROCHIP_PFSOC_PLIC_HART_CONFIG "MS"
#define MICROCHIP_PFSOC_PLIC_NUM_SOURCES 185
#define MICROCHIP_PFSOC_PLIC_NUM_PRIORITIES 7
#define MICROCHIP_PFSOC_PLIC_PRIORITY_BASE 0x04
diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h
index f71c90c..8f63a18 100644
--- a/include/hw/riscv/sifive_u.h
+++ b/include/hw/riscv/sifive_u.h
@@ -156,7 +156,6 @@ enum {
#define SIFIVE_U_MANAGEMENT_CPU_COUNT 1
#define SIFIVE_U_COMPUTE_CPU_COUNT 4
-#define SIFIVE_U_PLIC_HART_CONFIG "MS"
#define SIFIVE_U_PLIC_NUM_SOURCES 54
#define SIFIVE_U_PLIC_NUM_PRIORITIES 7
#define SIFIVE_U_PLIC_PRIORITY_BASE 0x04
diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h
index d9105c1..b8ef99f 100644
--- a/include/hw/riscv/virt.h
+++ b/include/hw/riscv/virt.h
@@ -73,7 +73,6 @@ enum {
VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */
};
-#define VIRT_PLIC_HART_CONFIG "MS"
#define VIRT_PLIC_NUM_SOURCES 127
#define VIRT_PLIC_NUM_PRIORITIES 7
#define VIRT_PLIC_PRIORITY_BASE 0x04
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 788fa0b..7d53125 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -271,6 +271,13 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
CSR_MSCRATCH,
CSR_SSCRATCH,
CSR_SATP,
+ CSR_MMTE,
+ CSR_UPMBASE,
+ CSR_UPMMASK,
+ CSR_SPMBASE,
+ CSR_SPMMASK,
+ CSR_MPMBASE,
+ CSR_MPMMASK,
};
for (int i = 0; i < ARRAY_SIZE(dump_csrs); ++i) {
@@ -367,6 +374,8 @@ static void riscv_cpu_reset(DeviceState *dev)
env->mcause = 0;
env->pc = env->resetvec;
env->two_stage_lookup = false;
+ /* mmte is supposed to have pm.current hardwired to 1 */
+ env->mmte |= (PM_EXT_INITIAL | MMTE_M_PM_CURRENT);
#endif
cs->exception_index = RISCV_EXCP_NONE;
env->load_res = -1;
@@ -553,6 +562,9 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
}
set_vext_version(env, vext_version);
}
+ if (cpu->cfg.ext_j) {
+ ext |= RVJ;
+ }
set_misa(env, env->misa_mxl, ext);
}
@@ -628,6 +640,7 @@ static Property riscv_cpu_properties[] = {
DEFINE_PROP_BOOL("x-zbc", RISCVCPU, cfg.ext_zbc, false),
DEFINE_PROP_BOOL("x-zbs", RISCVCPU, cfg.ext_zbs, false),
DEFINE_PROP_BOOL("x-h", RISCVCPU, cfg.ext_h, false),
+ DEFINE_PROP_BOOL("x-j", RISCVCPU, cfg.ext_j, false),
DEFINE_PROP_BOOL("x-v", RISCVCPU, cfg.ext_v, false),
DEFINE_PROP_STRING("vext_spec", RISCVCPU, cfg.vext_spec),
DEFINE_PROP_UINT16("vlen", RISCVCPU, cfg.vlen, 128),
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index a33dc30..0760c0a 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -65,6 +65,7 @@
#define RVS RV('S')
#define RVU RV('U')
#define RVH RV('H')
+#define RVJ RV('J')
/* S extension denotes that Supervisor mode exists, however it is possible
to have a core that support S mode but does not have an MMU and there
@@ -237,6 +238,17 @@ struct CPURISCVState {
/* True if in debugger mode. */
bool debugger;
+
+ /*
+ * CSRs for PointerMasking extension
+ */
+ target_ulong mmte;
+ target_ulong mpmmask;
+ target_ulong mpmbase;
+ target_ulong spmmask;
+ target_ulong spmbase;
+ target_ulong upmmask;
+ target_ulong upmbase;
#endif
float_status fp_status;
@@ -291,6 +303,7 @@ struct RISCVCPU {
bool ext_s;
bool ext_u;
bool ext_h;
+ bool ext_j;
bool ext_v;
bool ext_zba;
bool ext_zbb;
@@ -339,8 +352,6 @@ int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
bool riscv_cpu_fp_enabled(CPURISCVState *env);
bool riscv_cpu_virt_enabled(CPURISCVState *env);
void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable);
-bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env);
-void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable);
bool riscv_cpu_two_stage_lookup(int mmu_idx);
int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch);
hwaddr riscv_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr);
@@ -397,6 +408,8 @@ FIELD(TB_FLAGS, HLSX, 10, 1)
FIELD(TB_FLAGS, MSTATUS_HS_FS, 11, 2)
/* The combination of MXL/SXL/UXL that applies to the current cpu mode. */
FIELD(TB_FLAGS, XL, 13, 2)
+/* If PointerMasking should be applied */
+FIELD(TB_FLAGS, PM_ENABLED, 15, 1)
#ifdef TARGET_RISCV32
#define riscv_cpu_mxl(env) ((void)(env), MXL_RV32)
diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index cffcd3a..9913fa9 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -334,6 +334,38 @@
#define CSR_MHPMCOUNTER30H 0xb9e
#define CSR_MHPMCOUNTER31H 0xb9f
+/*
+ * User PointerMasking registers
+ * NB: actual CSR numbers might be changed in future
+ */
+#define CSR_UMTE 0x4c0
+#define CSR_UPMMASK 0x4c1
+#define CSR_UPMBASE 0x4c2
+
+/*
+ * Machine PointerMasking registers
+ * NB: actual CSR numbers might be changed in future
+ */
+#define CSR_MMTE 0x3c0
+#define CSR_MPMMASK 0x3c1
+#define CSR_MPMBASE 0x3c2
+
+/*
+ * Supervisor PointerMaster registers
+ * NB: actual CSR numbers might be changed in future
+ */
+#define CSR_SMTE 0x1c0
+#define CSR_SPMMASK 0x1c1
+#define CSR_SPMBASE 0x1c2
+
+/*
+ * Hypervisor PointerMaster registers
+ * NB: actual CSR numbers might be changed in future
+ */
+#define CSR_VSMTE 0x2c0
+#define CSR_VSPMMASK 0x2c1
+#define CSR_VSPMBASE 0x2c2
+
/* mstatus CSR bits */
#define MSTATUS_UIE 0x00000001
#define MSTATUS_SIE 0x00000002
@@ -412,12 +444,6 @@ typedef enum {
/* Virtulisation Register Fields */
#define VIRT_ONOFF 1
-/* This is used to save state for when we take an exception. If this is set
- * that means that we want to force a HS level exception (no matter what the
- * delegation is set to). This will occur for things such as a second level
- * page table fault.
- */
-#define FORCE_HS_EXCEP 2
/* RV32 satp CSR field masks */
#define SATP32_MODE 0x80000000
@@ -525,4 +551,68 @@ typedef enum RISCVException {
#define MIE_UTIE (1 << IRQ_U_TIMER)
#define MIE_SSIE (1 << IRQ_S_SOFT)
#define MIE_USIE (1 << IRQ_U_SOFT)
+
+/* General PointerMasking CSR bits*/
+#define PM_ENABLE 0x00000001ULL
+#define PM_CURRENT 0x00000002ULL
+#define PM_INSN 0x00000004ULL
+#define PM_XS_MASK 0x00000003ULL
+
+/* PointerMasking XS bits values */
+#define PM_EXT_DISABLE 0x00000000ULL
+#define PM_EXT_INITIAL 0x00000001ULL
+#define PM_EXT_CLEAN 0x00000002ULL
+#define PM_EXT_DIRTY 0x00000003ULL
+
+/* Offsets for every pair of control bits per each priv level */
+#define XS_OFFSET 0ULL
+#define U_OFFSET 2ULL
+#define S_OFFSET 5ULL
+#define M_OFFSET 8ULL
+
+#define PM_XS_BITS (PM_XS_MASK << XS_OFFSET)
+#define U_PM_ENABLE (PM_ENABLE << U_OFFSET)
+#define U_PM_CURRENT (PM_CURRENT << U_OFFSET)
+#define U_PM_INSN (PM_INSN << U_OFFSET)
+#define S_PM_ENABLE (PM_ENABLE << S_OFFSET)
+#define S_PM_CURRENT (PM_CURRENT << S_OFFSET)
+#define S_PM_INSN (PM_INSN << S_OFFSET)
+#define M_PM_ENABLE (PM_ENABLE << M_OFFSET)
+#define M_PM_CURRENT (PM_CURRENT << M_OFFSET)
+#define M_PM_INSN (PM_INSN << M_OFFSET)
+
+/* mmte CSR bits */
+#define MMTE_PM_XS_BITS PM_XS_BITS
+#define MMTE_U_PM_ENABLE U_PM_ENABLE
+#define MMTE_U_PM_CURRENT U_PM_CURRENT
+#define MMTE_U_PM_INSN U_PM_INSN
+#define MMTE_S_PM_ENABLE S_PM_ENABLE
+#define MMTE_S_PM_CURRENT S_PM_CURRENT
+#define MMTE_S_PM_INSN S_PM_INSN
+#define MMTE_M_PM_ENABLE M_PM_ENABLE
+#define MMTE_M_PM_CURRENT M_PM_CURRENT
+#define MMTE_M_PM_INSN M_PM_INSN
+#define MMTE_MASK (MMTE_U_PM_ENABLE | MMTE_U_PM_CURRENT | MMTE_U_PM_INSN | \
+ MMTE_S_PM_ENABLE | MMTE_S_PM_CURRENT | MMTE_S_PM_INSN | \
+ MMTE_M_PM_ENABLE | MMTE_M_PM_CURRENT | MMTE_M_PM_INSN | \
+ MMTE_PM_XS_BITS)
+
+/* (v)smte CSR bits */
+#define SMTE_PM_XS_BITS PM_XS_BITS
+#define SMTE_U_PM_ENABLE U_PM_ENABLE
+#define SMTE_U_PM_CURRENT U_PM_CURRENT
+#define SMTE_U_PM_INSN U_PM_INSN
+#define SMTE_S_PM_ENABLE S_PM_ENABLE
+#define SMTE_S_PM_CURRENT S_PM_CURRENT
+#define SMTE_S_PM_INSN S_PM_INSN
+#define SMTE_MASK (SMTE_U_PM_ENABLE | SMTE_U_PM_CURRENT | SMTE_U_PM_INSN | \
+ SMTE_S_PM_ENABLE | SMTE_S_PM_CURRENT | SMTE_S_PM_INSN | \
+ SMTE_PM_XS_BITS)
+
+/* umte CSR bits */
+#define UMTE_U_PM_ENABLE U_PM_ENABLE
+#define UMTE_U_PM_CURRENT U_PM_CURRENT
+#define UMTE_U_PM_INSN U_PM_INSN
+#define UMTE_MASK (UMTE_U_PM_ENABLE | MMTE_U_PM_CURRENT | UMTE_U_PM_INSN)
+
#endif
diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
index 0d1132f..f30ff67 100644
--- a/target/riscv/cpu_helper.c
+++ b/target/riscv/cpu_helper.c
@@ -107,6 +107,24 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
flags = FIELD_DP32(flags, TB_FLAGS, MSTATUS_HS_FS,
get_field(env->mstatus_hs, MSTATUS_FS));
}
+ if (riscv_has_ext(env, RVJ)) {
+ int priv = flags & TB_FLAGS_PRIV_MMU_MASK;
+ bool pm_enabled = false;
+ switch (priv) {
+ case PRV_U:
+ pm_enabled = env->mmte & U_PM_ENABLE;
+ break;
+ case PRV_S:
+ pm_enabled = env->mmte & S_PM_ENABLE;
+ break;
+ case PRV_M:
+ pm_enabled = env->mmte & M_PM_ENABLE;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ flags = FIELD_DP32(flags, TB_FLAGS, PM_ENABLED, pm_enabled);
+ }
#endif
flags = FIELD_DP32(flags, TB_FLAGS, XL, cpu_get_xl(env));
@@ -117,36 +135,24 @@ void cpu_get_tb_cpu_state(CPURISCVState *env, target_ulong *pc,
#ifndef CONFIG_USER_ONLY
static int riscv_cpu_local_irq_pending(CPURISCVState *env)
{
- target_ulong irqs;
+ target_ulong virt_enabled = riscv_cpu_virt_enabled(env);
target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
- target_ulong hs_mstatus_sie = get_field(env->mstatus_hs, MSTATUS_SIE);
- target_ulong pending = env->mip & env->mie &
- ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
- target_ulong vspending = (env->mip & env->mie &
- (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
+ target_ulong pending = env->mip & env->mie;
target_ulong mie = env->priv < PRV_M ||
(env->priv == PRV_M && mstatus_mie);
target_ulong sie = env->priv < PRV_S ||
(env->priv == PRV_S && mstatus_sie);
- target_ulong hs_sie = env->priv < PRV_S ||
- (env->priv == PRV_S && hs_mstatus_sie);
-
- if (riscv_cpu_virt_enabled(env)) {
- target_ulong pending_hs_irq = pending & -hs_sie;
-
- if (pending_hs_irq) {
- riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
- return ctz64(pending_hs_irq);
- }
-
- pending = vspending;
- }
+ target_ulong hsie = virt_enabled || sie;
+ target_ulong vsie = virt_enabled && sie;
- irqs = (pending & ~env->mideleg & -mie) | (pending & env->mideleg & -sie);
+ target_ulong irqs =
+ (pending & ~env->mideleg & -mie) |
+ (pending & env->mideleg & ~env->hideleg & -hsie) |
+ (pending & env->mideleg & env->hideleg & -vsie);
if (irqs) {
return ctz64(irqs); /* since non-zero */
@@ -264,24 +270,6 @@ void riscv_cpu_set_virt_enabled(CPURISCVState *env, bool enable)
env->virt = set_field(env->virt, VIRT_ONOFF, enable);
}
-bool riscv_cpu_force_hs_excep_enabled(CPURISCVState *env)
-{
- if (!riscv_has_ext(env, RVH)) {
- return false;
- }
-
- return get_field(env->virt, FORCE_HS_EXCEP);
-}
-
-void riscv_cpu_set_force_hs_excep(CPURISCVState *env, bool enable)
-{
- if (!riscv_has_ext(env, RVH)) {
- return;
- }
-
- env->virt = set_field(env->virt, FORCE_HS_EXCEP, enable);
-}
-
bool riscv_cpu_two_stage_lookup(int mmu_idx)
{
return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
@@ -998,7 +986,6 @@ void riscv_cpu_do_interrupt(CPUState *cs)
RISCVCPU *cpu = RISCV_CPU(cs);
CPURISCVState *env = &cpu->env;
- bool force_hs_execp = riscv_cpu_force_hs_excep_enabled(env);
uint64_t s;
/* cs->exception is 32-bits wide unlike mcause which is XLEN-bits wide
@@ -1027,8 +1014,6 @@ void riscv_cpu_do_interrupt(CPUState *cs)
case RISCV_EXCP_INST_GUEST_PAGE_FAULT:
case RISCV_EXCP_LOAD_GUEST_ACCESS_FAULT:
case RISCV_EXCP_STORE_GUEST_AMO_ACCESS_FAULT:
- force_hs_execp = true;
- /* fallthrough */
case RISCV_EXCP_INST_ADDR_MIS:
case RISCV_EXCP_INST_ACCESS_FAULT:
case RISCV_EXCP_LOAD_ADDR_MIS:
@@ -1087,8 +1072,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
env->hstatus = set_field(env->hstatus, HSTATUS_GVA, 0);
}
- if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1) &&
- !force_hs_execp) {
+ if (riscv_cpu_virt_enabled(env) && ((hdeleg >> cause) & 1)) {
/* Trap to VS mode */
/*
* See if we need to adjust cause. Yes if its VS mode interrupt
@@ -1110,7 +1094,6 @@ void riscv_cpu_do_interrupt(CPUState *cs)
htval = env->guest_phys_fault_addr;
riscv_cpu_set_virt_enabled(env, 0);
- riscv_cpu_set_force_hs_excep(env, 0);
} else {
/* Trap into HS mode */
env->hstatus = set_field(env->hstatus, HSTATUS_SPV, false);
@@ -1146,7 +1129,6 @@ void riscv_cpu_do_interrupt(CPUState *cs)
/* Trapping to M mode, virt is disabled */
riscv_cpu_set_virt_enabled(env, 0);
- riscv_cpu_set_force_hs_excep(env, 0);
}
s = env->mstatus;
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 69e4d65..9f41954 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -192,6 +192,16 @@ static RISCVException hmode32(CPURISCVState *env, int csrno)
}
+/* Checks if PointerMasking registers could be accessed */
+static RISCVException pointer_masking(CPURISCVState *env, int csrno)
+{
+ /* Check if j-ext is present */
+ if (riscv_has_ext(env, RVJ)) {
+ return RISCV_EXCP_NONE;
+ }
+ return RISCV_EXCP_ILLEGAL_INST;
+}
+
static RISCVException pmp(CPURISCVState *env, int csrno)
{
if (riscv_feature(env, RISCV_FEATURE_PMP)) {
@@ -1425,6 +1435,268 @@ static RISCVException write_pmpaddr(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
+/*
+ * Functions to access Pointer Masking feature registers
+ * We have to check if current priv lvl could modify
+ * csr in given mode
+ */
+static bool check_pm_current_disabled(CPURISCVState *env, int csrno)
+{
+ int csr_priv = get_field(csrno, 0x300);
+ int pm_current;
+
+ /*
+ * If priv lvls differ that means we're accessing csr from higher priv lvl,
+ * so allow the access
+ */
+ if (env->priv != csr_priv) {
+ return false;
+ }
+ switch (env->priv) {
+ case PRV_M:
+ pm_current = get_field(env->mmte, M_PM_CURRENT);
+ break;
+ case PRV_S:
+ pm_current = get_field(env->mmte, S_PM_CURRENT);
+ break;
+ case PRV_U:
+ pm_current = get_field(env->mmte, U_PM_CURRENT);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ /* It's same priv lvl, so we allow to modify csr only if pm.current==1 */
+ return !pm_current;
+}
+
+static RISCVException read_mmte(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mmte & MMTE_MASK;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mmte(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+ target_ulong wpri_val = val & MMTE_MASK;
+
+ if (val != wpri_val) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n",
+ "MMTE: WPRI violation written 0x", val,
+ "vs expected 0x", wpri_val);
+ }
+ /* for machine mode pm.current is hardwired to 1 */
+ wpri_val |= MMTE_M_PM_CURRENT;
+
+ /* hardwiring pm.instruction bit to 0, since it's not supported yet */
+ wpri_val &= ~(MMTE_M_PM_INSN | MMTE_S_PM_INSN | MMTE_U_PM_INSN);
+ env->mmte = wpri_val | PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_smte(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mmte & SMTE_MASK;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_smte(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ target_ulong wpri_val = val & SMTE_MASK;
+
+ if (val != wpri_val) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n",
+ "SMTE: WPRI violation written 0x", val,
+ "vs expected 0x", wpri_val);
+ }
+
+ /* if pm.current==0 we can't modify current PM CSRs */
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ wpri_val |= (env->mmte & ~SMTE_MASK);
+ write_mmte(env, csrno, wpri_val);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_umte(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mmte & UMTE_MASK;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_umte(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ target_ulong wpri_val = val & UMTE_MASK;
+
+ if (val != wpri_val) {
+ qemu_log_mask(LOG_GUEST_ERROR, "%s" TARGET_FMT_lx " %s" TARGET_FMT_lx "\n",
+ "UMTE: WPRI violation written 0x", val,
+ "vs expected 0x", wpri_val);
+ }
+
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+
+ wpri_val |= (env->mmte & ~UMTE_MASK);
+ write_mmte(env, csrno, wpri_val);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mpmmask(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mpmmask;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mpmmask(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ env->mpmmask = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_spmmask(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->spmmask;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_spmmask(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ /* if pm.current==0 we can't modify current PM CSRs */
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+ env->spmmask = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_upmmask(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->upmmask;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_upmmask(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ /* if pm.current==0 we can't modify current PM CSRs */
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+ env->upmmask = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_mpmbase(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->mpmbase;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_mpmbase(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ env->mpmbase = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_spmbase(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->spmbase;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_spmbase(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ /* if pm.current==0 we can't modify current PM CSRs */
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+ env->spmbase = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException read_upmbase(CPURISCVState *env, int csrno,
+ target_ulong *val)
+{
+ *val = env->upmbase;
+ return RISCV_EXCP_NONE;
+}
+
+static RISCVException write_upmbase(CPURISCVState *env, int csrno,
+ target_ulong val)
+{
+ uint64_t mstatus;
+
+ /* if pm.current==0 we can't modify current PM CSRs */
+ if (check_pm_current_disabled(env, csrno)) {
+ return RISCV_EXCP_NONE;
+ }
+ env->upmbase = val;
+ env->mmte |= PM_EXT_DIRTY;
+
+ /* Set XS and SD bits, since PM CSRs are dirty */
+ mstatus = env->mstatus | MSTATUS_XS;
+ write_mstatus(env, csrno, mstatus);
+ return RISCV_EXCP_NONE;
+}
+
#endif
/*
@@ -1659,6 +1931,19 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_PMPADDR14] = { "pmpaddr14", pmp, read_pmpaddr, write_pmpaddr },
[CSR_PMPADDR15] = { "pmpaddr15", pmp, read_pmpaddr, write_pmpaddr },
+ /* User Pointer Masking */
+ [CSR_UMTE] = { "umte", pointer_masking, read_umte, write_umte },
+ [CSR_UPMMASK] = { "upmmask", pointer_masking, read_upmmask, write_upmmask },
+ [CSR_UPMBASE] = { "upmbase", pointer_masking, read_upmbase, write_upmbase },
+ /* Machine Pointer Masking */
+ [CSR_MMTE] = { "mmte", pointer_masking, read_mmte, write_mmte },
+ [CSR_MPMMASK] = { "mpmmask", pointer_masking, read_mpmmask, write_mpmmask },
+ [CSR_MPMBASE] = { "mpmbase", pointer_masking, read_mpmbase, write_mpmbase },
+ /* Supervisor Pointer Masking */
+ [CSR_SMTE] = { "smte", pointer_masking, read_smte, write_smte },
+ [CSR_SPMMASK] = { "spmmask", pointer_masking, read_spmmask, write_spmmask },
+ [CSR_SPMBASE] = { "spmbase", pointer_masking, read_spmbase, write_spmbase },
+
/* Performance Counters */
[CSR_HPMCOUNTER3] = { "hpmcounter3", ctr, read_zero },
[CSR_HPMCOUNTER4] = { "hpmcounter4", ctr, read_zero },
diff --git a/target/riscv/fpu_helper.c b/target/riscv/fpu_helper.c
index 8700516..d62f470 100644
--- a/target/riscv/fpu_helper.c
+++ b/target/riscv/fpu_helper.c
@@ -174,14 +174,18 @@ uint64_t helper_fmin_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
{
float32 frs1 = check_nanbox_s(rs1);
float32 frs2 = check_nanbox_s(rs2);
- return nanbox_s(float32_minnum(frs1, frs2, &env->fp_status));
+ return nanbox_s(env->priv_ver < PRIV_VERSION_1_11_0 ?
+ float32_minnum(frs1, frs2, &env->fp_status) :
+ float32_minimum_number(frs1, frs2, &env->fp_status));
}
uint64_t helper_fmax_s(CPURISCVState *env, uint64_t rs1, uint64_t rs2)
{
float32 frs1 = check_nanbox_s(rs1);
float32 frs2 = check_nanbox_s(rs2);
- return nanbox_s(float32_maxnum(frs1, frs2, &env->fp_status));
+ return nanbox_s(env->priv_ver < PRIV_VERSION_1_11_0 ?
+ float32_maxnum(frs1, frs2, &env->fp_status) :
+ float32_maximum_number(frs1, frs2, &env->fp_status));
}
uint64_t helper_fsqrt_s(CPURISCVState *env, uint64_t rs1)
@@ -283,12 +287,16 @@ uint64_t helper_fdiv_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
uint64_t helper_fmin_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
{
- return float64_minnum(frs1, frs2, &env->fp_status);
+ return env->priv_ver < PRIV_VERSION_1_11_0 ?
+ float64_minnum(frs1, frs2, &env->fp_status) :
+ float64_minimum_number(frs1, frs2, &env->fp_status);
}
uint64_t helper_fmax_d(CPURISCVState *env, uint64_t frs1, uint64_t frs2)
{
- return float64_maxnum(frs1, frs2, &env->fp_status);
+ return env->priv_ver < PRIV_VERSION_1_11_0 ?
+ float64_maxnum(frs1, frs2, &env->fp_status) :
+ float64_maximum_number(frs1, frs2, &env->fp_status);
}
uint64_t helper_fcvt_s_d(CPURISCVState *env, uint64_t rs1)
diff --git a/target/riscv/insn_trans/trans_rva.c.inc b/target/riscv/insn_trans/trans_rva.c.inc
index 6ea07d8..40fe132 100644
--- a/target/riscv/insn_trans/trans_rva.c.inc
+++ b/target/riscv/insn_trans/trans_rva.c.inc
@@ -25,6 +25,7 @@ static bool gen_lr(DisasContext *ctx, arg_atomic *a, MemOp mop)
if (a->rl) {
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
}
+ src1 = gen_pm_adjust_address(ctx, src1);
tcg_gen_qemu_ld_tl(load_val, src1, ctx->mem_idx, mop);
if (a->aq) {
tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
@@ -44,6 +45,7 @@ static bool gen_sc(DisasContext *ctx, arg_atomic *a, MemOp mop)
TCGLabel *l2 = gen_new_label();
src1 = get_gpr(ctx, a->rs1, EXT_ZERO);
+ src1 = gen_pm_adjust_address(ctx, src1);
tcg_gen_brcond_tl(TCG_COND_NE, load_res, src1, l1);
/*
@@ -84,6 +86,7 @@ static bool gen_amo(DisasContext *ctx, arg_atomic *a,
TCGv src1 = get_gpr(ctx, a->rs1, EXT_NONE);
TCGv src2 = get_gpr(ctx, a->rs2, EXT_NONE);
+ src1 = gen_pm_adjust_address(ctx, src1);
func(dest, src1, src2, ctx->mem_idx, mop);
gen_set_gpr(ctx, a->rd, dest);
diff --git a/target/riscv/insn_trans/trans_rvd.c.inc b/target/riscv/insn_trans/trans_rvd.c.inc
index db9ae15..64fb004 100644
--- a/target/riscv/insn_trans/trans_rvd.c.inc
+++ b/target/riscv/insn_trans/trans_rvd.c.inc
@@ -31,6 +31,7 @@ static bool trans_fld(DisasContext *ctx, arg_fld *a)
tcg_gen_addi_tl(temp, addr, a->imm);
addr = temp;
}
+ addr = gen_pm_adjust_address(ctx, addr);
tcg_gen_qemu_ld_i64(cpu_fpr[a->rd], addr, ctx->mem_idx, MO_TEQ);
@@ -51,6 +52,7 @@ static bool trans_fsd(DisasContext *ctx, arg_fsd *a)
tcg_gen_addi_tl(temp, addr, a->imm);
addr = temp;
}
+ addr = gen_pm_adjust_address(ctx, addr);
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEQ);
diff --git a/target/riscv/insn_trans/trans_rvf.c.inc b/target/riscv/insn_trans/trans_rvf.c.inc
index bddbd41..b545924 100644
--- a/target/riscv/insn_trans/trans_rvf.c.inc
+++ b/target/riscv/insn_trans/trans_rvf.c.inc
@@ -37,6 +37,7 @@ static bool trans_flw(DisasContext *ctx, arg_flw *a)
tcg_gen_addi_tl(temp, addr, a->imm);
addr = temp;
}
+ addr = gen_pm_adjust_address(ctx, addr);
dest = cpu_fpr[a->rd];
tcg_gen_qemu_ld_i64(dest, addr, ctx->mem_idx, MO_TEUL);
@@ -59,6 +60,7 @@ static bool trans_fsw(DisasContext *ctx, arg_fsw *a)
tcg_gen_addi_tl(temp, addr, a->imm);
addr = temp;
}
+ addr = gen_pm_adjust_address(ctx, addr);
tcg_gen_qemu_st_i64(cpu_fpr[a->rs2], addr, ctx->mem_idx, MO_TEUL);
diff --git a/target/riscv/insn_trans/trans_rvi.c.inc b/target/riscv/insn_trans/trans_rvi.c.inc
index 91dc438..e51dbc4 100644
--- a/target/riscv/insn_trans/trans_rvi.c.inc
+++ b/target/riscv/insn_trans/trans_rvi.c.inc
@@ -144,6 +144,7 @@ static bool gen_load(DisasContext *ctx, arg_lb *a, MemOp memop)
tcg_gen_addi_tl(temp, addr, a->imm);
addr = temp;
}
+ addr = gen_pm_adjust_address(ctx, addr);
tcg_gen_qemu_ld_tl(dest, addr, ctx->mem_idx, memop);
gen_set_gpr(ctx, a->rd, dest);
@@ -185,6 +186,7 @@ static bool gen_store(DisasContext *ctx, arg_sb *a, MemOp memop)
tcg_gen_addi_tl(temp, addr, a->imm);
addr = temp;
}
+ addr = gen_pm_adjust_address(ctx, addr);
tcg_gen_qemu_st_tl(data, addr, ctx->mem_idx, memop);
return true;
diff --git a/target/riscv/machine.c b/target/riscv/machine.c
index f64b2a9..7b4c739 100644
--- a/target/riscv/machine.c
+++ b/target/riscv/machine.c
@@ -84,6 +84,14 @@ static bool vector_needed(void *opaque)
return riscv_has_ext(env, RVV);
}
+static bool pointermasking_needed(void *opaque)
+{
+ RISCVCPU *cpu = opaque;
+ CPURISCVState *env = &cpu->env;
+
+ return riscv_has_ext(env, RVJ);
+}
+
static const VMStateDescription vmstate_vector = {
.name = "cpu/vector",
.version_id = 1,
@@ -100,6 +108,24 @@ static const VMStateDescription vmstate_vector = {
}
};
+static const VMStateDescription vmstate_pointermasking = {
+ .name = "cpu/pointer_masking",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = pointermasking_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINTTL(env.mmte, RISCVCPU),
+ VMSTATE_UINTTL(env.mpmmask, RISCVCPU),
+ VMSTATE_UINTTL(env.mpmbase, RISCVCPU),
+ VMSTATE_UINTTL(env.spmmask, RISCVCPU),
+ VMSTATE_UINTTL(env.spmbase, RISCVCPU),
+ VMSTATE_UINTTL(env.upmmask, RISCVCPU),
+ VMSTATE_UINTTL(env.upmbase, RISCVCPU),
+
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_hyper = {
.name = "cpu/hyper",
.version_id = 1,
@@ -191,6 +217,7 @@ const VMStateDescription vmstate_riscv_cpu = {
&vmstate_pmp,
&vmstate_hyper,
&vmstate_vector,
+ &vmstate_pointermasking,
NULL
}
};
diff --git a/target/riscv/translate.c b/target/riscv/translate.c
index d38f87d..1d57bc9 100644
--- a/target/riscv/translate.c
+++ b/target/riscv/translate.c
@@ -36,6 +36,9 @@ static TCGv cpu_gpr[32], cpu_pc, cpu_vl;
static TCGv_i64 cpu_fpr[32]; /* assume F and D extensions */
static TCGv load_res;
static TCGv load_val;
+/* globals for PM CSRs */
+static TCGv pm_mask[4];
+static TCGv pm_base[4];
#include "exec/gen-icount.h"
@@ -83,6 +86,10 @@ typedef struct DisasContext {
TCGv zero;
/* Space for 3 operands plus 1 extra for address computation. */
TCGv temp[4];
+ /* PointerMasking extension */
+ bool pm_enabled;
+ TCGv pm_mask;
+ TCGv pm_base;
} DisasContext;
static inline bool has_ext(DisasContext *ctx, uint32_t ext)
@@ -271,6 +278,23 @@ static void gen_jal(DisasContext *ctx, int rd, target_ulong imm)
ctx->base.is_jmp = DISAS_NORETURN;
}
+/*
+ * Generates address adjustment for PointerMasking
+ */
+static TCGv gen_pm_adjust_address(DisasContext *s, TCGv src)
+{
+ TCGv temp;
+ if (!s->pm_enabled) {
+ /* Load unmodified address */
+ return src;
+ } else {
+ temp = temp_new(s);
+ tcg_gen_andc_tl(temp, src, s->pm_mask);
+ tcg_gen_or_tl(temp, temp, s->pm_base);
+ return temp;
+ }
+}
+
#ifndef CONFIG_USER_ONLY
/* The states of mstatus_fs are:
* 0 = disabled, 1 = initial, 2 = clean, 3 = dirty
@@ -614,6 +638,10 @@ static void riscv_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
ctx->cs = cs;
ctx->ntemp = 0;
memset(ctx->temp, 0, sizeof(ctx->temp));
+ ctx->pm_enabled = FIELD_EX32(tb_flags, TB_FLAGS, PM_ENABLED);
+ int priv = tb_flags & TB_FLAGS_PRIV_MMU_MASK;
+ ctx->pm_mask = pm_mask[priv];
+ ctx->pm_base = pm_base[priv];
ctx->zero = tcg_constant_tl(0);
}
@@ -727,4 +755,19 @@ void riscv_translate_init(void)
"load_res");
load_val = tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, load_val),
"load_val");
+#ifndef CONFIG_USER_ONLY
+ /* Assign PM CSRs to tcg globals */
+ pm_mask[PRV_U] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, upmmask), "upmmask");
+ pm_base[PRV_U] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, upmbase), "upmbase");
+ pm_mask[PRV_S] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, spmmask), "spmmask");
+ pm_base[PRV_S] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, spmbase), "spmbase");
+ pm_mask[PRV_M] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, mpmmask), "mpmmask");
+ pm_base[PRV_M] =
+ tcg_global_mem_new(cpu_env, offsetof(CPURISCVState, mpmbase), "mpmbase");
+#endif
}