target/riscv: Add support for Control Transfer Records extension CSRs.

This commit adds support for [m|s|vs]ctrcontrol, sctrstatus and
sctrdepth CSRs handling.

Signed-off-by: Rajnesh Kanwal <rkanwal@rivosinc.com>
Acked-by: Alistair Francis <alistair.francis@wdc.com>
Message-ID: <20250205-b4-ctr_upstream_v6-v6-3-439d8e06c8ef@rivosinc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Rajnesh Kanwal 2025-02-05 11:18:47 +00:00 committed by Alistair Francis
parent 3f833f8920
commit c48bd18eae
3 changed files with 151 additions and 0 deletions

View file

@ -313,6 +313,11 @@ struct CPUArchState {
target_ulong mcause;
target_ulong mtval; /* since: priv-1.10.0 */
uint64_t mctrctl;
uint32_t sctrdepth;
uint32_t sctrstatus;
uint64_t vsctrctl;
/* Machine and Supervisor interrupt priorities */
uint8_t miprio[64];
uint8_t siprio[64];

View file

@ -133,6 +133,8 @@ struct RISCVCPUConfig {
bool ext_zvfhmin;
bool ext_smaia;
bool ext_ssaia;
bool ext_smctr;
bool ext_ssctr;
bool ext_sscofpmf;
bool ext_smepmp;
bool ext_smrnmi;

View file

@ -635,6 +635,48 @@ static RISCVException hgatp(CPURISCVState *env, int csrno)
return hmode(env, csrno);
}
/*
* M-mode:
* Without ext_smctr raise illegal inst excep.
* Otherwise everything is accessible to m-mode.
*
* S-mode:
* Without ext_ssctr or mstateen.ctr raise illegal inst excep.
* Otherwise everything other than mctrctl is accessible.
*
* VS-mode:
* Without ext_ssctr or mstateen.ctr raise illegal inst excep.
* Without hstateen.ctr raise virtual illegal inst excep.
* Otherwise allow sctrctl (vsctrctl), sctrstatus, 0x200-0x2ff entry range.
* Always raise illegal instruction exception for sctrdepth.
*/
static RISCVException ctr_mmode(CPURISCVState *env, int csrno)
{
/* Check if smctr-ext is present */
if (riscv_cpu_cfg(env)->ext_smctr) {
return RISCV_EXCP_NONE;
}
return RISCV_EXCP_ILLEGAL_INST;
}
static RISCVException ctr_smode(CPURISCVState *env, int csrno)
{
const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
if (!cfg->ext_smctr && !cfg->ext_ssctr) {
return RISCV_EXCP_ILLEGAL_INST;
}
RISCVException ret = smstateen_acc_ok(env, 0, SMSTATEEN0_CTR);
if (ret == RISCV_EXCP_NONE && csrno == CSR_SCTRDEPTH &&
env->virt_enabled) {
return RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
}
return ret;
}
static RISCVException aia_hmode(CPURISCVState *env, int csrno)
{
int ret;
@ -3216,6 +3258,10 @@ static RISCVException write_mstateen0(CPURISCVState *env, int csrno,
wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
}
if (riscv_cpu_cfg(env)->ext_ssctr) {
wr_mask |= SMSTATEEN0_CTR;
}
return write_mstateen(env, csrno, wr_mask, new_val);
}
@ -3255,6 +3301,10 @@ static RISCVException write_mstateen0h(CPURISCVState *env, int csrno,
wr_mask |= SMSTATEEN0_P1P13;
}
if (riscv_cpu_cfg(env)->ext_ssctr) {
wr_mask |= SMSTATEEN0_CTR;
}
return write_mstateenh(env, csrno, wr_mask, new_val);
}
@ -3309,6 +3359,10 @@ static RISCVException write_hstateen0(CPURISCVState *env, int csrno,
wr_mask |= (SMSTATEEN0_AIA | SMSTATEEN0_IMSIC);
}
if (riscv_cpu_cfg(env)->ext_ssctr) {
wr_mask |= SMSTATEEN0_CTR;
}
return write_hstateen(env, csrno, wr_mask, new_val);
}
@ -3348,6 +3402,10 @@ static RISCVException write_hstateen0h(CPURISCVState *env, int csrno,
{
uint64_t wr_mask = SMSTATEEN_STATEEN | SMSTATEEN0_HSENVCFG;
if (riscv_cpu_cfg(env)->ext_ssctr) {
wr_mask |= SMSTATEEN0_CTR;
}
return write_hstateenh(env, csrno, wr_mask, new_val);
}
@ -4068,6 +4126,86 @@ static RISCVException write_satp(CPURISCVState *env, int csrno,
return RISCV_EXCP_NONE;
}
static RISCVException rmw_sctrdepth(CPURISCVState *env, int csrno,
target_ulong *ret_val,
target_ulong new_val, target_ulong wr_mask)
{
uint64_t mask = wr_mask & SCTRDEPTH_MASK;
if (ret_val) {
*ret_val = env->sctrdepth;
}
env->sctrdepth = (env->sctrdepth & ~mask) | (new_val & mask);
/* Correct depth. */
if (mask) {
uint64_t depth = get_field(env->sctrdepth, SCTRDEPTH_MASK);
if (depth > SCTRDEPTH_MAX) {
depth = SCTRDEPTH_MAX;
env->sctrdepth = set_field(env->sctrdepth, SCTRDEPTH_MASK, depth);
}
/* Update sctrstatus.WRPTR with a legal value */
depth = 16 << depth;
env->sctrstatus =
env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
}
return RISCV_EXCP_NONE;
}
static RISCVException rmw_sctrstatus(CPURISCVState *env, int csrno,
target_ulong *ret_val,
target_ulong new_val, target_ulong wr_mask)
{
uint32_t depth = 16 << get_field(env->sctrdepth, SCTRDEPTH_MASK);
uint32_t mask = wr_mask & SCTRSTATUS_MASK;
if (ret_val) {
*ret_val = env->sctrstatus;
}
env->sctrstatus = (env->sctrstatus & ~mask) | (new_val & mask);
/* Update sctrstatus.WRPTR with a legal value */
env->sctrstatus = env->sctrstatus & (~SCTRSTATUS_WRPTR_MASK | (depth - 1));
return RISCV_EXCP_NONE;
}
static RISCVException rmw_xctrctl(CPURISCVState *env, int csrno,
target_ulong *ret_val,
target_ulong new_val, target_ulong wr_mask)
{
uint64_t csr_mask, mask = wr_mask;
uint64_t *ctl_ptr = &env->mctrctl;
if (csrno == CSR_MCTRCTL) {
csr_mask = MCTRCTL_MASK;
} else if (csrno == CSR_SCTRCTL && !env->virt_enabled) {
csr_mask = SCTRCTL_MASK;
} else {
/*
* This is for csrno == CSR_SCTRCTL and env->virt_enabled == true
* or csrno == CSR_VSCTRCTL.
*/
csr_mask = VSCTRCTL_MASK;
ctl_ptr = &env->vsctrctl;
}
mask &= csr_mask;
if (ret_val) {
*ret_val = *ctl_ptr & csr_mask;
}
*ctl_ptr = (*ctl_ptr & ~mask) | (new_val & mask);
return RISCV_EXCP_NONE;
}
static RISCVException read_vstopi(CPURISCVState *env, int csrno,
target_ulong *val)
{
@ -5821,6 +5959,12 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
[CSR_TINFO] = { "tinfo", debug, read_tinfo, write_ignore },
[CSR_MCONTEXT] = { "mcontext", debug, read_mcontext, write_mcontext },
[CSR_MCTRCTL] = { "mctrctl", ctr_mmode, NULL, NULL, rmw_xctrctl },
[CSR_SCTRCTL] = { "sctrctl", ctr_smode, NULL, NULL, rmw_xctrctl },
[CSR_VSCTRCTL] = { "vsctrctl", ctr_smode, NULL, NULL, rmw_xctrctl },
[CSR_SCTRDEPTH] = { "sctrdepth", ctr_smode, NULL, NULL, rmw_sctrdepth },
[CSR_SCTRSTATUS] = { "sctrstatus", ctr_smode, NULL, NULL, rmw_sctrstatus },
/* Performance Counters */
[CSR_HPMCOUNTER3] = { "hpmcounter3", ctr, read_hpmcounter },
[CSR_HPMCOUNTER4] = { "hpmcounter4", ctr, read_hpmcounter },