diff options
Diffstat (limited to 'target/riscv/csr.c')
| -rw-r--r-- | target/riscv/csr.c | 1282 |
1 files changed, 1171 insertions, 111 deletions
diff --git a/target/riscv/csr.c b/target/riscv/csr.c index e5f9d4ef93..fe2c8dd40e 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -158,6 +158,24 @@ static RISCVException any32(CPURISCVState *env, int csrno) } +static int aia_any(CPURISCVState *env, int csrno) +{ + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return any(env, csrno); +} + +static int aia_any32(CPURISCVState *env, int csrno) +{ + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return any32(env, csrno); +} + static RISCVException smode(CPURISCVState *env, int csrno) { if (riscv_has_ext(env, RVS)) { @@ -167,6 +185,33 @@ static RISCVException smode(CPURISCVState *env, int csrno) return RISCV_EXCP_ILLEGAL_INST; } +static int smode32(CPURISCVState *env, int csrno) +{ + if (riscv_cpu_mxl(env) != MXL_RV32) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return smode(env, csrno); +} + +static int aia_smode(CPURISCVState *env, int csrno) +{ + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return smode(env, csrno); +} + +static int aia_smode32(CPURISCVState *env, int csrno) +{ + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return smode32(env, csrno); +} + static RISCVException hmode(CPURISCVState *env, int csrno) { if (riscv_has_ext(env, RVS) && @@ -186,7 +231,7 @@ static RISCVException hmode(CPURISCVState *env, int csrno) static RISCVException hmode32(CPURISCVState *env, int csrno) { if (riscv_cpu_mxl(env) != MXL_RV32) { - if (riscv_cpu_virt_enabled(env)) { + if (!riscv_cpu_virt_enabled(env)) { return RISCV_EXCP_ILLEGAL_INST; } else { return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; @@ -207,6 +252,24 @@ static RISCVException pointer_masking(CPURISCVState *env, int csrno) return RISCV_EXCP_ILLEGAL_INST; } +static int aia_hmode(CPURISCVState *env, int csrno) +{ + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return hmode(env, csrno); +} + +static int aia_hmode32(CPURISCVState *env, int csrno) +{ + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + return RISCV_EXCP_ILLEGAL_INST; + } + + return hmode32(env, csrno); +} + static RISCVException pmp(CPURISCVState *env, int csrno) { if (riscv_feature(env, RISCV_FEATURE_PMP)) { @@ -458,15 +521,18 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno, /* Machine constants */ -#define M_MODE_INTERRUPTS (MIP_MSIP | MIP_MTIP | MIP_MEIP) -#define S_MODE_INTERRUPTS (MIP_SSIP | MIP_STIP | MIP_SEIP) -#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP) +#define M_MODE_INTERRUPTS ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP)) +#define S_MODE_INTERRUPTS ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP)) +#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)) +#define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS)) -static const target_ulong delegable_ints = S_MODE_INTERRUPTS | +#define VSTOPI_NUM_SRCS 5 + +static const uint64_t delegable_ints = S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS; -static const target_ulong vs_delegable_ints = VS_MODE_INTERRUPTS; -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | - VS_MODE_INTERRUPTS; +static const uint64_t vs_delegable_ints = VS_MODE_INTERRUPTS; +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | + HS_MODE_INTERRUPTS; #define DELEGABLE_EXCPS ((1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | \ (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | \ (1ULL << (RISCV_EXCP_ILLEGAL_INST)) | \ @@ -522,6 +588,12 @@ static RISCVException read_zero(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException write_ignore(CPURISCVState *env, int csrno, + target_ulong val) +{ + return RISCV_EXCP_NONE; +} + static RISCVException read_mhartid(CPURISCVState *env, int csrno, target_ulong *val) { @@ -736,34 +808,471 @@ static RISCVException write_medeleg(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static RISCVException read_mideleg(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException rmw_mideleg64(CPURISCVState *env, int csrno, + uint64_t *ret_val, + uint64_t new_val, uint64_t wr_mask) { - *val = env->mideleg; + uint64_t mask = wr_mask & delegable_ints; + + if (ret_val) { + *ret_val = env->mideleg; + } + + env->mideleg = (env->mideleg & ~mask) | (new_val & mask); + + if (riscv_has_ext(env, RVH)) { + env->mideleg |= HS_MODE_INTERRUPTS; + } + return RISCV_EXCP_NONE; } -static RISCVException write_mideleg(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException rmw_mideleg(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) { - env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints); - if (riscv_has_ext(env, RVH)) { - env->mideleg |= VS_MODE_INTERRUPTS; + uint64_t rval; + RISCVException ret; + + ret = rmw_mideleg64(env, csrno, &rval, new_val, wr_mask); + if (ret_val) { + *ret_val = rval; } + + return ret; +} + +static RISCVException rmw_midelegh(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, + target_ulong wr_mask) +{ + uint64_t rval; + RISCVException ret; + + ret = rmw_mideleg64(env, csrno, &rval, + ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); + if (ret_val) { + *ret_val = rval >> 32; + } + + return ret; +} + +static RISCVException rmw_mie64(CPURISCVState *env, int csrno, + uint64_t *ret_val, + uint64_t new_val, uint64_t wr_mask) +{ + uint64_t mask = wr_mask & all_ints; + + if (ret_val) { + *ret_val = env->mie; + } + + env->mie = (env->mie & ~mask) | (new_val & mask); + + if (!riscv_has_ext(env, RVH)) { + env->mie &= ~((uint64_t)MIP_SGEIP); + } + return RISCV_EXCP_NONE; } -static RISCVException read_mie(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException rmw_mie(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) { - *val = env->mie; + uint64_t rval; + RISCVException ret; + + ret = rmw_mie64(env, csrno, &rval, new_val, wr_mask); + if (ret_val) { + *ret_val = rval; + } + + return ret; +} + +static RISCVException rmw_mieh(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) +{ + uint64_t rval; + RISCVException ret; + + ret = rmw_mie64(env, csrno, &rval, + ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); + if (ret_val) { + *ret_val = rval >> 32; + } + + return ret; +} + +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val) +{ + int irq; + uint8_t iprio; + + irq = riscv_cpu_mirq_pending(env); + if (irq <= 0 || irq > 63) { + *val = 0; + } else { + iprio = env->miprio[irq]; + if (!iprio) { + if (riscv_cpu_default_priority(irq) > IPRIO_DEFAULT_M) { + iprio = IPRIO_MMAXIPRIO; + } + } + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; + *val |= iprio; + } + return RISCV_EXCP_NONE; } -static RISCVException write_mie(CPURISCVState *env, int csrno, - target_ulong val) +static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno) +{ + if (!riscv_cpu_virt_enabled(env)) { + return csrno; + } + + switch (csrno) { + case CSR_SISELECT: + return CSR_VSISELECT; + case CSR_SIREG: + return CSR_VSIREG; + case CSR_SSETEIPNUM: + return CSR_VSSETEIPNUM; + case CSR_SCLREIPNUM: + return CSR_VSCLREIPNUM; + case CSR_SSETEIENUM: + return CSR_VSSETEIENUM; + case CSR_SCLREIENUM: + return CSR_VSCLREIENUM; + case CSR_STOPEI: + return CSR_VSTOPEI; + default: + return csrno; + }; +} + +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val, + target_ulong new_val, target_ulong wr_mask) +{ + target_ulong *iselect; + + /* Translate CSR number for VS-mode */ + csrno = aia_xlate_vs_csrno(env, csrno); + + /* Find the iselect CSR based on CSR number */ + switch (csrno) { + case CSR_MISELECT: + iselect = &env->miselect; + break; + case CSR_SISELECT: + iselect = &env->siselect; + break; + case CSR_VSISELECT: + iselect = &env->vsiselect; + break; + default: + return RISCV_EXCP_ILLEGAL_INST; + }; + + if (val) { + *val = *iselect; + } + + wr_mask &= ISELECT_MASK; + if (wr_mask) { + *iselect = (*iselect & ~wr_mask) | (new_val & wr_mask); + } + + return RISCV_EXCP_NONE; +} + +static int rmw_iprio(target_ulong xlen, + target_ulong iselect, uint8_t *iprio, + target_ulong *val, target_ulong new_val, + target_ulong wr_mask, int ext_irq_no) +{ + int i, firq, nirqs; + target_ulong old_val; + + if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) { + return -EINVAL; + } + if (xlen != 32 && iselect & 0x1) { + return -EINVAL; + } + + nirqs = 4 * (xlen / 32); + firq = ((iselect - ISELECT_IPRIO0) / (xlen / 32)) * (nirqs); + + old_val = 0; + for (i = 0; i < nirqs; i++) { + old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i); + } + + if (val) { + *val = old_val; + } + + if (wr_mask) { + new_val = (old_val & ~wr_mask) | (new_val & wr_mask); + for (i = 0; i < nirqs; i++) { + /* + * M-level and S-level external IRQ priority always read-only + * zero. This means default priority order is always preferred + * for M-level and S-level external IRQs. + */ + if ((firq + i) == ext_irq_no) { + continue; + } + iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff; + } + } + + return 0; +} + +static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val, + target_ulong new_val, target_ulong wr_mask) +{ + bool virt; + uint8_t *iprio; + int ret = -EINVAL; + target_ulong priv, isel, vgein; + + /* Translate CSR number for VS-mode */ + csrno = aia_xlate_vs_csrno(env, csrno); + + /* Decode register details from CSR number */ + virt = false; + switch (csrno) { + case CSR_MIREG: + iprio = env->miprio; + isel = env->miselect; + priv = PRV_M; + break; + case CSR_SIREG: + iprio = env->siprio; + isel = env->siselect; + priv = PRV_S; + break; + case CSR_VSIREG: + iprio = env->hviprio; + isel = env->vsiselect; + priv = PRV_S; + virt = true; + break; + default: + goto done; + }; + + /* Find the selected guest interrupt file */ + vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0; + + if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) { + /* Local interrupt priority registers not available for VS-mode */ + if (!virt) { + ret = rmw_iprio(riscv_cpu_mxl_bits(env), + isel, iprio, val, new_val, wr_mask, + (priv == PRV_M) ? IRQ_M_EXT : IRQ_S_EXT); + } + } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) { + /* IMSIC registers only available when machine implements it. */ + if (env->aia_ireg_rmw_fn[priv]) { + /* Selected guest interrupt file should not be zero */ + if (virt && (!vgein || env->geilen < vgein)) { + goto done; + } + /* Call machine specific IMSIC register emulation */ + ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], + AIA_MAKE_IREG(isel, priv, virt, vgein, + riscv_cpu_mxl_bits(env)), + val, new_val, wr_mask); + } + } + +done: + if (ret) { + return (riscv_cpu_virt_enabled(env) && virt) ? + RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; + } + return RISCV_EXCP_NONE; +} + +static int rmw_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val, + target_ulong new_val, target_ulong wr_mask) +{ + int ret = -EINVAL; + bool set, pend, virt; + target_ulong priv, isel, vgein, xlen, nval, wmask; + + /* Translate CSR number for VS-mode */ + csrno = aia_xlate_vs_csrno(env, csrno); + + /* Decode register details from CSR number */ + virt = set = pend = false; + switch (csrno) { + case CSR_MSETEIPNUM: + priv = PRV_M; + set = true; + pend = true; + break; + case CSR_MCLREIPNUM: + priv = PRV_M; + pend = true; + break; + case CSR_MSETEIENUM: + priv = PRV_M; + set = true; + break; + case CSR_MCLREIENUM: + priv = PRV_M; + break; + case CSR_SSETEIPNUM: + priv = PRV_S; + set = true; + pend = true; + break; + case CSR_SCLREIPNUM: + priv = PRV_S; + pend = true; + break; + case CSR_SSETEIENUM: + priv = PRV_S; + set = true; + break; + case CSR_SCLREIENUM: + priv = PRV_S; + break; + case CSR_VSSETEIPNUM: + priv = PRV_S; + virt = true; + set = true; + pend = true; + break; + case CSR_VSCLREIPNUM: + priv = PRV_S; + virt = true; + pend = true; + break; + case CSR_VSSETEIENUM: + priv = PRV_S; + virt = true; + set = true; + break; + case CSR_VSCLREIENUM: + priv = PRV_S; + virt = true; + break; + default: + goto done; + }; + + /* IMSIC CSRs only available when machine implements IMSIC. */ + if (!env->aia_ireg_rmw_fn[priv]) { + goto done; + } + + /* Find the selected guest interrupt file */ + vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0; + + /* Selected guest interrupt file should be valid */ + if (virt && (!vgein || env->geilen < vgein)) { + goto done; + } + + /* Set/Clear CSRs always read zero */ + if (val) { + *val = 0; + } + + if (wr_mask) { + /* Get interrupt number */ + new_val &= wr_mask; + + /* Find target interrupt pending/enable register */ + xlen = riscv_cpu_mxl_bits(env); + isel = (new_val / xlen); + isel *= (xlen / IMSIC_EIPx_BITS); + isel += (pend) ? ISELECT_IMSIC_EIP0 : ISELECT_IMSIC_EIE0; + + /* Find the interrupt bit to be set/clear */ + wmask = ((target_ulong)1) << (new_val % xlen); + nval = (set) ? wmask : 0; + + /* Call machine specific IMSIC register emulation */ + ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], + AIA_MAKE_IREG(isel, priv, virt, + vgein, xlen), + NULL, nval, wmask); + } else { + ret = 0; + } + +done: + if (ret) { + return (riscv_cpu_virt_enabled(env) && virt) ? + RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; + } + return RISCV_EXCP_NONE; +} + +static int rmw_xtopei(CPURISCVState *env, int csrno, target_ulong *val, + target_ulong new_val, target_ulong wr_mask) { - env->mie = (env->mie & ~all_ints) | (val & all_ints); + bool virt; + int ret = -EINVAL; + target_ulong priv, vgein; + + /* Translate CSR number for VS-mode */ + csrno = aia_xlate_vs_csrno(env, csrno); + + /* Decode register details from CSR number */ + virt = false; + switch (csrno) { + case CSR_MTOPEI: + priv = PRV_M; + break; + case CSR_STOPEI: + priv = PRV_S; + break; + case CSR_VSTOPEI: + priv = PRV_S; + virt = true; + break; + default: + goto done; + }; + + /* IMSIC CSRs only available when machine implements IMSIC. */ + if (!env->aia_ireg_rmw_fn[priv]) { + goto done; + } + + /* Find the selected guest interrupt file */ + vgein = (virt) ? get_field(env->hstatus, HSTATUS_VGEIN) : 0; + + /* Selected guest interrupt file should be valid */ + if (virt && (!vgein || env->geilen < vgein)) { + goto done; + } + + /* Call machine specific IMSIC register emulation for TOPEI */ + ret = env->aia_ireg_rmw_fn[priv](env->aia_ireg_rmw_fn_arg[priv], + AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, priv, virt, vgein, + riscv_cpu_mxl_bits(env)), + val, new_val, wr_mask); + +done: + if (ret) { + return (riscv_cpu_virt_enabled(env) && virt) ? + RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; + } return RISCV_EXCP_NONE; } @@ -872,28 +1381,64 @@ static RISCVException write_mtval(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static RISCVException rmw_mip(CPURISCVState *env, int csrno, - target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_mip64(CPURISCVState *env, int csrno, + uint64_t *ret_val, + uint64_t new_val, uint64_t wr_mask) { RISCVCPU *cpu = env_archcpu(env); /* Allow software control of delegable interrupts not claimed by hardware */ - target_ulong mask = write_mask & delegable_ints & ~env->miclaim; - uint32_t old_mip; + uint64_t old_mip, mask = wr_mask & delegable_ints & ~env->miclaim; + uint32_t gin; if (mask) { - old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); + old_mip = riscv_cpu_update_mip(cpu, mask, (new_val & mask)); } else { old_mip = env->mip; } - if (ret_value) { - *ret_value = old_mip; + if (csrno != CSR_HVIP) { + gin = get_field(env->hstatus, HSTATUS_VGEIN); + old_mip |= (env->hgeip & ((target_ulong)1 << gin)) ? MIP_VSEIP : 0; + } + + if (ret_val) { + *ret_val = old_mip; } return RISCV_EXCP_NONE; } +static RISCVException rmw_mip(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) +{ + uint64_t rval; + RISCVException ret; + + ret = rmw_mip64(env, csrno, &rval, new_val, wr_mask); + if (ret_val) { + *ret_val = rval; + } + + return ret; +} + +static RISCVException rmw_miph(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) +{ + uint64_t rval; + RISCVException ret; + + ret = rmw_mip64(env, csrno, &rval, + ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); + if (ret_val) { + *ret_val = rval >> 32; + } + + return ret; +} + /* Supervisor Trap Setup */ static RISCVException read_sstatus_i128(CPURISCVState *env, int csrno, Int128 *val) @@ -934,45 +1479,115 @@ static RISCVException write_sstatus(CPURISCVState *env, int csrno, return write_mstatus(env, CSR_MSTATUS, newval); } -static RISCVException read_vsie(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException rmw_vsie64(CPURISCVState *env, int csrno, + uint64_t *ret_val, + uint64_t new_val, uint64_t wr_mask) { - /* Shift the VS bits to their S bit location in vsie */ - *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1; - return RISCV_EXCP_NONE; + RISCVException ret; + uint64_t rval, vsbits, mask = env->hideleg & VS_MODE_INTERRUPTS; + + /* Bring VS-level bits to correct position */ + vsbits = new_val & (VS_MODE_INTERRUPTS >> 1); + new_val &= ~(VS_MODE_INTERRUPTS >> 1); + new_val |= vsbits << 1; + vsbits = wr_mask & (VS_MODE_INTERRUPTS >> 1); + wr_mask &= ~(VS_MODE_INTERRUPTS >> 1); + wr_mask |= vsbits << 1; + + ret = rmw_mie64(env, csrno, &rval, new_val, wr_mask & mask); + if (ret_val) { + rval &= mask; + vsbits = rval & VS_MODE_INTERRUPTS; + rval &= ~VS_MODE_INTERRUPTS; + *ret_val = rval | (vsbits >> 1); + } + + return ret; } -static RISCVException read_sie(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException rmw_vsie(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) { - if (riscv_cpu_virt_enabled(env)) { - read_vsie(env, CSR_VSIE, val); - } else { - *val = env->mie & env->mideleg; + uint64_t rval; + RISCVException ret; + + ret = rmw_vsie64(env, csrno, &rval, new_val, wr_mask); + if (ret_val) { + *ret_val = rval; } - return RISCV_EXCP_NONE; + + return ret; } -static RISCVException write_vsie(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException rmw_vsieh(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) { - /* Shift the S bits to their VS bit location in mie */ - target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | - ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS); - return write_mie(env, CSR_MIE, newval); + uint64_t rval; + RISCVException ret; + + ret = rmw_vsie64(env, csrno, &rval, + ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); + if (ret_val) { + *ret_val = rval >> 32; + } + + return ret; } -static int write_sie(CPURISCVState *env, int csrno, target_ulong val) +static RISCVException rmw_sie64(CPURISCVState *env, int csrno, + uint64_t *ret_val, + uint64_t new_val, uint64_t wr_mask) { + RISCVException ret; + uint64_t mask = env->mideleg & S_MODE_INTERRUPTS; + if (riscv_cpu_virt_enabled(env)) { - write_vsie(env, CSR_VSIE, val); + if (env->hvictl & HVICTL_VTI) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + ret = rmw_vsie64(env, CSR_VSIE, ret_val, new_val, wr_mask); } else { - target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) | - (val & S_MODE_INTERRUPTS); - write_mie(env, CSR_MIE, newval); + ret = rmw_mie64(env, csrno, ret_val, new_val, wr_mask & mask); } - return RISCV_EXCP_NONE; + if (ret_val) { + *ret_val &= mask; + } + + return ret; +} + +static RISCVException rmw_sie(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) +{ + uint64_t rval; + RISCVException ret; + + ret = rmw_sie64(env, csrno, &rval, new_val, wr_mask); + if (ret == RISCV_EXCP_NONE && ret_val) { + *ret_val = rval; + } + + return ret; +} + +static RISCVException rmw_sieh(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) +{ + uint64_t rval; + RISCVException ret; + + ret = rmw_sie64(env, csrno, &rval, + ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); + if (ret_val) { + *ret_val = rval >> 32; + } + + return ret; } static RISCVException read_stvec(CPURISCVState *env, int csrno, @@ -1080,38 +1695,114 @@ static RISCVException write_stval(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static RISCVException rmw_vsip64(CPURISCVState *env, int csrno, + uint64_t *ret_val, + uint64_t new_val, uint64_t wr_mask) +{ + RISCVException ret; + uint64_t rval, vsbits, mask = env->hideleg & vsip_writable_mask; + + /* Bring VS-level bits to correct position */ + vsbits = new_val & (VS_MODE_INTERRUPTS >> 1); + new_val &= ~(VS_MODE_INTERRUPTS >> 1); + new_val |= vsbits << 1; + vsbits = wr_mask & (VS_MODE_INTERRUPTS >> 1); + wr_mask &= ~(VS_MODE_INTERRUPTS >> 1); + wr_mask |= vsbits << 1; + + ret = rmw_mip64(env, csrno, &rval, new_val, wr_mask & mask); + if (ret_val) { + rval &= mask; + vsbits = rval & VS_MODE_INTERRUPTS; + rval &= ~VS_MODE_INTERRUPTS; + *ret_val = rval | (vsbits >> 1); + } + + return ret; +} + static RISCVException rmw_vsip(CPURISCVState *env, int csrno, - target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) { - /* Shift the S bits to their VS bit location in mip */ - int ret = rmw_mip(env, 0, ret_value, new_value << 1, - (write_mask << 1) & vsip_writable_mask & env->hideleg); + uint64_t rval; + RISCVException ret; - if (ret_value) { - *ret_value &= VS_MODE_INTERRUPTS; - /* Shift the VS bits to their S bit location in vsip */ - *ret_value >>= 1; + ret = rmw_vsip64(env, csrno, &rval, new_val, wr_mask); + if (ret_val) { + *ret_val = rval; } + return ret; } -static RISCVException rmw_sip(CPURISCVState *env, int csrno, - target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) +static RISCVException rmw_vsiph(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) { - int ret; + uint64_t rval; + RISCVException ret; + + ret = rmw_vsip64(env, csrno, &rval, + ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); + if (ret_val) { + *ret_val = rval >> 32; + } + + return ret; +} + +static RISCVException rmw_sip64(CPURISCVState *env, int csrno, + uint64_t *ret_val, + uint64_t new_val, uint64_t wr_mask) +{ + RISCVException ret; + uint64_t mask = env->mideleg & sip_writable_mask; if (riscv_cpu_virt_enabled(env)) { - ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); + if (env->hvictl & HVICTL_VTI) { + return RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + ret = rmw_vsip64(env, CSR_VSIP, ret_val, new_val, wr_mask); } else { - ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, - write_mask & env->mideleg & sip_writable_mask); + ret = rmw_mip64(env, csrno, ret_val, new_val, wr_mask & mask); } - if (ret_value) { - *ret_value &= env->mideleg; + if (ret_val) { + *ret_val &= env->mideleg & S_MODE_INTERRUPTS; + } + + return ret; +} + +static RISCVException rmw_sip(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) +{ + uint64_t rval; + RISCVException ret; + + ret = rmw_sip64(env, csrno, &rval, new_val, wr_mask); + if (ret_val) { + *ret_val = rval; } + + return ret; +} + +static RISCVException rmw_siph(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) +{ + uint64_t rval; + RISCVException ret; + + ret = rmw_sip64(env, csrno, &rval, + ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); + if (ret_val) { + *ret_val = rval >> 32; + } + return ret; } @@ -1165,6 +1856,120 @@ static RISCVException write_satp(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val) +{ + int irq, ret; + target_ulong topei; + uint64_t vseip, vsgein; + uint32_t iid, iprio, hviid, hviprio, gein; + uint32_t s, scount = 0, siid[VSTOPI_NUM_SRCS], siprio[VSTOPI_NUM_SRCS]; + + gein = get_field(env->hstatus, HSTATUS_VGEIN); + hviid = get_field(env->hvictl, HVICTL_IID); + hviprio = get_field(env->hvictl, HVICTL_IPRIO); + + if (gein) { + vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0; + vseip = env->mie & (env->mip | vsgein) & MIP_VSEIP; + if (gein <= env->geilen && vseip) { + siid[scount] = IRQ_S_EXT; + siprio[scount] = IPRIO_MMAXIPRIO + 1; + if (env->aia_ireg_rmw_fn[PRV_S]) { + /* + * Call machine specific IMSIC register emulation for + * reading TOPEI. + */ + ret = env->aia_ireg_rmw_fn[PRV_S]( + env->aia_ireg_rmw_fn_arg[PRV_S], + AIA_MAKE_IREG(ISELECT_IMSIC_TOPEI, PRV_S, true, gein, + riscv_cpu_mxl_bits(env)), + &topei, 0, 0); + if (!ret && topei) { + siprio[scount] = topei & IMSIC_TOPEI_IPRIO_MASK; + } + } + scount++; + } + } else { + if (hviid == IRQ_S_EXT && hviprio) { + siid[scount] = IRQ_S_EXT; + siprio[scount] = hviprio; + scount++; + } + } + + if (env->hvictl & HVICTL_VTI) { + if (hviid != IRQ_S_EXT) { + siid[scount] = hviid; + siprio[scount] = hviprio; + scount++; + } + } else { + irq = riscv_cpu_vsirq_pending(env); + if (irq != IRQ_S_EXT && 0 < irq && irq <= 63) { + siid[scount] = irq; + siprio[scount] = env->hviprio[irq]; + scount++; + } + } + + iid = 0; + iprio = UINT_MAX; + for (s = 0; s < scount; s++) { + if (siprio[s] < iprio) { + iid = siid[s]; + iprio = siprio[s]; + } + } + + if (iid) { + if (env->hvictl & HVICTL_IPRIOM) { + if (iprio > IPRIO_MMAXIPRIO) { + iprio = IPRIO_MMAXIPRIO; + } + if (!iprio) { + if (riscv_cpu_default_priority(iid) > IPRIO_DEFAULT_S) { + iprio = IPRIO_MMAXIPRIO; + } + } + } else { + iprio = 1; + } + } else { + iprio = 0; + } + + *val = (iid & TOPI_IID_MASK) << TOPI_IID_SHIFT; + *val |= iprio; + return RISCV_EXCP_NONE; +} + +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val) +{ + int irq; + uint8_t iprio; + + if (riscv_cpu_virt_enabled(env)) { + return read_vstopi(env, CSR_VSTOPI, val); + } + + irq = riscv_cpu_sirq_pending(env); + if (irq <= 0 || irq > 63) { + *val = 0; + } else { + iprio = env->siprio[irq]; + if (!iprio) { + if (riscv_cpu_default_priority(irq) > IPRIO_DEFAULT_S) { + iprio = IPRIO_MMAXIPRIO; + } + } + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; + *val |= iprio; + } + + return RISCV_EXCP_NONE; +} + /* Hypervisor Extensions */ static RISCVException read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) @@ -1206,30 +2011,94 @@ static RISCVException write_hedeleg(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static RISCVException read_hideleg(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException rmw_hideleg64(CPURISCVState *env, int csrno, + uint64_t *ret_val, + uint64_t new_val, uint64_t wr_mask) { - *val = env->hideleg; + uint64_t mask = wr_mask & vs_delegable_ints; + + if (ret_val) { + *ret_val = env->hideleg & vs_delegable_ints; + } + + env->hideleg = (env->hideleg & ~mask) | (new_val & mask); return RISCV_EXCP_NONE; } -static RISCVException write_hideleg(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException rmw_hideleg(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) { - env->hideleg = val & vs_delegable_ints; - return RISCV_EXCP_NONE; + uint64_t rval; + RISCVException ret; + + ret = rmw_hideleg64(env, csrno, &rval, new_val, wr_mask); + if (ret_val) { + *ret_val = rval; + } + + return ret; +} + +static RISCVException rmw_hidelegh(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) +{ + uint64_t rval; + RISCVException ret; + + ret = rmw_hideleg64(env, csrno, &rval, + ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); + if (ret_val) { + *ret_val = rval >> 32; + } + + return ret; +} + +static RISCVException rmw_hvip64(CPURISCVState *env, int csrno, + uint64_t *ret_val, + uint64_t new_val, uint64_t wr_mask) +{ + RISCVException ret; + + ret = rmw_mip64(env, csrno, ret_val, new_val, + wr_mask & hvip_writable_mask); + if (ret_val) { + *ret_val &= VS_MODE_INTERRUPTS; + } + + return ret; } static RISCVException rmw_hvip(CPURISCVState *env, int csrno, - target_ulong *ret_value, - target_ulong new_value, target_ulong write_mask) + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) { - int ret = rmw_mip(env, 0, ret_value, new_value, - write_mask & hvip_writable_mask); + uint64_t rval; + RISCVException ret; - if (ret_value) { - *ret_value &= hvip_writable_mask; + ret = rmw_hvip64(env, csrno, &rval, new_val, wr_mask); + if (ret_val) { + *ret_val = rval; } + + return ret; +} + +static RISCVException rmw_hviph(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) +{ + uint64_t rval; + RISCVException ret; + + ret = rmw_hvip64(env, csrno, &rval, + ((uint64_t)new_val) << 32, ((uint64_t)wr_mask) << 32); + if (ret_val) { + *ret_val = rval >> 32; + } + return ret; } @@ -1237,27 +2106,28 @@ static RISCVException rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask) { - int ret = rmw_mip(env, 0, ret_value, new_value, + int ret = rmw_mip(env, csrno, ret_value, new_value, write_mask & hip_writable_mask); if (ret_value) { - *ret_value &= hip_writable_mask; + *ret_value &= HS_MODE_INTERRUPTS; } return ret; } -static RISCVException read_hie(CPURISCVState *env, int csrno, - target_ulong *val) +static RISCVException rmw_hie(CPURISCVState *env, int csrno, + target_ulong *ret_val, + target_ulong new_val, target_ulong wr_mask) { - *val = env->mie & VS_MODE_INTERRUPTS; - return RISCV_EXCP_NONE; -} + uint64_t rval; + RISCVException ret; -static RISCVException write_hie(CPURISCVState *env, int csrno, - target_ulong val) -{ - target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS); - return write_mie(env, CSR_MIE, newval); + ret = rmw_mie64(env, csrno, &rval, new_val, wr_mask & HS_MODE_INTERRUPTS); + if (ret_val) { + *ret_val = rval & HS_MODE_INTERRUPTS; + } + + return ret; } static RISCVException read_hcounteren(CPURISCVState *env, int csrno, @@ -1274,15 +2144,27 @@ static RISCVException write_hcounteren(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static RISCVException write_hgeie(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException read_hgeie(CPURISCVState *env, int csrno, + target_ulong *val) { if (val) { - qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); + *val = env->hgeie; } return RISCV_EXCP_NONE; } +static RISCVException write_hgeie(CPURISCVState *env, int csrno, + target_ulong val) +{ + /* Only GEILEN:1 bits implemented and BIT0 is never implemented */ + val &= ((((target_ulong)1) << env->geilen) - 1) << 1; + env->hgeie = val; + /* Update mip.SGEIP bit */ + riscv_cpu_update_mip(env_archcpu(env), MIP_SGEIP, + BOOL_TO_MASK(!!(env->hgeie & env->hgeip))); + return RISCV_EXCP_NONE; +} + static RISCVException read_htval(CPURISCVState *env, int csrno, target_ulong *val) { @@ -1310,11 +2192,11 @@ static RISCVException write_htinst(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } -static RISCVException write_hgeip(CPURISCVState *env, int csrno, - target_ulong val) +static RISCVException read_hgeip(CPURISCVState *env, int csrno, + target_ulong *val) { if (val) { - qemu_log_mask(LOG_UNIMP, "No support for a non-zero GEILEN."); + *val = env->hgeip; } return RISCV_EXCP_NONE; } @@ -1381,6 +2263,110 @@ static RISCVException write_htimedeltah(CPURISCVState *env, int csrno, return RISCV_EXCP_NONE; } +static int read_hvictl(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hvictl; + return RISCV_EXCP_NONE; +} + +static int write_hvictl(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hvictl = val & HVICTL_VALID_MASK; + return RISCV_EXCP_NONE; +} + +static int read_hvipriox(CPURISCVState *env, int first_index, + uint8_t *iprio, target_ulong *val) +{ + int i, irq, rdzero, num_irqs = 4 * (riscv_cpu_mxl_bits(env) / 32); + + /* First index has to be a multiple of number of irqs per register */ + if (first_index % num_irqs) { + return (riscv_cpu_virt_enabled(env)) ? + RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; + } + + /* Fill-up return value */ + *val = 0; + for (i = 0; i < num_irqs; i++) { + if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) { + continue; + } + if (rdzero) { + continue; + } + *val |= ((target_ulong)iprio[irq]) << (i * 8); + } + + return RISCV_EXCP_NONE; +} + +static int write_hvipriox(CPURISCVState *env, int first_index, + uint8_t *iprio, target_ulong val) +{ + int i, irq, rdzero, num_irqs = 4 * (riscv_cpu_mxl_bits(env) / 32); + + /* First index has to be a multiple of number of irqs per register */ + if (first_index % num_irqs) { + return (riscv_cpu_virt_enabled(env)) ? + RISCV_EXCP_VIRT_INSTRUCTION_FAULT : RISCV_EXCP_ILLEGAL_INST; + } + + /* Fill-up priority arrary */ + for (i = 0; i < num_irqs; i++) { + if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) { + continue; + } + if (rdzero) { + iprio[irq] = 0; + } else { + iprio[irq] = (val >> (i * 8)) & 0xff; + } + } + + return RISCV_EXCP_NONE; +} + +static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val) +{ + return read_hvipriox(env, 0, env->hviprio, val); +} + +static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val) +{ + return write_hvipriox(env, 0, env->hviprio, val); +} + +static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val) +{ + return read_hvipriox(env, 4, env->hviprio, val); +} + +static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val) +{ + return write_hvipriox(env, 4, env->hviprio, val); +} + +static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val) +{ + return read_hvipriox(env, 8, env->hviprio, val); +} + +static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val) +{ + return write_hvipriox(env, 8, env->hviprio, val); +} + +static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val) +{ + return read_hvipriox(env, 12, env->hviprio, val); +} + +static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val) +{ + return write_hvipriox(env, 12, env->hviprio, val); +} + /* Virtual CSR Registers */ static RISCVException read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val) @@ -2103,9 +3089,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { read_mstatus_i128 }, [CSR_MISA] = { "misa", any, read_misa, write_misa, NULL, read_misa_i128 }, - [CSR_MIDELEG] = { "mideleg", any, read_mideleg, write_mideleg }, + [CSR_MIDELEG] = { "mideleg", any, NULL, NULL, rmw_mideleg }, [CSR_MEDELEG] = { "medeleg", any, read_medeleg, write_medeleg }, - [CSR_MIE] = { "mie", any, read_mie, write_mie }, + [CSR_MIE] = { "mie", any, NULL, NULL, rmw_mie }, [CSR_MTVEC] = { "mtvec", any, read_mtvec, write_mtvec }, [CSR_MCOUNTEREN] = { "mcounteren", any, read_mcounteren, write_mcounteren }, @@ -2119,10 +3105,35 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MTVAL] = { "mtval", any, read_mtval, write_mtval }, [CSR_MIP] = { "mip", any, NULL, NULL, rmw_mip }, + /* Machine-Level Window to Indirectly Accessed Registers (AIA) */ + [CSR_MISELECT] = { "miselect", aia_any, NULL, NULL, rmw_xiselect }, + [CSR_MIREG] = { "mireg", aia_any, NULL, NULL, rmw_xireg }, + + /* Machine-Level Interrupts (AIA) */ + [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi }, + + /* Machine-Level IMSIC Interface (AIA) */ + [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, NULL, NULL, rmw_xsetclreinum }, + [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, NULL, NULL, rmw_xsetclreinum }, + [CSR_MSETEIENUM] = { "mseteienum", aia_any, NULL, NULL, rmw_xsetclreinum }, + [CSR_MCLREIENUM] = { "mclreienum", aia_any, NULL, NULL, rmw_xsetclreinum }, + [CSR_MTOPEI] = { "mtopei", aia_any, NULL, NULL, rmw_xtopei }, + + /* Virtual Interrupts for Supervisor Level (AIA) */ + [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore }, + [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore }, + + /* Machine-Level High-Half CSRs (AIA) */ + [CSR_MIDELEGH] = { "midelegh", aia_any32, NULL, NULL, rmw_midelegh }, + [CSR_MIEH] = { "mieh", aia_any32, NULL, NULL, rmw_mieh }, + [CSR_MVIENH] = { "mvienh", aia_any32, read_zero, write_ignore }, + [CSR_MVIPH] = { "mviph", aia_any32, read_zero, write_ignore }, + [CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph }, + /* Supervisor Trap Setup */ [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus, NULL, read_sstatus_i128 }, - [CSR_SIE] = { "sie", smode, read_sie, write_sie }, + [CSR_SIE] = { "sie", smode, NULL, NULL, rmw_sie }, [CSR_STVEC] = { "stvec", smode, read_stvec, write_stvec }, [CSR_SCOUNTEREN] = { "scounteren", smode, read_scounteren, write_scounteren }, @@ -2137,24 +3148,42 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { /* Supervisor Protection and Translation */ [CSR_SATP] = { "satp", smode, read_satp, write_satp }, + /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */ + [CSR_SISELECT] = { "siselect", aia_smode, NULL, NULL, rmw_xiselect }, + [CSR_SIREG] = { "sireg", aia_smode, NULL, NULL, rmw_xireg }, + + /* Supervisor-Level Interrupts (AIA) */ + [CSR_STOPI] = { "stopi", aia_smode, read_stopi }, + + /* Supervisor-Level IMSIC Interface (AIA) */ + [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, NULL, NULL, rmw_xsetclreinum }, + [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, NULL, NULL, rmw_xsetclreinum }, + [CSR_SSETEIENUM] = { "sseteienum", aia_smode, NULL, NULL, rmw_xsetclreinum }, + [CSR_SCLREIENUM] = { "sclreienum", aia_smode, NULL, NULL, rmw_xsetclreinum }, + [CSR_STOPEI] = { "stopei", aia_smode, NULL, NULL, rmw_xtopei }, + + /* Supervisor-Level High-Half CSRs (AIA) */ + [CSR_SIEH] = { "sieh", aia_smode32, NULL, NULL, rmw_sieh }, + [CSR_SIPH] = { "siph", aia_smode32, NULL, NULL, rmw_siph }, + [CSR_HSTATUS] = { "hstatus", hmode, read_hstatus, write_hstatus }, [CSR_HEDELEG] = { "hedeleg", hmode, read_hedeleg, write_hedeleg }, - [CSR_HIDELEG] = { "hideleg", hmode, read_hideleg, write_hideleg }, + [CSR_HIDELEG] = { "hideleg", hmode, NULL, NULL, rmw_hideleg }, [CSR_HVIP] = { "hvip", hmode, NULL, NULL, rmw_hvip }, [CSR_HIP] = { "hip", hmode, NULL, NULL, rmw_hip }, - [CSR_HIE] = { "hie", hmode, read_hie, write_hie }, + [CSR_HIE] = { "hie", hmode, NULL, NULL, rmw_hie }, [CSR_HCOUNTEREN] = { "hcounteren", hmode, read_hcounteren, write_hcounteren }, - [CSR_HGEIE] = { "hgeie", hmode, read_zero, write_hgeie }, + [CSR_HGEIE] = { "hgeie", hmode, read_hgeie, write_hgeie }, [CSR_HTVAL] = { "htval", hmode, read_htval, write_htval }, [CSR_HTINST] = { "htinst", hmode, read_htinst, write_htinst }, - [CSR_HGEIP] = { "hgeip", hmode, read_zero, write_hgeip }, + [CSR_HGEIP] = { "hgeip", hmode, read_hgeip, NULL }, [CSR_HGATP] = { "hgatp", hmode, read_hgatp, write_hgatp }, [CSR_HTIMEDELTA] = { "htimedelta", hmode, read_htimedelta, write_htimedelta }, [CSR_HTIMEDELTAH] = { "htimedeltah", hmode32, read_htimedeltah, write_htimedeltah }, [CSR_VSSTATUS] = { "vsstatus", hmode, read_vsstatus, write_vsstatus }, [CSR_VSIP] = { "vsip", hmode, NULL, NULL, rmw_vsip }, - [CSR_VSIE] = { "vsie", hmode, read_vsie, write_vsie }, + [CSR_VSIE] = { "vsie", hmode, NULL, NULL, rmw_vsie }, [CSR_VSTVEC] = { "vstvec", hmode, read_vstvec, write_vstvec }, [CSR_VSSCRATCH] = { "vsscratch", hmode, read_vsscratch, write_vsscratch }, [CSR_VSEPC] = { "vsepc", hmode, read_vsepc, write_vsepc }, @@ -2165,6 +3194,37 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MTVAL2] = { "mtval2", hmode, read_mtval2, write_mtval2 }, [CSR_MTINST] = { "mtinst", hmode, read_mtinst, write_mtinst }, + /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */ + [CSR_HVIEN] = { "hvien", aia_hmode, read_zero, write_ignore }, + [CSR_HVICTL] = { "hvictl", aia_hmode, read_hvictl, write_hvictl }, + [CSR_HVIPRIO1] = { "hviprio1", aia_hmode, read_hviprio1, write_hviprio1 }, + [CSR_HVIPRIO2] = { "hviprio2", aia_hmode, read_hviprio2, write_hviprio2 }, + + /* + * VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) + */ + [CSR_VSISELECT] = { "vsiselect", aia_hmode, NULL, NULL, rmw_xiselect }, + [CSR_VSIREG] = { "vsireg", aia_hmode, NULL, NULL, rmw_xireg }, + + /* VS-Level Interrupts (H-extension with AIA) */ + [CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi }, + + /* VS-Level IMSIC Interface (H-extension with AIA) */ + [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, + [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, + [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, + [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, NULL, NULL, rmw_xsetclreinum }, + [CSR_VSTOPEI] = { "vstopei", aia_hmode, NULL, NULL, rmw_xtopei }, + + /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ + [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, NULL, NULL, rmw_hidelegh }, + [CSR_HVIENH] = { "hvienh", aia_hmode32, read_zero, write_ignore }, + [CSR_HVIPH] = { "hviph", aia_hmode32, NULL, NULL, rmw_hviph }, + [CSR_HVIPRIO1H] = { "hviprio1h", aia_hmode32, read_hviprio1h, write_hviprio1h }, + [CSR_HVIPRIO2H] = { "hviprio2h", aia_hmode32, read_hviprio2h, write_hviprio2h }, + [CSR_VSIEH] = { "vsieh", aia_hmode32, NULL, NULL, rmw_vsieh }, + [CSR_VSIPH] = { "vsiph", aia_hmode32, NULL, NULL, rmw_vsiph }, + /* Physical Memory Protection */ [CSR_MSECCFG] = { "mseccfg", epmp, read_mseccfg, write_mseccfg }, [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg }, |