Message ID | 20210514143242.377645-4-anup.patel@wdc.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | AIA local interrupt CSR support | expand |
On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote: > > We implement various AIA local interrupt CSRs for M-mode, HS-mode, > and VS-mode. > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > --- > target/riscv/cpu.c | 27 +- > target/riscv/cpu.h | 52 +- > target/riscv/cpu_helper.c | 245 ++++++++- > target/riscv/csr.c | 1059 +++++++++++++++++++++++++++++++++++-- > target/riscv/machine.c | 26 +- > 5 files changed, 1309 insertions(+), 100 deletions(-) I feel this patch could be split up more :) > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > index f3702111ae..795162834b 100644 > --- a/target/riscv/cpu.c > +++ b/target/riscv/cpu.c > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ", > (target_ulong)env->vsstatus); > } > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", env->mip); > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip ", env->mip); > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie ", env->mie); > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg); > if (riscv_has_ext(env, RVH)) { > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg); > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg); > } > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); > if (riscv_has_ext(env, RVH)) { > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, > > static void riscv_cpu_reset(DeviceState *dev) > { > + uint8_t iprio; > + int i, irq, rdzero; > CPUState *cs = CPU(dev); > RISCVCPU *cpu = RISCV_CPU(cs); > RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev) > env->mcause = 0; > env->pc = env->resetvec; > env->two_stage_lookup = false; > + > + /* Initialized default priorities of local interrupts. */ > + for (i = 0; i < ARRAY_SIZE(env->miprio); i++) { > + iprio = riscv_cpu_default_priority(i); > + env->miprio[i] = iprio; > + env->siprio[i] = iprio; > + env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO; > + } > + i = 0; > + while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) { > + if (rdzero) { > + env->hviprio[irq] = 0; > + } else { > + env->hviprio[irq] = env->miprio[irq]; > + } > + i++; > + } > #endif > cs->exception_index = EXCP_NONE; > env->load_res = -1; > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > index f00c60c840..780d3f9058 100644 > --- a/target/riscv/cpu.h > +++ b/target/riscv/cpu.h > @@ -157,12 +157,12 @@ struct CPURISCVState { > */ > uint64_t mstatus; > > - target_ulong mip; > + uint64_t mip; This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume all the other existing target_ulong CSRs are the same. Alistair > > - uint32_t miclaim; > + uint64_t miclaim; > > - target_ulong mie; > - target_ulong mideleg; > + uint64_t mie; > + uint64_t mideleg; > > target_ulong sptbr; /* until: priv-1.9.1 */ > target_ulong satp; /* since: priv-1.10.0 */ > @@ -179,16 +179,27 @@ struct CPURISCVState { > target_ulong mcause; > target_ulong mtval; /* since: priv-1.10.0 */ > > + /* AIA CSRs */ > + target_ulong miselect; > + target_ulong siselect; > + > + uint8_t miprio[64]; > + uint8_t siprio[64]; > + > /* Hypervisor CSRs */ > target_ulong hstatus; > target_ulong hedeleg; > - target_ulong hideleg; > + uint64_t hideleg; > target_ulong hcounteren; > target_ulong htval; > target_ulong htinst; > target_ulong hgatp; > uint64_t htimedelta; > > + /* AIA HS-mode CSRs */ > + uint8_t hviprio[64]; > + target_ulong hvicontrol; > + > /* Virtual CSRs */ > /* > * For RV32 this is 32-bit vsstatus and 32-bit vsstatush. > @@ -202,6 +213,9 @@ struct CPURISCVState { > target_ulong vstval; > target_ulong vsatp; > > + /* AIA VS-mode CSRs */ > + target_ulong vsiselect; > + > target_ulong mtval2; > target_ulong mtinst; > > @@ -236,6 +250,18 @@ struct CPURISCVState { > uint64_t (*rdtime_fn)(uint32_t); > uint32_t rdtime_fn_arg; > > + /* machine specific AIA IMSIC read-modify-write callback */ > +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \ > + ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \ > + (((__priv) & 0x3) << 16) | (__isel & 0xffff)) > +#define IMSIC_REG_ISEL(__reg) ((__reg) & 0xffff) > +#define IMSIC_REG_PRIV(__reg) (((__reg) >> 16) & 0x3) > +#define IMSIC_REG_VIRT(__reg) (((__reg) >> 20) & 0x1) > +#define IMSIC_REG_VGEIN(__reg) (((__reg) >> 24) & 0x3f) > + int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val, > + target_ulong new_val, target_ulong write_mask); > + void *imsic_rmw_fn_arg; > + > /* True if in debugger mode. */ > bool debugger; > #endif > @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, > int cpuid, void *opaque); > int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); > int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero); > +uint8_t riscv_cpu_default_priority(int irq); > +int riscv_cpu_mirq_pending(CPURISCVState *env); > +int riscv_cpu_sirq_pending(CPURISCVState *env); > +int riscv_cpu_vsirq_pending(CPURISCVState *env); > bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request); > bool riscv_cpu_fp_enabled(CPURISCVState *env); > bool riscv_cpu_virt_enabled(CPURISCVState *env); > @@ -364,9 +395,16 @@ void riscv_cpu_list(void); > > #ifndef CONFIG_USER_ONLY > void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env); > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value); > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts); > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value); > #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env, > + int (*rmw_fn)(void *arg, > + target_ulong reg, > + target_ulong *val, > + target_ulong new_val, > + target_ulong write_mask), > + void *rmw_fn_arg); > void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), > uint32_t arg); > #endif > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > index 21c54ef561..5b06b4f995 100644 > --- a/target/riscv/cpu_helper.c > +++ b/target/riscv/cpu_helper.c > @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) > } > > #ifndef CONFIG_USER_ONLY > -static int riscv_cpu_local_irq_pending(CPURISCVState *env) > + > +/* > + * The HS-mode is allowed to configure priority only for the > + * following VS-mode local interrupts: > + * > + * 0 (Reserved interrupt, reads as zero) > + * 1 Supervisor software interrupt > + * 4 (Reserved interrupt, reads as zero) > + * 5 Supervisor timer interrupt > + * 8 (Reserved interrupt, reads as zero) > + * 13 (Reserved interrupt) > + * 14 " > + * 15 " > + * 16 " > + * 18 Debug/trace interrupt > + * 20 (Reserved interrupt) > + * 22 ” > + * 24 ” > + * 26 ” > + * 28 " > + * 30 (Reserved for standard reporting of bus or system errors) > + */ > + > +static int hviprio_index2irq[] = > + { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 }; > +static int hviprio_index2rdzero[] = > + { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; > + > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero) > { > - target_ulong irqs; > + if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) { > + return -EINVAL; > + } > > - 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); > + if (out_irq) { > + *out_irq = hviprio_index2irq[index]; > + } > + > + if (out_rdzero) { > + *out_rdzero = hviprio_index2rdzero[index]; > + } > > - 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)); > + return 0; > +} > > - 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); > +uint8_t riscv_cpu_default_priority(int irq) > +{ > + int u, l; > + uint8_t iprio = IPRIO_MMAXIPRIO; > > - if (riscv_cpu_virt_enabled(env)) { > - target_ulong pending_hs_irq = pending & -hs_sie; > + if (irq < 0 || irq > 63) { > + return iprio; > + } > > - if (pending_hs_irq) { > - riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP); > - return ctz64(pending_hs_irq); > + /* > + * Default priorities of local interrupts are defined in the > + * RISC-V Advanced Interrupt Architecture specification. > + * > + * ---------------------------------------------------------------- > + * Default | > + * Priority | Major Interrupt Numbers > + * ---------------------------------------------------------------- > + * Highest | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c), > + * | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38), > + * | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34), > + * | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30) > + * | > + * | 11 (0b), 3 (03), 7 (07) > + * | 9 (09), 1 (01), 5 (05) > + * | 12 (0c) > + * | 10 (0a), 2 (02), 6 (06) > + * | > + * | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c), > + * | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28), > + * | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24), > + * Lowest | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20) > + * ---------------------------------------------------------------- > + */ > + > + u = IPRIO_DEFAULT_U(irq); > + l = IPRIO_DEFAULT_L(irq); > + if (u == 0) { > + if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER || > + irq == IRQ_VS_SOFT) { > + iprio = IPRIO_DEFAULT_VS; > + } else if (irq == IRQ_S_GEXT) { > + iprio = IPRIO_DEFAULT_SGEXT; > + } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER || > + irq == IRQ_S_SOFT) { > + iprio = IPRIO_DEFAULT_S; > + } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER || > + irq == IRQ_M_SOFT) { > + iprio = IPRIO_DEFAULT_M; > + } else { > + iprio = IPRIO_DEFAULT_VS; > } > + } else if (u == 1) { > + if (l < 8) { > + iprio = IPRIO_DEFAULT_16_23(irq); > + } else { > + iprio = IPRIO_DEFAULT_24_31(irq); > + } > + } else if (u == 2) { > + iprio = IPRIO_DEFAULT_32_47(irq); > + } else if (u == 3) { > + iprio = IPRIO_DEFAULT_48_63(irq); > + } > + > + return iprio; > +} > + > +static int riscv_cpu_pending_to_irq(CPURISCVState *env, > + uint64_t pending, uint8_t *iprio) > +{ > + int irq, best_irq = EXCP_NONE; > + unsigned int prio, best_prio = UINT_MAX; > > - pending = vspending; > + if (!pending) { > + return EXCP_NONE; > } > > - irqs = (pending & ~env->mideleg & -mie) | (pending & env->mideleg & -sie); > + irq = ctz64(pending); > + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { > + return irq; > + } > > - if (irqs) { > - return ctz64(irqs); /* since non-zero */ > + pending = pending >> irq; > + while (pending) { > + prio = iprio[irq]; > + if (!prio) { > + prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ? > + 1 : IPRIO_MMAXIPRIO; > + } > + if ((pending & 0x1) && (prio < best_prio)) { > + best_irq = irq; > + best_prio = prio; > + } > + irq++; > + pending = pending >> 1; > + } > + > + return best_irq; > +} > + > +int riscv_cpu_mirq_pending(CPURISCVState *env) > +{ > + uint64_t irqs = env->mip & env->mie & ~env->mideleg & > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > + > + return riscv_cpu_pending_to_irq(env, irqs, env->miprio); > +} > + > +int riscv_cpu_sirq_pending(CPURISCVState *env) > +{ > + uint64_t irqs = env->mip & env->mie & env->mideleg & > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > + > + return riscv_cpu_pending_to_irq(env, irqs, env->siprio); > +} > + > +int riscv_cpu_vsirq_pending(CPURISCVState *env) > +{ > + uint64_t irqs = env->mip & env->mie & env->mideleg & > + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > + > + return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio); > +} > + > +static int riscv_cpu_local_irq_pending(CPURISCVState *env) > +{ > + int virq; > + uint64_t irqs, mie, sie, vsie; > + uint64_t pending, vspending; > + > + /* Determine interrupt enable state of all privilege modes */ > + if (riscv_cpu_virt_enabled(env)) { > + mie = 1; > + sie = 1; > + vsie = (env->priv < PRV_S) || > + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE)); > } else { > - return EXCP_NONE; /* indicates no pending interrupt */ > + mie = (env->priv < PRV_M) || > + (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE)); > + sie = (env->priv < PRV_S) || > + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE)); > + vsie = 0; > + } > + > + /* Check M-mode interrupts */ > + pending = env->mip & env->mie & > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > + irqs = pending & ~env->mideleg & -mie; > + if (irqs) { > + return riscv_cpu_pending_to_irq(env, irqs, env->miprio); > + } > + > + /* Check HS-mode interrupts */ > + irqs = pending & env->mideleg & -sie; > + if (irqs) { > + return riscv_cpu_pending_to_irq(env, irqs, env->siprio); > + } > + > + /* Check VS-mode interrupts */ > + vspending = env->mip & env->mie & > + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > + irqs = vspending & env->hideleg & -vsie; > + if (irqs) { > + virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio); > + return (virq <= 0) ? virq : virq + 1; > } > + > + /* Indicates no pending interrupt */ > + return EXCP_NONE; > } > #endif > > @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx) > return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK; > } > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts) > { > CPURISCVState *env = &cpu->env; > if (env->miclaim & interrupts) { > @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) > } > } > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) > { > CPURISCVState *env = &cpu->env; > CPUState *cs = CPU(cpu); > - uint32_t old = env->mip; > + uint64_t old = env->mip; > bool locked = false; > > if (!qemu_mutex_iothread_locked()) { > @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) > return old; > } > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env, > + int (*rmw_fn)(void *arg, > + target_ulong reg, > + target_ulong *val, > + target_ulong new_val, > + target_ulong write_mask), > + void *rmw_fn_arg) > +{ > + env->imsic_rmw_fn = rmw_fn; > + env->imsic_rmw_fn_arg = rmw_fn_arg; > +} > + > void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), > uint32_t arg) > { > @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > */ > bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG); > target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK; > - target_ulong deleg = async ? env->mideleg : env->medeleg; > + uint64_t deleg = async ? env->mideleg : env->medeleg; > bool write_tval = false; > target_ulong tval = 0; > target_ulong htval = 0; > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > index d2585395bf..3c016d7452 100644 > --- a/target/riscv/csr.c > +++ b/target/riscv/csr.c > @@ -153,11 +153,56 @@ static int 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 int smode(CPURISCVState *env, int csrno) > { > return -!riscv_has_ext(env, RVS); > } > > +static int smode32(CPURISCVState *env, int csrno) > +{ > + if (!riscv_cpu_is_32bit(env)) { > + 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 int hmode(CPURISCVState *env, int csrno) > { > if (riscv_has_ext(env, RVS) && > @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno) > static int hmode32(CPURISCVState *env, int csrno) > { > if (!riscv_cpu_is_32bit(env)) { > - return 0; > + return -RISCV_EXCP_ILLEGAL_INST; > + } > + > + return hmode(env, csrno); > +} > + > +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 int pmp(CPURISCVState *env, int csrno) > @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) > > /* 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 TLOWBITS64 ((uint64_t)((target_ulong)-1)) > > -static const target_ulong delegable_ints = S_MODE_INTERRUPTS | > - VS_MODE_INTERRUPTS; > -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | > - VS_MODE_INTERRUPTS; > +static const uint64_t delegable_ints = S_MODE_INTERRUPTS | > + VS_MODE_INTERRUPTS; > +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | > + VS_MODE_INTERRUPTS; > static const target_ulong delegable_excps = > (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | > (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | > @@ -419,10 +483,10 @@ static const target_ulong delegable_excps = > static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | > SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | > SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD; > -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; > -static const target_ulong hip_writable_mask = MIP_VSSIP; > -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; > -static const target_ulong vsip_writable_mask = MIP_VSSIP; > +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; > +static const uint64_t hip_writable_mask = MIP_VSSIP; > +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; > +static const uint64_t vsip_writable_mask = MIP_VSSIP; > > static const char valid_vm_1_10_32[16] = { > [VM_1_10_MBARE] = 1, > @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val) > > static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val) > { > - env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints); > + uint64_t mask = delegable_ints & TLOWBITS64; > + > + env->mideleg = (env->mideleg & ~mask) | (val & mask); > + if (riscv_has_ext(env, RVH)) { > + env->mideleg |= VS_MODE_INTERRUPTS; > + } > + return 0; > +} > + > +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_STOPI: > + return CSR_VSTOPI; > + case CSR_SSETEIPNUM: > + return CSR_VSSETEIPNUM; > + case CSR_SCLREIPNUM: > + return CSR_VSCLREIPNUM; > + case CSR_SSETEIENUM: > + return CSR_VSSETEIENUM; > + case CSR_SCLREIENUM: > + return CSR_VSCLREIENUM; > + default: > + return csrno; > + }; > +} > + > +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val, > + target_ulong new_val, target_ulong write_mask) > +{ > + target_ulong *iselect; > + > + switch (csrno) { > + case CSR_MISELECT: > + iselect = &env->miselect; > + break; > + case CSR_SISELECT: > + iselect = riscv_cpu_virt_enabled(env) ? > + &env->vsiselect : &env->siselect; > + break; > + case CSR_VSISELECT: > + iselect = &env->vsiselect; > + break; > + default: > + return -RISCV_EXCP_ILLEGAL_INST; > + }; > + > + if (val) { > + *val = *iselect; > + } > + > + if (write_mask) { > + *iselect = (*iselect & ~write_mask) | (new_val & write_mask); > + } > + > + return 0; > +} > + > +static int rmw_iprio(target_ulong iselect, uint8_t *iprio, > + target_ulong *val, target_ulong new_val, > + target_ulong write_mask) > +{ > + int i, firq, nirqs; > + target_ulong old_val; > + > + if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) { > + return -EINVAL; > + } > +#if TARGET_LONG_BITS == 64 > + if (iselect & 0x1) { > + return -EINVAL; > + } > +#endif > + > + nirqs = 4 * (TARGET_LONG_BITS / 32); > + firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 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 (write_mask) { > + new_val = (old_val & ~write_mask) | (new_val & write_mask); > + for (i = 0; i < nirqs; i++) { > + 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 write_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) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > + > + if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) { > + /* Local interrupt priority registers not available for VS-mode */ > + if (!virt) { > + ret = rmw_iprio(isel, iprio, val, new_val, write_mask); > + } > + } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) { > + /* IMSIC registers only available when machine implements it. */ > + if (env->imsic_rmw_fn) { > + /* Selected guest interrupt file should not be zero */ > + if (virt && !vgein) { > + goto done; > + } > + /* Call machine specific IMSIC register emulation */ > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > + val, new_val, write_mask); > + } > + } > + > +done: > + if (ret) { > + return (riscv_cpu_virt_enabled(env) && virt) ? > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > + } > + return 0; > +} > + > +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + int irq; > + > + irq = riscv_cpu_mirq_pending(env); > + if (irq <= 0 || irq > 63) { > + *val = 0; > + } else { > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > + *val |= env->miprio[irq]; > + } > + > + return 0; > +} > + > +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + bool virt; > + int ret = -EINVAL; > + target_ulong 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_MSETEIPNUM: > + case CSR_MCLREIPNUM: > + case CSR_MSETEIENUM: > + case CSR_MCLREIENUM: > + case CSR_SSETEIPNUM: > + case CSR_SCLREIPNUM: > + case CSR_SSETEIENUM: > + case CSR_SCLREIENUM: > + break; > + case CSR_VSSETEIPNUM: > + case CSR_VSCLREIPNUM: > + case CSR_VSSETEIENUM: > + case CSR_VSCLREIENUM: > + virt = true; > + break; > + default: > + goto done; > + }; > + > + /* IMSIC CSRs only available when machine implements IMSIC. */ > + if (!env->imsic_rmw_fn) { > + goto done; > + } > + > + /* Find the selected guest interrupt file */ > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > + > + /* Selected guest interrupt file should not be zero */ > + if (virt && !vgein) { > + goto done; > + } > + > + /* Set/Clear CSRs always read zero */ > + ret = 0; > + if (val) { > + *val = 0; > + } > + > +done: > + if (ret) { > + return (riscv_cpu_virt_enabled(env) && virt) ? > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > + } > + return 0; > +} > + > +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val) > +{ > + int ret = -EINVAL; > + bool set, pend, virt; > + target_ulong priv, isel, vgein; > + target_ulong new_val, write_mask; > + > + /* 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; > + 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->imsic_rmw_fn) { > + goto done; > + } > + > + /* Find target interrupt pending/enable register */ > + if (pend) { > + isel = ISELECT_IMSIC_EIP0; > + } else { > + isel = ISELECT_IMSIC_EIE0; > + } > + isel += val / IMSIC_EIPx_BITS; > + > + /* Find the interrupt bit to be set/clear */ > + write_mask = 1 << (val % IMSIC_EIPx_BITS); > + new_val = (set) ? write_mask : 0; > + > + /* Find the selected guest interrupt file */ > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > + > + /* Selected guest interrupt file should not be zero */ > + if (virt && !vgein) { > + goto done; > + } > + > + /* Call machine specific IMSIC register emulation */ > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > + NULL, new_val, write_mask); > + > +done: > + if (ret) { > + return (riscv_cpu_virt_enabled(env) && virt) ? > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > + } > + return 0; > +} > + > +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + bool virt; > + int ret = -EINVAL; > + target_ulong priv, isel, vgein; > + target_ulong topei, write_mask; > + > + /* Decode register details from CSR number */ > + virt = false; > + switch (csrno) { > + case CSR_MCLAIMEI: > + priv = PRV_M; > + break; > + case CSR_SCLAIMEI: > + priv = PRV_S; > + virt = riscv_cpu_virt_enabled(env); > + break; > + default: > + goto done; > + }; > + > + /* IMSIC CSRs only available when machine implements IMSIC. */ > + if (!env->imsic_rmw_fn) { > + goto done; > + } > + > + /* Find the selected guest interrupt file */ > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > + > + /* Selected guest interrupt file should not be zero */ > + if (virt && !vgein) { > + goto done; > + } > + > + /* Call machine specific IMSIC register emulation for reading TOPEI */ > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > + IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein), > + &topei, -1, 0); > + if (ret) { > + goto done; > + } > + > + /* If no interrupt pending then we are done */ > + if (!topei) { > + goto done; > + } > + > + /* Find target interrupt pending register */ > + isel = ISELECT_IMSIC_EIP0; > + isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS); > + > + /* Find the interrupt bit to be cleared */ > + write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS); > + > + /* Call machine specific IMSIC register emulation to clear pending bit */ > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > + NULL, 0, write_mask); > + > + /* Update return value */ > + if (val) { > + *val = topei; > + } > + > +done: > + if (ret) { > + return (riscv_cpu_virt_enabled(env) && virt) ? > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > + } > + return 0; > +} > + > +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + *val = (env->mideleg >> 32); > + return 0; > +} > + > +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val) > +{ > + uint64_t mask = delegable_ints & ~TLOWBITS64; > + uint64_t newval = ((uint64_t)val) << 32; > + > + env->mideleg = (env->mideleg & ~mask) | (newval & mask); > if (riscv_has_ext(env, RVH)) { > env->mideleg |= VS_MODE_INTERRUPTS; > } > @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val) > > static int write_mie(CPURISCVState *env, int csrno, target_ulong val) > { > - env->mie = (env->mie & ~all_ints) | (val & all_ints); > + uint64_t mask = all_ints & TLOWBITS64; > + > + env->mie = (env->mie & ~mask) | (val & mask); > + return 0; > +} > + > +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + *val = (env->mie >> 32); > + return 0; > +} > + > +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val) > +{ > + uint64_t mask = all_ints & ~TLOWBITS64; > + uint64_t newval = ((uint64_t)val) << 32; > + > + env->mie = (env->mie & ~mask) | (newval & mask); > return 0; > } > > @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, > { > 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 mask = ((uint64_t)write_mask) & delegable_ints & > + ~env->miclaim & TLOWBITS64; > + uint64_t old_mip; > > if (mask) { > old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, > return 0; > } > > +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value, > + target_ulong new_value, target_ulong write_mask) > +{ > + RISCVCPU *cpu = env_archcpu(env); > + /* Allow software control of delegable interrupts not claimed by hardware */ > + uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints & > + ~env->miclaim & ~TLOWBITS64; > + uint64_t new_value64 = (uint64_t)new_value << 32; > + uint64_t old_mip; > + > + if (mask) { > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > + } else { > + old_mip = env->mip; > + } > + > + if (ret_value) { > + *ret_value = old_mip >> 32; > + } > + > + return 0; > +} > + > /* Supervisor Trap Setup */ > static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val) > { > @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val) > > static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val) > { > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64; > + > /* Shift the VS bits to their S bit location in vsie */ > - *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1; > + *val = (env->mie & mask) >> 1; > + return 0; > +} > + > +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64; > + > + /* Shift the VS bits to their S bit location in vsieh */ > + *val = (env->mie & mask) >> (32 + 1); > return 0; > } > > static int read_sie(CPURISCVState *env, int csrno, target_ulong *val) > { > if (riscv_cpu_virt_enabled(env)) { > - read_vsie(env, CSR_VSIE, val); > - } else { > - *val = env->mie & env->mideleg; > + if (env->hvicontrol & HVICONTROL_VTI) { > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > + } > + return read_vsie(env, CSR_VSIE, val); > } > + > + *val = env->mie & env->mideleg; > return 0; > } > > static int write_vsie(CPURISCVState *env, int csrno, target_ulong val) > { > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & > + all_ints & TLOWBITS64; > + > /* 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); > + env->mie = (env->mie & ~mask) | ((val << 1) & mask); > + > + return 0; > +} > + > +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val) > +{ > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & > + all_ints & ~TLOWBITS64; > + uint64_t newval = (uint64_t)val << 32; > + > + /* Shift the S bits to their VS bit location in mie */ > + env->mie = (env->mie & ~mask) | ((newval << 1) & mask); > + > + return 0; > } > > static int write_sie(CPURISCVState *env, int csrno, target_ulong val) > { > + uint64_t mask; > + > if (riscv_cpu_virt_enabled(env)) { > - write_vsie(env, CSR_VSIE, val); > - } else { > - target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) | > - (val & S_MODE_INTERRUPTS); > - write_mie(env, CSR_MIE, newval); > + if (env->hvicontrol & HVICONTROL_VTI) { > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > + } > + return write_vsie(env, CSR_VSIE, val); > + } > + > + mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64; > + env->mie = (env->mie & ~mask) | ((uint64_t)val & mask); > + > + return 0; > +} > + > +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + if (riscv_cpu_virt_enabled(env)) { > + if (env->hvicontrol & HVICONTROL_VTI) { > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > + } > + return read_vsieh(env, CSR_VSIEH, val); > + } > + > + *val = ((env->mie & env->mideleg) >> 32); > + return 0; > +} > + > +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val) > +{ > + uint64_t mask, newval; > + > + if (riscv_cpu_virt_enabled(env)) { > + if (env->hvicontrol & HVICONTROL_VTI) { > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > + } > + return write_vsieh(env, CSR_VSIEH, val); > } > > + mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64; > + newval = (uint64_t)val << 32; > + > + env->mie = (env->mie & ~mask) | (newval & mask); > return 0; > } > > @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val) > static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, > target_ulong new_value, target_ulong write_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); > - *ret_value &= VS_MODE_INTERRUPTS; > - /* Shift the VS bits to their S bit location in vsip */ > - *ret_value >>= 1; > - return ret; > + RISCVCPU *cpu = env_archcpu(env); > + /* Allow software control of delegable interrupts not claimed by hardware */ > + uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints & > + vsip_writable_mask & env->hideleg & > + ~env->miclaim & TLOWBITS64; > + uint64_t old_mip; > + > + if (mask) { > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > + } else { > + old_mip = env->mip; > + } > + > + if (ret_value) { > + *ret_value = old_mip & VS_MODE_INTERRUPTS; > + } > + > + return 0; > +} > + > +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value, > + target_ulong new_value, target_ulong write_mask) > +{ > + RISCVCPU *cpu = env_archcpu(env); > + /* Allow software control of delegable interrupts not claimed by hardware */ > + uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints & > + vsip_writable_mask & env->hideleg & > + ~env->miclaim & ~TLOWBITS64; > + uint64_t new_value64 = (uint64_t)new_value << 32; > + uint64_t old_mip; > + > + if (mask) { > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > + } else { > + old_mip = env->mip; > + } > + > + if (ret_value) { > + *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32; > + } > + > + return 0; > } > > static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, > target_ulong new_value, target_ulong write_mask) > { > - int ret; > + RISCVCPU *cpu = env_archcpu(env); > + uint64_t mask, old_mip; > > if (riscv_cpu_virt_enabled(env)) { > - ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); > + if (env->hvicontrol & HVICONTROL_VTI) { > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > + } > + return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); > + } > + > + /* Allow software control of delegable interrupts not claimed by hardware */ > + mask = ((uint64_t)write_mask) & delegable_ints & > + env->mideleg & sip_writable_mask & > + ~env->miclaim & TLOWBITS64; > + if (mask) { > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > } else { > - ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, > - write_mask & env->mideleg & sip_writable_mask); > + old_mip = env->mip; > } > > - *ret_value &= env->mideleg; > - return ret; > + if (ret_value) { > + *ret_value = old_mip; > + } > + > + return 0; > +} > + > +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value, > + target_ulong new_value, target_ulong write_mask) > +{ > + RISCVCPU *cpu = env_archcpu(env); > + uint64_t mask, new_value64; > + uint64_t old_mip; > + > + if (riscv_cpu_virt_enabled(env)) { > + if (env->hvicontrol & HVICONTROL_VTI) { > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > + } > + return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask); > + } > + > + /* Allow software control of delegable interrupts not claimed by hardware */ > + mask = ((uint64_t)write_mask << 32) & delegable_ints & > + env->mideleg & sip_writable_mask & > + ~env->miclaim & ~TLOWBITS64; > + new_value64 = (uint64_t)new_value << 32; > + if (mask) { > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > + } else { > + old_mip = env->mip; > + } > + > + if (ret_value) { > + *ret_value = (old_mip & env->mideleg) >> 32; > + } > + > + return 0; > } > > /* Supervisor Protection and Translation */ > @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) > return 0; > } > > +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + int irq, hiid; > + uint8_t hiprio, iprio; > + > + irq = riscv_cpu_vsirq_pending(env); > + if (irq <= 0 || irq > 63) { > + *val = 0; > + } else { > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > + iprio = env->hviprio[irq]; > + /* TODO: This needs to improve in specification */ > + if (!(env->hstatus & HSTATUS_VGEIN)) { > + hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >> > + HVICONTROL_IID_SHIFT; > + hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK; > + if (irq == hiid && hiprio) { > + iprio = hiprio; > + } > + } > + *val |= iprio; > + } > + > + return 0; > +} > + > +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + int irq; > + > + 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 { > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > + *val |= env->siprio[irq]; > + } > + > + return 0; > +} > + > /* Hypervisor Extensions */ > static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) > { > @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val) > return 0; > } > > +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + *val = env->hideleg >> 32; > + return 0; > +} > + > +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val) > +{ > + uint64_t mask = ~TLOWBITS64; > + uint64_t newval = ((uint64_t)val) << 32; > + > + env->hideleg = (env->hideleg & ~mask) | (newval & mask); > + > + return 0; > +} > + > static int rmw_hvip(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, > - write_mask & hvip_writable_mask); > + RISCVCPU *cpu = env_archcpu(env); > + /* Allow software control of delegable interrupts not claimed by hardware */ > + uint64_t mask = ((uint64_t)write_mask) & delegable_ints & > + hvip_writable_mask & > + ~env->miclaim & TLOWBITS64; > + uint64_t old_mip; > + > + if (mask) { > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > + } else { > + old_mip = env->mip; > + } > > - *ret_value &= hvip_writable_mask; > + if (ret_value) { > + *ret_value = old_mip & hvip_writable_mask; > + } > > - return ret; > + return 0; > +} > + > +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value, > + target_ulong new_value, target_ulong write_mask) > +{ > + RISCVCPU *cpu = env_archcpu(env); > + /* Allow software control of delegable interrupts not claimed by hardware */ > + uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints & > + hvip_writable_mask & > + ~env->miclaim & ~TLOWBITS64; > + uint64_t new_value64 = (uint64_t)new_value << 32; > + uint64_t old_mip; > + > + if (mask) { > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > + } else { > + old_mip = env->mip; > + } > + > + if (ret_value) { > + *ret_value = (old_mip & hvip_writable_mask) >> 32; > + } > + > + return 0; > } > > static int 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, > - write_mask & hip_writable_mask); > + RISCVCPU *cpu = env_archcpu(env); > + /* Allow software control of delegable interrupts not claimed by hardware */ > + uint64_t mask = ((uint64_t)write_mask) & delegable_ints & > + hip_writable_mask & > + ~env->miclaim & TLOWBITS64; > + uint64_t old_mip; > > - *ret_value &= hip_writable_mask; > + if (mask) { > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > + } else { > + old_mip = env->mip; > + } > > - return ret; > + if (ret_value) { > + *ret_value = old_mip & hip_writable_mask; > + } > + > + return 0; > } > > static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) > @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) > > static int 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); > + uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64; > + env->mie = (env->mie & ~mask) | ((uint64_t)val & mask); > + return 0; > } > > static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val) > @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) > return 0; > } > > +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val) > +{ > + *val = env->hvicontrol; > + return 0; > +} > + > +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val) > +{ > + env->hvicontrol = val & HVICONTROL_VALID_MASK; > + return 0; > +} > + > +static int read_hvipriox(CPURISCVState *env, int first_index, > + uint8_t *iprio, target_ulong *val) > +{ > + int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32); > + > + /* First index has to be multiple of numbe 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 0; > +} > + > +static int write_hvipriox(CPURISCVState *env, int first_index, > + uint8_t *iprio, target_ulong val) > +{ > + int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32); > + > + /* First index has to be multiple of numbe 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 0; > +} > + > +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 int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val) > { > @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { > [CSR_MBADADDR] = { "mbadaddr", any, read_mbadaddr, write_mbadaddr }, > [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, read_xsetclreinum, write_xsetclreinum }, > + [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum }, > + [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum }, > + [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum }, > + [CSR_MCLAIMEI] = { "mclaimei", aia_any, read_xclaimei }, > + > + /* Machine-Level High-Half CSRs (AIA) */ > + [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh }, > + [CSR_MIEH] = { "mieh", aia_any32, read_mieh, write_mieh }, > + [CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph }, > + > /* Supervisor Trap Setup */ > [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus }, > [CSR_SIE] = { "sie", smode, read_sie, write_sie }, > @@ -1444,6 +2357,24 @@ 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, read_xsetclreinum, write_xsetclreinum }, > + [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > + [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > + [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > + [CSR_SCLAIMEI] = { "sclaimei", aia_smode, read_xclaimei }, > + > + /* Supervisor-Level High-Half CSRs (AIA) */ > + [CSR_SIEH] = { "sieh", aia_smode32, read_sieh, write_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 }, > @@ -1472,6 +2403,32 @@ 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_HVICONTROL] = { "hvicontrol", aia_hmode, read_hvicontrol, write_hvicontrol }, > + [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, read_xsetclreinum, write_xsetclreinum }, > + [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > + [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > + [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > + > + /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ > + [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, read_hidelegh, write_hidelegh }, > + [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, read_vsieh, write_vsieh }, > + [CSR_VSIPH] = { "vsiep", aia_hmode32, NULL, NULL, rmw_vsiph }, > + > /* Physical Memory Protection */ > [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg }, > [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg }, > diff --git a/target/riscv/machine.c b/target/riscv/machine.c > index 44d4015bd6..f7fa48c240 100644 > --- a/target/riscv/machine.c > +++ b/target/riscv/machine.c > @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = { > > static const VMStateDescription vmstate_hyper = { > .name = "cpu/hyper", > - .version_id = 1, > - .minimum_version_id = 1, > + .version_id = 2, > + .minimum_version_id = 2, > .needed = hyper_needed, > .fields = (VMStateField[]) { > VMSTATE_UINTTL(env.hstatus, RISCVCPU), > VMSTATE_UINTTL(env.hedeleg, RISCVCPU), > - VMSTATE_UINTTL(env.hideleg, RISCVCPU), > + VMSTATE_UINT64(env.hideleg, RISCVCPU), > VMSTATE_UINTTL(env.hcounteren, RISCVCPU), > VMSTATE_UINTTL(env.htval, RISCVCPU), > VMSTATE_UINTTL(env.htinst, RISCVCPU), > VMSTATE_UINTTL(env.hgatp, RISCVCPU), > VMSTATE_UINT64(env.htimedelta, RISCVCPU), > > + VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64), > + VMSTATE_UINTTL(env.hvicontrol, RISCVCPU), > + > VMSTATE_UINT64(env.vsstatus, RISCVCPU), > VMSTATE_UINTTL(env.vstvec, RISCVCPU), > VMSTATE_UINTTL(env.vsscratch, RISCVCPU), > @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = { > VMSTATE_UINTTL(env.vscause, RISCVCPU), > VMSTATE_UINTTL(env.vstval, RISCVCPU), > VMSTATE_UINTTL(env.vsatp, RISCVCPU), > + VMSTATE_UINTTL(env.vsiselect, RISCVCPU), > > VMSTATE_UINTTL(env.mtval2, RISCVCPU), > VMSTATE_UINTTL(env.mtinst, RISCVCPU), > @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = { > > const VMStateDescription vmstate_riscv_cpu = { > .name = "cpu", > - .version_id = 1, > - .minimum_version_id = 1, > + .version_id = 2, > + .minimum_version_id = 2, > .fields = (VMStateField[]) { > VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), > VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32), > + VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64), > + VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64), > VMSTATE_UINTTL(env.pc, RISCVCPU), > VMSTATE_UINTTL(env.load_res, RISCVCPU), > VMSTATE_UINTTL(env.load_val, RISCVCPU), > @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = { > VMSTATE_UINTTL(env.resetvec, RISCVCPU), > VMSTATE_UINTTL(env.mhartid, RISCVCPU), > VMSTATE_UINT64(env.mstatus, RISCVCPU), > - VMSTATE_UINTTL(env.mip, RISCVCPU), > - VMSTATE_UINT32(env.miclaim, RISCVCPU), > - VMSTATE_UINTTL(env.mie, RISCVCPU), > - VMSTATE_UINTTL(env.mideleg, RISCVCPU), > + VMSTATE_UINT64(env.mip, RISCVCPU), > + VMSTATE_UINT64(env.miclaim, RISCVCPU), > + VMSTATE_UINT64(env.mie, RISCVCPU), > + VMSTATE_UINT64(env.mideleg, RISCVCPU), > VMSTATE_UINTTL(env.sptbr, RISCVCPU), > VMSTATE_UINTTL(env.satp, RISCVCPU), > VMSTATE_UINTTL(env.sbadaddr, RISCVCPU), > @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = { > VMSTATE_UINTTL(env.mepc, RISCVCPU), > VMSTATE_UINTTL(env.mcause, RISCVCPU), > VMSTATE_UINTTL(env.mtval, RISCVCPU), > + VMSTATE_UINTTL(env.miselect, RISCVCPU), > + VMSTATE_UINTTL(env.siselect, RISCVCPU), > VMSTATE_UINTTL(env.scounteren, RISCVCPU), > VMSTATE_UINTTL(env.mcounteren, RISCVCPU), > VMSTATE_UINTTL(env.sscratch, RISCVCPU), > -- > 2.25.1 > >
On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote: > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote: > > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode, > > and VS-mode. > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > > --- > > target/riscv/cpu.c | 27 +- > > target/riscv/cpu.h | 52 +- > > target/riscv/cpu_helper.c | 245 ++++++++- > > target/riscv/csr.c | 1059 +++++++++++++++++++++++++++++++++++-- > > target/riscv/machine.c | 26 +- > > 5 files changed, 1309 insertions(+), 100 deletions(-) > > I feel this patch could be split up more :) This is patch is large because I did not want to break functionality. I try again to break this patch. At the moment, the best I can do is to break in to two parts. 1) AIA local interrupt CSRs without IMSIC 2) Extend AIA local interrupt CSRs to support IMSIC register access > > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > index f3702111ae..795162834b 100644 > > --- a/target/riscv/cpu.c > > +++ b/target/riscv/cpu.c > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) > > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ", > > (target_ulong)env->vsstatus); > > } > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", env->mip); > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip ", env->mip); > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie ", env->mie); > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg); > > if (riscv_has_ext(env, RVH)) { > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg); > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg); > > } > > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); > > if (riscv_has_ext(env, RVH)) { > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, > > > > static void riscv_cpu_reset(DeviceState *dev) > > { > > + uint8_t iprio; > > + int i, irq, rdzero; > > CPUState *cs = CPU(dev); > > RISCVCPU *cpu = RISCV_CPU(cs); > > RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev) > > env->mcause = 0; > > env->pc = env->resetvec; > > env->two_stage_lookup = false; > > + > > + /* Initialized default priorities of local interrupts. */ > > + for (i = 0; i < ARRAY_SIZE(env->miprio); i++) { > > + iprio = riscv_cpu_default_priority(i); > > + env->miprio[i] = iprio; > > + env->siprio[i] = iprio; > > + env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO; > > + } > > + i = 0; > > + while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) { > > + if (rdzero) { > > + env->hviprio[irq] = 0; > > + } else { > > + env->hviprio[irq] = env->miprio[irq]; > > + } > > + i++; > > + } > > #endif > > cs->exception_index = EXCP_NONE; > > env->load_res = -1; > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > > index f00c60c840..780d3f9058 100644 > > --- a/target/riscv/cpu.h > > +++ b/target/riscv/cpu.h > > @@ -157,12 +157,12 @@ struct CPURISCVState { > > */ > > uint64_t mstatus; > > > > - target_ulong mip; > > + uint64_t mip; > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume > all the other existing target_ulong CSRs are the same. When AIA is available the number of local interrupts are 64 for both RV32 and RV64. The width of CSRs remain same as target_ulong but we have new CSRs for RV32 (such as mipH) for the high-half. Also, this patch changes does not break the case when AIA is not available (or disabled). Regards, Anup > > Alistair > > > > > - uint32_t miclaim; > > + uint64_t miclaim; > > > > - target_ulong mie; > > - target_ulong mideleg; > > + uint64_t mie; > > + uint64_t mideleg; > > > > target_ulong sptbr; /* until: priv-1.9.1 */ > > target_ulong satp; /* since: priv-1.10.0 */ > > @@ -179,16 +179,27 @@ struct CPURISCVState { > > target_ulong mcause; > > target_ulong mtval; /* since: priv-1.10.0 */ > > > > + /* AIA CSRs */ > > + target_ulong miselect; > > + target_ulong siselect; > > + > > + uint8_t miprio[64]; > > + uint8_t siprio[64]; > > + > > /* Hypervisor CSRs */ > > target_ulong hstatus; > > target_ulong hedeleg; > > - target_ulong hideleg; > > + uint64_t hideleg; > > target_ulong hcounteren; > > target_ulong htval; > > target_ulong htinst; > > target_ulong hgatp; > > uint64_t htimedelta; > > > > + /* AIA HS-mode CSRs */ > > + uint8_t hviprio[64]; > > + target_ulong hvicontrol; > > + > > /* Virtual CSRs */ > > /* > > * For RV32 this is 32-bit vsstatus and 32-bit vsstatush. > > @@ -202,6 +213,9 @@ struct CPURISCVState { > > target_ulong vstval; > > target_ulong vsatp; > > > > + /* AIA VS-mode CSRs */ > > + target_ulong vsiselect; > > + > > target_ulong mtval2; > > target_ulong mtinst; > > > > @@ -236,6 +250,18 @@ struct CPURISCVState { > > uint64_t (*rdtime_fn)(uint32_t); > > uint32_t rdtime_fn_arg; > > > > + /* machine specific AIA IMSIC read-modify-write callback */ > > +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \ > > + ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \ > > + (((__priv) & 0x3) << 16) | (__isel & 0xffff)) > > +#define IMSIC_REG_ISEL(__reg) ((__reg) & 0xffff) > > +#define IMSIC_REG_PRIV(__reg) (((__reg) >> 16) & 0x3) > > +#define IMSIC_REG_VIRT(__reg) (((__reg) >> 20) & 0x1) > > +#define IMSIC_REG_VGEIN(__reg) (((__reg) >> 24) & 0x3f) > > + int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val, > > + target_ulong new_val, target_ulong write_mask); > > + void *imsic_rmw_fn_arg; > > + > > /* True if in debugger mode. */ > > bool debugger; > > #endif > > @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, > > int cpuid, void *opaque); > > int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); > > int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero); > > +uint8_t riscv_cpu_default_priority(int irq); > > +int riscv_cpu_mirq_pending(CPURISCVState *env); > > +int riscv_cpu_sirq_pending(CPURISCVState *env); > > +int riscv_cpu_vsirq_pending(CPURISCVState *env); > > bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request); > > bool riscv_cpu_fp_enabled(CPURISCVState *env); > > bool riscv_cpu_virt_enabled(CPURISCVState *env); > > @@ -364,9 +395,16 @@ void riscv_cpu_list(void); > > > > #ifndef CONFIG_USER_ONLY > > void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env); > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value); > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts); > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value); > > #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env, > > + int (*rmw_fn)(void *arg, > > + target_ulong reg, > > + target_ulong *val, > > + target_ulong new_val, > > + target_ulong write_mask), > > + void *rmw_fn_arg); > > void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), > > uint32_t arg); > > #endif > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > > index 21c54ef561..5b06b4f995 100644 > > --- a/target/riscv/cpu_helper.c > > +++ b/target/riscv/cpu_helper.c > > @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) > > } > > > > #ifndef CONFIG_USER_ONLY > > -static int riscv_cpu_local_irq_pending(CPURISCVState *env) > > + > > +/* > > + * The HS-mode is allowed to configure priority only for the > > + * following VS-mode local interrupts: > > + * > > + * 0 (Reserved interrupt, reads as zero) > > + * 1 Supervisor software interrupt > > + * 4 (Reserved interrupt, reads as zero) > > + * 5 Supervisor timer interrupt > > + * 8 (Reserved interrupt, reads as zero) > > + * 13 (Reserved interrupt) > > + * 14 " > > + * 15 " > > + * 16 " > > + * 18 Debug/trace interrupt > > + * 20 (Reserved interrupt) > > + * 22 ” > > + * 24 ” > > + * 26 ” > > + * 28 " > > + * 30 (Reserved for standard reporting of bus or system errors) > > + */ > > + > > +static int hviprio_index2irq[] = > > + { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 }; > > +static int hviprio_index2rdzero[] = > > + { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; > > + > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero) > > { > > - target_ulong irqs; > > + if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) { > > + return -EINVAL; > > + } > > > > - 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); > > + if (out_irq) { > > + *out_irq = hviprio_index2irq[index]; > > + } > > + > > + if (out_rdzero) { > > + *out_rdzero = hviprio_index2rdzero[index]; > > + } > > > > - 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)); > > + return 0; > > +} > > > > - 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); > > +uint8_t riscv_cpu_default_priority(int irq) > > +{ > > + int u, l; > > + uint8_t iprio = IPRIO_MMAXIPRIO; > > > > - if (riscv_cpu_virt_enabled(env)) { > > - target_ulong pending_hs_irq = pending & -hs_sie; > > + if (irq < 0 || irq > 63) { > > + return iprio; > > + } > > > > - if (pending_hs_irq) { > > - riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP); > > - return ctz64(pending_hs_irq); > > + /* > > + * Default priorities of local interrupts are defined in the > > + * RISC-V Advanced Interrupt Architecture specification. > > + * > > + * ---------------------------------------------------------------- > > + * Default | > > + * Priority | Major Interrupt Numbers > > + * ---------------------------------------------------------------- > > + * Highest | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c), > > + * | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38), > > + * | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34), > > + * | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30) > > + * | > > + * | 11 (0b), 3 (03), 7 (07) > > + * | 9 (09), 1 (01), 5 (05) > > + * | 12 (0c) > > + * | 10 (0a), 2 (02), 6 (06) > > + * | > > + * | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c), > > + * | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28), > > + * | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24), > > + * Lowest | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20) > > + * ---------------------------------------------------------------- > > + */ > > + > > + u = IPRIO_DEFAULT_U(irq); > > + l = IPRIO_DEFAULT_L(irq); > > + if (u == 0) { > > + if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER || > > + irq == IRQ_VS_SOFT) { > > + iprio = IPRIO_DEFAULT_VS; > > + } else if (irq == IRQ_S_GEXT) { > > + iprio = IPRIO_DEFAULT_SGEXT; > > + } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER || > > + irq == IRQ_S_SOFT) { > > + iprio = IPRIO_DEFAULT_S; > > + } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER || > > + irq == IRQ_M_SOFT) { > > + iprio = IPRIO_DEFAULT_M; > > + } else { > > + iprio = IPRIO_DEFAULT_VS; > > } > > + } else if (u == 1) { > > + if (l < 8) { > > + iprio = IPRIO_DEFAULT_16_23(irq); > > + } else { > > + iprio = IPRIO_DEFAULT_24_31(irq); > > + } > > + } else if (u == 2) { > > + iprio = IPRIO_DEFAULT_32_47(irq); > > + } else if (u == 3) { > > + iprio = IPRIO_DEFAULT_48_63(irq); > > + } > > + > > + return iprio; > > +} > > + > > +static int riscv_cpu_pending_to_irq(CPURISCVState *env, > > + uint64_t pending, uint8_t *iprio) > > +{ > > + int irq, best_irq = EXCP_NONE; > > + unsigned int prio, best_prio = UINT_MAX; > > > > - pending = vspending; > > + if (!pending) { > > + return EXCP_NONE; > > } > > > > - irqs = (pending & ~env->mideleg & -mie) | (pending & env->mideleg & -sie); > > + irq = ctz64(pending); > > + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { > > + return irq; > > + } > > > > - if (irqs) { > > - return ctz64(irqs); /* since non-zero */ > > + pending = pending >> irq; > > + while (pending) { > > + prio = iprio[irq]; > > + if (!prio) { > > + prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ? > > + 1 : IPRIO_MMAXIPRIO; > > + } > > + if ((pending & 0x1) && (prio < best_prio)) { > > + best_irq = irq; > > + best_prio = prio; > > + } > > + irq++; > > + pending = pending >> 1; > > + } > > + > > + return best_irq; > > +} > > + > > +int riscv_cpu_mirq_pending(CPURISCVState *env) > > +{ > > + uint64_t irqs = env->mip & env->mie & ~env->mideleg & > > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > + > > + return riscv_cpu_pending_to_irq(env, irqs, env->miprio); > > +} > > + > > +int riscv_cpu_sirq_pending(CPURISCVState *env) > > +{ > > + uint64_t irqs = env->mip & env->mie & env->mideleg & > > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > + > > + return riscv_cpu_pending_to_irq(env, irqs, env->siprio); > > +} > > + > > +int riscv_cpu_vsirq_pending(CPURISCVState *env) > > +{ > > + uint64_t irqs = env->mip & env->mie & env->mideleg & > > + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > + > > + return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio); > > +} > > + > > +static int riscv_cpu_local_irq_pending(CPURISCVState *env) > > +{ > > + int virq; > > + uint64_t irqs, mie, sie, vsie; > > + uint64_t pending, vspending; > > + > > + /* Determine interrupt enable state of all privilege modes */ > > + if (riscv_cpu_virt_enabled(env)) { > > + mie = 1; > > + sie = 1; > > + vsie = (env->priv < PRV_S) || > > + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE)); > > } else { > > - return EXCP_NONE; /* indicates no pending interrupt */ > > + mie = (env->priv < PRV_M) || > > + (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE)); > > + sie = (env->priv < PRV_S) || > > + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE)); > > + vsie = 0; > > + } > > + > > + /* Check M-mode interrupts */ > > + pending = env->mip & env->mie & > > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > + irqs = pending & ~env->mideleg & -mie; > > + if (irqs) { > > + return riscv_cpu_pending_to_irq(env, irqs, env->miprio); > > + } > > + > > + /* Check HS-mode interrupts */ > > + irqs = pending & env->mideleg & -sie; > > + if (irqs) { > > + return riscv_cpu_pending_to_irq(env, irqs, env->siprio); > > + } > > + > > + /* Check VS-mode interrupts */ > > + vspending = env->mip & env->mie & > > + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > + irqs = vspending & env->hideleg & -vsie; > > + if (irqs) { > > + virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio); > > + return (virq <= 0) ? virq : virq + 1; > > } > > + > > + /* Indicates no pending interrupt */ > > + return EXCP_NONE; > > } > > #endif > > > > @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx) > > return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK; > > } > > > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts) > > { > > CPURISCVState *env = &cpu->env; > > if (env->miclaim & interrupts) { > > @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) > > } > > } > > > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) > > { > > CPURISCVState *env = &cpu->env; > > CPUState *cs = CPU(cpu); > > - uint32_t old = env->mip; > > + uint64_t old = env->mip; > > bool locked = false; > > > > if (!qemu_mutex_iothread_locked()) { > > @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) > > return old; > > } > > > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env, > > + int (*rmw_fn)(void *arg, > > + target_ulong reg, > > + target_ulong *val, > > + target_ulong new_val, > > + target_ulong write_mask), > > + void *rmw_fn_arg) > > +{ > > + env->imsic_rmw_fn = rmw_fn; > > + env->imsic_rmw_fn_arg = rmw_fn_arg; > > +} > > + > > void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), > > uint32_t arg) > > { > > @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > > */ > > bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG); > > target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK; > > - target_ulong deleg = async ? env->mideleg : env->medeleg; > > + uint64_t deleg = async ? env->mideleg : env->medeleg; > > bool write_tval = false; > > target_ulong tval = 0; > > target_ulong htval = 0; > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > > index d2585395bf..3c016d7452 100644 > > --- a/target/riscv/csr.c > > +++ b/target/riscv/csr.c > > @@ -153,11 +153,56 @@ static int 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 int smode(CPURISCVState *env, int csrno) > > { > > return -!riscv_has_ext(env, RVS); > > } > > > > +static int smode32(CPURISCVState *env, int csrno) > > +{ > > + if (!riscv_cpu_is_32bit(env)) { > > + 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 int hmode(CPURISCVState *env, int csrno) > > { > > if (riscv_has_ext(env, RVS) && > > @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno) > > static int hmode32(CPURISCVState *env, int csrno) > > { > > if (!riscv_cpu_is_32bit(env)) { > > - return 0; > > + return -RISCV_EXCP_ILLEGAL_INST; > > + } > > + > > + return hmode(env, csrno); > > +} > > + > > +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 int pmp(CPURISCVState *env, int csrno) > > @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) > > > > /* 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 TLOWBITS64 ((uint64_t)((target_ulong)-1)) > > > > -static const target_ulong delegable_ints = S_MODE_INTERRUPTS | > > - VS_MODE_INTERRUPTS; > > -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | > > - VS_MODE_INTERRUPTS; > > +static const uint64_t delegable_ints = S_MODE_INTERRUPTS | > > + VS_MODE_INTERRUPTS; > > +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | > > + VS_MODE_INTERRUPTS; > > static const target_ulong delegable_excps = > > (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | > > (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | > > @@ -419,10 +483,10 @@ static const target_ulong delegable_excps = > > static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | > > SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | > > SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD; > > -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; > > -static const target_ulong hip_writable_mask = MIP_VSSIP; > > -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; > > -static const target_ulong vsip_writable_mask = MIP_VSSIP; > > +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; > > +static const uint64_t hip_writable_mask = MIP_VSSIP; > > +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; > > +static const uint64_t vsip_writable_mask = MIP_VSSIP; > > > > static const char valid_vm_1_10_32[16] = { > > [VM_1_10_MBARE] = 1, > > @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val) > > > > static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val) > > { > > - env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints); > > + uint64_t mask = delegable_ints & TLOWBITS64; > > + > > + env->mideleg = (env->mideleg & ~mask) | (val & mask); > > + if (riscv_has_ext(env, RVH)) { > > + env->mideleg |= VS_MODE_INTERRUPTS; > > + } > > + return 0; > > +} > > + > > +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_STOPI: > > + return CSR_VSTOPI; > > + case CSR_SSETEIPNUM: > > + return CSR_VSSETEIPNUM; > > + case CSR_SCLREIPNUM: > > + return CSR_VSCLREIPNUM; > > + case CSR_SSETEIENUM: > > + return CSR_VSSETEIENUM; > > + case CSR_SCLREIENUM: > > + return CSR_VSCLREIENUM; > > + default: > > + return csrno; > > + }; > > +} > > + > > +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val, > > + target_ulong new_val, target_ulong write_mask) > > +{ > > + target_ulong *iselect; > > + > > + switch (csrno) { > > + case CSR_MISELECT: > > + iselect = &env->miselect; > > + break; > > + case CSR_SISELECT: > > + iselect = riscv_cpu_virt_enabled(env) ? > > + &env->vsiselect : &env->siselect; > > + break; > > + case CSR_VSISELECT: > > + iselect = &env->vsiselect; > > + break; > > + default: > > + return -RISCV_EXCP_ILLEGAL_INST; > > + }; > > + > > + if (val) { > > + *val = *iselect; > > + } > > + > > + if (write_mask) { > > + *iselect = (*iselect & ~write_mask) | (new_val & write_mask); > > + } > > + > > + return 0; > > +} > > + > > +static int rmw_iprio(target_ulong iselect, uint8_t *iprio, > > + target_ulong *val, target_ulong new_val, > > + target_ulong write_mask) > > +{ > > + int i, firq, nirqs; > > + target_ulong old_val; > > + > > + if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) { > > + return -EINVAL; > > + } > > +#if TARGET_LONG_BITS == 64 > > + if (iselect & 0x1) { > > + return -EINVAL; > > + } > > +#endif > > + > > + nirqs = 4 * (TARGET_LONG_BITS / 32); > > + firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 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 (write_mask) { > > + new_val = (old_val & ~write_mask) | (new_val & write_mask); > > + for (i = 0; i < nirqs; i++) { > > + 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 write_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) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > + > > + if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) { > > + /* Local interrupt priority registers not available for VS-mode */ > > + if (!virt) { > > + ret = rmw_iprio(isel, iprio, val, new_val, write_mask); > > + } > > + } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) { > > + /* IMSIC registers only available when machine implements it. */ > > + if (env->imsic_rmw_fn) { > > + /* Selected guest interrupt file should not be zero */ > > + if (virt && !vgein) { > > + goto done; > > + } > > + /* Call machine specific IMSIC register emulation */ > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > > + val, new_val, write_mask); > > + } > > + } > > + > > +done: > > + if (ret) { > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > + } > > + return 0; > > +} > > + > > +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + int irq; > > + > > + irq = riscv_cpu_mirq_pending(env); > > + if (irq <= 0 || irq > 63) { > > + *val = 0; > > + } else { > > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > > + *val |= env->miprio[irq]; > > + } > > + > > + return 0; > > +} > > + > > +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + bool virt; > > + int ret = -EINVAL; > > + target_ulong 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_MSETEIPNUM: > > + case CSR_MCLREIPNUM: > > + case CSR_MSETEIENUM: > > + case CSR_MCLREIENUM: > > + case CSR_SSETEIPNUM: > > + case CSR_SCLREIPNUM: > > + case CSR_SSETEIENUM: > > + case CSR_SCLREIENUM: > > + break; > > + case CSR_VSSETEIPNUM: > > + case CSR_VSCLREIPNUM: > > + case CSR_VSSETEIENUM: > > + case CSR_VSCLREIENUM: > > + virt = true; > > + break; > > + default: > > + goto done; > > + }; > > + > > + /* IMSIC CSRs only available when machine implements IMSIC. */ > > + if (!env->imsic_rmw_fn) { > > + goto done; > > + } > > + > > + /* Find the selected guest interrupt file */ > > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > + > > + /* Selected guest interrupt file should not be zero */ > > + if (virt && !vgein) { > > + goto done; > > + } > > + > > + /* Set/Clear CSRs always read zero */ > > + ret = 0; > > + if (val) { > > + *val = 0; > > + } > > + > > +done: > > + if (ret) { > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > + } > > + return 0; > > +} > > + > > +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val) > > +{ > > + int ret = -EINVAL; > > + bool set, pend, virt; > > + target_ulong priv, isel, vgein; > > + target_ulong new_val, write_mask; > > + > > + /* 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; > > + 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->imsic_rmw_fn) { > > + goto done; > > + } > > + > > + /* Find target interrupt pending/enable register */ > > + if (pend) { > > + isel = ISELECT_IMSIC_EIP0; > > + } else { > > + isel = ISELECT_IMSIC_EIE0; > > + } > > + isel += val / IMSIC_EIPx_BITS; > > + > > + /* Find the interrupt bit to be set/clear */ > > + write_mask = 1 << (val % IMSIC_EIPx_BITS); > > + new_val = (set) ? write_mask : 0; > > + > > + /* Find the selected guest interrupt file */ > > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > + > > + /* Selected guest interrupt file should not be zero */ > > + if (virt && !vgein) { > > + goto done; > > + } > > + > > + /* Call machine specific IMSIC register emulation */ > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > > + NULL, new_val, write_mask); > > + > > +done: > > + if (ret) { > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > + } > > + return 0; > > +} > > + > > +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + bool virt; > > + int ret = -EINVAL; > > + target_ulong priv, isel, vgein; > > + target_ulong topei, write_mask; > > + > > + /* Decode register details from CSR number */ > > + virt = false; > > + switch (csrno) { > > + case CSR_MCLAIMEI: > > + priv = PRV_M; > > + break; > > + case CSR_SCLAIMEI: > > + priv = PRV_S; > > + virt = riscv_cpu_virt_enabled(env); > > + break; > > + default: > > + goto done; > > + }; > > + > > + /* IMSIC CSRs only available when machine implements IMSIC. */ > > + if (!env->imsic_rmw_fn) { > > + goto done; > > + } > > + > > + /* Find the selected guest interrupt file */ > > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > + > > + /* Selected guest interrupt file should not be zero */ > > + if (virt && !vgein) { > > + goto done; > > + } > > + > > + /* Call machine specific IMSIC register emulation for reading TOPEI */ > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > + IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein), > > + &topei, -1, 0); > > + if (ret) { > > + goto done; > > + } > > + > > + /* If no interrupt pending then we are done */ > > + if (!topei) { > > + goto done; > > + } > > + > > + /* Find target interrupt pending register */ > > + isel = ISELECT_IMSIC_EIP0; > > + isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS); > > + > > + /* Find the interrupt bit to be cleared */ > > + write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS); > > + > > + /* Call machine specific IMSIC register emulation to clear pending bit */ > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > > + NULL, 0, write_mask); > > + > > + /* Update return value */ > > + if (val) { > > + *val = topei; > > + } > > + > > +done: > > + if (ret) { > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > + } > > + return 0; > > +} > > + > > +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + *val = (env->mideleg >> 32); > > + return 0; > > +} > > + > > +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val) > > +{ > > + uint64_t mask = delegable_ints & ~TLOWBITS64; > > + uint64_t newval = ((uint64_t)val) << 32; > > + > > + env->mideleg = (env->mideleg & ~mask) | (newval & mask); > > if (riscv_has_ext(env, RVH)) { > > env->mideleg |= VS_MODE_INTERRUPTS; > > } > > @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val) > > > > static int write_mie(CPURISCVState *env, int csrno, target_ulong val) > > { > > - env->mie = (env->mie & ~all_ints) | (val & all_ints); > > + uint64_t mask = all_ints & TLOWBITS64; > > + > > + env->mie = (env->mie & ~mask) | (val & mask); > > + return 0; > > +} > > + > > +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + *val = (env->mie >> 32); > > + return 0; > > +} > > + > > +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val) > > +{ > > + uint64_t mask = all_ints & ~TLOWBITS64; > > + uint64_t newval = ((uint64_t)val) << 32; > > + > > + env->mie = (env->mie & ~mask) | (newval & mask); > > return 0; > > } > > > > @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > { > > 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 mask = ((uint64_t)write_mask) & delegable_ints & > > + ~env->miclaim & TLOWBITS64; > > + uint64_t old_mip; > > > > if (mask) { > > old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > return 0; > > } > > > > +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > + target_ulong new_value, target_ulong write_mask) > > +{ > > + RISCVCPU *cpu = env_archcpu(env); > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > + uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints & > > + ~env->miclaim & ~TLOWBITS64; > > + uint64_t new_value64 = (uint64_t)new_value << 32; > > + uint64_t old_mip; > > + > > + if (mask) { > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > + } else { > > + old_mip = env->mip; > > + } > > + > > + if (ret_value) { > > + *ret_value = old_mip >> 32; > > + } > > + > > + return 0; > > +} > > + > > /* Supervisor Trap Setup */ > > static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val) > > { > > @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val) > > > > static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val) > > { > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64; > > + > > /* Shift the VS bits to their S bit location in vsie */ > > - *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1; > > + *val = (env->mie & mask) >> 1; > > + return 0; > > +} > > + > > +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64; > > + > > + /* Shift the VS bits to their S bit location in vsieh */ > > + *val = (env->mie & mask) >> (32 + 1); > > return 0; > > } > > > > static int read_sie(CPURISCVState *env, int csrno, target_ulong *val) > > { > > if (riscv_cpu_virt_enabled(env)) { > > - read_vsie(env, CSR_VSIE, val); > > - } else { > > - *val = env->mie & env->mideleg; > > + if (env->hvicontrol & HVICONTROL_VTI) { > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > + } > > + return read_vsie(env, CSR_VSIE, val); > > } > > + > > + *val = env->mie & env->mideleg; > > return 0; > > } > > > > static int write_vsie(CPURISCVState *env, int csrno, target_ulong val) > > { > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & > > + all_ints & TLOWBITS64; > > + > > /* 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); > > + env->mie = (env->mie & ~mask) | ((val << 1) & mask); > > + > > + return 0; > > +} > > + > > +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val) > > +{ > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & > > + all_ints & ~TLOWBITS64; > > + uint64_t newval = (uint64_t)val << 32; > > + > > + /* Shift the S bits to their VS bit location in mie */ > > + env->mie = (env->mie & ~mask) | ((newval << 1) & mask); > > + > > + return 0; > > } > > > > static int write_sie(CPURISCVState *env, int csrno, target_ulong val) > > { > > + uint64_t mask; > > + > > if (riscv_cpu_virt_enabled(env)) { > > - write_vsie(env, CSR_VSIE, val); > > - } else { > > - target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) | > > - (val & S_MODE_INTERRUPTS); > > - write_mie(env, CSR_MIE, newval); > > + if (env->hvicontrol & HVICONTROL_VTI) { > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > + } > > + return write_vsie(env, CSR_VSIE, val); > > + } > > + > > + mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64; > > + env->mie = (env->mie & ~mask) | ((uint64_t)val & mask); > > + > > + return 0; > > +} > > + > > +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + if (riscv_cpu_virt_enabled(env)) { > > + if (env->hvicontrol & HVICONTROL_VTI) { > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > + } > > + return read_vsieh(env, CSR_VSIEH, val); > > + } > > + > > + *val = ((env->mie & env->mideleg) >> 32); > > + return 0; > > +} > > + > > +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val) > > +{ > > + uint64_t mask, newval; > > + > > + if (riscv_cpu_virt_enabled(env)) { > > + if (env->hvicontrol & HVICONTROL_VTI) { > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > + } > > + return write_vsieh(env, CSR_VSIEH, val); > > } > > > > + mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64; > > + newval = (uint64_t)val << 32; > > + > > + env->mie = (env->mie & ~mask) | (newval & mask); > > return 0; > > } > > > > @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val) > > static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > target_ulong new_value, target_ulong write_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); > > - *ret_value &= VS_MODE_INTERRUPTS; > > - /* Shift the VS bits to their S bit location in vsip */ > > - *ret_value >>= 1; > > - return ret; > > + RISCVCPU *cpu = env_archcpu(env); > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > + uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints & > > + vsip_writable_mask & env->hideleg & > > + ~env->miclaim & TLOWBITS64; > > + uint64_t old_mip; > > + > > + if (mask) { > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > + } else { > > + old_mip = env->mip; > > + } > > + > > + if (ret_value) { > > + *ret_value = old_mip & VS_MODE_INTERRUPTS; > > + } > > + > > + return 0; > > +} > > + > > +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > + target_ulong new_value, target_ulong write_mask) > > +{ > > + RISCVCPU *cpu = env_archcpu(env); > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > + uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints & > > + vsip_writable_mask & env->hideleg & > > + ~env->miclaim & ~TLOWBITS64; > > + uint64_t new_value64 = (uint64_t)new_value << 32; > > + uint64_t old_mip; > > + > > + if (mask) { > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > + } else { > > + old_mip = env->mip; > > + } > > + > > + if (ret_value) { > > + *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32; > > + } > > + > > + return 0; > > } > > > > static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > target_ulong new_value, target_ulong write_mask) > > { > > - int ret; > > + RISCVCPU *cpu = env_archcpu(env); > > + uint64_t mask, old_mip; > > > > if (riscv_cpu_virt_enabled(env)) { > > - ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); > > + if (env->hvicontrol & HVICONTROL_VTI) { > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > + } > > + return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); > > + } > > + > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > + mask = ((uint64_t)write_mask) & delegable_ints & > > + env->mideleg & sip_writable_mask & > > + ~env->miclaim & TLOWBITS64; > > + if (mask) { > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > } else { > > - ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, > > - write_mask & env->mideleg & sip_writable_mask); > > + old_mip = env->mip; > > } > > > > - *ret_value &= env->mideleg; > > - return ret; > > + if (ret_value) { > > + *ret_value = old_mip; > > + } > > + > > + return 0; > > +} > > + > > +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > + target_ulong new_value, target_ulong write_mask) > > +{ > > + RISCVCPU *cpu = env_archcpu(env); > > + uint64_t mask, new_value64; > > + uint64_t old_mip; > > + > > + if (riscv_cpu_virt_enabled(env)) { > > + if (env->hvicontrol & HVICONTROL_VTI) { > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > + } > > + return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask); > > + } > > + > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > + mask = ((uint64_t)write_mask << 32) & delegable_ints & > > + env->mideleg & sip_writable_mask & > > + ~env->miclaim & ~TLOWBITS64; > > + new_value64 = (uint64_t)new_value << 32; > > + if (mask) { > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > + } else { > > + old_mip = env->mip; > > + } > > + > > + if (ret_value) { > > + *ret_value = (old_mip & env->mideleg) >> 32; > > + } > > + > > + return 0; > > } > > > > /* Supervisor Protection and Translation */ > > @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) > > return 0; > > } > > > > +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + int irq, hiid; > > + uint8_t hiprio, iprio; > > + > > + irq = riscv_cpu_vsirq_pending(env); > > + if (irq <= 0 || irq > 63) { > > + *val = 0; > > + } else { > > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > > + iprio = env->hviprio[irq]; > > + /* TODO: This needs to improve in specification */ > > + if (!(env->hstatus & HSTATUS_VGEIN)) { > > + hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >> > > + HVICONTROL_IID_SHIFT; > > + hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK; > > + if (irq == hiid && hiprio) { > > + iprio = hiprio; > > + } > > + } > > + *val |= iprio; > > + } > > + > > + return 0; > > +} > > + > > +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + int irq; > > + > > + 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 { > > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > > + *val |= env->siprio[irq]; > > + } > > + > > + return 0; > > +} > > + > > /* Hypervisor Extensions */ > > static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) > > { > > @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val) > > return 0; > > } > > > > +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + *val = env->hideleg >> 32; > > + return 0; > > +} > > + > > +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val) > > +{ > > + uint64_t mask = ~TLOWBITS64; > > + uint64_t newval = ((uint64_t)val) << 32; > > + > > + env->hideleg = (env->hideleg & ~mask) | (newval & mask); > > + > > + return 0; > > +} > > + > > static int rmw_hvip(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, > > - write_mask & hvip_writable_mask); > > + RISCVCPU *cpu = env_archcpu(env); > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > + uint64_t mask = ((uint64_t)write_mask) & delegable_ints & > > + hvip_writable_mask & > > + ~env->miclaim & TLOWBITS64; > > + uint64_t old_mip; > > + > > + if (mask) { > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > + } else { > > + old_mip = env->mip; > > + } > > > > - *ret_value &= hvip_writable_mask; > > + if (ret_value) { > > + *ret_value = old_mip & hvip_writable_mask; > > + } > > > > - return ret; > > + return 0; > > +} > > + > > +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > + target_ulong new_value, target_ulong write_mask) > > +{ > > + RISCVCPU *cpu = env_archcpu(env); > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > + uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints & > > + hvip_writable_mask & > > + ~env->miclaim & ~TLOWBITS64; > > + uint64_t new_value64 = (uint64_t)new_value << 32; > > + uint64_t old_mip; > > + > > + if (mask) { > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > + } else { > > + old_mip = env->mip; > > + } > > + > > + if (ret_value) { > > + *ret_value = (old_mip & hvip_writable_mask) >> 32; > > + } > > + > > + return 0; > > } > > > > static int 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, > > - write_mask & hip_writable_mask); > > + RISCVCPU *cpu = env_archcpu(env); > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > + uint64_t mask = ((uint64_t)write_mask) & delegable_ints & > > + hip_writable_mask & > > + ~env->miclaim & TLOWBITS64; > > + uint64_t old_mip; > > > > - *ret_value &= hip_writable_mask; > > + if (mask) { > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > + } else { > > + old_mip = env->mip; > > + } > > > > - return ret; > > + if (ret_value) { > > + *ret_value = old_mip & hip_writable_mask; > > + } > > + > > + return 0; > > } > > > > static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) > > @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) > > > > static int 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); > > + uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64; > > + env->mie = (env->mie & ~mask) | ((uint64_t)val & mask); > > + return 0; > > } > > > > static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val) > > @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) > > return 0; > > } > > > > +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val) > > +{ > > + *val = env->hvicontrol; > > + return 0; > > +} > > + > > +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val) > > +{ > > + env->hvicontrol = val & HVICONTROL_VALID_MASK; > > + return 0; > > +} > > + > > +static int read_hvipriox(CPURISCVState *env, int first_index, > > + uint8_t *iprio, target_ulong *val) > > +{ > > + int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32); > > + > > + /* First index has to be multiple of numbe 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 0; > > +} > > + > > +static int write_hvipriox(CPURISCVState *env, int first_index, > > + uint8_t *iprio, target_ulong val) > > +{ > > + int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32); > > + > > + /* First index has to be multiple of numbe 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 0; > > +} > > + > > +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 int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val) > > { > > @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { > > [CSR_MBADADDR] = { "mbadaddr", any, read_mbadaddr, write_mbadaddr }, > > [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, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_MCLAIMEI] = { "mclaimei", aia_any, read_xclaimei }, > > + > > + /* Machine-Level High-Half CSRs (AIA) */ > > + [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh }, > > + [CSR_MIEH] = { "mieh", aia_any32, read_mieh, write_mieh }, > > + [CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph }, > > + > > /* Supervisor Trap Setup */ > > [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus }, > > [CSR_SIE] = { "sie", smode, read_sie, write_sie }, > > @@ -1444,6 +2357,24 @@ 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, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_SCLAIMEI] = { "sclaimei", aia_smode, read_xclaimei }, > > + > > + /* Supervisor-Level High-Half CSRs (AIA) */ > > + [CSR_SIEH] = { "sieh", aia_smode32, read_sieh, write_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 }, > > @@ -1472,6 +2403,32 @@ 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_HVICONTROL] = { "hvicontrol", aia_hmode, read_hvicontrol, write_hvicontrol }, > > + [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, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > > + [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > > + > > + /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ > > + [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, read_hidelegh, write_hidelegh }, > > + [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, read_vsieh, write_vsieh }, > > + [CSR_VSIPH] = { "vsiep", aia_hmode32, NULL, NULL, rmw_vsiph }, > > + > > /* Physical Memory Protection */ > > [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg }, > > [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg }, > > diff --git a/target/riscv/machine.c b/target/riscv/machine.c > > index 44d4015bd6..f7fa48c240 100644 > > --- a/target/riscv/machine.c > > +++ b/target/riscv/machine.c > > @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = { > > > > static const VMStateDescription vmstate_hyper = { > > .name = "cpu/hyper", > > - .version_id = 1, > > - .minimum_version_id = 1, > > + .version_id = 2, > > + .minimum_version_id = 2, > > .needed = hyper_needed, > > .fields = (VMStateField[]) { > > VMSTATE_UINTTL(env.hstatus, RISCVCPU), > > VMSTATE_UINTTL(env.hedeleg, RISCVCPU), > > - VMSTATE_UINTTL(env.hideleg, RISCVCPU), > > + VMSTATE_UINT64(env.hideleg, RISCVCPU), > > VMSTATE_UINTTL(env.hcounteren, RISCVCPU), > > VMSTATE_UINTTL(env.htval, RISCVCPU), > > VMSTATE_UINTTL(env.htinst, RISCVCPU), > > VMSTATE_UINTTL(env.hgatp, RISCVCPU), > > VMSTATE_UINT64(env.htimedelta, RISCVCPU), > > > > + VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64), > > + VMSTATE_UINTTL(env.hvicontrol, RISCVCPU), > > + > > VMSTATE_UINT64(env.vsstatus, RISCVCPU), > > VMSTATE_UINTTL(env.vstvec, RISCVCPU), > > VMSTATE_UINTTL(env.vsscratch, RISCVCPU), > > @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = { > > VMSTATE_UINTTL(env.vscause, RISCVCPU), > > VMSTATE_UINTTL(env.vstval, RISCVCPU), > > VMSTATE_UINTTL(env.vsatp, RISCVCPU), > > + VMSTATE_UINTTL(env.vsiselect, RISCVCPU), > > > > VMSTATE_UINTTL(env.mtval2, RISCVCPU), > > VMSTATE_UINTTL(env.mtinst, RISCVCPU), > > @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = { > > > > const VMStateDescription vmstate_riscv_cpu = { > > .name = "cpu", > > - .version_id = 1, > > - .minimum_version_id = 1, > > + .version_id = 2, > > + .minimum_version_id = 2, > > .fields = (VMStateField[]) { > > VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), > > VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32), > > + VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64), > > + VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64), > > VMSTATE_UINTTL(env.pc, RISCVCPU), > > VMSTATE_UINTTL(env.load_res, RISCVCPU), > > VMSTATE_UINTTL(env.load_val, RISCVCPU), > > @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = { > > VMSTATE_UINTTL(env.resetvec, RISCVCPU), > > VMSTATE_UINTTL(env.mhartid, RISCVCPU), > > VMSTATE_UINT64(env.mstatus, RISCVCPU), > > - VMSTATE_UINTTL(env.mip, RISCVCPU), > > - VMSTATE_UINT32(env.miclaim, RISCVCPU), > > - VMSTATE_UINTTL(env.mie, RISCVCPU), > > - VMSTATE_UINTTL(env.mideleg, RISCVCPU), > > + VMSTATE_UINT64(env.mip, RISCVCPU), > > + VMSTATE_UINT64(env.miclaim, RISCVCPU), > > + VMSTATE_UINT64(env.mie, RISCVCPU), > > + VMSTATE_UINT64(env.mideleg, RISCVCPU), > > VMSTATE_UINTTL(env.sptbr, RISCVCPU), > > VMSTATE_UINTTL(env.satp, RISCVCPU), > > VMSTATE_UINTTL(env.sbadaddr, RISCVCPU), > > @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = { > > VMSTATE_UINTTL(env.mepc, RISCVCPU), > > VMSTATE_UINTTL(env.mcause, RISCVCPU), > > VMSTATE_UINTTL(env.mtval, RISCVCPU), > > + VMSTATE_UINTTL(env.miselect, RISCVCPU), > > + VMSTATE_UINTTL(env.siselect, RISCVCPU), > > VMSTATE_UINTTL(env.scounteren, RISCVCPU), > > VMSTATE_UINTTL(env.mcounteren, RISCVCPU), > > VMSTATE_UINTTL(env.sscratch, RISCVCPU), > > -- > > 2.25.1 > > > >
On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote: > > On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote: > > > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote: > > > > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode, > > > and VS-mode. > > > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > > > --- > > > target/riscv/cpu.c | 27 +- > > > target/riscv/cpu.h | 52 +- > > > target/riscv/cpu_helper.c | 245 ++++++++- > > > target/riscv/csr.c | 1059 +++++++++++++++++++++++++++++++++++-- > > > target/riscv/machine.c | 26 +- > > > 5 files changed, 1309 insertions(+), 100 deletions(-) > > > > I feel this patch could be split up more :) > > This is patch is large because I did not want to break functionality. > > I try again to break this patch. At the moment, the best I can do is > to break in to two parts. > 1) AIA local interrupt CSRs without IMSIC > 2) Extend AIA local interrupt CSRs to support IMSIC register access As the patch is being added while AIA isn't enabled you are able to add the AIA in breaking stages. That is the AIA isn't fully functional, you still have to make sure not to break existing users. > > > > > > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > > index f3702111ae..795162834b 100644 > > > --- a/target/riscv/cpu.c > > > +++ b/target/riscv/cpu.c > > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) > > > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ", > > > (target_ulong)env->vsstatus); > > > } > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", env->mip); > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip ", env->mip); > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie ", env->mie); > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg); > > > if (riscv_has_ext(env, RVH)) { > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg); > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg); > > > } > > > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); > > > if (riscv_has_ext(env, RVH)) { > > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, > > > > > > static void riscv_cpu_reset(DeviceState *dev) > > > { > > > + uint8_t iprio; > > > + int i, irq, rdzero; > > > CPUState *cs = CPU(dev); > > > RISCVCPU *cpu = RISCV_CPU(cs); > > > RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); > > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev) > > > env->mcause = 0; > > > env->pc = env->resetvec; > > > env->two_stage_lookup = false; > > > + > > > + /* Initialized default priorities of local interrupts. */ > > > + for (i = 0; i < ARRAY_SIZE(env->miprio); i++) { > > > + iprio = riscv_cpu_default_priority(i); > > > + env->miprio[i] = iprio; > > > + env->siprio[i] = iprio; > > > + env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO; > > > + } > > > + i = 0; > > > + while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) { > > > + if (rdzero) { > > > + env->hviprio[irq] = 0; > > > + } else { > > > + env->hviprio[irq] = env->miprio[irq]; > > > + } > > > + i++; > > > + } > > > #endif > > > cs->exception_index = EXCP_NONE; > > > env->load_res = -1; > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > > > index f00c60c840..780d3f9058 100644 > > > --- a/target/riscv/cpu.h > > > +++ b/target/riscv/cpu.h > > > @@ -157,12 +157,12 @@ struct CPURISCVState { > > > */ > > > uint64_t mstatus; > > > > > > - target_ulong mip; > > > + uint64_t mip; > > > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume > > all the other existing target_ulong CSRs are the same. > > When AIA is available the number of local interrupts are 64 for > both RV32 and RV64. Is that going to be reflected in the priv spec? > > The width of CSRs remain same as target_ulong but we have > new CSRs for RV32 (such as mipH) for the high-half. Ah! Sorry I missed that. This change should be in a seperate patch then. > > Also, this patch changes does not break the case when AIA > is not available (or disabled). Good, we need to make sure we don't. Alistair > > Regards, > Anup > > > > > Alistair > > > > > > > > - uint32_t miclaim; > > > + uint64_t miclaim; > > > > > > - target_ulong mie; > > > - target_ulong mideleg; > > > + uint64_t mie; > > > + uint64_t mideleg; > > > > > > target_ulong sptbr; /* until: priv-1.9.1 */ > > > target_ulong satp; /* since: priv-1.10.0 */ > > > @@ -179,16 +179,27 @@ struct CPURISCVState { > > > target_ulong mcause; > > > target_ulong mtval; /* since: priv-1.10.0 */ > > > > > > + /* AIA CSRs */ > > > + target_ulong miselect; > > > + target_ulong siselect; > > > + > > > + uint8_t miprio[64]; > > > + uint8_t siprio[64]; > > > + > > > /* Hypervisor CSRs */ > > > target_ulong hstatus; > > > target_ulong hedeleg; > > > - target_ulong hideleg; > > > + uint64_t hideleg; > > > target_ulong hcounteren; > > > target_ulong htval; > > > target_ulong htinst; > > > target_ulong hgatp; > > > uint64_t htimedelta; > > > > > > + /* AIA HS-mode CSRs */ > > > + uint8_t hviprio[64]; > > > + target_ulong hvicontrol; > > > + > > > /* Virtual CSRs */ > > > /* > > > * For RV32 this is 32-bit vsstatus and 32-bit vsstatush. > > > @@ -202,6 +213,9 @@ struct CPURISCVState { > > > target_ulong vstval; > > > target_ulong vsatp; > > > > > > + /* AIA VS-mode CSRs */ > > > + target_ulong vsiselect; > > > + > > > target_ulong mtval2; > > > target_ulong mtinst; > > > > > > @@ -236,6 +250,18 @@ struct CPURISCVState { > > > uint64_t (*rdtime_fn)(uint32_t); > > > uint32_t rdtime_fn_arg; > > > > > > + /* machine specific AIA IMSIC read-modify-write callback */ > > > +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \ > > > + ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \ > > > + (((__priv) & 0x3) << 16) | (__isel & 0xffff)) > > > +#define IMSIC_REG_ISEL(__reg) ((__reg) & 0xffff) > > > +#define IMSIC_REG_PRIV(__reg) (((__reg) >> 16) & 0x3) > > > +#define IMSIC_REG_VIRT(__reg) (((__reg) >> 20) & 0x1) > > > +#define IMSIC_REG_VGEIN(__reg) (((__reg) >> 24) & 0x3f) > > > + int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val, > > > + target_ulong new_val, target_ulong write_mask); > > > + void *imsic_rmw_fn_arg; > > > + > > > /* True if in debugger mode. */ > > > bool debugger; > > > #endif > > > @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, > > > int cpuid, void *opaque); > > > int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); > > > int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); > > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero); > > > +uint8_t riscv_cpu_default_priority(int irq); > > > +int riscv_cpu_mirq_pending(CPURISCVState *env); > > > +int riscv_cpu_sirq_pending(CPURISCVState *env); > > > +int riscv_cpu_vsirq_pending(CPURISCVState *env); > > > bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request); > > > bool riscv_cpu_fp_enabled(CPURISCVState *env); > > > bool riscv_cpu_virt_enabled(CPURISCVState *env); > > > @@ -364,9 +395,16 @@ void riscv_cpu_list(void); > > > > > > #ifndef CONFIG_USER_ONLY > > > void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env); > > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); > > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value); > > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts); > > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value); > > > #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ > > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env, > > > + int (*rmw_fn)(void *arg, > > > + target_ulong reg, > > > + target_ulong *val, > > > + target_ulong new_val, > > > + target_ulong write_mask), > > > + void *rmw_fn_arg); > > > void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), > > > uint32_t arg); > > > #endif > > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > > > index 21c54ef561..5b06b4f995 100644 > > > --- a/target/riscv/cpu_helper.c > > > +++ b/target/riscv/cpu_helper.c > > > @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) > > > } > > > > > > #ifndef CONFIG_USER_ONLY > > > -static int riscv_cpu_local_irq_pending(CPURISCVState *env) > > > + > > > +/* > > > + * The HS-mode is allowed to configure priority only for the > > > + * following VS-mode local interrupts: > > > + * > > > + * 0 (Reserved interrupt, reads as zero) > > > + * 1 Supervisor software interrupt > > > + * 4 (Reserved interrupt, reads as zero) > > > + * 5 Supervisor timer interrupt > > > + * 8 (Reserved interrupt, reads as zero) > > > + * 13 (Reserved interrupt) > > > + * 14 " > > > + * 15 " > > > + * 16 " > > > + * 18 Debug/trace interrupt > > > + * 20 (Reserved interrupt) > > > + * 22 ” > > > + * 24 ” > > > + * 26 ” > > > + * 28 " > > > + * 30 (Reserved for standard reporting of bus or system errors) > > > + */ > > > + > > > +static int hviprio_index2irq[] = > > > + { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 }; > > > +static int hviprio_index2rdzero[] = > > > + { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; > > > + > > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero) > > > { > > > - target_ulong irqs; > > > + if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) { > > > + return -EINVAL; > > > + } > > > > > > - 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); > > > + if (out_irq) { > > > + *out_irq = hviprio_index2irq[index]; > > > + } > > > + > > > + if (out_rdzero) { > > > + *out_rdzero = hviprio_index2rdzero[index]; > > > + } > > > > > > - 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)); > > > + return 0; > > > +} > > > > > > - 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); > > > +uint8_t riscv_cpu_default_priority(int irq) > > > +{ > > > + int u, l; > > > + uint8_t iprio = IPRIO_MMAXIPRIO; > > > > > > - if (riscv_cpu_virt_enabled(env)) { > > > - target_ulong pending_hs_irq = pending & -hs_sie; > > > + if (irq < 0 || irq > 63) { > > > + return iprio; > > > + } > > > > > > - if (pending_hs_irq) { > > > - riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP); > > > - return ctz64(pending_hs_irq); > > > + /* > > > + * Default priorities of local interrupts are defined in the > > > + * RISC-V Advanced Interrupt Architecture specification. > > > + * > > > + * ---------------------------------------------------------------- > > > + * Default | > > > + * Priority | Major Interrupt Numbers > > > + * ---------------------------------------------------------------- > > > + * Highest | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c), > > > + * | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38), > > > + * | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34), > > > + * | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30) > > > + * | > > > + * | 11 (0b), 3 (03), 7 (07) > > > + * | 9 (09), 1 (01), 5 (05) > > > + * | 12 (0c) > > > + * | 10 (0a), 2 (02), 6 (06) > > > + * | > > > + * | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c), > > > + * | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28), > > > + * | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24), > > > + * Lowest | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20) > > > + * ---------------------------------------------------------------- > > > + */ > > > + > > > + u = IPRIO_DEFAULT_U(irq); > > > + l = IPRIO_DEFAULT_L(irq); > > > + if (u == 0) { > > > + if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER || > > > + irq == IRQ_VS_SOFT) { > > > + iprio = IPRIO_DEFAULT_VS; > > > + } else if (irq == IRQ_S_GEXT) { > > > + iprio = IPRIO_DEFAULT_SGEXT; > > > + } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER || > > > + irq == IRQ_S_SOFT) { > > > + iprio = IPRIO_DEFAULT_S; > > > + } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER || > > > + irq == IRQ_M_SOFT) { > > > + iprio = IPRIO_DEFAULT_M; > > > + } else { > > > + iprio = IPRIO_DEFAULT_VS; > > > } > > > + } else if (u == 1) { > > > + if (l < 8) { > > > + iprio = IPRIO_DEFAULT_16_23(irq); > > > + } else { > > > + iprio = IPRIO_DEFAULT_24_31(irq); > > > + } > > > + } else if (u == 2) { > > > + iprio = IPRIO_DEFAULT_32_47(irq); > > > + } else if (u == 3) { > > > + iprio = IPRIO_DEFAULT_48_63(irq); > > > + } > > > + > > > + return iprio; > > > +} > > > + > > > +static int riscv_cpu_pending_to_irq(CPURISCVState *env, > > > + uint64_t pending, uint8_t *iprio) > > > +{ > > > + int irq, best_irq = EXCP_NONE; > > > + unsigned int prio, best_prio = UINT_MAX; > > > > > > - pending = vspending; > > > + if (!pending) { > > > + return EXCP_NONE; > > > } > > > > > > - irqs = (pending & ~env->mideleg & -mie) | (pending & env->mideleg & -sie); > > > + irq = ctz64(pending); > > > + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { > > > + return irq; > > > + } > > > > > > - if (irqs) { > > > - return ctz64(irqs); /* since non-zero */ > > > + pending = pending >> irq; > > > + while (pending) { > > > + prio = iprio[irq]; > > > + if (!prio) { > > > + prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ? > > > + 1 : IPRIO_MMAXIPRIO; > > > + } > > > + if ((pending & 0x1) && (prio < best_prio)) { > > > + best_irq = irq; > > > + best_prio = prio; > > > + } > > > + irq++; > > > + pending = pending >> 1; > > > + } > > > + > > > + return best_irq; > > > +} > > > + > > > +int riscv_cpu_mirq_pending(CPURISCVState *env) > > > +{ > > > + uint64_t irqs = env->mip & env->mie & ~env->mideleg & > > > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > > + > > > + return riscv_cpu_pending_to_irq(env, irqs, env->miprio); > > > +} > > > + > > > +int riscv_cpu_sirq_pending(CPURISCVState *env) > > > +{ > > > + uint64_t irqs = env->mip & env->mie & env->mideleg & > > > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > > + > > > + return riscv_cpu_pending_to_irq(env, irqs, env->siprio); > > > +} > > > + > > > +int riscv_cpu_vsirq_pending(CPURISCVState *env) > > > +{ > > > + uint64_t irqs = env->mip & env->mie & env->mideleg & > > > + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > > + > > > + return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio); > > > +} > > > + > > > +static int riscv_cpu_local_irq_pending(CPURISCVState *env) > > > +{ > > > + int virq; > > > + uint64_t irqs, mie, sie, vsie; > > > + uint64_t pending, vspending; > > > + > > > + /* Determine interrupt enable state of all privilege modes */ > > > + if (riscv_cpu_virt_enabled(env)) { > > > + mie = 1; > > > + sie = 1; > > > + vsie = (env->priv < PRV_S) || > > > + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE)); > > > } else { > > > - return EXCP_NONE; /* indicates no pending interrupt */ > > > + mie = (env->priv < PRV_M) || > > > + (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE)); > > > + sie = (env->priv < PRV_S) || > > > + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE)); > > > + vsie = 0; > > > + } > > > + > > > + /* Check M-mode interrupts */ > > > + pending = env->mip & env->mie & > > > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > > + irqs = pending & ~env->mideleg & -mie; > > > + if (irqs) { > > > + return riscv_cpu_pending_to_irq(env, irqs, env->miprio); > > > + } > > > + > > > + /* Check HS-mode interrupts */ > > > + irqs = pending & env->mideleg & -sie; > > > + if (irqs) { > > > + return riscv_cpu_pending_to_irq(env, irqs, env->siprio); > > > + } > > > + > > > + /* Check VS-mode interrupts */ > > > + vspending = env->mip & env->mie & > > > + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > > + irqs = vspending & env->hideleg & -vsie; > > > + if (irqs) { > > > + virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio); > > > + return (virq <= 0) ? virq : virq + 1; > > > } > > > + > > > + /* Indicates no pending interrupt */ > > > + return EXCP_NONE; > > > } > > > #endif > > > > > > @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx) > > > return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK; > > > } > > > > > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) > > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts) > > > { > > > CPURISCVState *env = &cpu->env; > > > if (env->miclaim & interrupts) { > > > @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) > > > } > > > } > > > > > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) > > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) > > > { > > > CPURISCVState *env = &cpu->env; > > > CPUState *cs = CPU(cpu); > > > - uint32_t old = env->mip; > > > + uint64_t old = env->mip; > > > bool locked = false; > > > > > > if (!qemu_mutex_iothread_locked()) { > > > @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) > > > return old; > > > } > > > > > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env, > > > + int (*rmw_fn)(void *arg, > > > + target_ulong reg, > > > + target_ulong *val, > > > + target_ulong new_val, > > > + target_ulong write_mask), > > > + void *rmw_fn_arg) > > > +{ > > > + env->imsic_rmw_fn = rmw_fn; > > > + env->imsic_rmw_fn_arg = rmw_fn_arg; > > > +} > > > + > > > void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), > > > uint32_t arg) > > > { > > > @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > > > */ > > > bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG); > > > target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK; > > > - target_ulong deleg = async ? env->mideleg : env->medeleg; > > > + uint64_t deleg = async ? env->mideleg : env->medeleg; > > > bool write_tval = false; > > > target_ulong tval = 0; > > > target_ulong htval = 0; > > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > > > index d2585395bf..3c016d7452 100644 > > > --- a/target/riscv/csr.c > > > +++ b/target/riscv/csr.c > > > @@ -153,11 +153,56 @@ static int 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 int smode(CPURISCVState *env, int csrno) > > > { > > > return -!riscv_has_ext(env, RVS); > > > } > > > > > > +static int smode32(CPURISCVState *env, int csrno) > > > +{ > > > + if (!riscv_cpu_is_32bit(env)) { > > > + 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 int hmode(CPURISCVState *env, int csrno) > > > { > > > if (riscv_has_ext(env, RVS) && > > > @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno) > > > static int hmode32(CPURISCVState *env, int csrno) > > > { > > > if (!riscv_cpu_is_32bit(env)) { > > > - return 0; > > > + return -RISCV_EXCP_ILLEGAL_INST; > > > + } > > > + > > > + return hmode(env, csrno); > > > +} > > > + > > > +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 int pmp(CPURISCVState *env, int csrno) > > > @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) > > > > > > /* 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 TLOWBITS64 ((uint64_t)((target_ulong)-1)) > > > > > > -static const target_ulong delegable_ints = S_MODE_INTERRUPTS | > > > - VS_MODE_INTERRUPTS; > > > -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | > > > - VS_MODE_INTERRUPTS; > > > +static const uint64_t delegable_ints = S_MODE_INTERRUPTS | > > > + VS_MODE_INTERRUPTS; > > > +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | > > > + VS_MODE_INTERRUPTS; > > > static const target_ulong delegable_excps = > > > (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | > > > (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | > > > @@ -419,10 +483,10 @@ static const target_ulong delegable_excps = > > > static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | > > > SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | > > > SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD; > > > -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; > > > -static const target_ulong hip_writable_mask = MIP_VSSIP; > > > -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; > > > -static const target_ulong vsip_writable_mask = MIP_VSSIP; > > > +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; > > > +static const uint64_t hip_writable_mask = MIP_VSSIP; > > > +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; > > > +static const uint64_t vsip_writable_mask = MIP_VSSIP; > > > > > > static const char valid_vm_1_10_32[16] = { > > > [VM_1_10_MBARE] = 1, > > > @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val) > > > > > > static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val) > > > { > > > - env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints); > > > + uint64_t mask = delegable_ints & TLOWBITS64; > > > + > > > + env->mideleg = (env->mideleg & ~mask) | (val & mask); > > > + if (riscv_has_ext(env, RVH)) { > > > + env->mideleg |= VS_MODE_INTERRUPTS; > > > + } > > > + return 0; > > > +} > > > + > > > +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_STOPI: > > > + return CSR_VSTOPI; > > > + case CSR_SSETEIPNUM: > > > + return CSR_VSSETEIPNUM; > > > + case CSR_SCLREIPNUM: > > > + return CSR_VSCLREIPNUM; > > > + case CSR_SSETEIENUM: > > > + return CSR_VSSETEIENUM; > > > + case CSR_SCLREIENUM: > > > + return CSR_VSCLREIENUM; > > > + default: > > > + return csrno; > > > + }; > > > +} > > > + > > > +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val, > > > + target_ulong new_val, target_ulong write_mask) > > > +{ > > > + target_ulong *iselect; > > > + > > > + switch (csrno) { > > > + case CSR_MISELECT: > > > + iselect = &env->miselect; > > > + break; > > > + case CSR_SISELECT: > > > + iselect = riscv_cpu_virt_enabled(env) ? > > > + &env->vsiselect : &env->siselect; > > > + break; > > > + case CSR_VSISELECT: > > > + iselect = &env->vsiselect; > > > + break; > > > + default: > > > + return -RISCV_EXCP_ILLEGAL_INST; > > > + }; > > > + > > > + if (val) { > > > + *val = *iselect; > > > + } > > > + > > > + if (write_mask) { > > > + *iselect = (*iselect & ~write_mask) | (new_val & write_mask); > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int rmw_iprio(target_ulong iselect, uint8_t *iprio, > > > + target_ulong *val, target_ulong new_val, > > > + target_ulong write_mask) > > > +{ > > > + int i, firq, nirqs; > > > + target_ulong old_val; > > > + > > > + if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) { > > > + return -EINVAL; > > > + } > > > +#if TARGET_LONG_BITS == 64 > > > + if (iselect & 0x1) { > > > + return -EINVAL; > > > + } > > > +#endif > > > + > > > + nirqs = 4 * (TARGET_LONG_BITS / 32); > > > + firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 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 (write_mask) { > > > + new_val = (old_val & ~write_mask) | (new_val & write_mask); > > > + for (i = 0; i < nirqs; i++) { > > > + 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 write_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) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > > + > > > + if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) { > > > + /* Local interrupt priority registers not available for VS-mode */ > > > + if (!virt) { > > > + ret = rmw_iprio(isel, iprio, val, new_val, write_mask); > > > + } > > > + } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) { > > > + /* IMSIC registers only available when machine implements it. */ > > > + if (env->imsic_rmw_fn) { > > > + /* Selected guest interrupt file should not be zero */ > > > + if (virt && !vgein) { > > > + goto done; > > > + } > > > + /* Call machine specific IMSIC register emulation */ > > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > > > + val, new_val, write_mask); > > > + } > > > + } > > > + > > > +done: > > > + if (ret) { > > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > > + } > > > + return 0; > > > +} > > > + > > > +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + int irq; > > > + > > > + irq = riscv_cpu_mirq_pending(env); > > > + if (irq <= 0 || irq > 63) { > > > + *val = 0; > > > + } else { > > > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > > > + *val |= env->miprio[irq]; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + bool virt; > > > + int ret = -EINVAL; > > > + target_ulong 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_MSETEIPNUM: > > > + case CSR_MCLREIPNUM: > > > + case CSR_MSETEIENUM: > > > + case CSR_MCLREIENUM: > > > + case CSR_SSETEIPNUM: > > > + case CSR_SCLREIPNUM: > > > + case CSR_SSETEIENUM: > > > + case CSR_SCLREIENUM: > > > + break; > > > + case CSR_VSSETEIPNUM: > > > + case CSR_VSCLREIPNUM: > > > + case CSR_VSSETEIENUM: > > > + case CSR_VSCLREIENUM: > > > + virt = true; > > > + break; > > > + default: > > > + goto done; > > > + }; > > > + > > > + /* IMSIC CSRs only available when machine implements IMSIC. */ > > > + if (!env->imsic_rmw_fn) { > > > + goto done; > > > + } > > > + > > > + /* Find the selected guest interrupt file */ > > > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > > + > > > + /* Selected guest interrupt file should not be zero */ > > > + if (virt && !vgein) { > > > + goto done; > > > + } > > > + > > > + /* Set/Clear CSRs always read zero */ > > > + ret = 0; > > > + if (val) { > > > + *val = 0; > > > + } > > > + > > > +done: > > > + if (ret) { > > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > > + } > > > + return 0; > > > +} > > > + > > > +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val) > > > +{ > > > + int ret = -EINVAL; > > > + bool set, pend, virt; > > > + target_ulong priv, isel, vgein; > > > + target_ulong new_val, write_mask; > > > + > > > + /* 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; > > > + 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->imsic_rmw_fn) { > > > + goto done; > > > + } > > > + > > > + /* Find target interrupt pending/enable register */ > > > + if (pend) { > > > + isel = ISELECT_IMSIC_EIP0; > > > + } else { > > > + isel = ISELECT_IMSIC_EIE0; > > > + } > > > + isel += val / IMSIC_EIPx_BITS; > > > + > > > + /* Find the interrupt bit to be set/clear */ > > > + write_mask = 1 << (val % IMSIC_EIPx_BITS); > > > + new_val = (set) ? write_mask : 0; > > > + > > > + /* Find the selected guest interrupt file */ > > > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > > + > > > + /* Selected guest interrupt file should not be zero */ > > > + if (virt && !vgein) { > > > + goto done; > > > + } > > > + > > > + /* Call machine specific IMSIC register emulation */ > > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > > > + NULL, new_val, write_mask); > > > + > > > +done: > > > + if (ret) { > > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > > + } > > > + return 0; > > > +} > > > + > > > +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + bool virt; > > > + int ret = -EINVAL; > > > + target_ulong priv, isel, vgein; > > > + target_ulong topei, write_mask; > > > + > > > + /* Decode register details from CSR number */ > > > + virt = false; > > > + switch (csrno) { > > > + case CSR_MCLAIMEI: > > > + priv = PRV_M; > > > + break; > > > + case CSR_SCLAIMEI: > > > + priv = PRV_S; > > > + virt = riscv_cpu_virt_enabled(env); > > > + break; > > > + default: > > > + goto done; > > > + }; > > > + > > > + /* IMSIC CSRs only available when machine implements IMSIC. */ > > > + if (!env->imsic_rmw_fn) { > > > + goto done; > > > + } > > > + > > > + /* Find the selected guest interrupt file */ > > > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > > + > > > + /* Selected guest interrupt file should not be zero */ > > > + if (virt && !vgein) { > > > + goto done; > > > + } > > > + > > > + /* Call machine specific IMSIC register emulation for reading TOPEI */ > > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > > + IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein), > > > + &topei, -1, 0); > > > + if (ret) { > > > + goto done; > > > + } > > > + > > > + /* If no interrupt pending then we are done */ > > > + if (!topei) { > > > + goto done; > > > + } > > > + > > > + /* Find target interrupt pending register */ > > > + isel = ISELECT_IMSIC_EIP0; > > > + isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS); > > > + > > > + /* Find the interrupt bit to be cleared */ > > > + write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS); > > > + > > > + /* Call machine specific IMSIC register emulation to clear pending bit */ > > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > > > + NULL, 0, write_mask); > > > + > > > + /* Update return value */ > > > + if (val) { > > > + *val = topei; > > > + } > > > + > > > +done: > > > + if (ret) { > > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > > + } > > > + return 0; > > > +} > > > + > > > +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + *val = (env->mideleg >> 32); > > > + return 0; > > > +} > > > + > > > +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val) > > > +{ > > > + uint64_t mask = delegable_ints & ~TLOWBITS64; > > > + uint64_t newval = ((uint64_t)val) << 32; > > > + > > > + env->mideleg = (env->mideleg & ~mask) | (newval & mask); > > > if (riscv_has_ext(env, RVH)) { > > > env->mideleg |= VS_MODE_INTERRUPTS; > > > } > > > @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val) > > > > > > static int write_mie(CPURISCVState *env, int csrno, target_ulong val) > > > { > > > - env->mie = (env->mie & ~all_ints) | (val & all_ints); > > > + uint64_t mask = all_ints & TLOWBITS64; > > > + > > > + env->mie = (env->mie & ~mask) | (val & mask); > > > + return 0; > > > +} > > > + > > > +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + *val = (env->mie >> 32); > > > + return 0; > > > +} > > > + > > > +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val) > > > +{ > > > + uint64_t mask = all_ints & ~TLOWBITS64; > > > + uint64_t newval = ((uint64_t)val) << 32; > > > + > > > + env->mie = (env->mie & ~mask) | (newval & mask); > > > return 0; > > > } > > > > > > @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > { > > > 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 mask = ((uint64_t)write_mask) & delegable_ints & > > > + ~env->miclaim & TLOWBITS64; > > > + uint64_t old_mip; > > > > > > if (mask) { > > > old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > > @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > return 0; > > > } > > > > > > +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > + target_ulong new_value, target_ulong write_mask) > > > +{ > > > + RISCVCPU *cpu = env_archcpu(env); > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > + uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints & > > > + ~env->miclaim & ~TLOWBITS64; > > > + uint64_t new_value64 = (uint64_t)new_value << 32; > > > + uint64_t old_mip; > > > + > > > + if (mask) { > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > > + } else { > > > + old_mip = env->mip; > > > + } > > > + > > > + if (ret_value) { > > > + *ret_value = old_mip >> 32; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > /* Supervisor Trap Setup */ > > > static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val) > > > { > > > @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val) > > > > > > static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val) > > > { > > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64; > > > + > > > /* Shift the VS bits to their S bit location in vsie */ > > > - *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1; > > > + *val = (env->mie & mask) >> 1; > > > + return 0; > > > +} > > > + > > > +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64; > > > + > > > + /* Shift the VS bits to their S bit location in vsieh */ > > > + *val = (env->mie & mask) >> (32 + 1); > > > return 0; > > > } > > > > > > static int read_sie(CPURISCVState *env, int csrno, target_ulong *val) > > > { > > > if (riscv_cpu_virt_enabled(env)) { > > > - read_vsie(env, CSR_VSIE, val); > > > - } else { > > > - *val = env->mie & env->mideleg; > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > + } > > > + return read_vsie(env, CSR_VSIE, val); > > > } > > > + > > > + *val = env->mie & env->mideleg; > > > return 0; > > > } > > > > > > static int write_vsie(CPURISCVState *env, int csrno, target_ulong val) > > > { > > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & > > > + all_ints & TLOWBITS64; > > > + > > > /* 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); > > > + env->mie = (env->mie & ~mask) | ((val << 1) & mask); > > > + > > > + return 0; > > > +} > > > + > > > +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val) > > > +{ > > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & > > > + all_ints & ~TLOWBITS64; > > > + uint64_t newval = (uint64_t)val << 32; > > > + > > > + /* Shift the S bits to their VS bit location in mie */ > > > + env->mie = (env->mie & ~mask) | ((newval << 1) & mask); > > > + > > > + return 0; > > > } > > > > > > static int write_sie(CPURISCVState *env, int csrno, target_ulong val) > > > { > > > + uint64_t mask; > > > + > > > if (riscv_cpu_virt_enabled(env)) { > > > - write_vsie(env, CSR_VSIE, val); > > > - } else { > > > - target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) | > > > - (val & S_MODE_INTERRUPTS); > > > - write_mie(env, CSR_MIE, newval); > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > + } > > > + return write_vsie(env, CSR_VSIE, val); > > > + } > > > + > > > + mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64; > > > + env->mie = (env->mie & ~mask) | ((uint64_t)val & mask); > > > + > > > + return 0; > > > +} > > > + > > > +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + if (riscv_cpu_virt_enabled(env)) { > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > + } > > > + return read_vsieh(env, CSR_VSIEH, val); > > > + } > > > + > > > + *val = ((env->mie & env->mideleg) >> 32); > > > + return 0; > > > +} > > > + > > > +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val) > > > +{ > > > + uint64_t mask, newval; > > > + > > > + if (riscv_cpu_virt_enabled(env)) { > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > + } > > > + return write_vsieh(env, CSR_VSIEH, val); > > > } > > > > > > + mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64; > > > + newval = (uint64_t)val << 32; > > > + > > > + env->mie = (env->mie & ~mask) | (newval & mask); > > > return 0; > > > } > > > > > > @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val) > > > static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > target_ulong new_value, target_ulong write_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); > > > - *ret_value &= VS_MODE_INTERRUPTS; > > > - /* Shift the VS bits to their S bit location in vsip */ > > > - *ret_value >>= 1; > > > - return ret; > > > + RISCVCPU *cpu = env_archcpu(env); > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > + uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints & > > > + vsip_writable_mask & env->hideleg & > > > + ~env->miclaim & TLOWBITS64; > > > + uint64_t old_mip; > > > + > > > + if (mask) { > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > > + } else { > > > + old_mip = env->mip; > > > + } > > > + > > > + if (ret_value) { > > > + *ret_value = old_mip & VS_MODE_INTERRUPTS; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > + target_ulong new_value, target_ulong write_mask) > > > +{ > > > + RISCVCPU *cpu = env_archcpu(env); > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > + uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints & > > > + vsip_writable_mask & env->hideleg & > > > + ~env->miclaim & ~TLOWBITS64; > > > + uint64_t new_value64 = (uint64_t)new_value << 32; > > > + uint64_t old_mip; > > > + > > > + if (mask) { > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > > + } else { > > > + old_mip = env->mip; > > > + } > > > + > > > + if (ret_value) { > > > + *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32; > > > + } > > > + > > > + return 0; > > > } > > > > > > static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > target_ulong new_value, target_ulong write_mask) > > > { > > > - int ret; > > > + RISCVCPU *cpu = env_archcpu(env); > > > + uint64_t mask, old_mip; > > > > > > if (riscv_cpu_virt_enabled(env)) { > > > - ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > + } > > > + return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); > > > + } > > > + > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > + mask = ((uint64_t)write_mask) & delegable_ints & > > > + env->mideleg & sip_writable_mask & > > > + ~env->miclaim & TLOWBITS64; > > > + if (mask) { > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > > } else { > > > - ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, > > > - write_mask & env->mideleg & sip_writable_mask); > > > + old_mip = env->mip; > > > } > > > > > > - *ret_value &= env->mideleg; > > > - return ret; > > > + if (ret_value) { > > > + *ret_value = old_mip; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > + target_ulong new_value, target_ulong write_mask) > > > +{ > > > + RISCVCPU *cpu = env_archcpu(env); > > > + uint64_t mask, new_value64; > > > + uint64_t old_mip; > > > + > > > + if (riscv_cpu_virt_enabled(env)) { > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > + } > > > + return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask); > > > + } > > > + > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > + mask = ((uint64_t)write_mask << 32) & delegable_ints & > > > + env->mideleg & sip_writable_mask & > > > + ~env->miclaim & ~TLOWBITS64; > > > + new_value64 = (uint64_t)new_value << 32; > > > + if (mask) { > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > > + } else { > > > + old_mip = env->mip; > > > + } > > > + > > > + if (ret_value) { > > > + *ret_value = (old_mip & env->mideleg) >> 32; > > > + } > > > + > > > + return 0; > > > } > > > > > > /* Supervisor Protection and Translation */ > > > @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) > > > return 0; > > > } > > > > > > +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + int irq, hiid; > > > + uint8_t hiprio, iprio; > > > + > > > + irq = riscv_cpu_vsirq_pending(env); > > > + if (irq <= 0 || irq > 63) { > > > + *val = 0; > > > + } else { > > > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > > > + iprio = env->hviprio[irq]; > > > + /* TODO: This needs to improve in specification */ > > > + if (!(env->hstatus & HSTATUS_VGEIN)) { > > > + hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >> > > > + HVICONTROL_IID_SHIFT; > > > + hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK; > > > + if (irq == hiid && hiprio) { > > > + iprio = hiprio; > > > + } > > > + } > > > + *val |= iprio; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + int irq; > > > + > > > + 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 { > > > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > > > + *val |= env->siprio[irq]; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > /* Hypervisor Extensions */ > > > static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) > > > { > > > @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val) > > > return 0; > > > } > > > > > > +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + *val = env->hideleg >> 32; > > > + return 0; > > > +} > > > + > > > +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val) > > > +{ > > > + uint64_t mask = ~TLOWBITS64; > > > + uint64_t newval = ((uint64_t)val) << 32; > > > + > > > + env->hideleg = (env->hideleg & ~mask) | (newval & mask); > > > + > > > + return 0; > > > +} > > > + > > > static int rmw_hvip(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, > > > - write_mask & hvip_writable_mask); > > > + RISCVCPU *cpu = env_archcpu(env); > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > + uint64_t mask = ((uint64_t)write_mask) & delegable_ints & > > > + hvip_writable_mask & > > > + ~env->miclaim & TLOWBITS64; > > > + uint64_t old_mip; > > > + > > > + if (mask) { > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > > + } else { > > > + old_mip = env->mip; > > > + } > > > > > > - *ret_value &= hvip_writable_mask; > > > + if (ret_value) { > > > + *ret_value = old_mip & hvip_writable_mask; > > > + } > > > > > > - return ret; > > > + return 0; > > > +} > > > + > > > +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > + target_ulong new_value, target_ulong write_mask) > > > +{ > > > + RISCVCPU *cpu = env_archcpu(env); > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > + uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints & > > > + hvip_writable_mask & > > > + ~env->miclaim & ~TLOWBITS64; > > > + uint64_t new_value64 = (uint64_t)new_value << 32; > > > + uint64_t old_mip; > > > + > > > + if (mask) { > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > > + } else { > > > + old_mip = env->mip; > > > + } > > > + > > > + if (ret_value) { > > > + *ret_value = (old_mip & hvip_writable_mask) >> 32; > > > + } > > > + > > > + return 0; > > > } > > > > > > static int 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, > > > - write_mask & hip_writable_mask); > > > + RISCVCPU *cpu = env_archcpu(env); > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > + uint64_t mask = ((uint64_t)write_mask) & delegable_ints & > > > + hip_writable_mask & > > > + ~env->miclaim & TLOWBITS64; > > > + uint64_t old_mip; > > > > > > - *ret_value &= hip_writable_mask; > > > + if (mask) { > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > > + } else { > > > + old_mip = env->mip; > > > + } > > > > > > - return ret; > > > + if (ret_value) { > > > + *ret_value = old_mip & hip_writable_mask; > > > + } > > > + > > > + return 0; > > > } > > > > > > static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) > > > @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) > > > > > > static int 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); > > > + uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64; > > > + env->mie = (env->mie & ~mask) | ((uint64_t)val & mask); > > > + return 0; > > > } > > > > > > static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val) > > > @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) > > > return 0; > > > } > > > > > > +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val) > > > +{ > > > + *val = env->hvicontrol; > > > + return 0; > > > +} > > > + > > > +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val) > > > +{ > > > + env->hvicontrol = val & HVICONTROL_VALID_MASK; > > > + return 0; > > > +} > > > + > > > +static int read_hvipriox(CPURISCVState *env, int first_index, > > > + uint8_t *iprio, target_ulong *val) > > > +{ > > > + int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32); > > > + > > > + /* First index has to be multiple of numbe 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 0; > > > +} > > > + > > > +static int write_hvipriox(CPURISCVState *env, int first_index, > > > + uint8_t *iprio, target_ulong val) > > > +{ > > > + int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32); > > > + > > > + /* First index has to be multiple of numbe 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 0; > > > +} > > > + > > > +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 int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val) > > > { > > > @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { > > > [CSR_MBADADDR] = { "mbadaddr", any, read_mbadaddr, write_mbadaddr }, > > > [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, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_MCLAIMEI] = { "mclaimei", aia_any, read_xclaimei }, > > > + > > > + /* Machine-Level High-Half CSRs (AIA) */ > > > + [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh }, > > > + [CSR_MIEH] = { "mieh", aia_any32, read_mieh, write_mieh }, > > > + [CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph }, > > > + > > > /* Supervisor Trap Setup */ > > > [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus }, > > > [CSR_SIE] = { "sie", smode, read_sie, write_sie }, > > > @@ -1444,6 +2357,24 @@ 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, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_SCLAIMEI] = { "sclaimei", aia_smode, read_xclaimei }, > > > + > > > + /* Supervisor-Level High-Half CSRs (AIA) */ > > > + [CSR_SIEH] = { "sieh", aia_smode32, read_sieh, write_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 }, > > > @@ -1472,6 +2403,32 @@ 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_HVICONTROL] = { "hvicontrol", aia_hmode, read_hvicontrol, write_hvicontrol }, > > > + [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, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > > > + [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > > > + > > > + /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ > > > + [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, read_hidelegh, write_hidelegh }, > > > + [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, read_vsieh, write_vsieh }, > > > + [CSR_VSIPH] = { "vsiep", aia_hmode32, NULL, NULL, rmw_vsiph }, > > > + > > > /* Physical Memory Protection */ > > > [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg }, > > > [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg }, > > > diff --git a/target/riscv/machine.c b/target/riscv/machine.c > > > index 44d4015bd6..f7fa48c240 100644 > > > --- a/target/riscv/machine.c > > > +++ b/target/riscv/machine.c > > > @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = { > > > > > > static const VMStateDescription vmstate_hyper = { > > > .name = "cpu/hyper", > > > - .version_id = 1, > > > - .minimum_version_id = 1, > > > + .version_id = 2, > > > + .minimum_version_id = 2, > > > .needed = hyper_needed, > > > .fields = (VMStateField[]) { > > > VMSTATE_UINTTL(env.hstatus, RISCVCPU), > > > VMSTATE_UINTTL(env.hedeleg, RISCVCPU), > > > - VMSTATE_UINTTL(env.hideleg, RISCVCPU), > > > + VMSTATE_UINT64(env.hideleg, RISCVCPU), > > > VMSTATE_UINTTL(env.hcounteren, RISCVCPU), > > > VMSTATE_UINTTL(env.htval, RISCVCPU), > > > VMSTATE_UINTTL(env.htinst, RISCVCPU), > > > VMSTATE_UINTTL(env.hgatp, RISCVCPU), > > > VMSTATE_UINT64(env.htimedelta, RISCVCPU), > > > > > > + VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64), > > > + VMSTATE_UINTTL(env.hvicontrol, RISCVCPU), > > > + > > > VMSTATE_UINT64(env.vsstatus, RISCVCPU), > > > VMSTATE_UINTTL(env.vstvec, RISCVCPU), > > > VMSTATE_UINTTL(env.vsscratch, RISCVCPU), > > > @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = { > > > VMSTATE_UINTTL(env.vscause, RISCVCPU), > > > VMSTATE_UINTTL(env.vstval, RISCVCPU), > > > VMSTATE_UINTTL(env.vsatp, RISCVCPU), > > > + VMSTATE_UINTTL(env.vsiselect, RISCVCPU), > > > > > > VMSTATE_UINTTL(env.mtval2, RISCVCPU), > > > VMSTATE_UINTTL(env.mtinst, RISCVCPU), > > > @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = { > > > > > > const VMStateDescription vmstate_riscv_cpu = { > > > .name = "cpu", > > > - .version_id = 1, > > > - .minimum_version_id = 1, > > > + .version_id = 2, > > > + .minimum_version_id = 2, > > > .fields = (VMStateField[]) { > > > VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), > > > VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32), > > > + VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64), > > > + VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64), > > > VMSTATE_UINTTL(env.pc, RISCVCPU), > > > VMSTATE_UINTTL(env.load_res, RISCVCPU), > > > VMSTATE_UINTTL(env.load_val, RISCVCPU), > > > @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = { > > > VMSTATE_UINTTL(env.resetvec, RISCVCPU), > > > VMSTATE_UINTTL(env.mhartid, RISCVCPU), > > > VMSTATE_UINT64(env.mstatus, RISCVCPU), > > > - VMSTATE_UINTTL(env.mip, RISCVCPU), > > > - VMSTATE_UINT32(env.miclaim, RISCVCPU), > > > - VMSTATE_UINTTL(env.mie, RISCVCPU), > > > - VMSTATE_UINTTL(env.mideleg, RISCVCPU), > > > + VMSTATE_UINT64(env.mip, RISCVCPU), > > > + VMSTATE_UINT64(env.miclaim, RISCVCPU), > > > + VMSTATE_UINT64(env.mie, RISCVCPU), > > > + VMSTATE_UINT64(env.mideleg, RISCVCPU), > > > VMSTATE_UINTTL(env.sptbr, RISCVCPU), > > > VMSTATE_UINTTL(env.satp, RISCVCPU), > > > VMSTATE_UINTTL(env.sbadaddr, RISCVCPU), > > > @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = { > > > VMSTATE_UINTTL(env.mepc, RISCVCPU), > > > VMSTATE_UINTTL(env.mcause, RISCVCPU), > > > VMSTATE_UINTTL(env.mtval, RISCVCPU), > > > + VMSTATE_UINTTL(env.miselect, RISCVCPU), > > > + VMSTATE_UINTTL(env.siselect, RISCVCPU), > > > VMSTATE_UINTTL(env.scounteren, RISCVCPU), > > > VMSTATE_UINTTL(env.mcounteren, RISCVCPU), > > > VMSTATE_UINTTL(env.sscratch, RISCVCPU), > > > -- > > > 2.25.1 > > > > > >
On Fri, Jun 11, 2021 at 2:16 PM Alistair Francis <alistair23@gmail.com> wrote: > > On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote: > > > > On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote: > > > > > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote: > > > > > > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode, > > > > and VS-mode. > > > > > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > > > > --- > > > > target/riscv/cpu.c | 27 +- > > > > target/riscv/cpu.h | 52 +- > > > > target/riscv/cpu_helper.c | 245 ++++++++- > > > > target/riscv/csr.c | 1059 +++++++++++++++++++++++++++++++++++-- > > > > target/riscv/machine.c | 26 +- > > > > 5 files changed, 1309 insertions(+), 100 deletions(-) > > > > > > I feel this patch could be split up more :) > > > > This is patch is large because I did not want to break functionality. > > > > I try again to break this patch. At the moment, the best I can do is > > to break in to two parts. > > 1) AIA local interrupt CSRs without IMSIC > > 2) Extend AIA local interrupt CSRs to support IMSIC register access > > As the patch is being added while AIA isn't enabled you are able to > add the AIA in breaking stages. That is the AIA isn't fully > functional, you still have to make sure not to break existing users. > > > > > > > > > > > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > > > index f3702111ae..795162834b 100644 > > > > --- a/target/riscv/cpu.c > > > > +++ b/target/riscv/cpu.c > > > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) > > > > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ", > > > > (target_ulong)env->vsstatus); > > > > } > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", env->mip); > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip ", env->mip); > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie ", env->mie); > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg); > > > > if (riscv_has_ext(env, RVH)) { > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg); > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg); > > > > } > > > > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); > > > > if (riscv_has_ext(env, RVH)) { > > > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, > > > > > > > > static void riscv_cpu_reset(DeviceState *dev) > > > > { > > > > + uint8_t iprio; > > > > + int i, irq, rdzero; > > > > CPUState *cs = CPU(dev); > > > > RISCVCPU *cpu = RISCV_CPU(cs); > > > > RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); > > > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev) > > > > env->mcause = 0; > > > > env->pc = env->resetvec; > > > > env->two_stage_lookup = false; > > > > + > > > > + /* Initialized default priorities of local interrupts. */ > > > > + for (i = 0; i < ARRAY_SIZE(env->miprio); i++) { > > > > + iprio = riscv_cpu_default_priority(i); > > > > + env->miprio[i] = iprio; > > > > + env->siprio[i] = iprio; > > > > + env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO; > > > > + } > > > > + i = 0; > > > > + while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) { > > > > + if (rdzero) { > > > > + env->hviprio[irq] = 0; > > > > + } else { > > > > + env->hviprio[irq] = env->miprio[irq]; > > > > + } > > > > + i++; > > > > + } > > > > #endif > > > > cs->exception_index = EXCP_NONE; > > > > env->load_res = -1; > > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > > > > index f00c60c840..780d3f9058 100644 > > > > --- a/target/riscv/cpu.h > > > > +++ b/target/riscv/cpu.h > > > > @@ -157,12 +157,12 @@ struct CPURISCVState { > > > > */ > > > > uint64_t mstatus; > > > > > > > > - target_ulong mip; > > > > + uint64_t mip; > > > > > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume > > > all the other existing target_ulong CSRs are the same. > > > > When AIA is available the number of local interrupts are 64 for > > both RV32 and RV64. > > Is that going to be reflected in the priv spec? The AIA spec is going to be separate from priv spec since it is totally optional. This AIA local interrupt CSRs will be part of AIA spec and should only be implemented if a RISC-V implementations wants to use AIA. We have four types of changes as far as CSRs go: 1) RV32 CSRs to support 64 local interrupts on RV32 2) Indirect CSRs to access local interrupt priorities 3) Interrupt filtering CSRs 4) IMSIC support CSRs From above #3 is totally optional and not implemented by this patch whereas #4 is only required when platform has RISC-V IMSIC. A platform can skip all four changes mentioned above, if the platform only wants AIA APLIC to manage wired interrupts. Regards, Anup > > > > > The width of CSRs remain same as target_ulong but we have > > new CSRs for RV32 (such as mipH) for the high-half. > > Ah! Sorry I missed that. > > This change should be in a seperate patch then. > > > > > Also, this patch changes does not break the case when AIA > > is not available (or disabled). > > Good, we need to make sure we don't. > > Alistair > > > > > Regards, > > Anup > > > > > > > > Alistair > > > > > > > > > > > - uint32_t miclaim; > > > > + uint64_t miclaim; > > > > > > > > - target_ulong mie; > > > > - target_ulong mideleg; > > > > + uint64_t mie; > > > > + uint64_t mideleg; > > > > > > > > target_ulong sptbr; /* until: priv-1.9.1 */ > > > > target_ulong satp; /* since: priv-1.10.0 */ > > > > @@ -179,16 +179,27 @@ struct CPURISCVState { > > > > target_ulong mcause; > > > > target_ulong mtval; /* since: priv-1.10.0 */ > > > > > > > > + /* AIA CSRs */ > > > > + target_ulong miselect; > > > > + target_ulong siselect; > > > > + > > > > + uint8_t miprio[64]; > > > > + uint8_t siprio[64]; > > > > + > > > > /* Hypervisor CSRs */ > > > > target_ulong hstatus; > > > > target_ulong hedeleg; > > > > - target_ulong hideleg; > > > > + uint64_t hideleg; > > > > target_ulong hcounteren; > > > > target_ulong htval; > > > > target_ulong htinst; > > > > target_ulong hgatp; > > > > uint64_t htimedelta; > > > > > > > > + /* AIA HS-mode CSRs */ > > > > + uint8_t hviprio[64]; > > > > + target_ulong hvicontrol; > > > > + > > > > /* Virtual CSRs */ > > > > /* > > > > * For RV32 this is 32-bit vsstatus and 32-bit vsstatush. > > > > @@ -202,6 +213,9 @@ struct CPURISCVState { > > > > target_ulong vstval; > > > > target_ulong vsatp; > > > > > > > > + /* AIA VS-mode CSRs */ > > > > + target_ulong vsiselect; > > > > + > > > > target_ulong mtval2; > > > > target_ulong mtinst; > > > > > > > > @@ -236,6 +250,18 @@ struct CPURISCVState { > > > > uint64_t (*rdtime_fn)(uint32_t); > > > > uint32_t rdtime_fn_arg; > > > > > > > > + /* machine specific AIA IMSIC read-modify-write callback */ > > > > +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \ > > > > + ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \ > > > > + (((__priv) & 0x3) << 16) | (__isel & 0xffff)) > > > > +#define IMSIC_REG_ISEL(__reg) ((__reg) & 0xffff) > > > > +#define IMSIC_REG_PRIV(__reg) (((__reg) >> 16) & 0x3) > > > > +#define IMSIC_REG_VIRT(__reg) (((__reg) >> 20) & 0x1) > > > > +#define IMSIC_REG_VGEIN(__reg) (((__reg) >> 24) & 0x3f) > > > > + int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val, > > > > + target_ulong new_val, target_ulong write_mask); > > > > + void *imsic_rmw_fn_arg; > > > > + > > > > /* True if in debugger mode. */ > > > > bool debugger; > > > > #endif > > > > @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, > > > > int cpuid, void *opaque); > > > > int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); > > > > int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); > > > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero); > > > > +uint8_t riscv_cpu_default_priority(int irq); > > > > +int riscv_cpu_mirq_pending(CPURISCVState *env); > > > > +int riscv_cpu_sirq_pending(CPURISCVState *env); > > > > +int riscv_cpu_vsirq_pending(CPURISCVState *env); > > > > bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request); > > > > bool riscv_cpu_fp_enabled(CPURISCVState *env); > > > > bool riscv_cpu_virt_enabled(CPURISCVState *env); > > > > @@ -364,9 +395,16 @@ void riscv_cpu_list(void); > > > > > > > > #ifndef CONFIG_USER_ONLY > > > > void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env); > > > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); > > > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value); > > > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts); > > > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value); > > > > #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ > > > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env, > > > > + int (*rmw_fn)(void *arg, > > > > + target_ulong reg, > > > > + target_ulong *val, > > > > + target_ulong new_val, > > > > + target_ulong write_mask), > > > > + void *rmw_fn_arg); > > > > void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), > > > > uint32_t arg); > > > > #endif > > > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c > > > > index 21c54ef561..5b06b4f995 100644 > > > > --- a/target/riscv/cpu_helper.c > > > > +++ b/target/riscv/cpu_helper.c > > > > @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) > > > > } > > > > > > > > #ifndef CONFIG_USER_ONLY > > > > -static int riscv_cpu_local_irq_pending(CPURISCVState *env) > > > > + > > > > +/* > > > > + * The HS-mode is allowed to configure priority only for the > > > > + * following VS-mode local interrupts: > > > > + * > > > > + * 0 (Reserved interrupt, reads as zero) > > > > + * 1 Supervisor software interrupt > > > > + * 4 (Reserved interrupt, reads as zero) > > > > + * 5 Supervisor timer interrupt > > > > + * 8 (Reserved interrupt, reads as zero) > > > > + * 13 (Reserved interrupt) > > > > + * 14 " > > > > + * 15 " > > > > + * 16 " > > > > + * 18 Debug/trace interrupt > > > > + * 20 (Reserved interrupt) > > > > + * 22 ” > > > > + * 24 ” > > > > + * 26 ” > > > > + * 28 " > > > > + * 30 (Reserved for standard reporting of bus or system errors) > > > > + */ > > > > + > > > > +static int hviprio_index2irq[] = > > > > + { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 }; > > > > +static int hviprio_index2rdzero[] = > > > > + { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; > > > > + > > > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero) > > > > { > > > > - target_ulong irqs; > > > > + if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) { > > > > + return -EINVAL; > > > > + } > > > > > > > > - 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); > > > > + if (out_irq) { > > > > + *out_irq = hviprio_index2irq[index]; > > > > + } > > > > + > > > > + if (out_rdzero) { > > > > + *out_rdzero = hviprio_index2rdzero[index]; > > > > + } > > > > > > > > - 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)); > > > > + return 0; > > > > +} > > > > > > > > - 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); > > > > +uint8_t riscv_cpu_default_priority(int irq) > > > > +{ > > > > + int u, l; > > > > + uint8_t iprio = IPRIO_MMAXIPRIO; > > > > > > > > - if (riscv_cpu_virt_enabled(env)) { > > > > - target_ulong pending_hs_irq = pending & -hs_sie; > > > > + if (irq < 0 || irq > 63) { > > > > + return iprio; > > > > + } > > > > > > > > - if (pending_hs_irq) { > > > > - riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP); > > > > - return ctz64(pending_hs_irq); > > > > + /* > > > > + * Default priorities of local interrupts are defined in the > > > > + * RISC-V Advanced Interrupt Architecture specification. > > > > + * > > > > + * ---------------------------------------------------------------- > > > > + * Default | > > > > + * Priority | Major Interrupt Numbers > > > > + * ---------------------------------------------------------------- > > > > + * Highest | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c), > > > > + * | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38), > > > > + * | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34), > > > > + * | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30) > > > > + * | > > > > + * | 11 (0b), 3 (03), 7 (07) > > > > + * | 9 (09), 1 (01), 5 (05) > > > > + * | 12 (0c) > > > > + * | 10 (0a), 2 (02), 6 (06) > > > > + * | > > > > + * | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c), > > > > + * | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28), > > > > + * | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24), > > > > + * Lowest | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20) > > > > + * ---------------------------------------------------------------- > > > > + */ > > > > + > > > > + u = IPRIO_DEFAULT_U(irq); > > > > + l = IPRIO_DEFAULT_L(irq); > > > > + if (u == 0) { > > > > + if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER || > > > > + irq == IRQ_VS_SOFT) { > > > > + iprio = IPRIO_DEFAULT_VS; > > > > + } else if (irq == IRQ_S_GEXT) { > > > > + iprio = IPRIO_DEFAULT_SGEXT; > > > > + } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER || > > > > + irq == IRQ_S_SOFT) { > > > > + iprio = IPRIO_DEFAULT_S; > > > > + } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER || > > > > + irq == IRQ_M_SOFT) { > > > > + iprio = IPRIO_DEFAULT_M; > > > > + } else { > > > > + iprio = IPRIO_DEFAULT_VS; > > > > } > > > > + } else if (u == 1) { > > > > + if (l < 8) { > > > > + iprio = IPRIO_DEFAULT_16_23(irq); > > > > + } else { > > > > + iprio = IPRIO_DEFAULT_24_31(irq); > > > > + } > > > > + } else if (u == 2) { > > > > + iprio = IPRIO_DEFAULT_32_47(irq); > > > > + } else if (u == 3) { > > > > + iprio = IPRIO_DEFAULT_48_63(irq); > > > > + } > > > > + > > > > + return iprio; > > > > +} > > > > + > > > > +static int riscv_cpu_pending_to_irq(CPURISCVState *env, > > > > + uint64_t pending, uint8_t *iprio) > > > > +{ > > > > + int irq, best_irq = EXCP_NONE; > > > > + unsigned int prio, best_prio = UINT_MAX; > > > > > > > > - pending = vspending; > > > > + if (!pending) { > > > > + return EXCP_NONE; > > > > } > > > > > > > > - irqs = (pending & ~env->mideleg & -mie) | (pending & env->mideleg & -sie); > > > > + irq = ctz64(pending); > > > > + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { > > > > + return irq; > > > > + } > > > > > > > > - if (irqs) { > > > > - return ctz64(irqs); /* since non-zero */ > > > > + pending = pending >> irq; > > > > + while (pending) { > > > > + prio = iprio[irq]; > > > > + if (!prio) { > > > > + prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ? > > > > + 1 : IPRIO_MMAXIPRIO; > > > > + } > > > > + if ((pending & 0x1) && (prio < best_prio)) { > > > > + best_irq = irq; > > > > + best_prio = prio; > > > > + } > > > > + irq++; > > > > + pending = pending >> 1; > > > > + } > > > > + > > > > + return best_irq; > > > > +} > > > > + > > > > +int riscv_cpu_mirq_pending(CPURISCVState *env) > > > > +{ > > > > + uint64_t irqs = env->mip & env->mie & ~env->mideleg & > > > > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > > > + > > > > + return riscv_cpu_pending_to_irq(env, irqs, env->miprio); > > > > +} > > > > + > > > > +int riscv_cpu_sirq_pending(CPURISCVState *env) > > > > +{ > > > > + uint64_t irqs = env->mip & env->mie & env->mideleg & > > > > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > > > + > > > > + return riscv_cpu_pending_to_irq(env, irqs, env->siprio); > > > > +} > > > > + > > > > +int riscv_cpu_vsirq_pending(CPURISCVState *env) > > > > +{ > > > > + uint64_t irqs = env->mip & env->mie & env->mideleg & > > > > + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > > > + > > > > + return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio); > > > > +} > > > > + > > > > +static int riscv_cpu_local_irq_pending(CPURISCVState *env) > > > > +{ > > > > + int virq; > > > > + uint64_t irqs, mie, sie, vsie; > > > > + uint64_t pending, vspending; > > > > + > > > > + /* Determine interrupt enable state of all privilege modes */ > > > > + if (riscv_cpu_virt_enabled(env)) { > > > > + mie = 1; > > > > + sie = 1; > > > > + vsie = (env->priv < PRV_S) || > > > > + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE)); > > > > } else { > > > > - return EXCP_NONE; /* indicates no pending interrupt */ > > > > + mie = (env->priv < PRV_M) || > > > > + (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE)); > > > > + sie = (env->priv < PRV_S) || > > > > + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE)); > > > > + vsie = 0; > > > > + } > > > > + > > > > + /* Check M-mode interrupts */ > > > > + pending = env->mip & env->mie & > > > > + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > > > + irqs = pending & ~env->mideleg & -mie; > > > > + if (irqs) { > > > > + return riscv_cpu_pending_to_irq(env, irqs, env->miprio); > > > > + } > > > > + > > > > + /* Check HS-mode interrupts */ > > > > + irqs = pending & env->mideleg & -sie; > > > > + if (irqs) { > > > > + return riscv_cpu_pending_to_irq(env, irqs, env->siprio); > > > > + } > > > > + > > > > + /* Check VS-mode interrupts */ > > > > + vspending = env->mip & env->mie & > > > > + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); > > > > + irqs = vspending & env->hideleg & -vsie; > > > > + if (irqs) { > > > > + virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio); > > > > + return (virq <= 0) ? virq : virq + 1; > > > > } > > > > + > > > > + /* Indicates no pending interrupt */ > > > > + return EXCP_NONE; > > > > } > > > > #endif > > > > > > > > @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx) > > > > return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK; > > > > } > > > > > > > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) > > > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts) > > > > { > > > > CPURISCVState *env = &cpu->env; > > > > if (env->miclaim & interrupts) { > > > > @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) > > > > } > > > > } > > > > > > > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) > > > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) > > > > { > > > > CPURISCVState *env = &cpu->env; > > > > CPUState *cs = CPU(cpu); > > > > - uint32_t old = env->mip; > > > > + uint64_t old = env->mip; > > > > bool locked = false; > > > > > > > > if (!qemu_mutex_iothread_locked()) { > > > > @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) > > > > return old; > > > > } > > > > > > > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env, > > > > + int (*rmw_fn)(void *arg, > > > > + target_ulong reg, > > > > + target_ulong *val, > > > > + target_ulong new_val, > > > > + target_ulong write_mask), > > > > + void *rmw_fn_arg) > > > > +{ > > > > + env->imsic_rmw_fn = rmw_fn; > > > > + env->imsic_rmw_fn_arg = rmw_fn_arg; > > > > +} > > > > + > > > > void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), > > > > uint32_t arg) > > > > { > > > > @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) > > > > */ > > > > bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG); > > > > target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK; > > > > - target_ulong deleg = async ? env->mideleg : env->medeleg; > > > > + uint64_t deleg = async ? env->mideleg : env->medeleg; > > > > bool write_tval = false; > > > > target_ulong tval = 0; > > > > target_ulong htval = 0; > > > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c > > > > index d2585395bf..3c016d7452 100644 > > > > --- a/target/riscv/csr.c > > > > +++ b/target/riscv/csr.c > > > > @@ -153,11 +153,56 @@ static int 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 int smode(CPURISCVState *env, int csrno) > > > > { > > > > return -!riscv_has_ext(env, RVS); > > > > } > > > > > > > > +static int smode32(CPURISCVState *env, int csrno) > > > > +{ > > > > + if (!riscv_cpu_is_32bit(env)) { > > > > + 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 int hmode(CPURISCVState *env, int csrno) > > > > { > > > > if (riscv_has_ext(env, RVS) && > > > > @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno) > > > > static int hmode32(CPURISCVState *env, int csrno) > > > > { > > > > if (!riscv_cpu_is_32bit(env)) { > > > > - return 0; > > > > + return -RISCV_EXCP_ILLEGAL_INST; > > > > + } > > > > + > > > > + return hmode(env, csrno); > > > > +} > > > > + > > > > +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 int pmp(CPURISCVState *env, int csrno) > > > > @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) > > > > > > > > /* 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 TLOWBITS64 ((uint64_t)((target_ulong)-1)) > > > > > > > > -static const target_ulong delegable_ints = S_MODE_INTERRUPTS | > > > > - VS_MODE_INTERRUPTS; > > > > -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | > > > > - VS_MODE_INTERRUPTS; > > > > +static const uint64_t delegable_ints = S_MODE_INTERRUPTS | > > > > + VS_MODE_INTERRUPTS; > > > > +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | > > > > + VS_MODE_INTERRUPTS; > > > > static const target_ulong delegable_excps = > > > > (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | > > > > (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | > > > > @@ -419,10 +483,10 @@ static const target_ulong delegable_excps = > > > > static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | > > > > SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | > > > > SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD; > > > > -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; > > > > -static const target_ulong hip_writable_mask = MIP_VSSIP; > > > > -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; > > > > -static const target_ulong vsip_writable_mask = MIP_VSSIP; > > > > +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; > > > > +static const uint64_t hip_writable_mask = MIP_VSSIP; > > > > +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; > > > > +static const uint64_t vsip_writable_mask = MIP_VSSIP; > > > > > > > > static const char valid_vm_1_10_32[16] = { > > > > [VM_1_10_MBARE] = 1, > > > > @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val) > > > > > > > > static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val) > > > > { > > > > - env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints); > > > > + uint64_t mask = delegable_ints & TLOWBITS64; > > > > + > > > > + env->mideleg = (env->mideleg & ~mask) | (val & mask); > > > > + if (riscv_has_ext(env, RVH)) { > > > > + env->mideleg |= VS_MODE_INTERRUPTS; > > > > + } > > > > + return 0; > > > > +} > > > > + > > > > +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_STOPI: > > > > + return CSR_VSTOPI; > > > > + case CSR_SSETEIPNUM: > > > > + return CSR_VSSETEIPNUM; > > > > + case CSR_SCLREIPNUM: > > > > + return CSR_VSCLREIPNUM; > > > > + case CSR_SSETEIENUM: > > > > + return CSR_VSSETEIENUM; > > > > + case CSR_SCLREIENUM: > > > > + return CSR_VSCLREIENUM; > > > > + default: > > > > + return csrno; > > > > + }; > > > > +} > > > > + > > > > +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val, > > > > + target_ulong new_val, target_ulong write_mask) > > > > +{ > > > > + target_ulong *iselect; > > > > + > > > > + switch (csrno) { > > > > + case CSR_MISELECT: > > > > + iselect = &env->miselect; > > > > + break; > > > > + case CSR_SISELECT: > > > > + iselect = riscv_cpu_virt_enabled(env) ? > > > > + &env->vsiselect : &env->siselect; > > > > + break; > > > > + case CSR_VSISELECT: > > > > + iselect = &env->vsiselect; > > > > + break; > > > > + default: > > > > + return -RISCV_EXCP_ILLEGAL_INST; > > > > + }; > > > > + > > > > + if (val) { > > > > + *val = *iselect; > > > > + } > > > > + > > > > + if (write_mask) { > > > > + *iselect = (*iselect & ~write_mask) | (new_val & write_mask); > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int rmw_iprio(target_ulong iselect, uint8_t *iprio, > > > > + target_ulong *val, target_ulong new_val, > > > > + target_ulong write_mask) > > > > +{ > > > > + int i, firq, nirqs; > > > > + target_ulong old_val; > > > > + > > > > + if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) { > > > > + return -EINVAL; > > > > + } > > > > +#if TARGET_LONG_BITS == 64 > > > > + if (iselect & 0x1) { > > > > + return -EINVAL; > > > > + } > > > > +#endif > > > > + > > > > + nirqs = 4 * (TARGET_LONG_BITS / 32); > > > > + firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 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 (write_mask) { > > > > + new_val = (old_val & ~write_mask) | (new_val & write_mask); > > > > + for (i = 0; i < nirqs; i++) { > > > > + 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 write_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) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > > > + > > > > + if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) { > > > > + /* Local interrupt priority registers not available for VS-mode */ > > > > + if (!virt) { > > > > + ret = rmw_iprio(isel, iprio, val, new_val, write_mask); > > > > + } > > > > + } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) { > > > > + /* IMSIC registers only available when machine implements it. */ > > > > + if (env->imsic_rmw_fn) { > > > > + /* Selected guest interrupt file should not be zero */ > > > > + if (virt && !vgein) { > > > > + goto done; > > > > + } > > > > + /* Call machine specific IMSIC register emulation */ > > > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > > > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > > > > + val, new_val, write_mask); > > > > + } > > > > + } > > > > + > > > > +done: > > > > + if (ret) { > > > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > > > + } > > > > + return 0; > > > > +} > > > > + > > > > +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + int irq; > > > > + > > > > + irq = riscv_cpu_mirq_pending(env); > > > > + if (irq <= 0 || irq > 63) { > > > > + *val = 0; > > > > + } else { > > > > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > > > > + *val |= env->miprio[irq]; > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + bool virt; > > > > + int ret = -EINVAL; > > > > + target_ulong 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_MSETEIPNUM: > > > > + case CSR_MCLREIPNUM: > > > > + case CSR_MSETEIENUM: > > > > + case CSR_MCLREIENUM: > > > > + case CSR_SSETEIPNUM: > > > > + case CSR_SCLREIPNUM: > > > > + case CSR_SSETEIENUM: > > > > + case CSR_SCLREIENUM: > > > > + break; > > > > + case CSR_VSSETEIPNUM: > > > > + case CSR_VSCLREIPNUM: > > > > + case CSR_VSSETEIENUM: > > > > + case CSR_VSCLREIENUM: > > > > + virt = true; > > > > + break; > > > > + default: > > > > + goto done; > > > > + }; > > > > + > > > > + /* IMSIC CSRs only available when machine implements IMSIC. */ > > > > + if (!env->imsic_rmw_fn) { > > > > + goto done; > > > > + } > > > > + > > > > + /* Find the selected guest interrupt file */ > > > > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > > > + > > > > + /* Selected guest interrupt file should not be zero */ > > > > + if (virt && !vgein) { > > > > + goto done; > > > > + } > > > > + > > > > + /* Set/Clear CSRs always read zero */ > > > > + ret = 0; > > > > + if (val) { > > > > + *val = 0; > > > > + } > > > > + > > > > +done: > > > > + if (ret) { > > > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > > > + } > > > > + return 0; > > > > +} > > > > + > > > > +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val) > > > > +{ > > > > + int ret = -EINVAL; > > > > + bool set, pend, virt; > > > > + target_ulong priv, isel, vgein; > > > > + target_ulong new_val, write_mask; > > > > + > > > > + /* 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; > > > > + 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->imsic_rmw_fn) { > > > > + goto done; > > > > + } > > > > + > > > > + /* Find target interrupt pending/enable register */ > > > > + if (pend) { > > > > + isel = ISELECT_IMSIC_EIP0; > > > > + } else { > > > > + isel = ISELECT_IMSIC_EIE0; > > > > + } > > > > + isel += val / IMSIC_EIPx_BITS; > > > > + > > > > + /* Find the interrupt bit to be set/clear */ > > > > + write_mask = 1 << (val % IMSIC_EIPx_BITS); > > > > + new_val = (set) ? write_mask : 0; > > > > + > > > > + /* Find the selected guest interrupt file */ > > > > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > > > + > > > > + /* Selected guest interrupt file should not be zero */ > > > > + if (virt && !vgein) { > > > > + goto done; > > > > + } > > > > + > > > > + /* Call machine specific IMSIC register emulation */ > > > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > > > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > > > > + NULL, new_val, write_mask); > > > > + > > > > +done: > > > > + if (ret) { > > > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > > > + } > > > > + return 0; > > > > +} > > > > + > > > > +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + bool virt; > > > > + int ret = -EINVAL; > > > > + target_ulong priv, isel, vgein; > > > > + target_ulong topei, write_mask; > > > > + > > > > + /* Decode register details from CSR number */ > > > > + virt = false; > > > > + switch (csrno) { > > > > + case CSR_MCLAIMEI: > > > > + priv = PRV_M; > > > > + break; > > > > + case CSR_SCLAIMEI: > > > > + priv = PRV_S; > > > > + virt = riscv_cpu_virt_enabled(env); > > > > + break; > > > > + default: > > > > + goto done; > > > > + }; > > > > + > > > > + /* IMSIC CSRs only available when machine implements IMSIC. */ > > > > + if (!env->imsic_rmw_fn) { > > > > + goto done; > > > > + } > > > > + > > > > + /* Find the selected guest interrupt file */ > > > > + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; > > > > + > > > > + /* Selected guest interrupt file should not be zero */ > > > > + if (virt && !vgein) { > > > > + goto done; > > > > + } > > > > + > > > > + /* Call machine specific IMSIC register emulation for reading TOPEI */ > > > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > > > + IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein), > > > > + &topei, -1, 0); > > > > + if (ret) { > > > > + goto done; > > > > + } > > > > + > > > > + /* If no interrupt pending then we are done */ > > > > + if (!topei) { > > > > + goto done; > > > > + } > > > > + > > > > + /* Find target interrupt pending register */ > > > > + isel = ISELECT_IMSIC_EIP0; > > > > + isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS); > > > > + > > > > + /* Find the interrupt bit to be cleared */ > > > > + write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS); > > > > + > > > > + /* Call machine specific IMSIC register emulation to clear pending bit */ > > > > + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, > > > > + IMSIC_MAKE_REG(isel, priv, virt, vgein), > > > > + NULL, 0, write_mask); > > > > + > > > > + /* Update return value */ > > > > + if (val) { > > > > + *val = topei; > > > > + } > > > > + > > > > +done: > > > > + if (ret) { > > > > + return (riscv_cpu_virt_enabled(env) && virt) ? > > > > + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; > > > > + } > > > > + return 0; > > > > +} > > > > + > > > > +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + *val = (env->mideleg >> 32); > > > > + return 0; > > > > +} > > > > + > > > > +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val) > > > > +{ > > > > + uint64_t mask = delegable_ints & ~TLOWBITS64; > > > > + uint64_t newval = ((uint64_t)val) << 32; > > > > + > > > > + env->mideleg = (env->mideleg & ~mask) | (newval & mask); > > > > if (riscv_has_ext(env, RVH)) { > > > > env->mideleg |= VS_MODE_INTERRUPTS; > > > > } > > > > @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val) > > > > > > > > static int write_mie(CPURISCVState *env, int csrno, target_ulong val) > > > > { > > > > - env->mie = (env->mie & ~all_ints) | (val & all_ints); > > > > + uint64_t mask = all_ints & TLOWBITS64; > > > > + > > > > + env->mie = (env->mie & ~mask) | (val & mask); > > > > + return 0; > > > > +} > > > > + > > > > +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + *val = (env->mie >> 32); > > > > + return 0; > > > > +} > > > > + > > > > +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val) > > > > +{ > > > > + uint64_t mask = all_ints & ~TLOWBITS64; > > > > + uint64_t newval = ((uint64_t)val) << 32; > > > > + > > > > + env->mie = (env->mie & ~mask) | (newval & mask); > > > > return 0; > > > > } > > > > > > > > @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > > { > > > > 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 mask = ((uint64_t)write_mask) & delegable_ints & > > > > + ~env->miclaim & TLOWBITS64; > > > > + uint64_t old_mip; > > > > > > > > if (mask) { > > > > old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > > > @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > > return 0; > > > > } > > > > > > > > +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > > + target_ulong new_value, target_ulong write_mask) > > > > +{ > > > > + RISCVCPU *cpu = env_archcpu(env); > > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > > + uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints & > > > > + ~env->miclaim & ~TLOWBITS64; > > > > + uint64_t new_value64 = (uint64_t)new_value << 32; > > > > + uint64_t old_mip; > > > > + > > > > + if (mask) { > > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > > > + } else { > > > > + old_mip = env->mip; > > > > + } > > > > + > > > > + if (ret_value) { > > > > + *ret_value = old_mip >> 32; > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > /* Supervisor Trap Setup */ > > > > static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val) > > > > { > > > > @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val) > > > > > > > > static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val) > > > > { > > > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64; > > > > + > > > > /* Shift the VS bits to their S bit location in vsie */ > > > > - *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1; > > > > + *val = (env->mie & mask) >> 1; > > > > + return 0; > > > > +} > > > > + > > > > +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64; > > > > + > > > > + /* Shift the VS bits to their S bit location in vsieh */ > > > > + *val = (env->mie & mask) >> (32 + 1); > > > > return 0; > > > > } > > > > > > > > static int read_sie(CPURISCVState *env, int csrno, target_ulong *val) > > > > { > > > > if (riscv_cpu_virt_enabled(env)) { > > > > - read_vsie(env, CSR_VSIE, val); > > > > - } else { > > > > - *val = env->mie & env->mideleg; > > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > > + } > > > > + return read_vsie(env, CSR_VSIE, val); > > > > } > > > > + > > > > + *val = env->mie & env->mideleg; > > > > return 0; > > > > } > > > > > > > > static int write_vsie(CPURISCVState *env, int csrno, target_ulong val) > > > > { > > > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & > > > > + all_ints & TLOWBITS64; > > > > + > > > > /* 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); > > > > + env->mie = (env->mie & ~mask) | ((val << 1) & mask); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val) > > > > +{ > > > > + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & > > > > + all_ints & ~TLOWBITS64; > > > > + uint64_t newval = (uint64_t)val << 32; > > > > + > > > > + /* Shift the S bits to their VS bit location in mie */ > > > > + env->mie = (env->mie & ~mask) | ((newval << 1) & mask); > > > > + > > > > + return 0; > > > > } > > > > > > > > static int write_sie(CPURISCVState *env, int csrno, target_ulong val) > > > > { > > > > + uint64_t mask; > > > > + > > > > if (riscv_cpu_virt_enabled(env)) { > > > > - write_vsie(env, CSR_VSIE, val); > > > > - } else { > > > > - target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) | > > > > - (val & S_MODE_INTERRUPTS); > > > > - write_mie(env, CSR_MIE, newval); > > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > > + } > > > > + return write_vsie(env, CSR_VSIE, val); > > > > + } > > > > + > > > > + mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64; > > > > + env->mie = (env->mie & ~mask) | ((uint64_t)val & mask); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + if (riscv_cpu_virt_enabled(env)) { > > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > > + } > > > > + return read_vsieh(env, CSR_VSIEH, val); > > > > + } > > > > + > > > > + *val = ((env->mie & env->mideleg) >> 32); > > > > + return 0; > > > > +} > > > > + > > > > +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val) > > > > +{ > > > > + uint64_t mask, newval; > > > > + > > > > + if (riscv_cpu_virt_enabled(env)) { > > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > > + } > > > > + return write_vsieh(env, CSR_VSIEH, val); > > > > } > > > > > > > > + mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64; > > > > + newval = (uint64_t)val << 32; > > > > + > > > > + env->mie = (env->mie & ~mask) | (newval & mask); > > > > return 0; > > > > } > > > > > > > > @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val) > > > > static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > > target_ulong new_value, target_ulong write_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); > > > > - *ret_value &= VS_MODE_INTERRUPTS; > > > > - /* Shift the VS bits to their S bit location in vsip */ > > > > - *ret_value >>= 1; > > > > - return ret; > > > > + RISCVCPU *cpu = env_archcpu(env); > > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > > + uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints & > > > > + vsip_writable_mask & env->hideleg & > > > > + ~env->miclaim & TLOWBITS64; > > > > + uint64_t old_mip; > > > > + > > > > + if (mask) { > > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > > > + } else { > > > > + old_mip = env->mip; > > > > + } > > > > + > > > > + if (ret_value) { > > > > + *ret_value = old_mip & VS_MODE_INTERRUPTS; > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > > + target_ulong new_value, target_ulong write_mask) > > > > +{ > > > > + RISCVCPU *cpu = env_archcpu(env); > > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > > + uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints & > > > > + vsip_writable_mask & env->hideleg & > > > > + ~env->miclaim & ~TLOWBITS64; > > > > + uint64_t new_value64 = (uint64_t)new_value << 32; > > > > + uint64_t old_mip; > > > > + > > > > + if (mask) { > > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > > > + } else { > > > > + old_mip = env->mip; > > > > + } > > > > + > > > > + if (ret_value) { > > > > + *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32; > > > > + } > > > > + > > > > + return 0; > > > > } > > > > > > > > static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > > target_ulong new_value, target_ulong write_mask) > > > > { > > > > - int ret; > > > > + RISCVCPU *cpu = env_archcpu(env); > > > > + uint64_t mask, old_mip; > > > > > > > > if (riscv_cpu_virt_enabled(env)) { > > > > - ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); > > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > > + } > > > > + return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); > > > > + } > > > > + > > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > > + mask = ((uint64_t)write_mask) & delegable_ints & > > > > + env->mideleg & sip_writable_mask & > > > > + ~env->miclaim & TLOWBITS64; > > > > + if (mask) { > > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > > > } else { > > > > - ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, > > > > - write_mask & env->mideleg & sip_writable_mask); > > > > + old_mip = env->mip; > > > > } > > > > > > > > - *ret_value &= env->mideleg; > > > > - return ret; > > > > + if (ret_value) { > > > > + *ret_value = old_mip; > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > > + target_ulong new_value, target_ulong write_mask) > > > > +{ > > > > + RISCVCPU *cpu = env_archcpu(env); > > > > + uint64_t mask, new_value64; > > > > + uint64_t old_mip; > > > > + > > > > + if (riscv_cpu_virt_enabled(env)) { > > > > + if (env->hvicontrol & HVICONTROL_VTI) { > > > > + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; > > > > + } > > > > + return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask); > > > > + } > > > > + > > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > > + mask = ((uint64_t)write_mask << 32) & delegable_ints & > > > > + env->mideleg & sip_writable_mask & > > > > + ~env->miclaim & ~TLOWBITS64; > > > > + new_value64 = (uint64_t)new_value << 32; > > > > + if (mask) { > > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > > > + } else { > > > > + old_mip = env->mip; > > > > + } > > > > + > > > > + if (ret_value) { > > > > + *ret_value = (old_mip & env->mideleg) >> 32; > > > > + } > > > > + > > > > + return 0; > > > > } > > > > > > > > /* Supervisor Protection and Translation */ > > > > @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) > > > > return 0; > > > > } > > > > > > > > +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + int irq, hiid; > > > > + uint8_t hiprio, iprio; > > > > + > > > > + irq = riscv_cpu_vsirq_pending(env); > > > > + if (irq <= 0 || irq > 63) { > > > > + *val = 0; > > > > + } else { > > > > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > > > > + iprio = env->hviprio[irq]; > > > > + /* TODO: This needs to improve in specification */ > > > > + if (!(env->hstatus & HSTATUS_VGEIN)) { > > > > + hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >> > > > > + HVICONTROL_IID_SHIFT; > > > > + hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK; > > > > + if (irq == hiid && hiprio) { > > > > + iprio = hiprio; > > > > + } > > > > + } > > > > + *val |= iprio; > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + int irq; > > > > + > > > > + 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 { > > > > + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; > > > > + *val |= env->siprio[irq]; > > > > + } > > > > + > > > > + return 0; > > > > +} > > > > + > > > > /* Hypervisor Extensions */ > > > > static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) > > > > { > > > > @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val) > > > > return 0; > > > > } > > > > > > > > +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + *val = env->hideleg >> 32; > > > > + return 0; > > > > +} > > > > + > > > > +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val) > > > > +{ > > > > + uint64_t mask = ~TLOWBITS64; > > > > + uint64_t newval = ((uint64_t)val) << 32; > > > > + > > > > + env->hideleg = (env->hideleg & ~mask) | (newval & mask); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > static int rmw_hvip(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, > > > > - write_mask & hvip_writable_mask); > > > > + RISCVCPU *cpu = env_archcpu(env); > > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > > + uint64_t mask = ((uint64_t)write_mask) & delegable_ints & > > > > + hvip_writable_mask & > > > > + ~env->miclaim & TLOWBITS64; > > > > + uint64_t old_mip; > > > > + > > > > + if (mask) { > > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > > > + } else { > > > > + old_mip = env->mip; > > > > + } > > > > > > > > - *ret_value &= hvip_writable_mask; > > > > + if (ret_value) { > > > > + *ret_value = old_mip & hvip_writable_mask; > > > > + } > > > > > > > > - return ret; > > > > + return 0; > > > > +} > > > > + > > > > +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value, > > > > + target_ulong new_value, target_ulong write_mask) > > > > +{ > > > > + RISCVCPU *cpu = env_archcpu(env); > > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > > + uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints & > > > > + hvip_writable_mask & > > > > + ~env->miclaim & ~TLOWBITS64; > > > > + uint64_t new_value64 = (uint64_t)new_value << 32; > > > > + uint64_t old_mip; > > > > + > > > > + if (mask) { > > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); > > > > + } else { > > > > + old_mip = env->mip; > > > > + } > > > > + > > > > + if (ret_value) { > > > > + *ret_value = (old_mip & hvip_writable_mask) >> 32; > > > > + } > > > > + > > > > + return 0; > > > > } > > > > > > > > static int 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, > > > > - write_mask & hip_writable_mask); > > > > + RISCVCPU *cpu = env_archcpu(env); > > > > + /* Allow software control of delegable interrupts not claimed by hardware */ > > > > + uint64_t mask = ((uint64_t)write_mask) & delegable_ints & > > > > + hip_writable_mask & > > > > + ~env->miclaim & TLOWBITS64; > > > > + uint64_t old_mip; > > > > > > > > - *ret_value &= hip_writable_mask; > > > > + if (mask) { > > > > + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); > > > > + } else { > > > > + old_mip = env->mip; > > > > + } > > > > > > > > - return ret; > > > > + if (ret_value) { > > > > + *ret_value = old_mip & hip_writable_mask; > > > > + } > > > > + > > > > + return 0; > > > > } > > > > > > > > static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) > > > > @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) > > > > > > > > static int 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); > > > > + uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64; > > > > + env->mie = (env->mie & ~mask) | ((uint64_t)val & mask); > > > > + return 0; > > > > } > > > > > > > > static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val) > > > > @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) > > > > return 0; > > > > } > > > > > > > > +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val) > > > > +{ > > > > + *val = env->hvicontrol; > > > > + return 0; > > > > +} > > > > + > > > > +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val) > > > > +{ > > > > + env->hvicontrol = val & HVICONTROL_VALID_MASK; > > > > + return 0; > > > > +} > > > > + > > > > +static int read_hvipriox(CPURISCVState *env, int first_index, > > > > + uint8_t *iprio, target_ulong *val) > > > > +{ > > > > + int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32); > > > > + > > > > + /* First index has to be multiple of numbe 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 0; > > > > +} > > > > + > > > > +static int write_hvipriox(CPURISCVState *env, int first_index, > > > > + uint8_t *iprio, target_ulong val) > > > > +{ > > > > + int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32); > > > > + > > > > + /* First index has to be multiple of numbe 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 0; > > > > +} > > > > + > > > > +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 int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val) > > > > { > > > > @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { > > > > [CSR_MBADADDR] = { "mbadaddr", any, read_mbadaddr, write_mbadaddr }, > > > > [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, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_MCLAIMEI] = { "mclaimei", aia_any, read_xclaimei }, > > > > + > > > > + /* Machine-Level High-Half CSRs (AIA) */ > > > > + [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh }, > > > > + [CSR_MIEH] = { "mieh", aia_any32, read_mieh, write_mieh }, > > > > + [CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph }, > > > > + > > > > /* Supervisor Trap Setup */ > > > > [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus }, > > > > [CSR_SIE] = { "sie", smode, read_sie, write_sie }, > > > > @@ -1444,6 +2357,24 @@ 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, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_SCLAIMEI] = { "sclaimei", aia_smode, read_xclaimei }, > > > > + > > > > + /* Supervisor-Level High-Half CSRs (AIA) */ > > > > + [CSR_SIEH] = { "sieh", aia_smode32, read_sieh, write_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 }, > > > > @@ -1472,6 +2403,32 @@ 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_HVICONTROL] = { "hvicontrol", aia_hmode, read_hvicontrol, write_hvicontrol }, > > > > + [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, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > > > > + [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, > > > > + > > > > + /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ > > > > + [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, read_hidelegh, write_hidelegh }, > > > > + [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, read_vsieh, write_vsieh }, > > > > + [CSR_VSIPH] = { "vsiep", aia_hmode32, NULL, NULL, rmw_vsiph }, > > > > + > > > > /* Physical Memory Protection */ > > > > [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg }, > > > > [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg }, > > > > diff --git a/target/riscv/machine.c b/target/riscv/machine.c > > > > index 44d4015bd6..f7fa48c240 100644 > > > > --- a/target/riscv/machine.c > > > > +++ b/target/riscv/machine.c > > > > @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = { > > > > > > > > static const VMStateDescription vmstate_hyper = { > > > > .name = "cpu/hyper", > > > > - .version_id = 1, > > > > - .minimum_version_id = 1, > > > > + .version_id = 2, > > > > + .minimum_version_id = 2, > > > > .needed = hyper_needed, > > > > .fields = (VMStateField[]) { > > > > VMSTATE_UINTTL(env.hstatus, RISCVCPU), > > > > VMSTATE_UINTTL(env.hedeleg, RISCVCPU), > > > > - VMSTATE_UINTTL(env.hideleg, RISCVCPU), > > > > + VMSTATE_UINT64(env.hideleg, RISCVCPU), > > > > VMSTATE_UINTTL(env.hcounteren, RISCVCPU), > > > > VMSTATE_UINTTL(env.htval, RISCVCPU), > > > > VMSTATE_UINTTL(env.htinst, RISCVCPU), > > > > VMSTATE_UINTTL(env.hgatp, RISCVCPU), > > > > VMSTATE_UINT64(env.htimedelta, RISCVCPU), > > > > > > > > + VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64), > > > > + VMSTATE_UINTTL(env.hvicontrol, RISCVCPU), > > > > + > > > > VMSTATE_UINT64(env.vsstatus, RISCVCPU), > > > > VMSTATE_UINTTL(env.vstvec, RISCVCPU), > > > > VMSTATE_UINTTL(env.vsscratch, RISCVCPU), > > > > @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = { > > > > VMSTATE_UINTTL(env.vscause, RISCVCPU), > > > > VMSTATE_UINTTL(env.vstval, RISCVCPU), > > > > VMSTATE_UINTTL(env.vsatp, RISCVCPU), > > > > + VMSTATE_UINTTL(env.vsiselect, RISCVCPU), > > > > > > > > VMSTATE_UINTTL(env.mtval2, RISCVCPU), > > > > VMSTATE_UINTTL(env.mtinst, RISCVCPU), > > > > @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = { > > > > > > > > const VMStateDescription vmstate_riscv_cpu = { > > > > .name = "cpu", > > > > - .version_id = 1, > > > > - .minimum_version_id = 1, > > > > + .version_id = 2, > > > > + .minimum_version_id = 2, > > > > .fields = (VMStateField[]) { > > > > VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), > > > > VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32), > > > > + VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64), > > > > + VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64), > > > > VMSTATE_UINTTL(env.pc, RISCVCPU), > > > > VMSTATE_UINTTL(env.load_res, RISCVCPU), > > > > VMSTATE_UINTTL(env.load_val, RISCVCPU), > > > > @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = { > > > > VMSTATE_UINTTL(env.resetvec, RISCVCPU), > > > > VMSTATE_UINTTL(env.mhartid, RISCVCPU), > > > > VMSTATE_UINT64(env.mstatus, RISCVCPU), > > > > - VMSTATE_UINTTL(env.mip, RISCVCPU), > > > > - VMSTATE_UINT32(env.miclaim, RISCVCPU), > > > > - VMSTATE_UINTTL(env.mie, RISCVCPU), > > > > - VMSTATE_UINTTL(env.mideleg, RISCVCPU), > > > > + VMSTATE_UINT64(env.mip, RISCVCPU), > > > > + VMSTATE_UINT64(env.miclaim, RISCVCPU), > > > > + VMSTATE_UINT64(env.mie, RISCVCPU), > > > > + VMSTATE_UINT64(env.mideleg, RISCVCPU), > > > > VMSTATE_UINTTL(env.sptbr, RISCVCPU), > > > > VMSTATE_UINTTL(env.satp, RISCVCPU), > > > > VMSTATE_UINTTL(env.sbadaddr, RISCVCPU), > > > > @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = { > > > > VMSTATE_UINTTL(env.mepc, RISCVCPU), > > > > VMSTATE_UINTTL(env.mcause, RISCVCPU), > > > > VMSTATE_UINTTL(env.mtval, RISCVCPU), > > > > + VMSTATE_UINTTL(env.miselect, RISCVCPU), > > > > + VMSTATE_UINTTL(env.siselect, RISCVCPU), > > > > VMSTATE_UINTTL(env.scounteren, RISCVCPU), > > > > VMSTATE_UINTTL(env.mcounteren, RISCVCPU), > > > > VMSTATE_UINTTL(env.sscratch, RISCVCPU), > > > > -- > > > > 2.25.1 > > > > > > > >
On Sat, Jun 12, 2021 at 12:04 AM Anup Patel <anup@brainfault.org> wrote: > > On Fri, Jun 11, 2021 at 2:16 PM Alistair Francis <alistair23@gmail.com> wrote: > > > > On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote: > > > > > > On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote: > > > > > > > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote: > > > > > > > > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode, > > > > > and VS-mode. > > > > > > > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > > > > > --- > > > > > target/riscv/cpu.c | 27 +- > > > > > target/riscv/cpu.h | 52 +- > > > > > target/riscv/cpu_helper.c | 245 ++++++++- > > > > > target/riscv/csr.c | 1059 +++++++++++++++++++++++++++++++++++-- > > > > > target/riscv/machine.c | 26 +- > > > > > 5 files changed, 1309 insertions(+), 100 deletions(-) > > > > > > > > I feel this patch could be split up more :) > > > > > > This is patch is large because I did not want to break functionality. > > > > > > I try again to break this patch. At the moment, the best I can do is > > > to break in to two parts. > > > 1) AIA local interrupt CSRs without IMSIC > > > 2) Extend AIA local interrupt CSRs to support IMSIC register access > > > > As the patch is being added while AIA isn't enabled you are able to > > add the AIA in breaking stages. That is the AIA isn't fully > > functional, you still have to make sure not to break existing users. > > > > > > > > > > > > > > > > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > > > > index f3702111ae..795162834b 100644 > > > > > --- a/target/riscv/cpu.c > > > > > +++ b/target/riscv/cpu.c > > > > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) > > > > > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ", > > > > > (target_ulong)env->vsstatus); > > > > > } > > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", env->mip); > > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); > > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); > > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip ", env->mip); > > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie ", env->mie); > > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg); > > > > > if (riscv_has_ext(env, RVH)) { > > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg); > > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg); > > > > > } > > > > > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); > > > > > if (riscv_has_ext(env, RVH)) { > > > > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, > > > > > > > > > > static void riscv_cpu_reset(DeviceState *dev) > > > > > { > > > > > + uint8_t iprio; > > > > > + int i, irq, rdzero; > > > > > CPUState *cs = CPU(dev); > > > > > RISCVCPU *cpu = RISCV_CPU(cs); > > > > > RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); > > > > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev) > > > > > env->mcause = 0; > > > > > env->pc = env->resetvec; > > > > > env->two_stage_lookup = false; > > > > > + > > > > > + /* Initialized default priorities of local interrupts. */ > > > > > + for (i = 0; i < ARRAY_SIZE(env->miprio); i++) { > > > > > + iprio = riscv_cpu_default_priority(i); > > > > > + env->miprio[i] = iprio; > > > > > + env->siprio[i] = iprio; > > > > > + env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO; > > > > > + } > > > > > + i = 0; > > > > > + while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) { > > > > > + if (rdzero) { > > > > > + env->hviprio[irq] = 0; > > > > > + } else { > > > > > + env->hviprio[irq] = env->miprio[irq]; > > > > > + } > > > > > + i++; > > > > > + } > > > > > #endif > > > > > cs->exception_index = EXCP_NONE; > > > > > env->load_res = -1; > > > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > > > > > index f00c60c840..780d3f9058 100644 > > > > > --- a/target/riscv/cpu.h > > > > > +++ b/target/riscv/cpu.h > > > > > @@ -157,12 +157,12 @@ struct CPURISCVState { > > > > > */ > > > > > uint64_t mstatus; > > > > > > > > > > - target_ulong mip; > > > > > + uint64_t mip; > > > > > > > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume > > > > all the other existing target_ulong CSRs are the same. > > > > > > When AIA is available the number of local interrupts are 64 for > > > both RV32 and RV64. > > > > Is that going to be reflected in the priv spec? > > The AIA spec is going to be separate from priv spec since > it is totally optional. > > This AIA local interrupt CSRs will be part of AIA spec and should > only be implemented if a RISC-V implementations wants to use > AIA. > > We have four types of changes as far as CSRs go: > 1) RV32 CSRs to support 64 local interrupts on RV32 Hmmm... This isn't ideal. So implementations without AIA will have a Xlen MIP while implementations with AIA will have a 64-bit MIP? I guess we just don't expose all of MIP, so it isn't that bad. Still that change should be it's own patch with good justification as why we aren't following the priv spec. > 2) Indirect CSRs to access local interrupt priorities > 3) Interrupt filtering CSRs > 4) IMSIC support CSRs New AIA CSRs are fine, it's just core changes that are more of a worry. Alistair > > From above #3 is totally optional and not implemented by this > patch whereas #4 is only required when platform has RISC-V IMSIC. > > A platform can skip all four changes mentioned above, if the > platform only wants AIA APLIC to manage wired interrupts. > > Regards, > Anup
On Tue, Jun 15, 2021 at 1:41 PM Alistair Francis <alistair23@gmail.com> wrote: > > On Sat, Jun 12, 2021 at 12:04 AM Anup Patel <anup@brainfault.org> wrote: > > > > On Fri, Jun 11, 2021 at 2:16 PM Alistair Francis <alistair23@gmail.com> wrote: > > > > > > On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote: > > > > > > > > On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote: > > > > > > > > > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote: > > > > > > > > > > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode, > > > > > > and VS-mode. > > > > > > > > > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com> > > > > > > --- > > > > > > target/riscv/cpu.c | 27 +- > > > > > > target/riscv/cpu.h | 52 +- > > > > > > target/riscv/cpu_helper.c | 245 ++++++++- > > > > > > target/riscv/csr.c | 1059 +++++++++++++++++++++++++++++++++++-- > > > > > > target/riscv/machine.c | 26 +- > > > > > > 5 files changed, 1309 insertions(+), 100 deletions(-) > > > > > > > > > > I feel this patch could be split up more :) > > > > > > > > This is patch is large because I did not want to break functionality. > > > > > > > > I try again to break this patch. At the moment, the best I can do is > > > > to break in to two parts. > > > > 1) AIA local interrupt CSRs without IMSIC > > > > 2) Extend AIA local interrupt CSRs to support IMSIC register access > > > > > > As the patch is being added while AIA isn't enabled you are able to > > > add the AIA in breaking stages. That is the AIA isn't fully > > > functional, you still have to make sure not to break existing users. > > > > > > > > > > > > > > > > > > > > > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c > > > > > > index f3702111ae..795162834b 100644 > > > > > > --- a/target/riscv/cpu.c > > > > > > +++ b/target/riscv/cpu.c > > > > > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) > > > > > > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ", > > > > > > (target_ulong)env->vsstatus); > > > > > > } > > > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", env->mip); > > > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); > > > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); > > > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip ", env->mip); > > > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie ", env->mie); > > > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg); > > > > > > if (riscv_has_ext(env, RVH)) { > > > > > > - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg); > > > > > > + qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg); > > > > > > } > > > > > > qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); > > > > > > if (riscv_has_ext(env, RVH)) { > > > > > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, > > > > > > > > > > > > static void riscv_cpu_reset(DeviceState *dev) > > > > > > { > > > > > > + uint8_t iprio; > > > > > > + int i, irq, rdzero; > > > > > > CPUState *cs = CPU(dev); > > > > > > RISCVCPU *cpu = RISCV_CPU(cs); > > > > > > RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); > > > > > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev) > > > > > > env->mcause = 0; > > > > > > env->pc = env->resetvec; > > > > > > env->two_stage_lookup = false; > > > > > > + > > > > > > + /* Initialized default priorities of local interrupts. */ > > > > > > + for (i = 0; i < ARRAY_SIZE(env->miprio); i++) { > > > > > > + iprio = riscv_cpu_default_priority(i); > > > > > > + env->miprio[i] = iprio; > > > > > > + env->siprio[i] = iprio; > > > > > > + env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO; > > > > > > + } > > > > > > + i = 0; > > > > > > + while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) { > > > > > > + if (rdzero) { > > > > > > + env->hviprio[irq] = 0; > > > > > > + } else { > > > > > > + env->hviprio[irq] = env->miprio[irq]; > > > > > > + } > > > > > > + i++; > > > > > > + } > > > > > > #endif > > > > > > cs->exception_index = EXCP_NONE; > > > > > > env->load_res = -1; > > > > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h > > > > > > index f00c60c840..780d3f9058 100644 > > > > > > --- a/target/riscv/cpu.h > > > > > > +++ b/target/riscv/cpu.h > > > > > > @@ -157,12 +157,12 @@ struct CPURISCVState { > > > > > > */ > > > > > > uint64_t mstatus; > > > > > > > > > > > > - target_ulong mip; > > > > > > + uint64_t mip; > > > > > > > > > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume > > > > > all the other existing target_ulong CSRs are the same. > > > > > > > > When AIA is available the number of local interrupts are 64 for > > > > both RV32 and RV64. > > > > > > Is that going to be reflected in the priv spec? > > > > The AIA spec is going to be separate from priv spec since > > it is totally optional. > > > > This AIA local interrupt CSRs will be part of AIA spec and should > > only be implemented if a RISC-V implementations wants to use > > AIA. > > > > We have four types of changes as far as CSRs go: > > 1) RV32 CSRs to support 64 local interrupts on RV32 > > Hmmm... This isn't ideal. So implementations without AIA will have a > Xlen MIP while implementations with AIA will have a 64-bit MIP? That's an inherent limitation of the Priv spec. > > I guess we just don't expose all of MIP, so it isn't that bad. Still > that change should be it's own patch with good justification as why we > aren't following the priv spec. The rationale with Priv spec allows implementations to support 32bit mode on RV64 HART so even RV64 HART running in 32bit mode can't use more than 32 local interrupts. This means we have a hard limit of 32 local interrupts in the Priv spec for both RV32 and RV64. The lower 13 interrupts are already standardized by Priv spec but we need to support good amount of per-HART local interrupts for future needs hence the AIA spec mandates minimum 64 local interrupts. Look at it this way, implementations which need future ready local interrupt support will implement AIA style local interrupts and implementations which don't can reduce hardware cost by staying with only XLEN local interrupts. The AIA style local interrupts are already approved by Andrew, Greg, and other folks because everyone accepts the local interrupt limitations of current Priv spec. > > > 2) Indirect CSRs to access local interrupt priorities > > 3) Interrupt filtering CSRs > > 4) IMSIC support CSRs > > New AIA CSRs are fine, it's just core changes that are more of a worry. Backward compatibility is a key requirement for RISC-V AIA and if you see this patch we keep the original Priv style local interrupts as-is with minor improvements. Regards, Anup > > Alistair > > > > > From above #3 is totally optional and not implemented by this > > patch whereas #4 is only required when platform has RISC-V IMSIC. > > > > A platform can skip all four changes mentioned above, if the > > platform only wants AIA APLIC to manage wired interrupts. > > > > Regards, > > Anup
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index f3702111ae..795162834b 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags) qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ", (target_ulong)env->vsstatus); } - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip ", env->mip); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie ", env->mie); - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg); + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip ", env->mip); + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie ", env->mie); + qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg); if (riscv_has_ext(env, RVH)) { - qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg); + qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg); } qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg); if (riscv_has_ext(env, RVH)) { @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb, static void riscv_cpu_reset(DeviceState *dev) { + uint8_t iprio; + int i, irq, rdzero; CPUState *cs = CPU(dev); RISCVCPU *cpu = RISCV_CPU(cs); RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu); @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev) env->mcause = 0; env->pc = env->resetvec; env->two_stage_lookup = false; + + /* Initialized default priorities of local interrupts. */ + for (i = 0; i < ARRAY_SIZE(env->miprio); i++) { + iprio = riscv_cpu_default_priority(i); + env->miprio[i] = iprio; + env->siprio[i] = iprio; + env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO; + } + i = 0; + while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) { + if (rdzero) { + env->hviprio[irq] = 0; + } else { + env->hviprio[irq] = env->miprio[irq]; + } + i++; + } #endif cs->exception_index = EXCP_NONE; env->load_res = -1; diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h index f00c60c840..780d3f9058 100644 --- a/target/riscv/cpu.h +++ b/target/riscv/cpu.h @@ -157,12 +157,12 @@ struct CPURISCVState { */ uint64_t mstatus; - target_ulong mip; + uint64_t mip; - uint32_t miclaim; + uint64_t miclaim; - target_ulong mie; - target_ulong mideleg; + uint64_t mie; + uint64_t mideleg; target_ulong sptbr; /* until: priv-1.9.1 */ target_ulong satp; /* since: priv-1.10.0 */ @@ -179,16 +179,27 @@ struct CPURISCVState { target_ulong mcause; target_ulong mtval; /* since: priv-1.10.0 */ + /* AIA CSRs */ + target_ulong miselect; + target_ulong siselect; + + uint8_t miprio[64]; + uint8_t siprio[64]; + /* Hypervisor CSRs */ target_ulong hstatus; target_ulong hedeleg; - target_ulong hideleg; + uint64_t hideleg; target_ulong hcounteren; target_ulong htval; target_ulong htinst; target_ulong hgatp; uint64_t htimedelta; + /* AIA HS-mode CSRs */ + uint8_t hviprio[64]; + target_ulong hvicontrol; + /* Virtual CSRs */ /* * For RV32 this is 32-bit vsstatus and 32-bit vsstatush. @@ -202,6 +213,9 @@ struct CPURISCVState { target_ulong vstval; target_ulong vsatp; + /* AIA VS-mode CSRs */ + target_ulong vsiselect; + target_ulong mtval2; target_ulong mtinst; @@ -236,6 +250,18 @@ struct CPURISCVState { uint64_t (*rdtime_fn)(uint32_t); uint32_t rdtime_fn_arg; + /* machine specific AIA IMSIC read-modify-write callback */ +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \ + ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \ + (((__priv) & 0x3) << 16) | (__isel & 0xffff)) +#define IMSIC_REG_ISEL(__reg) ((__reg) & 0xffff) +#define IMSIC_REG_PRIV(__reg) (((__reg) >> 16) & 0x3) +#define IMSIC_REG_VIRT(__reg) (((__reg) >> 20) & 0x1) +#define IMSIC_REG_VGEIN(__reg) (((__reg) >> 24) & 0x3f) + int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val, + target_ulong new_val, target_ulong write_mask); + void *imsic_rmw_fn_arg; + /* True if in debugger mode. */ bool debugger; #endif @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs, int cpuid, void *opaque); int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero); +uint8_t riscv_cpu_default_priority(int irq); +int riscv_cpu_mirq_pending(CPURISCVState *env); +int riscv_cpu_sirq_pending(CPURISCVState *env); +int riscv_cpu_vsirq_pending(CPURISCVState *env); bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request); bool riscv_cpu_fp_enabled(CPURISCVState *env); bool riscv_cpu_virt_enabled(CPURISCVState *env); @@ -364,9 +395,16 @@ void riscv_cpu_list(void); #ifndef CONFIG_USER_ONLY void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env); -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value); +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts); +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value); #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env, + int (*rmw_fn)(void *arg, + target_ulong reg, + target_ulong *val, + target_ulong new_val, + target_ulong write_mask), + void *rmw_fn_arg); void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), uint32_t arg); #endif diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 21c54ef561..5b06b4f995 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch) } #ifndef CONFIG_USER_ONLY -static int riscv_cpu_local_irq_pending(CPURISCVState *env) + +/* + * The HS-mode is allowed to configure priority only for the + * following VS-mode local interrupts: + * + * 0 (Reserved interrupt, reads as zero) + * 1 Supervisor software interrupt + * 4 (Reserved interrupt, reads as zero) + * 5 Supervisor timer interrupt + * 8 (Reserved interrupt, reads as zero) + * 13 (Reserved interrupt) + * 14 " + * 15 " + * 16 " + * 18 Debug/trace interrupt + * 20 (Reserved interrupt) + * 22 ” + * 24 ” + * 26 ” + * 28 " + * 30 (Reserved for standard reporting of bus or system errors) + */ + +static int hviprio_index2irq[] = + { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 }; +static int hviprio_index2rdzero[] = + { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero) { - target_ulong irqs; + if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) { + return -EINVAL; + } - 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); + if (out_irq) { + *out_irq = hviprio_index2irq[index]; + } + + if (out_rdzero) { + *out_rdzero = hviprio_index2rdzero[index]; + } - 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)); + return 0; +} - 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); +uint8_t riscv_cpu_default_priority(int irq) +{ + int u, l; + uint8_t iprio = IPRIO_MMAXIPRIO; - if (riscv_cpu_virt_enabled(env)) { - target_ulong pending_hs_irq = pending & -hs_sie; + if (irq < 0 || irq > 63) { + return iprio; + } - if (pending_hs_irq) { - riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP); - return ctz64(pending_hs_irq); + /* + * Default priorities of local interrupts are defined in the + * RISC-V Advanced Interrupt Architecture specification. + * + * ---------------------------------------------------------------- + * Default | + * Priority | Major Interrupt Numbers + * ---------------------------------------------------------------- + * Highest | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c), + * | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38), + * | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34), + * | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30) + * | + * | 11 (0b), 3 (03), 7 (07) + * | 9 (09), 1 (01), 5 (05) + * | 12 (0c) + * | 10 (0a), 2 (02), 6 (06) + * | + * | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c), + * | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28), + * | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24), + * Lowest | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20) + * ---------------------------------------------------------------- + */ + + u = IPRIO_DEFAULT_U(irq); + l = IPRIO_DEFAULT_L(irq); + if (u == 0) { + if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER || + irq == IRQ_VS_SOFT) { + iprio = IPRIO_DEFAULT_VS; + } else if (irq == IRQ_S_GEXT) { + iprio = IPRIO_DEFAULT_SGEXT; + } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER || + irq == IRQ_S_SOFT) { + iprio = IPRIO_DEFAULT_S; + } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER || + irq == IRQ_M_SOFT) { + iprio = IPRIO_DEFAULT_M; + } else { + iprio = IPRIO_DEFAULT_VS; } + } else if (u == 1) { + if (l < 8) { + iprio = IPRIO_DEFAULT_16_23(irq); + } else { + iprio = IPRIO_DEFAULT_24_31(irq); + } + } else if (u == 2) { + iprio = IPRIO_DEFAULT_32_47(irq); + } else if (u == 3) { + iprio = IPRIO_DEFAULT_48_63(irq); + } + + return iprio; +} + +static int riscv_cpu_pending_to_irq(CPURISCVState *env, + uint64_t pending, uint8_t *iprio) +{ + int irq, best_irq = EXCP_NONE; + unsigned int prio, best_prio = UINT_MAX; - pending = vspending; + if (!pending) { + return EXCP_NONE; } - irqs = (pending & ~env->mideleg & -mie) | (pending & env->mideleg & -sie); + irq = ctz64(pending); + if (!riscv_feature(env, RISCV_FEATURE_AIA)) { + return irq; + } - if (irqs) { - return ctz64(irqs); /* since non-zero */ + pending = pending >> irq; + while (pending) { + prio = iprio[irq]; + if (!prio) { + prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ? + 1 : IPRIO_MMAXIPRIO; + } + if ((pending & 0x1) && (prio < best_prio)) { + best_irq = irq; + best_prio = prio; + } + irq++; + pending = pending >> 1; + } + + return best_irq; +} + +int riscv_cpu_mirq_pending(CPURISCVState *env) +{ + uint64_t irqs = env->mip & env->mie & ~env->mideleg & + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); + + return riscv_cpu_pending_to_irq(env, irqs, env->miprio); +} + +int riscv_cpu_sirq_pending(CPURISCVState *env) +{ + uint64_t irqs = env->mip & env->mie & env->mideleg & + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); + + return riscv_cpu_pending_to_irq(env, irqs, env->siprio); +} + +int riscv_cpu_vsirq_pending(CPURISCVState *env) +{ + uint64_t irqs = env->mip & env->mie & env->mideleg & + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); + + return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio); +} + +static int riscv_cpu_local_irq_pending(CPURISCVState *env) +{ + int virq; + uint64_t irqs, mie, sie, vsie; + uint64_t pending, vspending; + + /* Determine interrupt enable state of all privilege modes */ + if (riscv_cpu_virt_enabled(env)) { + mie = 1; + sie = 1; + vsie = (env->priv < PRV_S) || + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE)); } else { - return EXCP_NONE; /* indicates no pending interrupt */ + mie = (env->priv < PRV_M) || + (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE)); + sie = (env->priv < PRV_S) || + (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE)); + vsie = 0; + } + + /* Check M-mode interrupts */ + pending = env->mip & env->mie & + ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); + irqs = pending & ~env->mideleg & -mie; + if (irqs) { + return riscv_cpu_pending_to_irq(env, irqs, env->miprio); + } + + /* Check HS-mode interrupts */ + irqs = pending & env->mideleg & -sie; + if (irqs) { + return riscv_cpu_pending_to_irq(env, irqs, env->siprio); + } + + /* Check VS-mode interrupts */ + vspending = env->mip & env->mie & + (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP); + irqs = vspending & env->hideleg & -vsie; + if (irqs) { + virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio); + return (virq <= 0) ? virq : virq + 1; } + + /* Indicates no pending interrupt */ + return EXCP_NONE; } #endif @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx) return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK; } -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts) { CPURISCVState *env = &cpu->env; if (env->miclaim & interrupts) { @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) } } -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value) { CPURISCVState *env = &cpu->env; CPUState *cs = CPU(cpu); - uint32_t old = env->mip; + uint64_t old = env->mip; bool locked = false; if (!qemu_mutex_iothread_locked()) { @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) return old; } +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env, + int (*rmw_fn)(void *arg, + target_ulong reg, + target_ulong *val, + target_ulong new_val, + target_ulong write_mask), + void *rmw_fn_arg) +{ + env->imsic_rmw_fn = rmw_fn; + env->imsic_rmw_fn_arg = rmw_fn_arg; +} + void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t), uint32_t arg) { @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs) */ bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG); target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK; - target_ulong deleg = async ? env->mideleg : env->medeleg; + uint64_t deleg = async ? env->mideleg : env->medeleg; bool write_tval = false; target_ulong tval = 0; target_ulong htval = 0; diff --git a/target/riscv/csr.c b/target/riscv/csr.c index d2585395bf..3c016d7452 100644 --- a/target/riscv/csr.c +++ b/target/riscv/csr.c @@ -153,11 +153,56 @@ static int 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 int smode(CPURISCVState *env, int csrno) { return -!riscv_has_ext(env, RVS); } +static int smode32(CPURISCVState *env, int csrno) +{ + if (!riscv_cpu_is_32bit(env)) { + 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 int hmode(CPURISCVState *env, int csrno) { if (riscv_has_ext(env, RVS) && @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno) static int hmode32(CPURISCVState *env, int csrno) { if (!riscv_cpu_is_32bit(env)) { - return 0; + return -RISCV_EXCP_ILLEGAL_INST; + } + + return hmode(env, csrno); +} + +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 int pmp(CPURISCVState *env, int csrno) @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val) /* 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 TLOWBITS64 ((uint64_t)((target_ulong)-1)) -static const target_ulong delegable_ints = S_MODE_INTERRUPTS | - VS_MODE_INTERRUPTS; -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | - VS_MODE_INTERRUPTS; +static const uint64_t delegable_ints = S_MODE_INTERRUPTS | + VS_MODE_INTERRUPTS; +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS | + VS_MODE_INTERRUPTS; static const target_ulong delegable_excps = (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) | (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) | @@ -419,10 +483,10 @@ static const target_ulong delegable_excps = static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE | SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS | SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD; -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; -static const target_ulong hip_writable_mask = MIP_VSSIP; -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; -static const target_ulong vsip_writable_mask = MIP_VSSIP; +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP; +static const uint64_t hip_writable_mask = MIP_VSSIP; +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP; +static const uint64_t vsip_writable_mask = MIP_VSSIP; static const char valid_vm_1_10_32[16] = { [VM_1_10_MBARE] = 1, @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val) static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val) { - env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints); + uint64_t mask = delegable_ints & TLOWBITS64; + + env->mideleg = (env->mideleg & ~mask) | (val & mask); + if (riscv_has_ext(env, RVH)) { + env->mideleg |= VS_MODE_INTERRUPTS; + } + return 0; +} + +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_STOPI: + return CSR_VSTOPI; + case CSR_SSETEIPNUM: + return CSR_VSSETEIPNUM; + case CSR_SCLREIPNUM: + return CSR_VSCLREIPNUM; + case CSR_SSETEIENUM: + return CSR_VSSETEIENUM; + case CSR_SCLREIENUM: + return CSR_VSCLREIENUM; + default: + return csrno; + }; +} + +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val, + target_ulong new_val, target_ulong write_mask) +{ + target_ulong *iselect; + + switch (csrno) { + case CSR_MISELECT: + iselect = &env->miselect; + break; + case CSR_SISELECT: + iselect = riscv_cpu_virt_enabled(env) ? + &env->vsiselect : &env->siselect; + break; + case CSR_VSISELECT: + iselect = &env->vsiselect; + break; + default: + return -RISCV_EXCP_ILLEGAL_INST; + }; + + if (val) { + *val = *iselect; + } + + if (write_mask) { + *iselect = (*iselect & ~write_mask) | (new_val & write_mask); + } + + return 0; +} + +static int rmw_iprio(target_ulong iselect, uint8_t *iprio, + target_ulong *val, target_ulong new_val, + target_ulong write_mask) +{ + int i, firq, nirqs; + target_ulong old_val; + + if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) { + return -EINVAL; + } +#if TARGET_LONG_BITS == 64 + if (iselect & 0x1) { + return -EINVAL; + } +#endif + + nirqs = 4 * (TARGET_LONG_BITS / 32); + firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 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 (write_mask) { + new_val = (old_val & ~write_mask) | (new_val & write_mask); + for (i = 0; i < nirqs; i++) { + 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 write_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) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; + + if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) { + /* Local interrupt priority registers not available for VS-mode */ + if (!virt) { + ret = rmw_iprio(isel, iprio, val, new_val, write_mask); + } + } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) { + /* IMSIC registers only available when machine implements it. */ + if (env->imsic_rmw_fn) { + /* Selected guest interrupt file should not be zero */ + if (virt && !vgein) { + goto done; + } + /* Call machine specific IMSIC register emulation */ + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, + IMSIC_MAKE_REG(isel, priv, virt, vgein), + val, new_val, write_mask); + } + } + +done: + if (ret) { + return (riscv_cpu_virt_enabled(env) && virt) ? + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; + } + return 0; +} + +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val) +{ + int irq; + + irq = riscv_cpu_mirq_pending(env); + if (irq <= 0 || irq > 63) { + *val = 0; + } else { + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; + *val |= env->miprio[irq]; + } + + return 0; +} + +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val) +{ + bool virt; + int ret = -EINVAL; + target_ulong 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_MSETEIPNUM: + case CSR_MCLREIPNUM: + case CSR_MSETEIENUM: + case CSR_MCLREIENUM: + case CSR_SSETEIPNUM: + case CSR_SCLREIPNUM: + case CSR_SSETEIENUM: + case CSR_SCLREIENUM: + break; + case CSR_VSSETEIPNUM: + case CSR_VSCLREIPNUM: + case CSR_VSSETEIENUM: + case CSR_VSCLREIENUM: + virt = true; + break; + default: + goto done; + }; + + /* IMSIC CSRs only available when machine implements IMSIC. */ + if (!env->imsic_rmw_fn) { + goto done; + } + + /* Find the selected guest interrupt file */ + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; + + /* Selected guest interrupt file should not be zero */ + if (virt && !vgein) { + goto done; + } + + /* Set/Clear CSRs always read zero */ + ret = 0; + if (val) { + *val = 0; + } + +done: + if (ret) { + return (riscv_cpu_virt_enabled(env) && virt) ? + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; + } + return 0; +} + +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val) +{ + int ret = -EINVAL; + bool set, pend, virt; + target_ulong priv, isel, vgein; + target_ulong new_val, write_mask; + + /* 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; + 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->imsic_rmw_fn) { + goto done; + } + + /* Find target interrupt pending/enable register */ + if (pend) { + isel = ISELECT_IMSIC_EIP0; + } else { + isel = ISELECT_IMSIC_EIE0; + } + isel += val / IMSIC_EIPx_BITS; + + /* Find the interrupt bit to be set/clear */ + write_mask = 1 << (val % IMSIC_EIPx_BITS); + new_val = (set) ? write_mask : 0; + + /* Find the selected guest interrupt file */ + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; + + /* Selected guest interrupt file should not be zero */ + if (virt && !vgein) { + goto done; + } + + /* Call machine specific IMSIC register emulation */ + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, + IMSIC_MAKE_REG(isel, priv, virt, vgein), + NULL, new_val, write_mask); + +done: + if (ret) { + return (riscv_cpu_virt_enabled(env) && virt) ? + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; + } + return 0; +} + +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val) +{ + bool virt; + int ret = -EINVAL; + target_ulong priv, isel, vgein; + target_ulong topei, write_mask; + + /* Decode register details from CSR number */ + virt = false; + switch (csrno) { + case CSR_MCLAIMEI: + priv = PRV_M; + break; + case CSR_SCLAIMEI: + priv = PRV_S; + virt = riscv_cpu_virt_enabled(env); + break; + default: + goto done; + }; + + /* IMSIC CSRs only available when machine implements IMSIC. */ + if (!env->imsic_rmw_fn) { + goto done; + } + + /* Find the selected guest interrupt file */ + vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0; + + /* Selected guest interrupt file should not be zero */ + if (virt && !vgein) { + goto done; + } + + /* Call machine specific IMSIC register emulation for reading TOPEI */ + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, + IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein), + &topei, -1, 0); + if (ret) { + goto done; + } + + /* If no interrupt pending then we are done */ + if (!topei) { + goto done; + } + + /* Find target interrupt pending register */ + isel = ISELECT_IMSIC_EIP0; + isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS); + + /* Find the interrupt bit to be cleared */ + write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS); + + /* Call machine specific IMSIC register emulation to clear pending bit */ + ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg, + IMSIC_MAKE_REG(isel, priv, virt, vgein), + NULL, 0, write_mask); + + /* Update return value */ + if (val) { + *val = topei; + } + +done: + if (ret) { + return (riscv_cpu_virt_enabled(env) && virt) ? + -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST; + } + return 0; +} + +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = (env->mideleg >> 32); + return 0; +} + +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val) +{ + uint64_t mask = delegable_ints & ~TLOWBITS64; + uint64_t newval = ((uint64_t)val) << 32; + + env->mideleg = (env->mideleg & ~mask) | (newval & mask); if (riscv_has_ext(env, RVH)) { env->mideleg |= VS_MODE_INTERRUPTS; } @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val) static int write_mie(CPURISCVState *env, int csrno, target_ulong val) { - env->mie = (env->mie & ~all_ints) | (val & all_ints); + uint64_t mask = all_ints & TLOWBITS64; + + env->mie = (env->mie & ~mask) | (val & mask); + return 0; +} + +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = (env->mie >> 32); + return 0; +} + +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val) +{ + uint64_t mask = all_ints & ~TLOWBITS64; + uint64_t newval = ((uint64_t)val) << 32; + + env->mie = (env->mie & ~mask) | (newval & mask); return 0; } @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, { 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 mask = ((uint64_t)write_mask) & delegable_ints & + ~env->miclaim & TLOWBITS64; + uint64_t old_mip; if (mask) { old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, return 0; } +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) +{ + RISCVCPU *cpu = env_archcpu(env); + /* Allow software control of delegable interrupts not claimed by hardware */ + uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints & + ~env->miclaim & ~TLOWBITS64; + uint64_t new_value64 = (uint64_t)new_value << 32; + uint64_t old_mip; + + if (mask) { + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); + } else { + old_mip = env->mip; + } + + if (ret_value) { + *ret_value = old_mip >> 32; + } + + return 0; +} + /* Supervisor Trap Setup */ static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val) { @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val) static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val) { + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64; + /* Shift the VS bits to their S bit location in vsie */ - *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1; + *val = (env->mie & mask) >> 1; + return 0; +} + +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val) +{ + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64; + + /* Shift the VS bits to their S bit location in vsieh */ + *val = (env->mie & mask) >> (32 + 1); return 0; } static int read_sie(CPURISCVState *env, int csrno, target_ulong *val) { if (riscv_cpu_virt_enabled(env)) { - read_vsie(env, CSR_VSIE, val); - } else { - *val = env->mie & env->mideleg; + if (env->hvicontrol & HVICONTROL_VTI) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + return read_vsie(env, CSR_VSIE, val); } + + *val = env->mie & env->mideleg; return 0; } static int write_vsie(CPURISCVState *env, int csrno, target_ulong val) { + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & + all_ints & TLOWBITS64; + /* 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); + env->mie = (env->mie & ~mask) | ((val << 1) & mask); + + return 0; +} + +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val) +{ + uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & + all_ints & ~TLOWBITS64; + uint64_t newval = (uint64_t)val << 32; + + /* Shift the S bits to their VS bit location in mie */ + env->mie = (env->mie & ~mask) | ((newval << 1) & mask); + + return 0; } static int write_sie(CPURISCVState *env, int csrno, target_ulong val) { + uint64_t mask; + if (riscv_cpu_virt_enabled(env)) { - write_vsie(env, CSR_VSIE, val); - } else { - target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) | - (val & S_MODE_INTERRUPTS); - write_mie(env, CSR_MIE, newval); + if (env->hvicontrol & HVICONTROL_VTI) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + return write_vsie(env, CSR_VSIE, val); + } + + mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64; + env->mie = (env->mie & ~mask) | ((uint64_t)val & mask); + + return 0; +} + +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val) +{ + if (riscv_cpu_virt_enabled(env)) { + if (env->hvicontrol & HVICONTROL_VTI) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + return read_vsieh(env, CSR_VSIEH, val); + } + + *val = ((env->mie & env->mideleg) >> 32); + return 0; +} + +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val) +{ + uint64_t mask, newval; + + if (riscv_cpu_virt_enabled(env)) { + if (env->hvicontrol & HVICONTROL_VTI) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + return write_vsieh(env, CSR_VSIEH, val); } + mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64; + newval = (uint64_t)val << 32; + + env->mie = (env->mie & ~mask) | (newval & mask); return 0; } @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val) static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_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); - *ret_value &= VS_MODE_INTERRUPTS; - /* Shift the VS bits to their S bit location in vsip */ - *ret_value >>= 1; - return ret; + RISCVCPU *cpu = env_archcpu(env); + /* Allow software control of delegable interrupts not claimed by hardware */ + uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints & + vsip_writable_mask & env->hideleg & + ~env->miclaim & TLOWBITS64; + uint64_t old_mip; + + if (mask) { + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); + } else { + old_mip = env->mip; + } + + if (ret_value) { + *ret_value = old_mip & VS_MODE_INTERRUPTS; + } + + return 0; +} + +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) +{ + RISCVCPU *cpu = env_archcpu(env); + /* Allow software control of delegable interrupts not claimed by hardware */ + uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints & + vsip_writable_mask & env->hideleg & + ~env->miclaim & ~TLOWBITS64; + uint64_t new_value64 = (uint64_t)new_value << 32; + uint64_t old_mip; + + if (mask) { + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); + } else { + old_mip = env->mip; + } + + if (ret_value) { + *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32; + } + + return 0; } static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask) { - int ret; + RISCVCPU *cpu = env_archcpu(env); + uint64_t mask, old_mip; if (riscv_cpu_virt_enabled(env)) { - ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); + if (env->hvicontrol & HVICONTROL_VTI) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask); + } + + /* Allow software control of delegable interrupts not claimed by hardware */ + mask = ((uint64_t)write_mask) & delegable_ints & + env->mideleg & sip_writable_mask & + ~env->miclaim & TLOWBITS64; + if (mask) { + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); } else { - ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value, - write_mask & env->mideleg & sip_writable_mask); + old_mip = env->mip; } - *ret_value &= env->mideleg; - return ret; + if (ret_value) { + *ret_value = old_mip; + } + + return 0; +} + +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) +{ + RISCVCPU *cpu = env_archcpu(env); + uint64_t mask, new_value64; + uint64_t old_mip; + + if (riscv_cpu_virt_enabled(env)) { + if (env->hvicontrol & HVICONTROL_VTI) { + return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT; + } + return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask); + } + + /* Allow software control of delegable interrupts not claimed by hardware */ + mask = ((uint64_t)write_mask << 32) & delegable_ints & + env->mideleg & sip_writable_mask & + ~env->miclaim & ~TLOWBITS64; + new_value64 = (uint64_t)new_value << 32; + if (mask) { + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); + } else { + old_mip = env->mip; + } + + if (ret_value) { + *ret_value = (old_mip & env->mideleg) >> 32; + } + + return 0; } /* Supervisor Protection and Translation */ @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val) return 0; } +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val) +{ + int irq, hiid; + uint8_t hiprio, iprio; + + irq = riscv_cpu_vsirq_pending(env); + if (irq <= 0 || irq > 63) { + *val = 0; + } else { + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; + iprio = env->hviprio[irq]; + /* TODO: This needs to improve in specification */ + if (!(env->hstatus & HSTATUS_VGEIN)) { + hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >> + HVICONTROL_IID_SHIFT; + hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK; + if (irq == hiid && hiprio) { + iprio = hiprio; + } + } + *val |= iprio; + } + + return 0; +} + +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val) +{ + int irq; + + 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 { + *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT; + *val |= env->siprio[irq]; + } + + return 0; +} + /* Hypervisor Extensions */ static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val) { @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val) return 0; } +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hideleg >> 32; + return 0; +} + +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val) +{ + uint64_t mask = ~TLOWBITS64; + uint64_t newval = ((uint64_t)val) << 32; + + env->hideleg = (env->hideleg & ~mask) | (newval & mask); + + return 0; +} + static int rmw_hvip(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, - write_mask & hvip_writable_mask); + RISCVCPU *cpu = env_archcpu(env); + /* Allow software control of delegable interrupts not claimed by hardware */ + uint64_t mask = ((uint64_t)write_mask) & delegable_ints & + hvip_writable_mask & + ~env->miclaim & TLOWBITS64; + uint64_t old_mip; + + if (mask) { + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); + } else { + old_mip = env->mip; + } - *ret_value &= hvip_writable_mask; + if (ret_value) { + *ret_value = old_mip & hvip_writable_mask; + } - return ret; + return 0; +} + +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value, + target_ulong new_value, target_ulong write_mask) +{ + RISCVCPU *cpu = env_archcpu(env); + /* Allow software control of delegable interrupts not claimed by hardware */ + uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints & + hvip_writable_mask & + ~env->miclaim & ~TLOWBITS64; + uint64_t new_value64 = (uint64_t)new_value << 32; + uint64_t old_mip; + + if (mask) { + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask)); + } else { + old_mip = env->mip; + } + + if (ret_value) { + *ret_value = (old_mip & hvip_writable_mask) >> 32; + } + + return 0; } static int 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, - write_mask & hip_writable_mask); + RISCVCPU *cpu = env_archcpu(env); + /* Allow software control of delegable interrupts not claimed by hardware */ + uint64_t mask = ((uint64_t)write_mask) & delegable_ints & + hip_writable_mask & + ~env->miclaim & TLOWBITS64; + uint64_t old_mip; - *ret_value &= hip_writable_mask; + if (mask) { + old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask)); + } else { + old_mip = env->mip; + } - return ret; + if (ret_value) { + *ret_value = old_mip & hip_writable_mask; + } + + return 0; } static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val) static int 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); + uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64; + env->mie = (env->mie & ~mask) | ((uint64_t)val & mask); + return 0; } static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val) @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val) return 0; } +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val) +{ + *val = env->hvicontrol; + return 0; +} + +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val) +{ + env->hvicontrol = val & HVICONTROL_VALID_MASK; + return 0; +} + +static int read_hvipriox(CPURISCVState *env, int first_index, + uint8_t *iprio, target_ulong *val) +{ + int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32); + + /* First index has to be multiple of numbe 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 0; +} + +static int write_hvipriox(CPURISCVState *env, int first_index, + uint8_t *iprio, target_ulong val) +{ + int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32); + + /* First index has to be multiple of numbe 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 0; +} + +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 int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val) { @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = { [CSR_MBADADDR] = { "mbadaddr", any, read_mbadaddr, write_mbadaddr }, [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, read_xsetclreinum, write_xsetclreinum }, + [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum }, + [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum }, + [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum }, + [CSR_MCLAIMEI] = { "mclaimei", aia_any, read_xclaimei }, + + /* Machine-Level High-Half CSRs (AIA) */ + [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh }, + [CSR_MIEH] = { "mieh", aia_any32, read_mieh, write_mieh }, + [CSR_MIPH] = { "miph", aia_any32, NULL, NULL, rmw_miph }, + /* Supervisor Trap Setup */ [CSR_SSTATUS] = { "sstatus", smode, read_sstatus, write_sstatus }, [CSR_SIE] = { "sie", smode, read_sie, write_sie }, @@ -1444,6 +2357,24 @@ 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, read_xsetclreinum, write_xsetclreinum }, + [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum }, + [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum }, + [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum }, + [CSR_SCLAIMEI] = { "sclaimei", aia_smode, read_xclaimei }, + + /* Supervisor-Level High-Half CSRs (AIA) */ + [CSR_SIEH] = { "sieh", aia_smode32, read_sieh, write_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 }, @@ -1472,6 +2403,32 @@ 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_HVICONTROL] = { "hvicontrol", aia_hmode, read_hvicontrol, write_hvicontrol }, + [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, read_xsetclreinum, write_xsetclreinum }, + [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, + [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, + [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum }, + + /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */ + [CSR_HIDELEGH] = { "hidelegh", aia_hmode32, read_hidelegh, write_hidelegh }, + [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, read_vsieh, write_vsieh }, + [CSR_VSIPH] = { "vsiep", aia_hmode32, NULL, NULL, rmw_vsiph }, + /* Physical Memory Protection */ [CSR_PMPCFG0] = { "pmpcfg0", pmp, read_pmpcfg, write_pmpcfg }, [CSR_PMPCFG1] = { "pmpcfg1", pmp, read_pmpcfg, write_pmpcfg }, diff --git a/target/riscv/machine.c b/target/riscv/machine.c index 44d4015bd6..f7fa48c240 100644 --- a/target/riscv/machine.c +++ b/target/riscv/machine.c @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = { static const VMStateDescription vmstate_hyper = { .name = "cpu/hyper", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .needed = hyper_needed, .fields = (VMStateField[]) { VMSTATE_UINTTL(env.hstatus, RISCVCPU), VMSTATE_UINTTL(env.hedeleg, RISCVCPU), - VMSTATE_UINTTL(env.hideleg, RISCVCPU), + VMSTATE_UINT64(env.hideleg, RISCVCPU), VMSTATE_UINTTL(env.hcounteren, RISCVCPU), VMSTATE_UINTTL(env.htval, RISCVCPU), VMSTATE_UINTTL(env.htinst, RISCVCPU), VMSTATE_UINTTL(env.hgatp, RISCVCPU), VMSTATE_UINT64(env.htimedelta, RISCVCPU), + VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64), + VMSTATE_UINTTL(env.hvicontrol, RISCVCPU), + VMSTATE_UINT64(env.vsstatus, RISCVCPU), VMSTATE_UINTTL(env.vstvec, RISCVCPU), VMSTATE_UINTTL(env.vsscratch, RISCVCPU), @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = { VMSTATE_UINTTL(env.vscause, RISCVCPU), VMSTATE_UINTTL(env.vstval, RISCVCPU), VMSTATE_UINTTL(env.vsatp, RISCVCPU), + VMSTATE_UINTTL(env.vsiselect, RISCVCPU), VMSTATE_UINTTL(env.mtval2, RISCVCPU), VMSTATE_UINTTL(env.mtinst, RISCVCPU), @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = { const VMStateDescription vmstate_riscv_cpu = { .name = "cpu", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (VMStateField[]) { VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32), VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32), + VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64), + VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64), VMSTATE_UINTTL(env.pc, RISCVCPU), VMSTATE_UINTTL(env.load_res, RISCVCPU), VMSTATE_UINTTL(env.load_val, RISCVCPU), @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINTTL(env.resetvec, RISCVCPU), VMSTATE_UINTTL(env.mhartid, RISCVCPU), VMSTATE_UINT64(env.mstatus, RISCVCPU), - VMSTATE_UINTTL(env.mip, RISCVCPU), - VMSTATE_UINT32(env.miclaim, RISCVCPU), - VMSTATE_UINTTL(env.mie, RISCVCPU), - VMSTATE_UINTTL(env.mideleg, RISCVCPU), + VMSTATE_UINT64(env.mip, RISCVCPU), + VMSTATE_UINT64(env.miclaim, RISCVCPU), + VMSTATE_UINT64(env.mie, RISCVCPU), + VMSTATE_UINT64(env.mideleg, RISCVCPU), VMSTATE_UINTTL(env.sptbr, RISCVCPU), VMSTATE_UINTTL(env.satp, RISCVCPU), VMSTATE_UINTTL(env.sbadaddr, RISCVCPU), @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = { VMSTATE_UINTTL(env.mepc, RISCVCPU), VMSTATE_UINTTL(env.mcause, RISCVCPU), VMSTATE_UINTTL(env.mtval, RISCVCPU), + VMSTATE_UINTTL(env.miselect, RISCVCPU), + VMSTATE_UINTTL(env.siselect, RISCVCPU), VMSTATE_UINTTL(env.scounteren, RISCVCPU), VMSTATE_UINTTL(env.mcounteren, RISCVCPU), VMSTATE_UINTTL(env.sscratch, RISCVCPU),
We implement various AIA local interrupt CSRs for M-mode, HS-mode, and VS-mode. Signed-off-by: Anup Patel <anup.patel@wdc.com> --- target/riscv/cpu.c | 27 +- target/riscv/cpu.h | 52 +- target/riscv/cpu_helper.c | 245 ++++++++- target/riscv/csr.c | 1059 +++++++++++++++++++++++++++++++++++-- target/riscv/machine.c | 26 +- 5 files changed, 1309 insertions(+), 100 deletions(-)