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
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAmF7nNMACgkQIeENKd+X
 cFQhegf/U3L/SOPCU5uICn67TZHRUeyzH1ebw6p9hHkGbhUq2hLsg2N5yqIPusbM
 Y/uouTHciRXqSNiqNle24wvdORxBPdwkE+hplyU3os3wvIelU+8HAhBIrFsJPOVV
 G3kuMoc7rKPhjbwSjSIQcrfDA52pT3wQJUfza3bvVZ1VoI4jb+I2yopRLVq7S0qA
 d/Hl5QoUC/CcSrpubDp8AtN/lQWnmFlFq4vfbaFg/NJK3+lCR1JWc8RxfRJ3Y9T0
 V3AZP8m8+dTubjoMAbNkuIlRLKtvCfa+qFe9WFwxLKul6sbM/qONVDFQJAiHczyG
 Pjkg77ZXRXvu1McMN/rF4tz5k9dQOA==
 =5EIe
 -----END PGP SIGNATURE-----

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>
This commit is contained in:
Richard Henderson 2021-10-29 10:59:09 -07:00
commit 6450ce5634
24 changed files with 605 additions and 115 deletions

View File

@ -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);
}

View File

@ -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)

View File

@ -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)) {

View File

@ -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,

View File

@ -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)) {

View File

@ -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,

View File

@ -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(

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -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)

View File

@ -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

View File

@ -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);
target_ulong hsie = virt_enabled || sie;
target_ulong vsie = virt_enabled && 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;
}
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;

View File

@ -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 },

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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
}
};

View File

@ -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
}