mirror of https://github.com/xemu-project/xemu.git
target/riscv: Support CSRs required for RISC-V PM extension except for the h-mode
Signed-off-by: Alexey Baturo <space.monkey.delivers@gmail.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Message-id: 20211025173609.2724490-4-space.monkey.delivers@gmail.com Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
parent
138b5c5f8f
commit
4bbe8033fc
|
@ -367,6 +367,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;
|
||||
|
|
|
@ -238,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;
|
||||
|
|
|
@ -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 },
|
||||
|
|
Loading…
Reference in New Issue