All of lore.kernel.org
 help / color / mirror / Atom feed
From: Anup Patel <anup.patel@wdc.com>
To: Peter Maydell <peter.maydell@linaro.org>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Alistair Francis <Alistair.Francis@wdc.com>,
	Sagar Karandikar <sagark@eecs.berkeley.edu>
Cc: Atish Patra <atish.patra@wdc.com>,
	Anup Patel <anup.patel@wdc.com>,
	qemu-riscv@nongnu.org, qemu-devel@nongnu.org,
	Anup Patel <anup@brainfault.org>
Subject: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
Date: Fri, 14 May 2021 20:02:41 +0530	[thread overview]
Message-ID: <20210514143242.377645-4-anup.patel@wdc.com> (raw)
In-Reply-To: <20210514143242.377645-1-anup.patel@wdc.com>

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(-)

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),
-- 
2.25.1



WARNING: multiple messages have this Message-ID (diff)
From: Anup Patel <anup.patel@wdc.com>
To: Peter Maydell <peter.maydell@linaro.org>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Alistair Francis <Alistair.Francis@wdc.com>,
	Sagar Karandikar <sagark@eecs.berkeley.edu>
Cc: Atish Patra <atish.patra@wdc.com>,
	Anup Patel <anup@brainfault.org>,
	qemu-riscv@nongnu.org, qemu-devel@nongnu.org,
	Anup Patel <anup.patel@wdc.com>
Subject: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
Date: Fri, 14 May 2021 20:02:41 +0530	[thread overview]
Message-ID: <20210514143242.377645-4-anup.patel@wdc.com> (raw)
In-Reply-To: <20210514143242.377645-1-anup.patel@wdc.com>

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(-)

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),
-- 
2.25.1



  parent reply	other threads:[~2021-05-14 14:35 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-14 14:32 [PATCH 0/4] AIA local interrupt CSR support Anup Patel
2021-05-14 14:32 ` Anup Patel
2021-05-14 14:32 ` [PATCH 1/4] target/riscv: Add defines for AIA local interrupt CSRs Anup Patel
2021-05-14 14:32   ` Anup Patel
2021-06-10 22:26   ` Alistair Francis
2021-06-10 22:26     ` Alistair Francis
2021-05-14 14:32 ` [PATCH 2/4] target/riscv: Add CPU feature for AIA CSRs Anup Patel
2021-05-14 14:32   ` Anup Patel
2021-06-10 23:15   ` Alistair Francis
2021-06-10 23:15     ` Alistair Francis
2021-06-11  4:58     ` Anup Patel
2021-06-11  4:58       ` Anup Patel
2021-05-14 14:32 ` Anup Patel [this message]
2021-05-14 14:32   ` [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs Anup Patel
2021-06-10 23:19   ` Alistair Francis
2021-06-10 23:19     ` Alistair Francis
2021-06-11  5:04     ` Anup Patel
2021-06-11  5:04       ` Anup Patel
2021-06-11  8:45       ` Alistair Francis
2021-06-11  8:45         ` Alistair Francis
2021-06-11 14:04         ` Anup Patel
2021-06-11 14:04           ` Anup Patel
2021-06-15  8:11           ` Alistair Francis
2021-06-15  8:11             ` Alistair Francis
2021-06-15 12:48             ` Anup Patel
2021-06-15 12:48               ` Anup Patel
2021-05-14 14:32 ` [PATCH 4/4] hw/riscv: virt: Use AIA INTC compatible string when available Anup Patel
2021-05-14 14:32   ` Anup Patel
2021-06-10 23:20   ` Alistair Francis
2021-06-10 23:20     ` Alistair Francis
2021-06-11  6:47 ` [PATCH 0/4] AIA local interrupt CSR support Anup Patel
2021-06-11  6:47   ` Anup Patel
2021-06-11  8:40   ` Alistair Francis
2021-06-11  8:40     ` Alistair Francis

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210514143242.377645-4-anup.patel@wdc.com \
    --to=anup.patel@wdc.com \
    --cc=Alistair.Francis@wdc.com \
    --cc=anup@brainfault.org \
    --cc=atish.patra@wdc.com \
    --cc=palmer@dabbelt.com \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-devel@nongnu.org \
    --cc=qemu-riscv@nongnu.org \
    --cc=sagark@eecs.berkeley.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.