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:
commit
6450ce5634
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)) {
|
||||
|
@ -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,
|
||||
|
@ -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)) {
|
||||
|
@ -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,
|
||||
|
@ -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(
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 },
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user