Message ID | 20211230123539.52786-14-anup@brainfault.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | QEMU RISC-V AIA support | expand |
Anup Patel <anup@brainfault.org> 於 2021年12月30日 週四 下午8:47寫道: > From: Anup Patel <anup.patel@wdc.com> > > The AIA specification introduces new [m|s|vs]topi CSRs for > reporting pending local IRQ number and associated IRQ priority. > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > Signed-off-by: Anup Patel <anup@brainfault.org> > --- > target/riscv/csr.c | 156 +++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 156 insertions(+) > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > index 55e747fbf7..5a27c3bfbb 100644 > --- a/target/riscv/csr.c > +++ b/target/riscv/csr.c > @@ -190,6 +190,15 @@ static int smode32(CPURISCVState *env, int csrno) > 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)) { > @@ -502,6 +511,8 @@ static RISCVException read_timeh(CPURISCVState *env, > int csrno, > #define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)) > #define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS)) > > +#define VSTOPI_NUM_SRCS 5 > Nit: VSTOPI_NUM_SRCS can be reduced to 2 as AIA spec says: The list of candidate interrupts can be reduced to two finalists relatively. But it's fine to keep it to 5 if you think it has better readability. > + > static const uint64_t delegable_ints = S_MODE_INTERRUPTS | > VS_MODE_INTERRUPTS; > static const uint64_t vs_delegable_ints = VS_MODE_INTERRUPTS; > @@ -862,6 +873,28 @@ static RISCVException rmw_mieh(CPURISCVState *env, > int csrno, > 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 read_mtvec(CPURISCVState *env, int csrno, > target_ulong *val) > { > @@ -1391,6 +1424,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) > @@ -2389,6 +2536,9 @@ 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 Interrupts (AIA) */ > + [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi }, > + > /* Virtual Interrupts for Supervisor Level (AIA) */ > [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore }, > [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore }, > @@ -2416,6 +2566,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { > /* Supervisor Protection and Translation */ > [CSR_SATP] = { "satp", smode, read_satp, write_satp }, > > + /* Supervisor-Level Interrupts (AIA) */ > + [CSR_STOPI] = { "stopi", aia_smode, read_stopi }, > + > /* Supervisor-Level High-Half CSRs (AIA) */ > [CSR_SIEH] = { "sieh", aia_smode32, NULL, NULL, rmw_sieh }, > [CSR_SIPH] = { "siph", aia_smode32, NULL, NULL, rmw_siph }, > @@ -2454,6 +2607,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { > [CSR_HVIPRIO1] = { "hviprio1", aia_hmode, read_hviprio1, > write_hviprio1 }, > [CSR_HVIPRIO2] = { "hviprio2", aia_hmode, read_hviprio2, > write_hviprio2 }, > > + /* VS-Level Interrupts (H-extension with AIA) */ > + [CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi }, > + > /* 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 }, > -- > 2.25.1 > > > Reviewed-by: Frank Chang <frank.chang@sifive.com>
On Wed, Jan 12, 2022 at 5:46 PM Frank Chang <frank.chang@sifive.com> wrote: > > Anup Patel <anup@brainfault.org> 於 2021年12月30日 週四 下午8:47寫道: >> >> From: Anup Patel <anup.patel@wdc.com> >> >> The AIA specification introduces new [m|s|vs]topi CSRs for >> reporting pending local IRQ number and associated IRQ priority. >> >> Signed-off-by: Anup Patel <anup.patel@wdc.com> >> Signed-off-by: Anup Patel <anup@brainfault.org> >> --- >> target/riscv/csr.c | 156 +++++++++++++++++++++++++++++++++++++++++++++ >> 1 file changed, 156 insertions(+) >> >> diff --git a/target/riscv/csr.c b/target/riscv/csr.c >> index 55e747fbf7..5a27c3bfbb 100644 >> --- a/target/riscv/csr.c >> +++ b/target/riscv/csr.c >> @@ -190,6 +190,15 @@ static int smode32(CPURISCVState *env, int csrno) >> 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)) { >> @@ -502,6 +511,8 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno, >> #define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)) >> #define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS)) >> >> +#define VSTOPI_NUM_SRCS 5 > > > Nit: > VSTOPI_NUM_SRCS can be reduced to 2 as AIA spec says: > The list of candidate interrupts can be reduced to two finalists relatively. > But it's fine to keep it to 5 if you think it has better readability. Let's keep is 5 for now. This is little high to ensure that we don't run out space in the candidate array. Regards, Anup > >> >> + >> static const uint64_t delegable_ints = S_MODE_INTERRUPTS | >> VS_MODE_INTERRUPTS; >> static const uint64_t vs_delegable_ints = VS_MODE_INTERRUPTS; >> @@ -862,6 +873,28 @@ static RISCVException rmw_mieh(CPURISCVState *env, int csrno, >> 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 read_mtvec(CPURISCVState *env, int csrno, >> target_ulong *val) >> { >> @@ -1391,6 +1424,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) >> @@ -2389,6 +2536,9 @@ 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 Interrupts (AIA) */ >> + [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi }, >> + >> /* Virtual Interrupts for Supervisor Level (AIA) */ >> [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore }, >> [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore }, >> @@ -2416,6 +2566,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { >> /* Supervisor Protection and Translation */ >> [CSR_SATP] = { "satp", smode, read_satp, write_satp }, >> >> + /* Supervisor-Level Interrupts (AIA) */ >> + [CSR_STOPI] = { "stopi", aia_smode, read_stopi }, >> + >> /* Supervisor-Level High-Half CSRs (AIA) */ >> [CSR_SIEH] = { "sieh", aia_smode32, NULL, NULL, rmw_sieh }, >> [CSR_SIPH] = { "siph", aia_smode32, NULL, NULL, rmw_siph }, >> @@ -2454,6 +2607,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { >> [CSR_HVIPRIO1] = { "hviprio1", aia_hmode, read_hviprio1, write_hviprio1 }, >> [CSR_HVIPRIO2] = { "hviprio2", aia_hmode, read_hviprio2, write_hviprio2 }, >> >> + /* VS-Level Interrupts (H-extension with AIA) */ >> + [CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi }, >> + >> /* 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 }, >> -- >> 2.25.1 >> >> > > Reviewed-by: Frank Chang <frank.chang@sifive.com>
diff --git a/target/riscv/csr.c b/target/riscv/csr.c index 55e747fbf7..5a27c3bfbb 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -190,6 +190,15 @@ static int smode32(CPURISCVState *env, int csrno) 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)) { @@ -502,6 +511,8 @@ static RISCVException read_timeh(CPURISCVState *env, int csrno, #define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)) #define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS)) +#define VSTOPI_NUM_SRCS 5 + static const uint64_t delegable_ints = S_MODE_INTERRUPTS | VS_MODE_INTERRUPTS; static const uint64_t vs_delegable_ints = VS_MODE_INTERRUPTS; @@ -862,6 +873,28 @@ static RISCVException rmw_mieh(CPURISCVState *env, int csrno, 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 read_mtvec(CPURISCVState *env, int csrno, target_ulong *val) { @@ -1391,6 +1424,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) @@ -2389,6 +2536,9 @@ 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 Interrupts (AIA) */ + [CSR_MTOPI] = { "mtopi", aia_any, read_mtopi }, + /* Virtual Interrupts for Supervisor Level (AIA) */ [CSR_MVIEN] = { "mvien", aia_any, read_zero, write_ignore }, [CSR_MVIP] = { "mvip", aia_any, read_zero, write_ignore }, @@ -2416,6 +2566,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { /* Supervisor Protection and Translation */ [CSR_SATP] = { "satp", smode, read_satp, write_satp }, + /* Supervisor-Level Interrupts (AIA) */ + [CSR_STOPI] = { "stopi", aia_smode, read_stopi }, + /* Supervisor-Level High-Half CSRs (AIA) */ [CSR_SIEH] = { "sieh", aia_smode32, NULL, NULL, rmw_sieh }, [CSR_SIPH] = { "siph", aia_smode32, NULL, NULL, rmw_siph }, @@ -2454,6 +2607,9 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_HVIPRIO1] = { "hviprio1", aia_hmode, read_hviprio1, write_hviprio1 }, [CSR_HVIPRIO2] = { "hviprio2", aia_hmode, read_hviprio2, write_hviprio2 }, + /* VS-Level Interrupts (H-extension with AIA) */ + [CSR_VSTOPI] = { "vstopi", aia_hmode, read_vstopi }, + /* 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 },