All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] AIA local interrupt CSR support
@ 2021-05-14 14:32 ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

The advanced interrupt architecture (AIA) extends the per-HART local
interrupt support. Along with this, it also adds IMSIC (MSI contrllor)
and Advanced PLIC (wired interrupt controller).

The latest AIA draft specification can be found here:
http://jhauser.us/private/RISCV-AIA/riscv-interrupts-021.pdf

This series adds initial AIA support in QEMU which includes emulating all
AIA local CSR. To enable AIA in QEMU, we just need to pass "x-aia=true"
paramenter in "-cpu" QEMU command-line.

To test series, we require OpenSBI and Linux with AIA support which
can be found in riscv_aia_v1 branch at:
https://github.com/avpatel/opensbi.git
https://github.com/avpatel/linux.git

Anup Patel (4):
  target/riscv: Add defines for AIA local interrupt CSRs
  target/riscv: Add CPU feature for AIA CSRs
  target/riscv: Implement AIA local interrupt CSRs
  hw/riscv: virt: Use AIA INTC compatible string when available

 hw/riscv/virt.c           |   11 +-
 target/riscv/cpu.c        |   32 +-
 target/riscv/cpu.h        |   56 +-
 target/riscv/cpu_bits.h   |  128 +++++
 target/riscv/cpu_helper.c |  245 ++++++++-
 target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
 target/riscv/machine.c    |   26 +-
 7 files changed, 1454 insertions(+), 103 deletions(-)

-- 
2.25.1



^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 0/4] AIA local interrupt CSR support
@ 2021-05-14 14:32 ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

The advanced interrupt architecture (AIA) extends the per-HART local
interrupt support. Along with this, it also adds IMSIC (MSI contrllor)
and Advanced PLIC (wired interrupt controller).

The latest AIA draft specification can be found here:
http://jhauser.us/private/RISCV-AIA/riscv-interrupts-021.pdf

This series adds initial AIA support in QEMU which includes emulating all
AIA local CSR. To enable AIA in QEMU, we just need to pass "x-aia=true"
paramenter in "-cpu" QEMU command-line.

To test series, we require OpenSBI and Linux with AIA support which
can be found in riscv_aia_v1 branch at:
https://github.com/avpatel/opensbi.git
https://github.com/avpatel/linux.git

Anup Patel (4):
  target/riscv: Add defines for AIA local interrupt CSRs
  target/riscv: Add CPU feature for AIA CSRs
  target/riscv: Implement AIA local interrupt CSRs
  hw/riscv: virt: Use AIA INTC compatible string when available

 hw/riscv/virt.c           |   11 +-
 target/riscv/cpu.c        |   32 +-
 target/riscv/cpu.h        |   56 +-
 target/riscv/cpu_bits.h   |  128 +++++
 target/riscv/cpu_helper.c |  245 ++++++++-
 target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
 target/riscv/machine.c    |   26 +-
 7 files changed, 1454 insertions(+), 103 deletions(-)

-- 
2.25.1



^ permalink raw reply	[flat|nested] 34+ messages in thread

* [PATCH 1/4] target/riscv: Add defines for AIA local interrupt CSRs
  2021-05-14 14:32 ` Anup Patel
@ 2021-05-14 14:32   ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

The RISC-V AIA specification extends RISC-V local interrupts and
introduces new CSRs. This patch adds defines for the new AIA
local interrupt CSRs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 target/riscv/cpu_bits.h | 128 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index caf4599207..d23242655e 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -169,6 +169,31 @@
 /* Legacy Machine Trap Handling (priv v1.9.1) */
 #define CSR_MBADADDR        0x343
 
+/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
+#define CSR_MISELECT        0x350
+#define CSR_MIREG           0x351
+
+/* Machine-Level Interrupts (AIA) */
+#define CSR_MTOPI           0xfb0
+
+/* Machine-Level IMSIC Interface (AIA) */
+#define CSR_MSETEIPNUM      0x358
+#define CSR_MCLREIPNUM      0x359
+#define CSR_MSETEIENUM      0x35a
+#define CSR_MCLREIENUM      0x35b
+#define CSR_MCLAIMEI        0xfa8
+
+/* Virtual Interrupts for Supervisor Level (AIA) */
+#define CSR_MVIEN           0x308
+#define CSR_MVIP            0x309
+
+/* Machine-Level High-Half CSRs (AIA) */
+#define CSR_MIDELEGH        0x313
+#define CSR_MIEH            0x314
+#define CSR_MVIENH          0x318
+#define CSR_MVIPH           0x319
+#define CSR_MIPH            0x354
+
 /* Supervisor Trap Setup */
 #define CSR_SSTATUS         0x100
 #define CSR_SEDELEG         0x102
@@ -191,6 +216,24 @@
 #define CSR_SPTBR           0x180
 #define CSR_SATP            0x180
 
+/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
+#define CSR_SISELECT        0x150
+#define CSR_SIREG           0x151
+
+/* Supervisor-Level Interrupts (AIA) */
+#define CSR_STOPI           0xdb0
+
+/* Supervisor-Level IMSIC Interface (AIA) */
+#define CSR_SSETEIPNUM      0x158
+#define CSR_SCLREIPNUM      0x159
+#define CSR_SSETEIENUM      0x15a
+#define CSR_SCLREIENUM      0x15b
+#define CSR_SCLAIMEI        0xda8
+
+/* Supervisor-Level High-Half CSRs (AIA) */
+#define CSR_SIEH            0x114
+#define CSR_SIPH            0x154
+
 /* Hpervisor CSRs */
 #define CSR_HSTATUS         0x600
 #define CSR_HEDELEG         0x602
@@ -232,6 +275,34 @@
 #define CSR_MTINST          0x34a
 #define CSR_MTVAL2          0x34b
 
+/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
+#define CSR_HVIEN           0x608
+#define CSR_HVICONTROL      0x609
+#define CSR_HVIPRIO1        0x646
+#define CSR_HVIPRIO2        0x647
+
+/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
+#define CSR_VSISELECT       0x250
+#define CSR_VSIREG          0x251
+
+/* VS-Level Interrupts (H-extension with AIA) */
+#define CSR_VSTOPI          0xeb0
+
+/* VS-Level IMSIC Interface (H-extension with AIA) */
+#define CSR_VSSETEIPNUM     0x258
+#define CSR_VSCLREIPNUM     0x259
+#define CSR_VSSETEIENUM     0x25a
+#define CSR_VSCLREIENUM     0x25b
+
+/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
+#define CSR_HIDELEGH        0x613
+#define CSR_HVIENH          0x618
+#define CSR_HVIPH           0x655
+#define CSR_HVIPRIO1H       0x656
+#define CSR_HVIPRIO2H       0x657
+#define CSR_VSIEH           0x214
+#define CSR_VSIPH           0x254
+
 /* Physical Memory Protection */
 #define CSR_PMPCFG0         0x3a0
 #define CSR_PMPCFG1         0x3a1
@@ -436,6 +507,7 @@
 #define HSTATUS_SPVP         0x00000100
 #define HSTATUS_HU           0x00000200
 #define HSTATUS_VGEIN        0x0003F000
+#define HSTATUS_VGEIN_SHIFT  12
 #define HSTATUS_VTVM         0x00100000
 #define HSTATUS_VTSR         0x00400000
 #define HSTATUS_VSXL         0x300000000
@@ -565,6 +637,7 @@
 #define IRQ_S_EXT                          9
 #define IRQ_VS_EXT                         10
 #define IRQ_M_EXT                          11
+#define IRQ_S_GEXT                         12
 
 /* mip masks */
 #define MIP_USIP                           (1 << IRQ_U_SOFT)
@@ -592,4 +665,59 @@
 #define MIE_UTIE                           (1 << IRQ_U_TIMER)
 #define MIE_SSIE                           (1 << IRQ_S_SOFT)
 #define MIE_USIE                           (1 << IRQ_U_SOFT)
+
+/* MISELECT, SISELECT, and VSISELECT bits (AIA) */
+#define ISELECT_IPRIO0                     0x30
+#define ISELECT_IPRIO15                    0x3f
+#define ISELECT_IMSIC_EIDELIVERY           0x70
+#define ISELECT_IMSIC_EITHRESHOLD          0x72
+#define ISELECT_IMSIC_TOPEI                0x76
+#define ISELECT_IMSIC_EIP0                 0x80
+#define ISELECT_IMSIC_EIP63                0xbf
+#define ISELECT_IMSIC_EIE0                 0xc0
+#define ISELECT_IMSIC_EIE63                0xff
+#define ISELECT_IMSIC_FIRST                ISELECT_IMSIC_EIDELIVERY
+#define ISELECT_IMSIC_LAST                 ISELECT_IMSIC_EIE63
+
+/* IMSIC bits (AIA) */
+#define IMSIC_TOPEI_IID_SHIFT              16
+#define IMSIC_TOPEI_IID_MASK               0x7ff
+#define IMSIC_TOPEI_IPIRO_MASK             0x7ff
+#define IMSIC_EIPx_BITS                    32
+#define IMSIC_EIEx_BITS                    32
+
+/* MTOPI and STOPI bits (AIA) */
+#define TOPI_IID_SHIFT                     16
+#define TOPI_IID_MASK                      0xfff
+#define TOPI_IPRIO_MASK                    0xff
+
+/* Interrupt priority bits (AIA) */
+#define IPRIO_IRQ_BITS                     8
+#define IPRIO_MMAXIPRIO                    255
+#define IPRIO_DEFAULT_MMAXIPRIO            15
+#define IPRIO_DEFAULT_VS                   (IPRIO_DEFAULT_MMAXIPRIO - 4)
+#define IPRIO_DEFAULT_SGEXT                (IPRIO_DEFAULT_MMAXIPRIO - 5)
+#define IPRIO_DEFAULT_S                    (IPRIO_DEFAULT_MMAXIPRIO - 6)
+#define IPRIO_DEFAULT_M                    (IPRIO_DEFAULT_MMAXIPRIO - 7)
+#define IPRIO_DEFAULT_U(_i)                (((_i) >> 4) & 0x3)
+#define IPRIO_DEFAULT_L(_i)                ((_i) & 0xf)
+#define IPRIO_DEFAULT_16_23(_i)            \
+    (IPRIO_DEFAULT_MMAXIPRIO - (IPRIO_DEFAULT_L(_i) >> 1))
+#define IPRIO_DEFAULT_24_31(_i)            \
+    (IPRIO_DEFAULT_MMAXIPRIO - (4 + (IPRIO_DEFAULT_L(_i) >> 1)))
+#define IPRIO_DEFAULT_32_47(_i)            \
+    (IPRIO_DEFAULT_MMAXIPRIO - (IPRIO_DEFAULT_L(_i) >> 2))
+#define IPRIO_DEFAULT_48_63(_i)            \
+    (IPRIO_DEFAULT_MMAXIPRIO - (8 + (IPRIO_DEFAULT_L(_i) >> 2)))
+
+/* HVICONTROL bits (AIA) */
+#define HVICONTROL_VTI                     0x40000000
+#define HVICONTROL_IID_MASK                0xfff
+#define HVICONTROL_IID_SHIFT               16
+#define HVICONTROL_IPRIO_MASK              0xff
+#define HVICONTROL_VALID_MASK              \
+    (HVICONTROL_VTI | \
+     (HVICONTROL_IID_MASK << HVICONTROL_IID_SHIFT) | \
+     HVICONTROL_IPRIO_MASK)
+
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 1/4] target/riscv: Add defines for AIA local interrupt CSRs
@ 2021-05-14 14:32   ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

The RISC-V AIA specification extends RISC-V local interrupts and
introduces new CSRs. This patch adds defines for the new AIA
local interrupt CSRs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 target/riscv/cpu_bits.h | 128 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 128 insertions(+)

diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
index caf4599207..d23242655e 100644
--- a/target/riscv/cpu_bits.h
+++ b/target/riscv/cpu_bits.h
@@ -169,6 +169,31 @@
 /* Legacy Machine Trap Handling (priv v1.9.1) */
 #define CSR_MBADADDR        0x343
 
+/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
+#define CSR_MISELECT        0x350
+#define CSR_MIREG           0x351
+
+/* Machine-Level Interrupts (AIA) */
+#define CSR_MTOPI           0xfb0
+
+/* Machine-Level IMSIC Interface (AIA) */
+#define CSR_MSETEIPNUM      0x358
+#define CSR_MCLREIPNUM      0x359
+#define CSR_MSETEIENUM      0x35a
+#define CSR_MCLREIENUM      0x35b
+#define CSR_MCLAIMEI        0xfa8
+
+/* Virtual Interrupts for Supervisor Level (AIA) */
+#define CSR_MVIEN           0x308
+#define CSR_MVIP            0x309
+
+/* Machine-Level High-Half CSRs (AIA) */
+#define CSR_MIDELEGH        0x313
+#define CSR_MIEH            0x314
+#define CSR_MVIENH          0x318
+#define CSR_MVIPH           0x319
+#define CSR_MIPH            0x354
+
 /* Supervisor Trap Setup */
 #define CSR_SSTATUS         0x100
 #define CSR_SEDELEG         0x102
@@ -191,6 +216,24 @@
 #define CSR_SPTBR           0x180
 #define CSR_SATP            0x180
 
+/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
+#define CSR_SISELECT        0x150
+#define CSR_SIREG           0x151
+
+/* Supervisor-Level Interrupts (AIA) */
+#define CSR_STOPI           0xdb0
+
+/* Supervisor-Level IMSIC Interface (AIA) */
+#define CSR_SSETEIPNUM      0x158
+#define CSR_SCLREIPNUM      0x159
+#define CSR_SSETEIENUM      0x15a
+#define CSR_SCLREIENUM      0x15b
+#define CSR_SCLAIMEI        0xda8
+
+/* Supervisor-Level High-Half CSRs (AIA) */
+#define CSR_SIEH            0x114
+#define CSR_SIPH            0x154
+
 /* Hpervisor CSRs */
 #define CSR_HSTATUS         0x600
 #define CSR_HEDELEG         0x602
@@ -232,6 +275,34 @@
 #define CSR_MTINST          0x34a
 #define CSR_MTVAL2          0x34b
 
+/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
+#define CSR_HVIEN           0x608
+#define CSR_HVICONTROL      0x609
+#define CSR_HVIPRIO1        0x646
+#define CSR_HVIPRIO2        0x647
+
+/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
+#define CSR_VSISELECT       0x250
+#define CSR_VSIREG          0x251
+
+/* VS-Level Interrupts (H-extension with AIA) */
+#define CSR_VSTOPI          0xeb0
+
+/* VS-Level IMSIC Interface (H-extension with AIA) */
+#define CSR_VSSETEIPNUM     0x258
+#define CSR_VSCLREIPNUM     0x259
+#define CSR_VSSETEIENUM     0x25a
+#define CSR_VSCLREIENUM     0x25b
+
+/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
+#define CSR_HIDELEGH        0x613
+#define CSR_HVIENH          0x618
+#define CSR_HVIPH           0x655
+#define CSR_HVIPRIO1H       0x656
+#define CSR_HVIPRIO2H       0x657
+#define CSR_VSIEH           0x214
+#define CSR_VSIPH           0x254
+
 /* Physical Memory Protection */
 #define CSR_PMPCFG0         0x3a0
 #define CSR_PMPCFG1         0x3a1
@@ -436,6 +507,7 @@
 #define HSTATUS_SPVP         0x00000100
 #define HSTATUS_HU           0x00000200
 #define HSTATUS_VGEIN        0x0003F000
+#define HSTATUS_VGEIN_SHIFT  12
 #define HSTATUS_VTVM         0x00100000
 #define HSTATUS_VTSR         0x00400000
 #define HSTATUS_VSXL         0x300000000
@@ -565,6 +637,7 @@
 #define IRQ_S_EXT                          9
 #define IRQ_VS_EXT                         10
 #define IRQ_M_EXT                          11
+#define IRQ_S_GEXT                         12
 
 /* mip masks */
 #define MIP_USIP                           (1 << IRQ_U_SOFT)
@@ -592,4 +665,59 @@
 #define MIE_UTIE                           (1 << IRQ_U_TIMER)
 #define MIE_SSIE                           (1 << IRQ_S_SOFT)
 #define MIE_USIE                           (1 << IRQ_U_SOFT)
+
+/* MISELECT, SISELECT, and VSISELECT bits (AIA) */
+#define ISELECT_IPRIO0                     0x30
+#define ISELECT_IPRIO15                    0x3f
+#define ISELECT_IMSIC_EIDELIVERY           0x70
+#define ISELECT_IMSIC_EITHRESHOLD          0x72
+#define ISELECT_IMSIC_TOPEI                0x76
+#define ISELECT_IMSIC_EIP0                 0x80
+#define ISELECT_IMSIC_EIP63                0xbf
+#define ISELECT_IMSIC_EIE0                 0xc0
+#define ISELECT_IMSIC_EIE63                0xff
+#define ISELECT_IMSIC_FIRST                ISELECT_IMSIC_EIDELIVERY
+#define ISELECT_IMSIC_LAST                 ISELECT_IMSIC_EIE63
+
+/* IMSIC bits (AIA) */
+#define IMSIC_TOPEI_IID_SHIFT              16
+#define IMSIC_TOPEI_IID_MASK               0x7ff
+#define IMSIC_TOPEI_IPIRO_MASK             0x7ff
+#define IMSIC_EIPx_BITS                    32
+#define IMSIC_EIEx_BITS                    32
+
+/* MTOPI and STOPI bits (AIA) */
+#define TOPI_IID_SHIFT                     16
+#define TOPI_IID_MASK                      0xfff
+#define TOPI_IPRIO_MASK                    0xff
+
+/* Interrupt priority bits (AIA) */
+#define IPRIO_IRQ_BITS                     8
+#define IPRIO_MMAXIPRIO                    255
+#define IPRIO_DEFAULT_MMAXIPRIO            15
+#define IPRIO_DEFAULT_VS                   (IPRIO_DEFAULT_MMAXIPRIO - 4)
+#define IPRIO_DEFAULT_SGEXT                (IPRIO_DEFAULT_MMAXIPRIO - 5)
+#define IPRIO_DEFAULT_S                    (IPRIO_DEFAULT_MMAXIPRIO - 6)
+#define IPRIO_DEFAULT_M                    (IPRIO_DEFAULT_MMAXIPRIO - 7)
+#define IPRIO_DEFAULT_U(_i)                (((_i) >> 4) & 0x3)
+#define IPRIO_DEFAULT_L(_i)                ((_i) & 0xf)
+#define IPRIO_DEFAULT_16_23(_i)            \
+    (IPRIO_DEFAULT_MMAXIPRIO - (IPRIO_DEFAULT_L(_i) >> 1))
+#define IPRIO_DEFAULT_24_31(_i)            \
+    (IPRIO_DEFAULT_MMAXIPRIO - (4 + (IPRIO_DEFAULT_L(_i) >> 1)))
+#define IPRIO_DEFAULT_32_47(_i)            \
+    (IPRIO_DEFAULT_MMAXIPRIO - (IPRIO_DEFAULT_L(_i) >> 2))
+#define IPRIO_DEFAULT_48_63(_i)            \
+    (IPRIO_DEFAULT_MMAXIPRIO - (8 + (IPRIO_DEFAULT_L(_i) >> 2)))
+
+/* HVICONTROL bits (AIA) */
+#define HVICONTROL_VTI                     0x40000000
+#define HVICONTROL_IID_MASK                0xfff
+#define HVICONTROL_IID_SHIFT               16
+#define HVICONTROL_IPRIO_MASK              0xff
+#define HVICONTROL_VALID_MASK              \
+    (HVICONTROL_VTI | \
+     (HVICONTROL_IID_MASK << HVICONTROL_IID_SHIFT) | \
+     HVICONTROL_IPRIO_MASK)
+
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 2/4] target/riscv: Add CPU feature for AIA CSRs
  2021-05-14 14:32 ` Anup Patel
@ 2021-05-14 14:32   ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

We add experimental CPU feature to enable AIA CSRs. This experimental
feature can be enabled by setting "x-aia=true" for CPU in the QEMU
command-line parameters.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 target/riscv/cpu.c | 5 +++++
 target/riscv/cpu.h | 4 +++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 7d6ed80f6b..f3702111ae 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -414,6 +414,10 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
         set_feature(env, RISCV_FEATURE_PMP);
     }
 
+    if (cpu->cfg.aia) {
+        set_feature(env, RISCV_FEATURE_AIA);
+    }
+
     set_resetvec(env, cpu->cfg.resetvec);
 
     /* If only XLEN is set for misa, then set misa from properties */
@@ -554,6 +558,7 @@ static Property riscv_cpu_properties[] = {
     DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
     DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
     DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
+    DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false),
     DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
     DEFINE_PROP_END_OF_LIST(),
 };
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0a33d387ba..f00c60c840 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -80,7 +80,8 @@
 enum {
     RISCV_FEATURE_MMU,
     RISCV_FEATURE_PMP,
-    RISCV_FEATURE_MISA
+    RISCV_FEATURE_MISA,
+    RISCV_FEATURE_AIA
 };
 
 #define PRIV_VERSION_1_10_0 0x00011000
@@ -303,6 +304,7 @@ struct RISCVCPU {
         uint16_t elen;
         bool mmu;
         bool pmp;
+        bool aia;
         uint64_t resetvec;
     } cfg;
 };
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 2/4] target/riscv: Add CPU feature for AIA CSRs
@ 2021-05-14 14:32   ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

We add experimental CPU feature to enable AIA CSRs. This experimental
feature can be enabled by setting "x-aia=true" for CPU in the QEMU
command-line parameters.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 target/riscv/cpu.c | 5 +++++
 target/riscv/cpu.h | 4 +++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 7d6ed80f6b..f3702111ae 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -414,6 +414,10 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
         set_feature(env, RISCV_FEATURE_PMP);
     }
 
+    if (cpu->cfg.aia) {
+        set_feature(env, RISCV_FEATURE_AIA);
+    }
+
     set_resetvec(env, cpu->cfg.resetvec);
 
     /* If only XLEN is set for misa, then set misa from properties */
@@ -554,6 +558,7 @@ static Property riscv_cpu_properties[] = {
     DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
     DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
     DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
+    DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false),
     DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
     DEFINE_PROP_END_OF_LIST(),
 };
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index 0a33d387ba..f00c60c840 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -80,7 +80,8 @@
 enum {
     RISCV_FEATURE_MMU,
     RISCV_FEATURE_PMP,
-    RISCV_FEATURE_MISA
+    RISCV_FEATURE_MISA,
+    RISCV_FEATURE_AIA
 };
 
 #define PRIV_VERSION_1_10_0 0x00011000
@@ -303,6 +304,7 @@ struct RISCVCPU {
         uint16_t elen;
         bool mmu;
         bool pmp;
+        bool aia;
         uint64_t resetvec;
     } cfg;
 };
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
  2021-05-14 14:32 ` Anup Patel
@ 2021-05-14 14:32   ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

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



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
@ 2021-05-14 14:32   ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

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



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 4/4] hw/riscv: virt: Use AIA INTC compatible string when available
  2021-05-14 14:32 ` Anup Patel
@ 2021-05-14 14:32   ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

We should use the AIA INTC compatible string in the CPU INTC
DT nodes when the CPUs support AIA feature. This will allow
Linux INTC driver to use AIA local interrupt CSRs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 hw/riscv/virt.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index c0dc69ff33..981a3a06d5 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -262,8 +262,15 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
             qemu_fdt_add_subnode(fdt, intc_name);
             intc_phandle = phandle++;
             qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
-            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
-                "riscv,cpu-intc");
+            if (riscv_feature(&s->soc[socket].harts[cpu].env,
+                              RISCV_FEATURE_AIA)) {
+                const char intcomp[] = "riscv,cpu-intc-aia\0riscv,cpu-intc";
+                qemu_fdt_setprop(fdt, name, "compatible",
+                    intcomp, sizeof(intcomp));
+            } else {
+                qemu_fdt_setprop_string(fdt, intc_name, "compatible",
+                    "riscv,cpu-intc");
+            }
             qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
             qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* [PATCH 4/4] hw/riscv: virt: Use AIA INTC compatible string when available
@ 2021-05-14 14:32   ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-05-14 14:32 UTC (permalink / raw)
  To: Peter Maydell, Palmer Dabbelt, Alistair Francis, Sagar Karandikar
  Cc: Atish Patra, Anup Patel, qemu-riscv, qemu-devel, Anup Patel

We should use the AIA INTC compatible string in the CPU INTC
DT nodes when the CPUs support AIA feature. This will allow
Linux INTC driver to use AIA local interrupt CSRs.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
---
 hw/riscv/virt.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
index c0dc69ff33..981a3a06d5 100644
--- a/hw/riscv/virt.c
+++ b/hw/riscv/virt.c
@@ -262,8 +262,15 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
             qemu_fdt_add_subnode(fdt, intc_name);
             intc_phandle = phandle++;
             qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
-            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
-                "riscv,cpu-intc");
+            if (riscv_feature(&s->soc[socket].harts[cpu].env,
+                              RISCV_FEATURE_AIA)) {
+                const char intcomp[] = "riscv,cpu-intc-aia\0riscv,cpu-intc";
+                qemu_fdt_setprop(fdt, name, "compatible",
+                    intcomp, sizeof(intcomp));
+            } else {
+                qemu_fdt_setprop_string(fdt, intc_name, "compatible",
+                    "riscv,cpu-intc");
+            }
             qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
             qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/4] target/riscv: Add defines for AIA local interrupt CSRs
  2021-05-14 14:32   ` Anup Patel
@ 2021-06-10 22:26     ` Alistair Francis
  -1 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-10 22:26 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Sat, May 15, 2021 at 12:33 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> The RISC-V AIA specification extends RISC-V local interrupts and
> introduces new CSRs. This patch adds defines for the new AIA
> local interrupt CSRs.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/cpu_bits.h | 128 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 128 insertions(+)
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index caf4599207..d23242655e 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -169,6 +169,31 @@
>  /* Legacy Machine Trap Handling (priv v1.9.1) */
>  #define CSR_MBADADDR        0x343
>
> +/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
> +#define CSR_MISELECT        0x350
> +#define CSR_MIREG           0x351
> +
> +/* Machine-Level Interrupts (AIA) */
> +#define CSR_MTOPI           0xfb0
> +
> +/* Machine-Level IMSIC Interface (AIA) */
> +#define CSR_MSETEIPNUM      0x358
> +#define CSR_MCLREIPNUM      0x359
> +#define CSR_MSETEIENUM      0x35a
> +#define CSR_MCLREIENUM      0x35b
> +#define CSR_MCLAIMEI        0xfa8
> +
> +/* Virtual Interrupts for Supervisor Level (AIA) */
> +#define CSR_MVIEN           0x308
> +#define CSR_MVIP            0x309
> +
> +/* Machine-Level High-Half CSRs (AIA) */
> +#define CSR_MIDELEGH        0x313
> +#define CSR_MIEH            0x314
> +#define CSR_MVIENH          0x318
> +#define CSR_MVIPH           0x319
> +#define CSR_MIPH            0x354
> +
>  /* Supervisor Trap Setup */
>  #define CSR_SSTATUS         0x100
>  #define CSR_SEDELEG         0x102
> @@ -191,6 +216,24 @@
>  #define CSR_SPTBR           0x180
>  #define CSR_SATP            0x180
>
> +/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
> +#define CSR_SISELECT        0x150
> +#define CSR_SIREG           0x151
> +
> +/* Supervisor-Level Interrupts (AIA) */
> +#define CSR_STOPI           0xdb0
> +
> +/* Supervisor-Level IMSIC Interface (AIA) */
> +#define CSR_SSETEIPNUM      0x158
> +#define CSR_SCLREIPNUM      0x159
> +#define CSR_SSETEIENUM      0x15a
> +#define CSR_SCLREIENUM      0x15b
> +#define CSR_SCLAIMEI        0xda8
> +
> +/* Supervisor-Level High-Half CSRs (AIA) */
> +#define CSR_SIEH            0x114
> +#define CSR_SIPH            0x154
> +
>  /* Hpervisor CSRs */
>  #define CSR_HSTATUS         0x600
>  #define CSR_HEDELEG         0x602
> @@ -232,6 +275,34 @@
>  #define CSR_MTINST          0x34a
>  #define CSR_MTVAL2          0x34b
>
> +/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
> +#define CSR_HVIEN           0x608
> +#define CSR_HVICONTROL      0x609
> +#define CSR_HVIPRIO1        0x646
> +#define CSR_HVIPRIO2        0x647
> +
> +/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
> +#define CSR_VSISELECT       0x250
> +#define CSR_VSIREG          0x251
> +
> +/* VS-Level Interrupts (H-extension with AIA) */
> +#define CSR_VSTOPI          0xeb0
> +
> +/* VS-Level IMSIC Interface (H-extension with AIA) */
> +#define CSR_VSSETEIPNUM     0x258
> +#define CSR_VSCLREIPNUM     0x259
> +#define CSR_VSSETEIENUM     0x25a
> +#define CSR_VSCLREIENUM     0x25b
> +
> +/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
> +#define CSR_HIDELEGH        0x613
> +#define CSR_HVIENH          0x618
> +#define CSR_HVIPH           0x655
> +#define CSR_HVIPRIO1H       0x656
> +#define CSR_HVIPRIO2H       0x657
> +#define CSR_VSIEH           0x214
> +#define CSR_VSIPH           0x254
> +
>  /* Physical Memory Protection */
>  #define CSR_PMPCFG0         0x3a0
>  #define CSR_PMPCFG1         0x3a1
> @@ -436,6 +507,7 @@
>  #define HSTATUS_SPVP         0x00000100
>  #define HSTATUS_HU           0x00000200
>  #define HSTATUS_VGEIN        0x0003F000
> +#define HSTATUS_VGEIN_SHIFT  12
>  #define HSTATUS_VTVM         0x00100000
>  #define HSTATUS_VTSR         0x00400000
>  #define HSTATUS_VSXL         0x300000000
> @@ -565,6 +637,7 @@
>  #define IRQ_S_EXT                          9
>  #define IRQ_VS_EXT                         10
>  #define IRQ_M_EXT                          11
> +#define IRQ_S_GEXT                         12
>
>  /* mip masks */
>  #define MIP_USIP                           (1 << IRQ_U_SOFT)
> @@ -592,4 +665,59 @@
>  #define MIE_UTIE                           (1 << IRQ_U_TIMER)
>  #define MIE_SSIE                           (1 << IRQ_S_SOFT)
>  #define MIE_USIE                           (1 << IRQ_U_SOFT)
> +
> +/* MISELECT, SISELECT, and VSISELECT bits (AIA) */
> +#define ISELECT_IPRIO0                     0x30
> +#define ISELECT_IPRIO15                    0x3f
> +#define ISELECT_IMSIC_EIDELIVERY           0x70
> +#define ISELECT_IMSIC_EITHRESHOLD          0x72
> +#define ISELECT_IMSIC_TOPEI                0x76
> +#define ISELECT_IMSIC_EIP0                 0x80
> +#define ISELECT_IMSIC_EIP63                0xbf
> +#define ISELECT_IMSIC_EIE0                 0xc0
> +#define ISELECT_IMSIC_EIE63                0xff
> +#define ISELECT_IMSIC_FIRST                ISELECT_IMSIC_EIDELIVERY
> +#define ISELECT_IMSIC_LAST                 ISELECT_IMSIC_EIE63
> +
> +/* IMSIC bits (AIA) */
> +#define IMSIC_TOPEI_IID_SHIFT              16
> +#define IMSIC_TOPEI_IID_MASK               0x7ff
> +#define IMSIC_TOPEI_IPIRO_MASK             0x7ff
> +#define IMSIC_EIPx_BITS                    32
> +#define IMSIC_EIEx_BITS                    32
> +
> +/* MTOPI and STOPI bits (AIA) */
> +#define TOPI_IID_SHIFT                     16
> +#define TOPI_IID_MASK                      0xfff
> +#define TOPI_IPRIO_MASK                    0xff
> +
> +/* Interrupt priority bits (AIA) */
> +#define IPRIO_IRQ_BITS                     8
> +#define IPRIO_MMAXIPRIO                    255
> +#define IPRIO_DEFAULT_MMAXIPRIO            15
> +#define IPRIO_DEFAULT_VS                   (IPRIO_DEFAULT_MMAXIPRIO - 4)
> +#define IPRIO_DEFAULT_SGEXT                (IPRIO_DEFAULT_MMAXIPRIO - 5)
> +#define IPRIO_DEFAULT_S                    (IPRIO_DEFAULT_MMAXIPRIO - 6)
> +#define IPRIO_DEFAULT_M                    (IPRIO_DEFAULT_MMAXIPRIO - 7)
> +#define IPRIO_DEFAULT_U(_i)                (((_i) >> 4) & 0x3)
> +#define IPRIO_DEFAULT_L(_i)                ((_i) & 0xf)
> +#define IPRIO_DEFAULT_16_23(_i)            \
> +    (IPRIO_DEFAULT_MMAXIPRIO - (IPRIO_DEFAULT_L(_i) >> 1))
> +#define IPRIO_DEFAULT_24_31(_i)            \
> +    (IPRIO_DEFAULT_MMAXIPRIO - (4 + (IPRIO_DEFAULT_L(_i) >> 1)))
> +#define IPRIO_DEFAULT_32_47(_i)            \
> +    (IPRIO_DEFAULT_MMAXIPRIO - (IPRIO_DEFAULT_L(_i) >> 2))
> +#define IPRIO_DEFAULT_48_63(_i)            \
> +    (IPRIO_DEFAULT_MMAXIPRIO - (8 + (IPRIO_DEFAULT_L(_i) >> 2)))
> +
> +/* HVICONTROL bits (AIA) */
> +#define HVICONTROL_VTI                     0x40000000
> +#define HVICONTROL_IID_MASK                0xfff
> +#define HVICONTROL_IID_SHIFT               16
> +#define HVICONTROL_IPRIO_MASK              0xff
> +#define HVICONTROL_VALID_MASK              \
> +    (HVICONTROL_VTI | \
> +     (HVICONTROL_IID_MASK << HVICONTROL_IID_SHIFT) | \
> +     HVICONTROL_IPRIO_MASK)
> +
>  #endif
> --
> 2.25.1
>
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 1/4] target/riscv: Add defines for AIA local interrupt CSRs
@ 2021-06-10 22:26     ` Alistair Francis
  0 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-10 22:26 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers, Anup Patel

On Sat, May 15, 2021 at 12:33 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> The RISC-V AIA specification extends RISC-V local interrupts and
> introduces new CSRs. This patch adds defines for the new AIA
> local interrupt CSRs.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  target/riscv/cpu_bits.h | 128 ++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 128 insertions(+)
>
> diff --git a/target/riscv/cpu_bits.h b/target/riscv/cpu_bits.h
> index caf4599207..d23242655e 100644
> --- a/target/riscv/cpu_bits.h
> +++ b/target/riscv/cpu_bits.h
> @@ -169,6 +169,31 @@
>  /* Legacy Machine Trap Handling (priv v1.9.1) */
>  #define CSR_MBADADDR        0x343
>
> +/* Machine-Level Window to Indirectly Accessed Registers (AIA) */
> +#define CSR_MISELECT        0x350
> +#define CSR_MIREG           0x351
> +
> +/* Machine-Level Interrupts (AIA) */
> +#define CSR_MTOPI           0xfb0
> +
> +/* Machine-Level IMSIC Interface (AIA) */
> +#define CSR_MSETEIPNUM      0x358
> +#define CSR_MCLREIPNUM      0x359
> +#define CSR_MSETEIENUM      0x35a
> +#define CSR_MCLREIENUM      0x35b
> +#define CSR_MCLAIMEI        0xfa8
> +
> +/* Virtual Interrupts for Supervisor Level (AIA) */
> +#define CSR_MVIEN           0x308
> +#define CSR_MVIP            0x309
> +
> +/* Machine-Level High-Half CSRs (AIA) */
> +#define CSR_MIDELEGH        0x313
> +#define CSR_MIEH            0x314
> +#define CSR_MVIENH          0x318
> +#define CSR_MVIPH           0x319
> +#define CSR_MIPH            0x354
> +
>  /* Supervisor Trap Setup */
>  #define CSR_SSTATUS         0x100
>  #define CSR_SEDELEG         0x102
> @@ -191,6 +216,24 @@
>  #define CSR_SPTBR           0x180
>  #define CSR_SATP            0x180
>
> +/* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
> +#define CSR_SISELECT        0x150
> +#define CSR_SIREG           0x151
> +
> +/* Supervisor-Level Interrupts (AIA) */
> +#define CSR_STOPI           0xdb0
> +
> +/* Supervisor-Level IMSIC Interface (AIA) */
> +#define CSR_SSETEIPNUM      0x158
> +#define CSR_SCLREIPNUM      0x159
> +#define CSR_SSETEIENUM      0x15a
> +#define CSR_SCLREIENUM      0x15b
> +#define CSR_SCLAIMEI        0xda8
> +
> +/* Supervisor-Level High-Half CSRs (AIA) */
> +#define CSR_SIEH            0x114
> +#define CSR_SIPH            0x154
> +
>  /* Hpervisor CSRs */
>  #define CSR_HSTATUS         0x600
>  #define CSR_HEDELEG         0x602
> @@ -232,6 +275,34 @@
>  #define CSR_MTINST          0x34a
>  #define CSR_MTVAL2          0x34b
>
> +/* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
> +#define CSR_HVIEN           0x608
> +#define CSR_HVICONTROL      0x609
> +#define CSR_HVIPRIO1        0x646
> +#define CSR_HVIPRIO2        0x647
> +
> +/* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
> +#define CSR_VSISELECT       0x250
> +#define CSR_VSIREG          0x251
> +
> +/* VS-Level Interrupts (H-extension with AIA) */
> +#define CSR_VSTOPI          0xeb0
> +
> +/* VS-Level IMSIC Interface (H-extension with AIA) */
> +#define CSR_VSSETEIPNUM     0x258
> +#define CSR_VSCLREIPNUM     0x259
> +#define CSR_VSSETEIENUM     0x25a
> +#define CSR_VSCLREIENUM     0x25b
> +
> +/* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
> +#define CSR_HIDELEGH        0x613
> +#define CSR_HVIENH          0x618
> +#define CSR_HVIPH           0x655
> +#define CSR_HVIPRIO1H       0x656
> +#define CSR_HVIPRIO2H       0x657
> +#define CSR_VSIEH           0x214
> +#define CSR_VSIPH           0x254
> +
>  /* Physical Memory Protection */
>  #define CSR_PMPCFG0         0x3a0
>  #define CSR_PMPCFG1         0x3a1
> @@ -436,6 +507,7 @@
>  #define HSTATUS_SPVP         0x00000100
>  #define HSTATUS_HU           0x00000200
>  #define HSTATUS_VGEIN        0x0003F000
> +#define HSTATUS_VGEIN_SHIFT  12
>  #define HSTATUS_VTVM         0x00100000
>  #define HSTATUS_VTSR         0x00400000
>  #define HSTATUS_VSXL         0x300000000
> @@ -565,6 +637,7 @@
>  #define IRQ_S_EXT                          9
>  #define IRQ_VS_EXT                         10
>  #define IRQ_M_EXT                          11
> +#define IRQ_S_GEXT                         12
>
>  /* mip masks */
>  #define MIP_USIP                           (1 << IRQ_U_SOFT)
> @@ -592,4 +665,59 @@
>  #define MIE_UTIE                           (1 << IRQ_U_TIMER)
>  #define MIE_SSIE                           (1 << IRQ_S_SOFT)
>  #define MIE_USIE                           (1 << IRQ_U_SOFT)
> +
> +/* MISELECT, SISELECT, and VSISELECT bits (AIA) */
> +#define ISELECT_IPRIO0                     0x30
> +#define ISELECT_IPRIO15                    0x3f
> +#define ISELECT_IMSIC_EIDELIVERY           0x70
> +#define ISELECT_IMSIC_EITHRESHOLD          0x72
> +#define ISELECT_IMSIC_TOPEI                0x76
> +#define ISELECT_IMSIC_EIP0                 0x80
> +#define ISELECT_IMSIC_EIP63                0xbf
> +#define ISELECT_IMSIC_EIE0                 0xc0
> +#define ISELECT_IMSIC_EIE63                0xff
> +#define ISELECT_IMSIC_FIRST                ISELECT_IMSIC_EIDELIVERY
> +#define ISELECT_IMSIC_LAST                 ISELECT_IMSIC_EIE63
> +
> +/* IMSIC bits (AIA) */
> +#define IMSIC_TOPEI_IID_SHIFT              16
> +#define IMSIC_TOPEI_IID_MASK               0x7ff
> +#define IMSIC_TOPEI_IPIRO_MASK             0x7ff
> +#define IMSIC_EIPx_BITS                    32
> +#define IMSIC_EIEx_BITS                    32
> +
> +/* MTOPI and STOPI bits (AIA) */
> +#define TOPI_IID_SHIFT                     16
> +#define TOPI_IID_MASK                      0xfff
> +#define TOPI_IPRIO_MASK                    0xff
> +
> +/* Interrupt priority bits (AIA) */
> +#define IPRIO_IRQ_BITS                     8
> +#define IPRIO_MMAXIPRIO                    255
> +#define IPRIO_DEFAULT_MMAXIPRIO            15
> +#define IPRIO_DEFAULT_VS                   (IPRIO_DEFAULT_MMAXIPRIO - 4)
> +#define IPRIO_DEFAULT_SGEXT                (IPRIO_DEFAULT_MMAXIPRIO - 5)
> +#define IPRIO_DEFAULT_S                    (IPRIO_DEFAULT_MMAXIPRIO - 6)
> +#define IPRIO_DEFAULT_M                    (IPRIO_DEFAULT_MMAXIPRIO - 7)
> +#define IPRIO_DEFAULT_U(_i)                (((_i) >> 4) & 0x3)
> +#define IPRIO_DEFAULT_L(_i)                ((_i) & 0xf)
> +#define IPRIO_DEFAULT_16_23(_i)            \
> +    (IPRIO_DEFAULT_MMAXIPRIO - (IPRIO_DEFAULT_L(_i) >> 1))
> +#define IPRIO_DEFAULT_24_31(_i)            \
> +    (IPRIO_DEFAULT_MMAXIPRIO - (4 + (IPRIO_DEFAULT_L(_i) >> 1)))
> +#define IPRIO_DEFAULT_32_47(_i)            \
> +    (IPRIO_DEFAULT_MMAXIPRIO - (IPRIO_DEFAULT_L(_i) >> 2))
> +#define IPRIO_DEFAULT_48_63(_i)            \
> +    (IPRIO_DEFAULT_MMAXIPRIO - (8 + (IPRIO_DEFAULT_L(_i) >> 2)))
> +
> +/* HVICONTROL bits (AIA) */
> +#define HVICONTROL_VTI                     0x40000000
> +#define HVICONTROL_IID_MASK                0xfff
> +#define HVICONTROL_IID_SHIFT               16
> +#define HVICONTROL_IPRIO_MASK              0xff
> +#define HVICONTROL_VALID_MASK              \
> +    (HVICONTROL_VTI | \
> +     (HVICONTROL_IID_MASK << HVICONTROL_IID_SHIFT) | \
> +     HVICONTROL_IPRIO_MASK)
> +
>  #endif
> --
> 2.25.1
>
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/4] target/riscv: Add CPU feature for AIA CSRs
  2021-05-14 14:32   ` Anup Patel
@ 2021-06-10 23:15     ` Alistair Francis
  -1 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-10 23:15 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Sat, May 15, 2021 at 12:35 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We add experimental CPU feature to enable AIA CSRs. This experimental
> feature can be enabled by setting "x-aia=true" for CPU in the QEMU
> command-line parameters.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  target/riscv/cpu.c | 5 +++++
>  target/riscv/cpu.h | 4 +++-
>  2 files changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 7d6ed80f6b..f3702111ae 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -414,6 +414,10 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
>          set_feature(env, RISCV_FEATURE_PMP);
>      }
>
> +    if (cpu->cfg.aia) {
> +        set_feature(env, RISCV_FEATURE_AIA);
> +    }
> +
>      set_resetvec(env, cpu->cfg.resetvec);
>
>      /* If only XLEN is set for misa, then set misa from properties */
> @@ -554,6 +558,7 @@ static Property riscv_cpu_properties[] = {
>      DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
>      DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
>      DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
> +    DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false),

This line should be a seperate patch at the end of the series.

The idea is that we don't allow users to enable the feature until it
has been fully implemented.

Alistair

>      DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
>      DEFINE_PROP_END_OF_LIST(),
>  };
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 0a33d387ba..f00c60c840 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -80,7 +80,8 @@
>  enum {
>      RISCV_FEATURE_MMU,
>      RISCV_FEATURE_PMP,
> -    RISCV_FEATURE_MISA
> +    RISCV_FEATURE_MISA,
> +    RISCV_FEATURE_AIA
>  };
>
>  #define PRIV_VERSION_1_10_0 0x00011000
> @@ -303,6 +304,7 @@ struct RISCVCPU {
>          uint16_t elen;
>          bool mmu;
>          bool pmp;
> +        bool aia;
>          uint64_t resetvec;
>      } cfg;
>  };
> --
> 2.25.1
>
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/4] target/riscv: Add CPU feature for AIA CSRs
@ 2021-06-10 23:15     ` Alistair Francis
  0 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-10 23:15 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers, Anup Patel

On Sat, May 15, 2021 at 12:35 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We add experimental CPU feature to enable AIA CSRs. This experimental
> feature can be enabled by setting "x-aia=true" for CPU in the QEMU
> command-line parameters.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  target/riscv/cpu.c | 5 +++++
>  target/riscv/cpu.h | 4 +++-
>  2 files changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index 7d6ed80f6b..f3702111ae 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -414,6 +414,10 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
>          set_feature(env, RISCV_FEATURE_PMP);
>      }
>
> +    if (cpu->cfg.aia) {
> +        set_feature(env, RISCV_FEATURE_AIA);
> +    }
> +
>      set_resetvec(env, cpu->cfg.resetvec);
>
>      /* If only XLEN is set for misa, then set misa from properties */
> @@ -554,6 +558,7 @@ static Property riscv_cpu_properties[] = {
>      DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
>      DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
>      DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
> +    DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false),

This line should be a seperate patch at the end of the series.

The idea is that we don't allow users to enable the feature until it
has been fully implemented.

Alistair

>      DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
>      DEFINE_PROP_END_OF_LIST(),
>  };
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index 0a33d387ba..f00c60c840 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -80,7 +80,8 @@
>  enum {
>      RISCV_FEATURE_MMU,
>      RISCV_FEATURE_PMP,
> -    RISCV_FEATURE_MISA
> +    RISCV_FEATURE_MISA,
> +    RISCV_FEATURE_AIA
>  };
>
>  #define PRIV_VERSION_1_10_0 0x00011000
> @@ -303,6 +304,7 @@ struct RISCVCPU {
>          uint16_t elen;
>          bool mmu;
>          bool pmp;
> +        bool aia;
>          uint64_t resetvec;
>      } cfg;
>  };
> --
> 2.25.1
>
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
  2021-05-14 14:32   ` Anup Patel
@ 2021-06-10 23:19     ` Alistair Francis
  -1 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-10 23:19 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> and VS-mode.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  target/riscv/cpu.c        |   27 +-
>  target/riscv/cpu.h        |   52 +-
>  target/riscv/cpu_helper.c |  245 ++++++++-
>  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
>  target/riscv/machine.c    |   26 +-
>  5 files changed, 1309 insertions(+), 100 deletions(-)

I feel this patch could be split up more :)

>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index f3702111ae..795162834b 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
>                       (target_ulong)env->vsstatus);
>      }
> -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
>      if (riscv_has_ext(env, RVH)) {
> -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
>      }
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
>      if (riscv_has_ext(env, RVH)) {
> @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
>
>  static void riscv_cpu_reset(DeviceState *dev)
>  {
> +    uint8_t iprio;
> +    int i, irq, rdzero;
>      CPUState *cs = CPU(dev);
>      RISCVCPU *cpu = RISCV_CPU(cs);
>      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
>      env->mcause = 0;
>      env->pc = env->resetvec;
>      env->two_stage_lookup = false;
> +
> +    /* Initialized default priorities of local interrupts. */
> +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> +        iprio = riscv_cpu_default_priority(i);
> +        env->miprio[i] = iprio;
> +        env->siprio[i] = iprio;
> +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> +    }
> +    i = 0;
> +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> +        if (rdzero) {
> +            env->hviprio[irq] = 0;
> +        } else {
> +            env->hviprio[irq] = env->miprio[irq];
> +        }
> +        i++;
> +    }
>  #endif
>      cs->exception_index = EXCP_NONE;
>      env->load_res = -1;
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index f00c60c840..780d3f9058 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -157,12 +157,12 @@ struct CPURISCVState {
>       */
>      uint64_t mstatus;
>
> -    target_ulong mip;
> +    uint64_t mip;

This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
all the other existing target_ulong CSRs are the same.

Alistair

>
> -    uint32_t miclaim;
> +    uint64_t miclaim;
>
> -    target_ulong mie;
> -    target_ulong mideleg;
> +    uint64_t mie;
> +    uint64_t mideleg;
>
>      target_ulong sptbr;  /* until: priv-1.9.1 */
>      target_ulong satp;   /* since: priv-1.10.0 */
> @@ -179,16 +179,27 @@ struct CPURISCVState {
>      target_ulong mcause;
>      target_ulong mtval;  /* since: priv-1.10.0 */
>
> +    /* AIA CSRs */
> +    target_ulong miselect;
> +    target_ulong siselect;
> +
> +    uint8_t miprio[64];
> +    uint8_t siprio[64];
> +
>      /* Hypervisor CSRs */
>      target_ulong hstatus;
>      target_ulong hedeleg;
> -    target_ulong hideleg;
> +    uint64_t hideleg;
>      target_ulong hcounteren;
>      target_ulong htval;
>      target_ulong htinst;
>      target_ulong hgatp;
>      uint64_t htimedelta;
>
> +    /* AIA HS-mode CSRs */
> +    uint8_t hviprio[64];
> +    target_ulong hvicontrol;
> +
>      /* Virtual CSRs */
>      /*
>       * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
> @@ -202,6 +213,9 @@ struct CPURISCVState {
>      target_ulong vstval;
>      target_ulong vsatp;
>
> +    /* AIA VS-mode CSRs */
> +    target_ulong vsiselect;
> +
>      target_ulong mtval2;
>      target_ulong mtinst;
>
> @@ -236,6 +250,18 @@ struct CPURISCVState {
>      uint64_t (*rdtime_fn)(uint32_t);
>      uint32_t rdtime_fn_arg;
>
> +    /* machine specific AIA IMSIC read-modify-write callback */
> +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \
> +    ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \
> +     (((__priv) & 0x3) << 16) | (__isel & 0xffff))
> +#define IMSIC_REG_ISEL(__reg)                  ((__reg) & 0xffff)
> +#define IMSIC_REG_PRIV(__reg)                  (((__reg) >> 16) & 0x3)
> +#define IMSIC_REG_VIRT(__reg)                  (((__reg) >> 20) & 0x1)
> +#define IMSIC_REG_VGEIN(__reg)                 (((__reg) >> 24) & 0x3f)
> +    int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val,
> +                        target_ulong new_val, target_ulong write_mask);
> +    void *imsic_rmw_fn_arg;
> +
>      /* True if in debugger mode.  */
>      bool debugger;
>  #endif
> @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
>                                 int cpuid, void *opaque);
>  int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
>  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero);
> +uint8_t riscv_cpu_default_priority(int irq);
> +int riscv_cpu_mirq_pending(CPURISCVState *env);
> +int riscv_cpu_sirq_pending(CPURISCVState *env);
> +int riscv_cpu_vsirq_pending(CPURISCVState *env);
>  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
>  bool riscv_cpu_fp_enabled(CPURISCVState *env);
>  bool riscv_cpu_virt_enabled(CPURISCVState *env);
> @@ -364,9 +395,16 @@ void riscv_cpu_list(void);
>
>  #ifndef CONFIG_USER_ONLY
>  void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
> -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
> -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
> +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
> +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value);
>  #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
> +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> +                                int (*rmw_fn)(void *arg,
> +                                              target_ulong reg,
> +                                              target_ulong *val,
> +                                              target_ulong new_val,
> +                                              target_ulong write_mask),
> +                                void *rmw_fn_arg);
>  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
>                               uint32_t arg);
>  #endif
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 21c54ef561..5b06b4f995 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
>  }
>
>  #ifndef CONFIG_USER_ONLY
> -static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> +
> +/*
> + * The HS-mode is allowed to configure priority only for the
> + * following VS-mode local interrupts:
> + *
> + * 0  (Reserved interrupt, reads as zero)
> + * 1  Supervisor software interrupt
> + * 4  (Reserved interrupt, reads as zero)
> + * 5  Supervisor timer interrupt
> + * 8  (Reserved interrupt, reads as zero)
> + * 13 (Reserved interrupt)
> + * 14 "
> + * 15 "
> + * 16 "
> + * 18 Debug/trace interrupt
> + * 20 (Reserved interrupt)
> + * 22 ”
> + * 24 ”
> + * 26 ”
> + * 28 "
> + * 30 (Reserved for standard reporting of bus or system errors)
> + */
> +
> +static int hviprio_index2irq[] =
> +    { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
> +static int hviprio_index2rdzero[] =
> +    { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> +
> +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
>  {
> -    target_ulong irqs;
> +    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
> +        return -EINVAL;
> +    }
>
> -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> -    target_ulong hs_mstatus_sie = get_field(env->mstatus_hs, MSTATUS_SIE);
> +    if (out_irq) {
> +        *out_irq = hviprio_index2irq[index];
> +    }
> +
> +    if (out_rdzero) {
> +        *out_rdzero = hviprio_index2rdzero[index];
> +    }
>
> -    target_ulong pending = env->mip & env->mie &
> -                               ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> -    target_ulong vspending = (env->mip & env->mie &
> -                              (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> +    return 0;
> +}
>
> -    target_ulong mie    = env->priv < PRV_M ||
> -                          (env->priv == PRV_M && mstatus_mie);
> -    target_ulong sie    = env->priv < PRV_S ||
> -                          (env->priv == PRV_S && mstatus_sie);
> -    target_ulong hs_sie = env->priv < PRV_S ||
> -                          (env->priv == PRV_S && hs_mstatus_sie);
> +uint8_t riscv_cpu_default_priority(int irq)
> +{
> +    int u, l;
> +    uint8_t iprio = IPRIO_MMAXIPRIO;
>
> -    if (riscv_cpu_virt_enabled(env)) {
> -        target_ulong pending_hs_irq = pending & -hs_sie;
> +    if (irq < 0 || irq > 63) {
> +        return iprio;
> +    }
>
> -        if (pending_hs_irq) {
> -            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> -            return ctz64(pending_hs_irq);
> +    /*
> +     * Default priorities of local interrupts are defined in the
> +     * RISC-V Advanced Interrupt Architecture specification.
> +     *
> +     * ----------------------------------------------------------------
> +     *  Default  |
> +     *  Priority | Major Interrupt Numbers
> +     * ----------------------------------------------------------------
> +     *  Highest  | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c),
> +     *           | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38),
> +     *           | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34),
> +     *           | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30)
> +     *           |
> +     *           | 11 (0b),  3 (03),  7 (07)
> +     *           |  9 (09),  1 (01),  5 (05)
> +     *           | 12 (0c)
> +     *           | 10 (0a),  2 (02),  6 (06)
> +     *           |
> +     *           | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c),
> +     *           | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28),
> +     *           | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24),
> +     *  Lowest   | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20)
> +     * ----------------------------------------------------------------
> +     */
> +
> +    u = IPRIO_DEFAULT_U(irq);
> +    l = IPRIO_DEFAULT_L(irq);
> +    if (u == 0) {
> +        if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER ||
> +            irq == IRQ_VS_SOFT) {
> +            iprio = IPRIO_DEFAULT_VS;
> +        } else if (irq == IRQ_S_GEXT) {
> +            iprio = IPRIO_DEFAULT_SGEXT;
> +        } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER ||
> +                   irq == IRQ_S_SOFT) {
> +            iprio = IPRIO_DEFAULT_S;
> +        } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER ||
> +                   irq == IRQ_M_SOFT) {
> +            iprio = IPRIO_DEFAULT_M;
> +        } else {
> +            iprio = IPRIO_DEFAULT_VS;
>          }
> +    } else if (u == 1) {
> +        if (l < 8) {
> +            iprio = IPRIO_DEFAULT_16_23(irq);
> +        } else {
> +            iprio = IPRIO_DEFAULT_24_31(irq);
> +        }
> +    } else if (u == 2) {
> +        iprio = IPRIO_DEFAULT_32_47(irq);
> +    } else if (u == 3) {
> +        iprio = IPRIO_DEFAULT_48_63(irq);
> +    }
> +
> +    return iprio;
> +}
> +
> +static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> +                                    uint64_t pending, uint8_t *iprio)
> +{
> +    int irq, best_irq = EXCP_NONE;
> +    unsigned int prio, best_prio = UINT_MAX;
>
> -        pending = vspending;
> +    if (!pending) {
> +        return EXCP_NONE;
>      }
>
> -    irqs = (pending & ~env->mideleg & -mie) | (pending &  env->mideleg & -sie);
> +    irq = ctz64(pending);
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return irq;
> +    }
>
> -    if (irqs) {
> -        return ctz64(irqs); /* since non-zero */
> +    pending = pending >> irq;
> +    while (pending) {
> +        prio = iprio[irq];
> +        if (!prio) {
> +            prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ?
> +                   1 : IPRIO_MMAXIPRIO;
> +        }
> +        if ((pending & 0x1) && (prio < best_prio)) {
> +            best_irq = irq;
> +            best_prio = prio;
> +        }
> +        irq++;
> +        pending = pending >> 1;
> +    }
> +
> +    return best_irq;
> +}
> +
> +int riscv_cpu_mirq_pending(CPURISCVState *env)
> +{
> +    uint64_t irqs = env->mip & env->mie & ~env->mideleg &
> +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> +
> +    return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> +}
> +
> +int riscv_cpu_sirq_pending(CPURISCVState *env)
> +{
> +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> +
> +    return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> +}
> +
> +int riscv_cpu_vsirq_pending(CPURISCVState *env)
> +{
> +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> +                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> +
> +    return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> +}
> +
> +static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> +{
> +    int virq;
> +    uint64_t irqs, mie, sie, vsie;
> +    uint64_t pending, vspending;
> +
> +    /* Determine interrupt enable state of all privilege modes */
> +    if (riscv_cpu_virt_enabled(env)) {
> +        mie = 1;
> +        sie = 1;
> +        vsie = (env->priv < PRV_S) ||
> +               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
>      } else {
> -        return EXCP_NONE; /* indicates no pending interrupt */
> +        mie = (env->priv < PRV_M) ||
> +              (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
> +        sie = (env->priv < PRV_S) ||
> +              (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> +        vsie = 0;
> +    }
> +
> +    /* Check M-mode interrupts */
> +    pending = env->mip & env->mie &
> +              ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> +    irqs = pending & ~env->mideleg & -mie;
> +    if (irqs) {
> +        return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> +    }
> +
> +    /* Check HS-mode interrupts */
> +    irqs = pending & env->mideleg & -sie;
> +    if (irqs) {
> +        return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> +    }
> +
> +    /* Check VS-mode interrupts */
> +    vspending = env->mip & env->mie &
> +                (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> +    irqs = vspending & env->hideleg & -vsie;
> +    if (irqs) {
> +        virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> +        return (virq <= 0) ? virq : virq + 1;
>      }
> +
> +    /* Indicates no pending interrupt */
> +    return EXCP_NONE;
>  }
>  #endif
>
> @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx)
>      return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
>  }
>
> -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
>  {
>      CPURISCVState *env = &cpu->env;
>      if (env->miclaim & interrupts) {
> @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
>      }
>  }
>
> -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
>  {
>      CPURISCVState *env = &cpu->env;
>      CPUState *cs = CPU(cpu);
> -    uint32_t old = env->mip;
> +    uint64_t old = env->mip;
>      bool locked = false;
>
>      if (!qemu_mutex_iothread_locked()) {
> @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
>      return old;
>  }
>
> +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> +                                int (*rmw_fn)(void *arg,
> +                                              target_ulong reg,
> +                                              target_ulong *val,
> +                                              target_ulong new_val,
> +                                              target_ulong write_mask),
> +                                void *rmw_fn_arg)
> +{
> +    env->imsic_rmw_fn = rmw_fn;
> +    env->imsic_rmw_fn_arg = rmw_fn_arg;
> +}
> +
>  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
>                               uint32_t arg)
>  {
> @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>       */
>      bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
>      target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
> -    target_ulong deleg = async ? env->mideleg : env->medeleg;
> +    uint64_t deleg = async ? env->mideleg : env->medeleg;
>      bool write_tval = false;
>      target_ulong tval = 0;
>      target_ulong htval = 0;
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index d2585395bf..3c016d7452 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -153,11 +153,56 @@ static int any32(CPURISCVState *env, int csrno)
>
>  }
>
> +static int aia_any(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return any(env, csrno);
> +}
> +
> +static int aia_any32(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return any32(env, csrno);
> +}
> +
>  static int smode(CPURISCVState *env, int csrno)
>  {
>      return -!riscv_has_ext(env, RVS);
>  }
>
> +static int smode32(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_cpu_is_32bit(env)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return smode(env, csrno);
> +}
> +
> +static int aia_smode(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return smode(env, csrno);
> +}
> +
> +static int aia_smode32(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return smode32(env, csrno);
> +}
> +
>  static int hmode(CPURISCVState *env, int csrno)
>  {
>      if (riscv_has_ext(env, RVS) &&
> @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno)
>  static int hmode32(CPURISCVState *env, int csrno)
>  {
>      if (!riscv_cpu_is_32bit(env)) {
> -        return 0;
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return hmode(env, csrno);
> +}
> +
> +static int aia_hmode(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
>      }
>
>      return hmode(env, csrno);
> +}
>
> +static int aia_hmode32(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return hmode32(env, csrno);
>  }
>
>  static int pmp(CPURISCVState *env, int csrno)
> @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
>
>  /* Machine constants */
>
> -#define M_MODE_INTERRUPTS  (MIP_MSIP | MIP_MTIP | MIP_MEIP)
> -#define S_MODE_INTERRUPTS  (MIP_SSIP | MIP_STIP | MIP_SEIP)
> -#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)
> +#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
> +#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
> +#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
> +
> +#define TLOWBITS64         ((uint64_t)((target_ulong)-1))
>
> -static const target_ulong delegable_ints = S_MODE_INTERRUPTS |
> -                                           VS_MODE_INTERRUPTS;
> -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> -                                     VS_MODE_INTERRUPTS;
> +static const uint64_t delegable_ints = S_MODE_INTERRUPTS |
> +                                       VS_MODE_INTERRUPTS;
> +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> +                                 VS_MODE_INTERRUPTS;
>  static const target_ulong delegable_excps =
>      (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) |
>      (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) |
> @@ -419,10 +483,10 @@ static const target_ulong delegable_excps =
>  static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
>      SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
>      SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
> -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> -static const target_ulong hip_writable_mask = MIP_VSSIP;
> -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> -static const target_ulong vsip_writable_mask = MIP_VSSIP;
> +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> +static const uint64_t hip_writable_mask = MIP_VSSIP;
> +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> +static const uint64_t vsip_writable_mask = MIP_VSSIP;
>
>  static const char valid_vm_1_10_32[16] = {
>      [VM_1_10_MBARE] = 1,
> @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val)
>
>  static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
>  {
> -    env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
> +    uint64_t mask = delegable_ints & TLOWBITS64;
> +
> +    env->mideleg = (env->mideleg & ~mask) | (val & mask);
> +    if (riscv_has_ext(env, RVH)) {
> +        env->mideleg |= VS_MODE_INTERRUPTS;
> +    }
> +    return 0;
> +}
> +
> +static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_cpu_virt_enabled(env)) {
> +        return csrno;
> +    }
> +
> +    switch (csrno) {
> +    case CSR_SISELECT:
> +        return CSR_VSISELECT;
> +    case CSR_SIREG:
> +        return CSR_VSIREG;
> +    case CSR_STOPI:
> +        return CSR_VSTOPI;
> +    case CSR_SSETEIPNUM:
> +        return CSR_VSSETEIPNUM;
> +    case CSR_SCLREIPNUM:
> +        return CSR_VSCLREIPNUM;
> +    case CSR_SSETEIENUM:
> +        return CSR_VSSETEIENUM;
> +    case CSR_SCLREIENUM:
> +        return CSR_VSCLREIENUM;
> +    default:
> +        return csrno;
> +    };
> +}
> +
> +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val,
> +                        target_ulong new_val, target_ulong write_mask)
> +{
> +    target_ulong *iselect;
> +
> +    switch (csrno) {
> +    case CSR_MISELECT:
> +        iselect = &env->miselect;
> +        break;
> +    case CSR_SISELECT:
> +        iselect = riscv_cpu_virt_enabled(env) ?
> +                  &env->vsiselect : &env->siselect;
> +        break;
> +    case CSR_VSISELECT:
> +        iselect = &env->vsiselect;
> +        break;
> +    default:
> +         return -RISCV_EXCP_ILLEGAL_INST;
> +    };
> +
> +    if (val) {
> +        *val = *iselect;
> +    }
> +
> +    if (write_mask) {
> +        *iselect = (*iselect & ~write_mask) | (new_val & write_mask);
> +    }
> +
> +    return 0;
> +}
> +
> +static int rmw_iprio(target_ulong iselect, uint8_t *iprio,
> +                     target_ulong *val, target_ulong new_val,
> +                     target_ulong write_mask)
> +{
> +    int i, firq, nirqs;
> +    target_ulong old_val;
> +
> +    if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) {
> +        return -EINVAL;
> +    }
> +#if TARGET_LONG_BITS == 64
> +    if (iselect & 0x1) {
> +        return -EINVAL;
> +    }
> +#endif
> +
> +    nirqs = 4 * (TARGET_LONG_BITS / 32);
> +    firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 32)) * (nirqs);
> +
> +    old_val = 0;
> +    for (i = 0; i < nirqs; i++) {
> +        old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i);
> +    }
> +
> +    if (val) {
> +        *val = old_val;
> +    }
> +
> +    if (write_mask) {
> +        new_val = (old_val & ~write_mask) | (new_val & write_mask);
> +        for (i = 0; i < nirqs; i++) {
> +            iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
> +                     target_ulong new_val, target_ulong write_mask)
> +{
> +    bool virt;
> +    uint8_t *iprio;
> +    int ret = -EINVAL;
> +    target_ulong priv, isel, vgein;
> +
> +    /* Translate CSR number for VS-mode */
> +    csrno = aia_xlate_vs_csrno(env, csrno);
> +
> +    /* Decode register details from CSR number */
> +    virt = false;
> +    switch (csrno) {
> +    case CSR_MIREG:
> +        iprio = env->miprio;
> +        isel = env->miselect;
> +        priv = PRV_M;
> +        break;
> +    case CSR_SIREG:
> +        iprio = env->siprio;
> +        isel = env->siselect;
> +        priv = PRV_S;
> +        break;
> +    case CSR_VSIREG:
> +        iprio = env->hviprio;
> +        isel = env->vsiselect;
> +        priv = PRV_S;
> +        virt = true;
> +        break;
> +    default:
> +         goto done;
> +    };
> +
> +    /* Find the selected guest interrupt file */
> +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> +
> +    if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) {
> +        /* Local interrupt priority registers not available for VS-mode */
> +        if (!virt) {
> +            ret = rmw_iprio(isel, iprio, val, new_val, write_mask);
> +        }
> +    } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) {
> +        /* IMSIC registers only available when machine implements it. */
> +        if (env->imsic_rmw_fn) {
> +            /* Selected guest interrupt file should not be zero */
> +            if (virt && !vgein) {
> +                goto done;
> +            }
> +            /* Call machine specific IMSIC register emulation */
> +            ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> +                                    IMSIC_MAKE_REG(isel, priv, virt, vgein),
> +                                    val, new_val, write_mask);
> +        }
> +    }
> +
> +done:
> +    if (ret) {
> +        return (riscv_cpu_virt_enabled(env) && virt) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +    return 0;
> +}
> +
> +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    int irq;
> +
> +    irq = riscv_cpu_mirq_pending(env);
> +    if (irq <= 0 || irq > 63) {
> +       *val = 0;
> +    } else {
> +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> +       *val |= env->miprio[irq];
> +    }
> +
> +    return 0;
> +}
> +
> +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    bool virt;
> +    int ret = -EINVAL;
> +    target_ulong vgein;
> +
> +    /* Translate CSR number for VS-mode */
> +    csrno = aia_xlate_vs_csrno(env, csrno);
> +
> +    /* Decode register details from CSR number */
> +    virt = false;
> +    switch (csrno) {
> +    case CSR_MSETEIPNUM:
> +    case CSR_MCLREIPNUM:
> +    case CSR_MSETEIENUM:
> +    case CSR_MCLREIENUM:
> +    case CSR_SSETEIPNUM:
> +    case CSR_SCLREIPNUM:
> +    case CSR_SSETEIENUM:
> +    case CSR_SCLREIENUM:
> +        break;
> +    case CSR_VSSETEIPNUM:
> +    case CSR_VSCLREIPNUM:
> +    case CSR_VSSETEIENUM:
> +    case CSR_VSCLREIENUM:
> +        virt = true;
> +        break;
> +    default:
> +         goto done;
> +    };
> +
> +    /* IMSIC CSRs only available when machine implements IMSIC. */
> +    if (!env->imsic_rmw_fn) {
> +        goto done;
> +    }
> +
> +    /* Find the selected guest interrupt file */
> +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> +
> +    /* Selected guest interrupt file should not be zero */
> +    if (virt && !vgein) {
> +        goto done;
> +    }
> +
> +    /* Set/Clear CSRs always read zero */
> +    ret = 0;
> +    if (val) {
> +        *val = 0;
> +    }
> +
> +done:
> +    if (ret) {
> +        return (riscv_cpu_virt_enabled(env) && virt) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +    return 0;
> +}
> +
> +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    int ret = -EINVAL;
> +    bool set, pend, virt;
> +    target_ulong priv, isel, vgein;
> +    target_ulong new_val, write_mask;
> +
> +    /* Translate CSR number for VS-mode */
> +    csrno = aia_xlate_vs_csrno(env, csrno);
> +
> +    /* Decode register details from CSR number */
> +    virt = set = pend = false;
> +    switch (csrno) {
> +    case CSR_MSETEIPNUM:
> +        priv = PRV_M;
> +        set = true;
> +        break;
> +    case CSR_MCLREIPNUM:
> +        priv = PRV_M;
> +        pend = true;
> +        break;
> +    case CSR_MSETEIENUM:
> +        priv = PRV_M;
> +        set = true;
> +        break;
> +    case CSR_MCLREIENUM:
> +        priv = PRV_M;
> +        break;
> +    case CSR_SSETEIPNUM:
> +        priv = PRV_S;
> +        set = true;
> +        pend = true;
> +        break;
> +    case CSR_SCLREIPNUM:
> +        priv = PRV_S;
> +        pend = true;
> +        break;
> +    case CSR_SSETEIENUM:
> +        priv = PRV_S;
> +        set = true;
> +        break;
> +    case CSR_SCLREIENUM:
> +        priv = PRV_S;
> +        break;
> +    case CSR_VSSETEIPNUM:
> +        priv = PRV_S;
> +        virt = true;
> +        set = true;
> +        pend = true;
> +        break;
> +    case CSR_VSCLREIPNUM:
> +        priv = PRV_S;
> +        virt = true;
> +        pend = true;
> +        break;
> +    case CSR_VSSETEIENUM:
> +        priv = PRV_S;
> +        virt = true;
> +        set = true;
> +        break;
> +    case CSR_VSCLREIENUM:
> +        priv = PRV_S;
> +        virt = true;
> +        break;
> +    default:
> +         goto done;
> +    };
> +
> +    /* IMSIC CSRs only available when machine implements IMSIC. */
> +    if (!env->imsic_rmw_fn) {
> +        goto done;
> +    }
> +
> +    /* Find target interrupt pending/enable register */
> +    if (pend) {
> +        isel = ISELECT_IMSIC_EIP0;
> +    } else {
> +        isel = ISELECT_IMSIC_EIE0;
> +    }
> +    isel += val / IMSIC_EIPx_BITS;
> +
> +    /* Find the interrupt bit to be set/clear */
> +    write_mask = 1 << (val % IMSIC_EIPx_BITS);
> +    new_val = (set) ? write_mask : 0;
> +
> +    /* Find the selected guest interrupt file */
> +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> +
> +    /* Selected guest interrupt file should not be zero */
> +    if (virt && !vgein) {
> +        goto done;
> +    }
> +
> +    /* Call machine specific IMSIC register emulation */
> +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> +                            NULL, new_val, write_mask);
> +
> +done:
> +    if (ret) {
> +        return (riscv_cpu_virt_enabled(env) && virt) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +    return 0;
> +}
> +
> +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    bool virt;
> +    int ret = -EINVAL;
> +    target_ulong priv, isel, vgein;
> +    target_ulong topei, write_mask;
> +
> +    /* Decode register details from CSR number */
> +    virt = false;
> +    switch (csrno) {
> +    case CSR_MCLAIMEI:
> +        priv = PRV_M;
> +        break;
> +    case CSR_SCLAIMEI:
> +        priv = PRV_S;
> +        virt = riscv_cpu_virt_enabled(env);
> +        break;
> +    default:
> +        goto done;
> +    };
> +
> +    /* IMSIC CSRs only available when machine implements IMSIC. */
> +    if (!env->imsic_rmw_fn) {
> +        goto done;
> +    }
> +
> +    /* Find the selected guest interrupt file */
> +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> +
> +    /* Selected guest interrupt file should not be zero */
> +    if (virt && !vgein) {
> +        goto done;
> +    }
> +
> +    /* Call machine specific IMSIC register emulation for reading TOPEI */
> +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> +                            IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein),
> +                            &topei, -1, 0);
> +    if (ret) {
> +        goto done;
> +    }
> +
> +    /* If no interrupt pending then we are done */
> +    if (!topei) {
> +        goto done;
> +    }
> +
> +    /* Find target interrupt pending register */
> +    isel = ISELECT_IMSIC_EIP0;
> +    isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS);
> +
> +    /* Find the interrupt bit to be cleared */
> +    write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS);
> +
> +    /* Call machine specific IMSIC register emulation to clear pending bit */
> +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> +                            NULL, 0, write_mask);
> +
> +    /* Update return value */
> +    if (val) {
> +        *val = topei;
> +    }
> +
> +done:
> +    if (ret) {
> +        return (riscv_cpu_virt_enabled(env) && virt) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +    return 0;
> +}
> +
> +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = (env->mideleg >> 32);
> +    return 0;
> +}
> +
> +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    uint64_t mask = delegable_ints & ~TLOWBITS64;
> +    uint64_t newval = ((uint64_t)val) << 32;
> +
> +    env->mideleg = (env->mideleg & ~mask) | (newval & mask);
>      if (riscv_has_ext(env, RVH)) {
>          env->mideleg |= VS_MODE_INTERRUPTS;
>      }
> @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
>
>  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
>  {
> -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> +    uint64_t mask = all_ints & TLOWBITS64;
> +
> +    env->mie = (env->mie & ~mask) | (val & mask);
> +    return 0;
> +}
> +
> +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = (env->mie >> 32);
> +    return 0;
> +}
> +
> +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    uint64_t mask = all_ints & ~TLOWBITS64;
> +    uint64_t newval = ((uint64_t)val) << 32;
> +
> +    env->mie = (env->mie & ~mask) | (newval & mask);
>      return 0;
>  }
>
> @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>  {
>      RISCVCPU *cpu = env_archcpu(env);
>      /* Allow software control of delegable interrupts not claimed by hardware */
> -    target_ulong mask = write_mask & delegable_ints & ~env->miclaim;
> -    uint32_t old_mip;
> +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> +                    ~env->miclaim & TLOWBITS64;
> +    uint64_t old_mip;
>
>      if (mask) {
>          old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>      return 0;
>  }
>
> +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> +                    target_ulong new_value, target_ulong write_mask)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> +                    ~env->miclaim & ~TLOWBITS64;
> +    uint64_t new_value64 = (uint64_t)new_value << 32;
> +    uint64_t old_mip;
> +
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
> +
> +    if (ret_value) {
> +        *ret_value = old_mip >> 32;
> +    }
> +
> +    return 0;
> +}
> +
>  /* Supervisor Trap Setup */
>  static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
>
>  static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64;
> +
>      /* Shift the VS bits to their S bit location in vsie */
> -    *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
> +    *val = (env->mie & mask) >> 1;
> +    return 0;
> +}
> +
> +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64;
> +
> +    /* Shift the VS bits to their S bit location in vsieh */
> +    *val = (env->mie & mask) >> (32 + 1);
>      return 0;
>  }
>
>  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
>  {
>      if (riscv_cpu_virt_enabled(env)) {
> -        read_vsie(env, CSR_VSIE, val);
> -    } else {
> -        *val = env->mie & env->mideleg;
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return read_vsie(env, CSR_VSIE, val);
>      }
> +
> +    *val = env->mie & env->mideleg;
>      return 0;
>  }
>
>  static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
>  {
> +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> +                    all_ints & TLOWBITS64;
> +
>      /* Shift the S bits to their VS bit location in mie */
> -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
> -                          ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS);
> -    return write_mie(env, CSR_MIE, newval);
> +    env->mie = (env->mie & ~mask) | ((val << 1) & mask);
> +
> +    return 0;
> +}
> +
> +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> +                    all_ints & ~TLOWBITS64;
> +    uint64_t newval = (uint64_t)val << 32;
> +
> +    /* Shift the S bits to their VS bit location in mie */
> +    env->mie = (env->mie & ~mask) | ((newval << 1) & mask);
> +
> +    return 0;
>  }
>
>  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
>  {
> +    uint64_t mask;
> +
>      if (riscv_cpu_virt_enabled(env)) {
> -        write_vsie(env, CSR_VSIE, val);
> -    } else {
> -        target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) |
> -                              (val & S_MODE_INTERRUPTS);
> -        write_mie(env, CSR_MIE, newval);
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return write_vsie(env, CSR_VSIE, val);
> +    }
> +
> +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64;
> +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> +
> +    return 0;
> +}
> +
> +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    if (riscv_cpu_virt_enabled(env)) {
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return read_vsieh(env, CSR_VSIEH, val);
> +    }
> +
> +    *val = ((env->mie & env->mideleg) >> 32);
> +    return 0;
> +}
> +
> +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    uint64_t mask, newval;
> +
> +    if (riscv_cpu_virt_enabled(env)) {
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return write_vsieh(env, CSR_VSIEH, val);
>      }
>
> +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64;
> +    newval = (uint64_t)val << 32;
> +
> +    env->mie = (env->mie & ~mask) | (newval & mask);
>      return 0;
>  }
>
> @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
>  static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>                      target_ulong new_value, target_ulong write_mask)
>  {
> -    /* Shift the S bits to their VS bit location in mip */
> -    int ret = rmw_mip(env, 0, ret_value, new_value << 1,
> -                      (write_mask << 1) & vsip_writable_mask & env->hideleg);
> -    *ret_value &= VS_MODE_INTERRUPTS;
> -    /* Shift the VS bits to their S bit location in vsip */
> -    *ret_value >>= 1;
> -    return ret;
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints &
> +                    vsip_writable_mask & env->hideleg &
> +                    ~env->miclaim & TLOWBITS64;
> +    uint64_t old_mip;
> +
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
> +
> +    if (ret_value) {
> +        *ret_value = old_mip & VS_MODE_INTERRUPTS;
> +    }
> +
> +    return 0;
> +}
> +
> +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> +                     target_ulong new_value, target_ulong write_mask)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints &
> +                    vsip_writable_mask & env->hideleg &
> +                    ~env->miclaim & ~TLOWBITS64;
> +    uint64_t new_value64 = (uint64_t)new_value << 32;
> +    uint64_t old_mip;
> +
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
> +
> +    if (ret_value) {
> +        *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32;
> +    }
> +
> +    return 0;
>  }
>
>  static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>                     target_ulong new_value, target_ulong write_mask)
>  {
> -    int ret;
> +    RISCVCPU *cpu = env_archcpu(env);
> +    uint64_t mask, old_mip;
>
>      if (riscv_cpu_virt_enabled(env)) {
> -        ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> +    }
> +
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    mask = ((uint64_t)write_mask) & delegable_ints &
> +           env->mideleg & sip_writable_mask &
> +           ~env->miclaim & TLOWBITS64;
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
>      } else {
> -        ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
> -                      write_mask & env->mideleg & sip_writable_mask);
> +        old_mip = env->mip;
>      }
>
> -    *ret_value &= env->mideleg;
> -    return ret;
> +    if (ret_value) {
> +        *ret_value = old_mip;
> +    }
> +
> +    return 0;
> +}
> +
> +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> +                    target_ulong new_value, target_ulong write_mask)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    uint64_t mask, new_value64;
> +    uint64_t old_mip;
> +
> +    if (riscv_cpu_virt_enabled(env)) {
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask);
> +    }
> +
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    mask = ((uint64_t)write_mask << 32) & delegable_ints &
> +           env->mideleg & sip_writable_mask &
> +           ~env->miclaim & ~TLOWBITS64;
> +    new_value64 = (uint64_t)new_value << 32;
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
> +
> +    if (ret_value) {
> +        *ret_value = (old_mip & env->mideleg) >> 32;
> +    }
> +
> +    return 0;
>  }
>
>  /* Supervisor Protection and Translation */
> @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
>      return 0;
>  }
>
> +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    int irq, hiid;
> +    uint8_t hiprio, iprio;
> +
> +    irq = riscv_cpu_vsirq_pending(env);
> +    if (irq <= 0 || irq > 63) {
> +       *val = 0;
> +    } else {
> +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> +       iprio = env->hviprio[irq];
> +       /* TODO: This needs to improve in specification */
> +       if (!(env->hstatus & HSTATUS_VGEIN)) {
> +           hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >>
> +                 HVICONTROL_IID_SHIFT;
> +           hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK;
> +           if (irq == hiid && hiprio) {
> +               iprio = hiprio;
> +           }
> +       }
> +       *val |= iprio;
> +    }
> +
> +    return 0;
> +}
> +
> +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    int irq;
> +
> +    if (riscv_cpu_virt_enabled(env)) {
> +        return read_vstopi(env, CSR_VSTOPI, val);
> +    }
> +
> +    irq = riscv_cpu_sirq_pending(env);
> +    if (irq <= 0 || irq > 63) {
> +       *val = 0;
> +    } else {
> +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> +       *val |= env->siprio[irq];
> +    }
> +
> +    return 0;
> +}
> +
>  /* Hypervisor Extensions */
>  static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
>      return 0;
>  }
>
> +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->hideleg >> 32;
> +    return 0;
> +}
> +
> +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    uint64_t mask = ~TLOWBITS64;
> +    uint64_t newval = ((uint64_t)val) << 32;
> +
> +    env->hideleg = (env->hideleg & ~mask) | (newval & mask);
> +
> +    return 0;
> +}
> +
>  static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>                     target_ulong new_value, target_ulong write_mask)
>  {
> -    int ret = rmw_mip(env, 0, ret_value, new_value,
> -                      write_mask & hvip_writable_mask);
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> +                    hvip_writable_mask &
> +                    ~env->miclaim & TLOWBITS64;
> +    uint64_t old_mip;
> +
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
>
> -    *ret_value &= hvip_writable_mask;
> +    if (ret_value) {
> +        *ret_value = old_mip & hvip_writable_mask;
> +    }
>
> -    return ret;
> +    return 0;
> +}
> +
> +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> +                    target_ulong new_value, target_ulong write_mask)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> +                    hvip_writable_mask &
> +                    ~env->miclaim & ~TLOWBITS64;
> +    uint64_t new_value64 = (uint64_t)new_value << 32;
> +    uint64_t old_mip;
> +
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
> +
> +    if (ret_value) {
> +        *ret_value = (old_mip & hvip_writable_mask) >> 32;
> +    }
> +
> +    return 0;
>  }
>
>  static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>                     target_ulong new_value, target_ulong write_mask)
>  {
> -    int ret = rmw_mip(env, 0, ret_value, new_value,
> -                      write_mask & hip_writable_mask);
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> +                    hip_writable_mask &
> +                    ~env->miclaim & TLOWBITS64;
> +    uint64_t old_mip;
>
> -    *ret_value &= hip_writable_mask;
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
>
> -    return ret;
> +    if (ret_value) {
> +        *ret_value = old_mip & hip_writable_mask;
> +    }
> +
> +    return 0;
>  }
>
>  static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
>
>  static int write_hie(CPURISCVState *env, int csrno, target_ulong val)
>  {
> -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS);
> -    return write_mie(env, CSR_MIE, newval);
> +    uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64;
> +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> +    return 0;
>  }
>
>  static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val)
> @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val)
>      return 0;
>  }
>
> +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->hvicontrol;
> +    return 0;
> +}
> +
> +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->hvicontrol = val & HVICONTROL_VALID_MASK;
> +    return 0;
> +}
> +
> +static int read_hvipriox(CPURISCVState *env, int first_index,
> +                         uint8_t *iprio, target_ulong *val)
> +{
> +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> +
> +    /* First index has to be multiple of numbe of irqs per register */
> +    if (first_index % num_irqs) {
> +        return (riscv_cpu_virt_enabled(env)) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    /* Fill-up return value */
> +    *val = 0;
> +    for (i = 0; i < num_irqs; i++) {
> +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> +            continue;
> +        }
> +        if (rdzero) {
> +            continue;
> +        }
> +        *val |= ((target_ulong)iprio[irq]) << (i * 8);
> +    }
> +
> +    return 0;
> +}
> +
> +static int write_hvipriox(CPURISCVState *env, int first_index,
> +                          uint8_t *iprio, target_ulong val)
> +{
> +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> +
> +    /* First index has to be multiple of numbe of irqs per register */
> +    if (first_index % num_irqs) {
> +        return (riscv_cpu_virt_enabled(env)) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    /* Fill-up priority arrary */
> +    for (i = 0; i < num_irqs; i++) {
> +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> +            continue;
> +        }
> +        if (rdzero) {
> +            iprio[irq] = 0;
> +        } else {
> +            iprio[irq] = (val >> (i * 8)) & 0xff;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    return read_hvipriox(env, 0, env->hviprio, val);
> +}
> +
> +static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    return write_hvipriox(env, 0, env->hviprio, val);
> +}
> +
> +static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    return read_hvipriox(env, 4, env->hviprio, val);
> +}
> +
> +static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    return write_hvipriox(env, 4, env->hviprio, val);
> +}
> +
> +static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    return read_hvipriox(env, 8, env->hviprio, val);
> +}
> +
> +static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    return write_hvipriox(env, 8, env->hviprio, val);
> +}
> +
> +static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    return read_hvipriox(env, 12, env->hviprio, val);
> +}
> +
> +static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    return write_hvipriox(env, 12, env->hviprio, val);
> +}
> +
>  /* Virtual CSR Registers */
>  static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      [CSR_MBADADDR] = { "mbadaddr", any,  read_mbadaddr, write_mbadaddr },
>      [CSR_MIP]      = { "mip",      any,  NULL,    NULL, rmw_mip        },
>
> +    /* Machine-Level Window to Indirectly Accessed Registers (AIA) */
> +    [CSR_MISELECT] = { "miselect", aia_any,   NULL, NULL,    rmw_xiselect },
> +    [CSR_MIREG]    = { "mireg",    aia_any,   NULL, NULL,    rmw_xireg },
> +
> +    /* Machine-Level Interrupts (AIA) */
> +    [CSR_MTOPI]    = { "mtopi",    aia_any,   read_mtopi },
> +
> +    /* Machine-Level IMSIC Interface (AIA) */
> +    [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_MCLAIMEI]   = { "mclaimei",   aia_any, read_xclaimei },
> +
> +    /* Machine-Level High-Half CSRs (AIA) */
> +    [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh },
> +    [CSR_MIEH]     = { "mieh",     aia_any32, read_mieh,     write_mieh     },
> +    [CSR_MIPH]     = { "miph",     aia_any32, NULL,    NULL, rmw_miph       },
> +
>      /* Supervisor Trap Setup */
>      [CSR_SSTATUS]    = { "sstatus",    smode, read_sstatus,    write_sstatus    },
>      [CSR_SIE]        = { "sie",        smode, read_sie,        write_sie        },
> @@ -1444,6 +2357,24 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      /* Supervisor Protection and Translation */
>      [CSR_SATP]     = { "satp",     smode, read_satp,    write_satp      },
>
> +    /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
> +    [CSR_SISELECT]   = { "siselect",   aia_smode, NULL, NULL, rmw_xiselect },
> +    [CSR_SIREG]      = { "sireg",      aia_smode, NULL, NULL, rmw_xireg },
> +
> +    /* Supervisor-Level Interrupts (AIA) */
> +    [CSR_STOPI]      = { "stopi",      aia_smode, read_stopi },
> +
> +    /* Supervisor-Level IMSIC Interface (AIA) */
> +    [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_SCLAIMEI]   = { "sclaimei",   aia_smode, read_xclaimei },
> +
> +    /* Supervisor-Level High-Half CSRs (AIA) */
> +    [CSR_SIEH]       = { "sieh",       aia_smode32, read_sieh,  write_sieh },
> +    [CSR_SIPH]       = { "siph",       aia_smode32, NULL, NULL, rmw_siph   },
> +
>      [CSR_HSTATUS]     = { "hstatus",     hmode,   read_hstatus,     write_hstatus     },
>      [CSR_HEDELEG]     = { "hedeleg",     hmode,   read_hedeleg,     write_hedeleg     },
>      [CSR_HIDELEG]     = { "hideleg",     hmode,   read_hideleg,     write_hideleg     },
> @@ -1472,6 +2403,32 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      [CSR_MTVAL2]      = { "mtval2",      hmode,   read_mtval2,      write_mtval2      },
>      [CSR_MTINST]      = { "mtinst",      hmode,   read_mtinst,      write_mtinst      },
>
> +    /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
> +    [CSR_HVICONTROL]  = { "hvicontrol",  aia_hmode, read_hvicontrol, write_hvicontrol },
> +    [CSR_HVIPRIO1]    = { "hviprio1",    aia_hmode, read_hviprio1,   write_hviprio1 },
> +    [CSR_HVIPRIO2]    = { "hviprio2",    aia_hmode, read_hviprio2,   write_hviprio2 },
> +
> +    /* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
> +    [CSR_VSISELECT]   = { "vsiselect",   aia_hmode, NULL, NULL,      rmw_xiselect },
> +    [CSR_VSIREG]      = { "vsireg",      aia_hmode, NULL, NULL,      rmw_xireg },
> +
> +    /* VS-Level Interrupts (H-extension with AIA) */
> +    [CSR_VSTOPI]      = { "vstopi",      aia_hmode, read_vstopi },
> +
> +    /* VS-Level IMSIC Interface (H-extension with AIA) */
> +    [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> +
> +    /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
> +    [CSR_HIDELEGH]    = { "hidelegh",    aia_hmode32, read_hidelegh,  write_hidelegh },
> +    [CSR_HVIPH]       = { "hviph",       aia_hmode32, NULL, NULL,     rmw_hviph },
> +    [CSR_HVIPRIO1H]   = { "hviprio1h",   aia_hmode32, read_hviprio1h, write_hviprio1h },
> +    [CSR_HVIPRIO2H]   = { "hviprio2h",   aia_hmode32, read_hviprio2h, write_hviprio2h },
> +    [CSR_VSIEH]       = { "vsieh",       aia_hmode32, read_vsieh,     write_vsieh },
> +    [CSR_VSIPH]       = { "vsiep",       aia_hmode32, NULL, NULL,     rmw_vsiph },
> +
>      /* Physical Memory Protection */
>      [CSR_PMPCFG0]    = { "pmpcfg0",   pmp, read_pmpcfg,  write_pmpcfg  },
>      [CSR_PMPCFG1]    = { "pmpcfg1",   pmp, read_pmpcfg,  write_pmpcfg  },
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 44d4015bd6..f7fa48c240 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = {
>
>  static const VMStateDescription vmstate_hyper = {
>      .name = "cpu/hyper",
> -    .version_id = 1,
> -    .minimum_version_id = 1,
> +    .version_id = 2,
> +    .minimum_version_id = 2,
>      .needed = hyper_needed,
>      .fields = (VMStateField[]) {
>          VMSTATE_UINTTL(env.hstatus, RISCVCPU),
>          VMSTATE_UINTTL(env.hedeleg, RISCVCPU),
> -        VMSTATE_UINTTL(env.hideleg, RISCVCPU),
> +        VMSTATE_UINT64(env.hideleg, RISCVCPU),
>          VMSTATE_UINTTL(env.hcounteren, RISCVCPU),
>          VMSTATE_UINTTL(env.htval, RISCVCPU),
>          VMSTATE_UINTTL(env.htinst, RISCVCPU),
>          VMSTATE_UINTTL(env.hgatp, RISCVCPU),
>          VMSTATE_UINT64(env.htimedelta, RISCVCPU),
>
> +        VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
> +        VMSTATE_UINTTL(env.hvicontrol, RISCVCPU),
> +
>          VMSTATE_UINT64(env.vsstatus, RISCVCPU),
>          VMSTATE_UINTTL(env.vstvec, RISCVCPU),
>          VMSTATE_UINTTL(env.vsscratch, RISCVCPU),
> @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = {
>          VMSTATE_UINTTL(env.vscause, RISCVCPU),
>          VMSTATE_UINTTL(env.vstval, RISCVCPU),
>          VMSTATE_UINTTL(env.vsatp, RISCVCPU),
> +        VMSTATE_UINTTL(env.vsiselect, RISCVCPU),
>
>          VMSTATE_UINTTL(env.mtval2, RISCVCPU),
>          VMSTATE_UINTTL(env.mtinst, RISCVCPU),
> @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = {
>
>  const VMStateDescription vmstate_riscv_cpu = {
>      .name = "cpu",
> -    .version_id = 1,
> -    .minimum_version_id = 1,
> +    .version_id = 2,
> +    .minimum_version_id = 2,
>      .fields = (VMStateField[]) {
>          VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
>          VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
> +        VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
> +        VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
>          VMSTATE_UINTTL(env.pc, RISCVCPU),
>          VMSTATE_UINTTL(env.load_res, RISCVCPU),
>          VMSTATE_UINTTL(env.load_val, RISCVCPU),
> @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = {
>          VMSTATE_UINTTL(env.resetvec, RISCVCPU),
>          VMSTATE_UINTTL(env.mhartid, RISCVCPU),
>          VMSTATE_UINT64(env.mstatus, RISCVCPU),
> -        VMSTATE_UINTTL(env.mip, RISCVCPU),
> -        VMSTATE_UINT32(env.miclaim, RISCVCPU),
> -        VMSTATE_UINTTL(env.mie, RISCVCPU),
> -        VMSTATE_UINTTL(env.mideleg, RISCVCPU),
> +        VMSTATE_UINT64(env.mip, RISCVCPU),
> +        VMSTATE_UINT64(env.miclaim, RISCVCPU),
> +        VMSTATE_UINT64(env.mie, RISCVCPU),
> +        VMSTATE_UINT64(env.mideleg, RISCVCPU),
>          VMSTATE_UINTTL(env.sptbr, RISCVCPU),
>          VMSTATE_UINTTL(env.satp, RISCVCPU),
>          VMSTATE_UINTTL(env.sbadaddr, RISCVCPU),
> @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = {
>          VMSTATE_UINTTL(env.mepc, RISCVCPU),
>          VMSTATE_UINTTL(env.mcause, RISCVCPU),
>          VMSTATE_UINTTL(env.mtval, RISCVCPU),
> +        VMSTATE_UINTTL(env.miselect, RISCVCPU),
> +        VMSTATE_UINTTL(env.siselect, RISCVCPU),
>          VMSTATE_UINTTL(env.scounteren, RISCVCPU),
>          VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
>          VMSTATE_UINTTL(env.sscratch, RISCVCPU),
> --
> 2.25.1
>
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
@ 2021-06-10 23:19     ` Alistair Francis
  0 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-10 23:19 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers, Anup Patel

On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> and VS-mode.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>
> ---
>  target/riscv/cpu.c        |   27 +-
>  target/riscv/cpu.h        |   52 +-
>  target/riscv/cpu_helper.c |  245 ++++++++-
>  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
>  target/riscv/machine.c    |   26 +-
>  5 files changed, 1309 insertions(+), 100 deletions(-)

I feel this patch could be split up more :)

>
> diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> index f3702111ae..795162834b 100644
> --- a/target/riscv/cpu.c
> +++ b/target/riscv/cpu.c
> @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
>          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
>                       (target_ulong)env->vsstatus);
>      }
> -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
>      if (riscv_has_ext(env, RVH)) {
> -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
>      }
>      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
>      if (riscv_has_ext(env, RVH)) {
> @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
>
>  static void riscv_cpu_reset(DeviceState *dev)
>  {
> +    uint8_t iprio;
> +    int i, irq, rdzero;
>      CPUState *cs = CPU(dev);
>      RISCVCPU *cpu = RISCV_CPU(cs);
>      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
>      env->mcause = 0;
>      env->pc = env->resetvec;
>      env->two_stage_lookup = false;
> +
> +    /* Initialized default priorities of local interrupts. */
> +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> +        iprio = riscv_cpu_default_priority(i);
> +        env->miprio[i] = iprio;
> +        env->siprio[i] = iprio;
> +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> +    }
> +    i = 0;
> +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> +        if (rdzero) {
> +            env->hviprio[irq] = 0;
> +        } else {
> +            env->hviprio[irq] = env->miprio[irq];
> +        }
> +        i++;
> +    }
>  #endif
>      cs->exception_index = EXCP_NONE;
>      env->load_res = -1;
> diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> index f00c60c840..780d3f9058 100644
> --- a/target/riscv/cpu.h
> +++ b/target/riscv/cpu.h
> @@ -157,12 +157,12 @@ struct CPURISCVState {
>       */
>      uint64_t mstatus;
>
> -    target_ulong mip;
> +    uint64_t mip;

This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
all the other existing target_ulong CSRs are the same.

Alistair

>
> -    uint32_t miclaim;
> +    uint64_t miclaim;
>
> -    target_ulong mie;
> -    target_ulong mideleg;
> +    uint64_t mie;
> +    uint64_t mideleg;
>
>      target_ulong sptbr;  /* until: priv-1.9.1 */
>      target_ulong satp;   /* since: priv-1.10.0 */
> @@ -179,16 +179,27 @@ struct CPURISCVState {
>      target_ulong mcause;
>      target_ulong mtval;  /* since: priv-1.10.0 */
>
> +    /* AIA CSRs */
> +    target_ulong miselect;
> +    target_ulong siselect;
> +
> +    uint8_t miprio[64];
> +    uint8_t siprio[64];
> +
>      /* Hypervisor CSRs */
>      target_ulong hstatus;
>      target_ulong hedeleg;
> -    target_ulong hideleg;
> +    uint64_t hideleg;
>      target_ulong hcounteren;
>      target_ulong htval;
>      target_ulong htinst;
>      target_ulong hgatp;
>      uint64_t htimedelta;
>
> +    /* AIA HS-mode CSRs */
> +    uint8_t hviprio[64];
> +    target_ulong hvicontrol;
> +
>      /* Virtual CSRs */
>      /*
>       * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
> @@ -202,6 +213,9 @@ struct CPURISCVState {
>      target_ulong vstval;
>      target_ulong vsatp;
>
> +    /* AIA VS-mode CSRs */
> +    target_ulong vsiselect;
> +
>      target_ulong mtval2;
>      target_ulong mtinst;
>
> @@ -236,6 +250,18 @@ struct CPURISCVState {
>      uint64_t (*rdtime_fn)(uint32_t);
>      uint32_t rdtime_fn_arg;
>
> +    /* machine specific AIA IMSIC read-modify-write callback */
> +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \
> +    ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \
> +     (((__priv) & 0x3) << 16) | (__isel & 0xffff))
> +#define IMSIC_REG_ISEL(__reg)                  ((__reg) & 0xffff)
> +#define IMSIC_REG_PRIV(__reg)                  (((__reg) >> 16) & 0x3)
> +#define IMSIC_REG_VIRT(__reg)                  (((__reg) >> 20) & 0x1)
> +#define IMSIC_REG_VGEIN(__reg)                 (((__reg) >> 24) & 0x3f)
> +    int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val,
> +                        target_ulong new_val, target_ulong write_mask);
> +    void *imsic_rmw_fn_arg;
> +
>      /* True if in debugger mode.  */
>      bool debugger;
>  #endif
> @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
>                                 int cpuid, void *opaque);
>  int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
>  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero);
> +uint8_t riscv_cpu_default_priority(int irq);
> +int riscv_cpu_mirq_pending(CPURISCVState *env);
> +int riscv_cpu_sirq_pending(CPURISCVState *env);
> +int riscv_cpu_vsirq_pending(CPURISCVState *env);
>  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
>  bool riscv_cpu_fp_enabled(CPURISCVState *env);
>  bool riscv_cpu_virt_enabled(CPURISCVState *env);
> @@ -364,9 +395,16 @@ void riscv_cpu_list(void);
>
>  #ifndef CONFIG_USER_ONLY
>  void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
> -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
> -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
> +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
> +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value);
>  #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
> +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> +                                int (*rmw_fn)(void *arg,
> +                                              target_ulong reg,
> +                                              target_ulong *val,
> +                                              target_ulong new_val,
> +                                              target_ulong write_mask),
> +                                void *rmw_fn_arg);
>  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
>                               uint32_t arg);
>  #endif
> diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> index 21c54ef561..5b06b4f995 100644
> --- a/target/riscv/cpu_helper.c
> +++ b/target/riscv/cpu_helper.c
> @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
>  }
>
>  #ifndef CONFIG_USER_ONLY
> -static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> +
> +/*
> + * The HS-mode is allowed to configure priority only for the
> + * following VS-mode local interrupts:
> + *
> + * 0  (Reserved interrupt, reads as zero)
> + * 1  Supervisor software interrupt
> + * 4  (Reserved interrupt, reads as zero)
> + * 5  Supervisor timer interrupt
> + * 8  (Reserved interrupt, reads as zero)
> + * 13 (Reserved interrupt)
> + * 14 "
> + * 15 "
> + * 16 "
> + * 18 Debug/trace interrupt
> + * 20 (Reserved interrupt)
> + * 22 ”
> + * 24 ”
> + * 26 ”
> + * 28 "
> + * 30 (Reserved for standard reporting of bus or system errors)
> + */
> +
> +static int hviprio_index2irq[] =
> +    { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
> +static int hviprio_index2rdzero[] =
> +    { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> +
> +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
>  {
> -    target_ulong irqs;
> +    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
> +        return -EINVAL;
> +    }
>
> -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> -    target_ulong hs_mstatus_sie = get_field(env->mstatus_hs, MSTATUS_SIE);
> +    if (out_irq) {
> +        *out_irq = hviprio_index2irq[index];
> +    }
> +
> +    if (out_rdzero) {
> +        *out_rdzero = hviprio_index2rdzero[index];
> +    }
>
> -    target_ulong pending = env->mip & env->mie &
> -                               ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> -    target_ulong vspending = (env->mip & env->mie &
> -                              (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> +    return 0;
> +}
>
> -    target_ulong mie    = env->priv < PRV_M ||
> -                          (env->priv == PRV_M && mstatus_mie);
> -    target_ulong sie    = env->priv < PRV_S ||
> -                          (env->priv == PRV_S && mstatus_sie);
> -    target_ulong hs_sie = env->priv < PRV_S ||
> -                          (env->priv == PRV_S && hs_mstatus_sie);
> +uint8_t riscv_cpu_default_priority(int irq)
> +{
> +    int u, l;
> +    uint8_t iprio = IPRIO_MMAXIPRIO;
>
> -    if (riscv_cpu_virt_enabled(env)) {
> -        target_ulong pending_hs_irq = pending & -hs_sie;
> +    if (irq < 0 || irq > 63) {
> +        return iprio;
> +    }
>
> -        if (pending_hs_irq) {
> -            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> -            return ctz64(pending_hs_irq);
> +    /*
> +     * Default priorities of local interrupts are defined in the
> +     * RISC-V Advanced Interrupt Architecture specification.
> +     *
> +     * ----------------------------------------------------------------
> +     *  Default  |
> +     *  Priority | Major Interrupt Numbers
> +     * ----------------------------------------------------------------
> +     *  Highest  | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c),
> +     *           | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38),
> +     *           | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34),
> +     *           | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30)
> +     *           |
> +     *           | 11 (0b),  3 (03),  7 (07)
> +     *           |  9 (09),  1 (01),  5 (05)
> +     *           | 12 (0c)
> +     *           | 10 (0a),  2 (02),  6 (06)
> +     *           |
> +     *           | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c),
> +     *           | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28),
> +     *           | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24),
> +     *  Lowest   | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20)
> +     * ----------------------------------------------------------------
> +     */
> +
> +    u = IPRIO_DEFAULT_U(irq);
> +    l = IPRIO_DEFAULT_L(irq);
> +    if (u == 0) {
> +        if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER ||
> +            irq == IRQ_VS_SOFT) {
> +            iprio = IPRIO_DEFAULT_VS;
> +        } else if (irq == IRQ_S_GEXT) {
> +            iprio = IPRIO_DEFAULT_SGEXT;
> +        } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER ||
> +                   irq == IRQ_S_SOFT) {
> +            iprio = IPRIO_DEFAULT_S;
> +        } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER ||
> +                   irq == IRQ_M_SOFT) {
> +            iprio = IPRIO_DEFAULT_M;
> +        } else {
> +            iprio = IPRIO_DEFAULT_VS;
>          }
> +    } else if (u == 1) {
> +        if (l < 8) {
> +            iprio = IPRIO_DEFAULT_16_23(irq);
> +        } else {
> +            iprio = IPRIO_DEFAULT_24_31(irq);
> +        }
> +    } else if (u == 2) {
> +        iprio = IPRIO_DEFAULT_32_47(irq);
> +    } else if (u == 3) {
> +        iprio = IPRIO_DEFAULT_48_63(irq);
> +    }
> +
> +    return iprio;
> +}
> +
> +static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> +                                    uint64_t pending, uint8_t *iprio)
> +{
> +    int irq, best_irq = EXCP_NONE;
> +    unsigned int prio, best_prio = UINT_MAX;
>
> -        pending = vspending;
> +    if (!pending) {
> +        return EXCP_NONE;
>      }
>
> -    irqs = (pending & ~env->mideleg & -mie) | (pending &  env->mideleg & -sie);
> +    irq = ctz64(pending);
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return irq;
> +    }
>
> -    if (irqs) {
> -        return ctz64(irqs); /* since non-zero */
> +    pending = pending >> irq;
> +    while (pending) {
> +        prio = iprio[irq];
> +        if (!prio) {
> +            prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ?
> +                   1 : IPRIO_MMAXIPRIO;
> +        }
> +        if ((pending & 0x1) && (prio < best_prio)) {
> +            best_irq = irq;
> +            best_prio = prio;
> +        }
> +        irq++;
> +        pending = pending >> 1;
> +    }
> +
> +    return best_irq;
> +}
> +
> +int riscv_cpu_mirq_pending(CPURISCVState *env)
> +{
> +    uint64_t irqs = env->mip & env->mie & ~env->mideleg &
> +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> +
> +    return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> +}
> +
> +int riscv_cpu_sirq_pending(CPURISCVState *env)
> +{
> +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> +
> +    return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> +}
> +
> +int riscv_cpu_vsirq_pending(CPURISCVState *env)
> +{
> +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> +                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> +
> +    return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> +}
> +
> +static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> +{
> +    int virq;
> +    uint64_t irqs, mie, sie, vsie;
> +    uint64_t pending, vspending;
> +
> +    /* Determine interrupt enable state of all privilege modes */
> +    if (riscv_cpu_virt_enabled(env)) {
> +        mie = 1;
> +        sie = 1;
> +        vsie = (env->priv < PRV_S) ||
> +               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
>      } else {
> -        return EXCP_NONE; /* indicates no pending interrupt */
> +        mie = (env->priv < PRV_M) ||
> +              (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
> +        sie = (env->priv < PRV_S) ||
> +              (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> +        vsie = 0;
> +    }
> +
> +    /* Check M-mode interrupts */
> +    pending = env->mip & env->mie &
> +              ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> +    irqs = pending & ~env->mideleg & -mie;
> +    if (irqs) {
> +        return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> +    }
> +
> +    /* Check HS-mode interrupts */
> +    irqs = pending & env->mideleg & -sie;
> +    if (irqs) {
> +        return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> +    }
> +
> +    /* Check VS-mode interrupts */
> +    vspending = env->mip & env->mie &
> +                (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> +    irqs = vspending & env->hideleg & -vsie;
> +    if (irqs) {
> +        virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> +        return (virq <= 0) ? virq : virq + 1;
>      }
> +
> +    /* Indicates no pending interrupt */
> +    return EXCP_NONE;
>  }
>  #endif
>
> @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx)
>      return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
>  }
>
> -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
>  {
>      CPURISCVState *env = &cpu->env;
>      if (env->miclaim & interrupts) {
> @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
>      }
>  }
>
> -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
>  {
>      CPURISCVState *env = &cpu->env;
>      CPUState *cs = CPU(cpu);
> -    uint32_t old = env->mip;
> +    uint64_t old = env->mip;
>      bool locked = false;
>
>      if (!qemu_mutex_iothread_locked()) {
> @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
>      return old;
>  }
>
> +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> +                                int (*rmw_fn)(void *arg,
> +                                              target_ulong reg,
> +                                              target_ulong *val,
> +                                              target_ulong new_val,
> +                                              target_ulong write_mask),
> +                                void *rmw_fn_arg)
> +{
> +    env->imsic_rmw_fn = rmw_fn;
> +    env->imsic_rmw_fn_arg = rmw_fn_arg;
> +}
> +
>  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
>                               uint32_t arg)
>  {
> @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
>       */
>      bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
>      target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
> -    target_ulong deleg = async ? env->mideleg : env->medeleg;
> +    uint64_t deleg = async ? env->mideleg : env->medeleg;
>      bool write_tval = false;
>      target_ulong tval = 0;
>      target_ulong htval = 0;
> diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> index d2585395bf..3c016d7452 100644
> --- a/target/riscv/csr.c
> +++ b/target/riscv/csr.c
> @@ -153,11 +153,56 @@ static int any32(CPURISCVState *env, int csrno)
>
>  }
>
> +static int aia_any(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return any(env, csrno);
> +}
> +
> +static int aia_any32(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return any32(env, csrno);
> +}
> +
>  static int smode(CPURISCVState *env, int csrno)
>  {
>      return -!riscv_has_ext(env, RVS);
>  }
>
> +static int smode32(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_cpu_is_32bit(env)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return smode(env, csrno);
> +}
> +
> +static int aia_smode(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return smode(env, csrno);
> +}
> +
> +static int aia_smode32(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return smode32(env, csrno);
> +}
> +
>  static int hmode(CPURISCVState *env, int csrno)
>  {
>      if (riscv_has_ext(env, RVS) &&
> @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno)
>  static int hmode32(CPURISCVState *env, int csrno)
>  {
>      if (!riscv_cpu_is_32bit(env)) {
> -        return 0;
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return hmode(env, csrno);
> +}
> +
> +static int aia_hmode(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
>      }
>
>      return hmode(env, csrno);
> +}
>
> +static int aia_hmode32(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> +        return -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    return hmode32(env, csrno);
>  }
>
>  static int pmp(CPURISCVState *env, int csrno)
> @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
>
>  /* Machine constants */
>
> -#define M_MODE_INTERRUPTS  (MIP_MSIP | MIP_MTIP | MIP_MEIP)
> -#define S_MODE_INTERRUPTS  (MIP_SSIP | MIP_STIP | MIP_SEIP)
> -#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)
> +#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
> +#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
> +#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
> +
> +#define TLOWBITS64         ((uint64_t)((target_ulong)-1))
>
> -static const target_ulong delegable_ints = S_MODE_INTERRUPTS |
> -                                           VS_MODE_INTERRUPTS;
> -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> -                                     VS_MODE_INTERRUPTS;
> +static const uint64_t delegable_ints = S_MODE_INTERRUPTS |
> +                                       VS_MODE_INTERRUPTS;
> +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> +                                 VS_MODE_INTERRUPTS;
>  static const target_ulong delegable_excps =
>      (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) |
>      (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) |
> @@ -419,10 +483,10 @@ static const target_ulong delegable_excps =
>  static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
>      SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
>      SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
> -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> -static const target_ulong hip_writable_mask = MIP_VSSIP;
> -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> -static const target_ulong vsip_writable_mask = MIP_VSSIP;
> +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> +static const uint64_t hip_writable_mask = MIP_VSSIP;
> +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> +static const uint64_t vsip_writable_mask = MIP_VSSIP;
>
>  static const char valid_vm_1_10_32[16] = {
>      [VM_1_10_MBARE] = 1,
> @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val)
>
>  static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
>  {
> -    env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
> +    uint64_t mask = delegable_ints & TLOWBITS64;
> +
> +    env->mideleg = (env->mideleg & ~mask) | (val & mask);
> +    if (riscv_has_ext(env, RVH)) {
> +        env->mideleg |= VS_MODE_INTERRUPTS;
> +    }
> +    return 0;
> +}
> +
> +static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
> +{
> +    if (!riscv_cpu_virt_enabled(env)) {
> +        return csrno;
> +    }
> +
> +    switch (csrno) {
> +    case CSR_SISELECT:
> +        return CSR_VSISELECT;
> +    case CSR_SIREG:
> +        return CSR_VSIREG;
> +    case CSR_STOPI:
> +        return CSR_VSTOPI;
> +    case CSR_SSETEIPNUM:
> +        return CSR_VSSETEIPNUM;
> +    case CSR_SCLREIPNUM:
> +        return CSR_VSCLREIPNUM;
> +    case CSR_SSETEIENUM:
> +        return CSR_VSSETEIENUM;
> +    case CSR_SCLREIENUM:
> +        return CSR_VSCLREIENUM;
> +    default:
> +        return csrno;
> +    };
> +}
> +
> +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val,
> +                        target_ulong new_val, target_ulong write_mask)
> +{
> +    target_ulong *iselect;
> +
> +    switch (csrno) {
> +    case CSR_MISELECT:
> +        iselect = &env->miselect;
> +        break;
> +    case CSR_SISELECT:
> +        iselect = riscv_cpu_virt_enabled(env) ?
> +                  &env->vsiselect : &env->siselect;
> +        break;
> +    case CSR_VSISELECT:
> +        iselect = &env->vsiselect;
> +        break;
> +    default:
> +         return -RISCV_EXCP_ILLEGAL_INST;
> +    };
> +
> +    if (val) {
> +        *val = *iselect;
> +    }
> +
> +    if (write_mask) {
> +        *iselect = (*iselect & ~write_mask) | (new_val & write_mask);
> +    }
> +
> +    return 0;
> +}
> +
> +static int rmw_iprio(target_ulong iselect, uint8_t *iprio,
> +                     target_ulong *val, target_ulong new_val,
> +                     target_ulong write_mask)
> +{
> +    int i, firq, nirqs;
> +    target_ulong old_val;
> +
> +    if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) {
> +        return -EINVAL;
> +    }
> +#if TARGET_LONG_BITS == 64
> +    if (iselect & 0x1) {
> +        return -EINVAL;
> +    }
> +#endif
> +
> +    nirqs = 4 * (TARGET_LONG_BITS / 32);
> +    firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 32)) * (nirqs);
> +
> +    old_val = 0;
> +    for (i = 0; i < nirqs; i++) {
> +        old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i);
> +    }
> +
> +    if (val) {
> +        *val = old_val;
> +    }
> +
> +    if (write_mask) {
> +        new_val = (old_val & ~write_mask) | (new_val & write_mask);
> +        for (i = 0; i < nirqs; i++) {
> +            iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
> +                     target_ulong new_val, target_ulong write_mask)
> +{
> +    bool virt;
> +    uint8_t *iprio;
> +    int ret = -EINVAL;
> +    target_ulong priv, isel, vgein;
> +
> +    /* Translate CSR number for VS-mode */
> +    csrno = aia_xlate_vs_csrno(env, csrno);
> +
> +    /* Decode register details from CSR number */
> +    virt = false;
> +    switch (csrno) {
> +    case CSR_MIREG:
> +        iprio = env->miprio;
> +        isel = env->miselect;
> +        priv = PRV_M;
> +        break;
> +    case CSR_SIREG:
> +        iprio = env->siprio;
> +        isel = env->siselect;
> +        priv = PRV_S;
> +        break;
> +    case CSR_VSIREG:
> +        iprio = env->hviprio;
> +        isel = env->vsiselect;
> +        priv = PRV_S;
> +        virt = true;
> +        break;
> +    default:
> +         goto done;
> +    };
> +
> +    /* Find the selected guest interrupt file */
> +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> +
> +    if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) {
> +        /* Local interrupt priority registers not available for VS-mode */
> +        if (!virt) {
> +            ret = rmw_iprio(isel, iprio, val, new_val, write_mask);
> +        }
> +    } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) {
> +        /* IMSIC registers only available when machine implements it. */
> +        if (env->imsic_rmw_fn) {
> +            /* Selected guest interrupt file should not be zero */
> +            if (virt && !vgein) {
> +                goto done;
> +            }
> +            /* Call machine specific IMSIC register emulation */
> +            ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> +                                    IMSIC_MAKE_REG(isel, priv, virt, vgein),
> +                                    val, new_val, write_mask);
> +        }
> +    }
> +
> +done:
> +    if (ret) {
> +        return (riscv_cpu_virt_enabled(env) && virt) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +    return 0;
> +}
> +
> +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    int irq;
> +
> +    irq = riscv_cpu_mirq_pending(env);
> +    if (irq <= 0 || irq > 63) {
> +       *val = 0;
> +    } else {
> +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> +       *val |= env->miprio[irq];
> +    }
> +
> +    return 0;
> +}
> +
> +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    bool virt;
> +    int ret = -EINVAL;
> +    target_ulong vgein;
> +
> +    /* Translate CSR number for VS-mode */
> +    csrno = aia_xlate_vs_csrno(env, csrno);
> +
> +    /* Decode register details from CSR number */
> +    virt = false;
> +    switch (csrno) {
> +    case CSR_MSETEIPNUM:
> +    case CSR_MCLREIPNUM:
> +    case CSR_MSETEIENUM:
> +    case CSR_MCLREIENUM:
> +    case CSR_SSETEIPNUM:
> +    case CSR_SCLREIPNUM:
> +    case CSR_SSETEIENUM:
> +    case CSR_SCLREIENUM:
> +        break;
> +    case CSR_VSSETEIPNUM:
> +    case CSR_VSCLREIPNUM:
> +    case CSR_VSSETEIENUM:
> +    case CSR_VSCLREIENUM:
> +        virt = true;
> +        break;
> +    default:
> +         goto done;
> +    };
> +
> +    /* IMSIC CSRs only available when machine implements IMSIC. */
> +    if (!env->imsic_rmw_fn) {
> +        goto done;
> +    }
> +
> +    /* Find the selected guest interrupt file */
> +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> +
> +    /* Selected guest interrupt file should not be zero */
> +    if (virt && !vgein) {
> +        goto done;
> +    }
> +
> +    /* Set/Clear CSRs always read zero */
> +    ret = 0;
> +    if (val) {
> +        *val = 0;
> +    }
> +
> +done:
> +    if (ret) {
> +        return (riscv_cpu_virt_enabled(env) && virt) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +    return 0;
> +}
> +
> +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    int ret = -EINVAL;
> +    bool set, pend, virt;
> +    target_ulong priv, isel, vgein;
> +    target_ulong new_val, write_mask;
> +
> +    /* Translate CSR number for VS-mode */
> +    csrno = aia_xlate_vs_csrno(env, csrno);
> +
> +    /* Decode register details from CSR number */
> +    virt = set = pend = false;
> +    switch (csrno) {
> +    case CSR_MSETEIPNUM:
> +        priv = PRV_M;
> +        set = true;
> +        break;
> +    case CSR_MCLREIPNUM:
> +        priv = PRV_M;
> +        pend = true;
> +        break;
> +    case CSR_MSETEIENUM:
> +        priv = PRV_M;
> +        set = true;
> +        break;
> +    case CSR_MCLREIENUM:
> +        priv = PRV_M;
> +        break;
> +    case CSR_SSETEIPNUM:
> +        priv = PRV_S;
> +        set = true;
> +        pend = true;
> +        break;
> +    case CSR_SCLREIPNUM:
> +        priv = PRV_S;
> +        pend = true;
> +        break;
> +    case CSR_SSETEIENUM:
> +        priv = PRV_S;
> +        set = true;
> +        break;
> +    case CSR_SCLREIENUM:
> +        priv = PRV_S;
> +        break;
> +    case CSR_VSSETEIPNUM:
> +        priv = PRV_S;
> +        virt = true;
> +        set = true;
> +        pend = true;
> +        break;
> +    case CSR_VSCLREIPNUM:
> +        priv = PRV_S;
> +        virt = true;
> +        pend = true;
> +        break;
> +    case CSR_VSSETEIENUM:
> +        priv = PRV_S;
> +        virt = true;
> +        set = true;
> +        break;
> +    case CSR_VSCLREIENUM:
> +        priv = PRV_S;
> +        virt = true;
> +        break;
> +    default:
> +         goto done;
> +    };
> +
> +    /* IMSIC CSRs only available when machine implements IMSIC. */
> +    if (!env->imsic_rmw_fn) {
> +        goto done;
> +    }
> +
> +    /* Find target interrupt pending/enable register */
> +    if (pend) {
> +        isel = ISELECT_IMSIC_EIP0;
> +    } else {
> +        isel = ISELECT_IMSIC_EIE0;
> +    }
> +    isel += val / IMSIC_EIPx_BITS;
> +
> +    /* Find the interrupt bit to be set/clear */
> +    write_mask = 1 << (val % IMSIC_EIPx_BITS);
> +    new_val = (set) ? write_mask : 0;
> +
> +    /* Find the selected guest interrupt file */
> +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> +
> +    /* Selected guest interrupt file should not be zero */
> +    if (virt && !vgein) {
> +        goto done;
> +    }
> +
> +    /* Call machine specific IMSIC register emulation */
> +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> +                            NULL, new_val, write_mask);
> +
> +done:
> +    if (ret) {
> +        return (riscv_cpu_virt_enabled(env) && virt) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +    return 0;
> +}
> +
> +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    bool virt;
> +    int ret = -EINVAL;
> +    target_ulong priv, isel, vgein;
> +    target_ulong topei, write_mask;
> +
> +    /* Decode register details from CSR number */
> +    virt = false;
> +    switch (csrno) {
> +    case CSR_MCLAIMEI:
> +        priv = PRV_M;
> +        break;
> +    case CSR_SCLAIMEI:
> +        priv = PRV_S;
> +        virt = riscv_cpu_virt_enabled(env);
> +        break;
> +    default:
> +        goto done;
> +    };
> +
> +    /* IMSIC CSRs only available when machine implements IMSIC. */
> +    if (!env->imsic_rmw_fn) {
> +        goto done;
> +    }
> +
> +    /* Find the selected guest interrupt file */
> +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> +
> +    /* Selected guest interrupt file should not be zero */
> +    if (virt && !vgein) {
> +        goto done;
> +    }
> +
> +    /* Call machine specific IMSIC register emulation for reading TOPEI */
> +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> +                            IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein),
> +                            &topei, -1, 0);
> +    if (ret) {
> +        goto done;
> +    }
> +
> +    /* If no interrupt pending then we are done */
> +    if (!topei) {
> +        goto done;
> +    }
> +
> +    /* Find target interrupt pending register */
> +    isel = ISELECT_IMSIC_EIP0;
> +    isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS);
> +
> +    /* Find the interrupt bit to be cleared */
> +    write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS);
> +
> +    /* Call machine specific IMSIC register emulation to clear pending bit */
> +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> +                            NULL, 0, write_mask);
> +
> +    /* Update return value */
> +    if (val) {
> +        *val = topei;
> +    }
> +
> +done:
> +    if (ret) {
> +        return (riscv_cpu_virt_enabled(env) && virt) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +    return 0;
> +}
> +
> +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = (env->mideleg >> 32);
> +    return 0;
> +}
> +
> +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    uint64_t mask = delegable_ints & ~TLOWBITS64;
> +    uint64_t newval = ((uint64_t)val) << 32;
> +
> +    env->mideleg = (env->mideleg & ~mask) | (newval & mask);
>      if (riscv_has_ext(env, RVH)) {
>          env->mideleg |= VS_MODE_INTERRUPTS;
>      }
> @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
>
>  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
>  {
> -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> +    uint64_t mask = all_ints & TLOWBITS64;
> +
> +    env->mie = (env->mie & ~mask) | (val & mask);
> +    return 0;
> +}
> +
> +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = (env->mie >> 32);
> +    return 0;
> +}
> +
> +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    uint64_t mask = all_ints & ~TLOWBITS64;
> +    uint64_t newval = ((uint64_t)val) << 32;
> +
> +    env->mie = (env->mie & ~mask) | (newval & mask);
>      return 0;
>  }
>
> @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>  {
>      RISCVCPU *cpu = env_archcpu(env);
>      /* Allow software control of delegable interrupts not claimed by hardware */
> -    target_ulong mask = write_mask & delegable_ints & ~env->miclaim;
> -    uint32_t old_mip;
> +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> +                    ~env->miclaim & TLOWBITS64;
> +    uint64_t old_mip;
>
>      if (mask) {
>          old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>      return 0;
>  }
>
> +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> +                    target_ulong new_value, target_ulong write_mask)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> +                    ~env->miclaim & ~TLOWBITS64;
> +    uint64_t new_value64 = (uint64_t)new_value << 32;
> +    uint64_t old_mip;
> +
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
> +
> +    if (ret_value) {
> +        *ret_value = old_mip >> 32;
> +    }
> +
> +    return 0;
> +}
> +
>  /* Supervisor Trap Setup */
>  static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
>
>  static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64;
> +
>      /* Shift the VS bits to their S bit location in vsie */
> -    *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
> +    *val = (env->mie & mask) >> 1;
> +    return 0;
> +}
> +
> +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64;
> +
> +    /* Shift the VS bits to their S bit location in vsieh */
> +    *val = (env->mie & mask) >> (32 + 1);
>      return 0;
>  }
>
>  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
>  {
>      if (riscv_cpu_virt_enabled(env)) {
> -        read_vsie(env, CSR_VSIE, val);
> -    } else {
> -        *val = env->mie & env->mideleg;
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return read_vsie(env, CSR_VSIE, val);
>      }
> +
> +    *val = env->mie & env->mideleg;
>      return 0;
>  }
>
>  static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
>  {
> +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> +                    all_ints & TLOWBITS64;
> +
>      /* Shift the S bits to their VS bit location in mie */
> -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
> -                          ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS);
> -    return write_mie(env, CSR_MIE, newval);
> +    env->mie = (env->mie & ~mask) | ((val << 1) & mask);
> +
> +    return 0;
> +}
> +
> +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> +                    all_ints & ~TLOWBITS64;
> +    uint64_t newval = (uint64_t)val << 32;
> +
> +    /* Shift the S bits to their VS bit location in mie */
> +    env->mie = (env->mie & ~mask) | ((newval << 1) & mask);
> +
> +    return 0;
>  }
>
>  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
>  {
> +    uint64_t mask;
> +
>      if (riscv_cpu_virt_enabled(env)) {
> -        write_vsie(env, CSR_VSIE, val);
> -    } else {
> -        target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) |
> -                              (val & S_MODE_INTERRUPTS);
> -        write_mie(env, CSR_MIE, newval);
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return write_vsie(env, CSR_VSIE, val);
> +    }
> +
> +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64;
> +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> +
> +    return 0;
> +}
> +
> +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    if (riscv_cpu_virt_enabled(env)) {
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return read_vsieh(env, CSR_VSIEH, val);
> +    }
> +
> +    *val = ((env->mie & env->mideleg) >> 32);
> +    return 0;
> +}
> +
> +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    uint64_t mask, newval;
> +
> +    if (riscv_cpu_virt_enabled(env)) {
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return write_vsieh(env, CSR_VSIEH, val);
>      }
>
> +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64;
> +    newval = (uint64_t)val << 32;
> +
> +    env->mie = (env->mie & ~mask) | (newval & mask);
>      return 0;
>  }
>
> @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
>  static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>                      target_ulong new_value, target_ulong write_mask)
>  {
> -    /* Shift the S bits to their VS bit location in mip */
> -    int ret = rmw_mip(env, 0, ret_value, new_value << 1,
> -                      (write_mask << 1) & vsip_writable_mask & env->hideleg);
> -    *ret_value &= VS_MODE_INTERRUPTS;
> -    /* Shift the VS bits to their S bit location in vsip */
> -    *ret_value >>= 1;
> -    return ret;
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints &
> +                    vsip_writable_mask & env->hideleg &
> +                    ~env->miclaim & TLOWBITS64;
> +    uint64_t old_mip;
> +
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
> +
> +    if (ret_value) {
> +        *ret_value = old_mip & VS_MODE_INTERRUPTS;
> +    }
> +
> +    return 0;
> +}
> +
> +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> +                     target_ulong new_value, target_ulong write_mask)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints &
> +                    vsip_writable_mask & env->hideleg &
> +                    ~env->miclaim & ~TLOWBITS64;
> +    uint64_t new_value64 = (uint64_t)new_value << 32;
> +    uint64_t old_mip;
> +
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
> +
> +    if (ret_value) {
> +        *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32;
> +    }
> +
> +    return 0;
>  }
>
>  static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>                     target_ulong new_value, target_ulong write_mask)
>  {
> -    int ret;
> +    RISCVCPU *cpu = env_archcpu(env);
> +    uint64_t mask, old_mip;
>
>      if (riscv_cpu_virt_enabled(env)) {
> -        ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> +    }
> +
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    mask = ((uint64_t)write_mask) & delegable_ints &
> +           env->mideleg & sip_writable_mask &
> +           ~env->miclaim & TLOWBITS64;
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
>      } else {
> -        ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
> -                      write_mask & env->mideleg & sip_writable_mask);
> +        old_mip = env->mip;
>      }
>
> -    *ret_value &= env->mideleg;
> -    return ret;
> +    if (ret_value) {
> +        *ret_value = old_mip;
> +    }
> +
> +    return 0;
> +}
> +
> +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> +                    target_ulong new_value, target_ulong write_mask)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    uint64_t mask, new_value64;
> +    uint64_t old_mip;
> +
> +    if (riscv_cpu_virt_enabled(env)) {
> +        if (env->hvicontrol & HVICONTROL_VTI) {
> +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> +        }
> +        return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask);
> +    }
> +
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    mask = ((uint64_t)write_mask << 32) & delegable_ints &
> +           env->mideleg & sip_writable_mask &
> +           ~env->miclaim & ~TLOWBITS64;
> +    new_value64 = (uint64_t)new_value << 32;
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
> +
> +    if (ret_value) {
> +        *ret_value = (old_mip & env->mideleg) >> 32;
> +    }
> +
> +    return 0;
>  }
>
>  /* Supervisor Protection and Translation */
> @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
>      return 0;
>  }
>
> +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    int irq, hiid;
> +    uint8_t hiprio, iprio;
> +
> +    irq = riscv_cpu_vsirq_pending(env);
> +    if (irq <= 0 || irq > 63) {
> +       *val = 0;
> +    } else {
> +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> +       iprio = env->hviprio[irq];
> +       /* TODO: This needs to improve in specification */
> +       if (!(env->hstatus & HSTATUS_VGEIN)) {
> +           hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >>
> +                 HVICONTROL_IID_SHIFT;
> +           hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK;
> +           if (irq == hiid && hiprio) {
> +               iprio = hiprio;
> +           }
> +       }
> +       *val |= iprio;
> +    }
> +
> +    return 0;
> +}
> +
> +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    int irq;
> +
> +    if (riscv_cpu_virt_enabled(env)) {
> +        return read_vstopi(env, CSR_VSTOPI, val);
> +    }
> +
> +    irq = riscv_cpu_sirq_pending(env);
> +    if (irq <= 0 || irq > 63) {
> +       *val = 0;
> +    } else {
> +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> +       *val |= env->siprio[irq];
> +    }
> +
> +    return 0;
> +}
> +
>  /* Hypervisor Extensions */
>  static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
>      return 0;
>  }
>
> +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->hideleg >> 32;
> +    return 0;
> +}
> +
> +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    uint64_t mask = ~TLOWBITS64;
> +    uint64_t newval = ((uint64_t)val) << 32;
> +
> +    env->hideleg = (env->hideleg & ~mask) | (newval & mask);
> +
> +    return 0;
> +}
> +
>  static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>                     target_ulong new_value, target_ulong write_mask)
>  {
> -    int ret = rmw_mip(env, 0, ret_value, new_value,
> -                      write_mask & hvip_writable_mask);
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> +                    hvip_writable_mask &
> +                    ~env->miclaim & TLOWBITS64;
> +    uint64_t old_mip;
> +
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
>
> -    *ret_value &= hvip_writable_mask;
> +    if (ret_value) {
> +        *ret_value = old_mip & hvip_writable_mask;
> +    }
>
> -    return ret;
> +    return 0;
> +}
> +
> +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> +                    target_ulong new_value, target_ulong write_mask)
> +{
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> +                    hvip_writable_mask &
> +                    ~env->miclaim & ~TLOWBITS64;
> +    uint64_t new_value64 = (uint64_t)new_value << 32;
> +    uint64_t old_mip;
> +
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
> +
> +    if (ret_value) {
> +        *ret_value = (old_mip & hvip_writable_mask) >> 32;
> +    }
> +
> +    return 0;
>  }
>
>  static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
>                     target_ulong new_value, target_ulong write_mask)
>  {
> -    int ret = rmw_mip(env, 0, ret_value, new_value,
> -                      write_mask & hip_writable_mask);
> +    RISCVCPU *cpu = env_archcpu(env);
> +    /* Allow software control of delegable interrupts not claimed by hardware */
> +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> +                    hip_writable_mask &
> +                    ~env->miclaim & TLOWBITS64;
> +    uint64_t old_mip;
>
> -    *ret_value &= hip_writable_mask;
> +    if (mask) {
> +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> +    } else {
> +        old_mip = env->mip;
> +    }
>
> -    return ret;
> +    if (ret_value) {
> +        *ret_value = old_mip & hip_writable_mask;
> +    }
> +
> +    return 0;
>  }
>
>  static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
>
>  static int write_hie(CPURISCVState *env, int csrno, target_ulong val)
>  {
> -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS);
> -    return write_mie(env, CSR_MIE, newval);
> +    uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64;
> +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> +    return 0;
>  }
>
>  static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val)
> @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val)
>      return 0;
>  }
>
> +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    *val = env->hvicontrol;
> +    return 0;
> +}
> +
> +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    env->hvicontrol = val & HVICONTROL_VALID_MASK;
> +    return 0;
> +}
> +
> +static int read_hvipriox(CPURISCVState *env, int first_index,
> +                         uint8_t *iprio, target_ulong *val)
> +{
> +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> +
> +    /* First index has to be multiple of numbe of irqs per register */
> +    if (first_index % num_irqs) {
> +        return (riscv_cpu_virt_enabled(env)) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    /* Fill-up return value */
> +    *val = 0;
> +    for (i = 0; i < num_irqs; i++) {
> +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> +            continue;
> +        }
> +        if (rdzero) {
> +            continue;
> +        }
> +        *val |= ((target_ulong)iprio[irq]) << (i * 8);
> +    }
> +
> +    return 0;
> +}
> +
> +static int write_hvipriox(CPURISCVState *env, int first_index,
> +                          uint8_t *iprio, target_ulong val)
> +{
> +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> +
> +    /* First index has to be multiple of numbe of irqs per register */
> +    if (first_index % num_irqs) {
> +        return (riscv_cpu_virt_enabled(env)) ?
> +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> +    }
> +
> +    /* Fill-up priority arrary */
> +    for (i = 0; i < num_irqs; i++) {
> +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> +            continue;
> +        }
> +        if (rdzero) {
> +            iprio[irq] = 0;
> +        } else {
> +            iprio[irq] = (val >> (i * 8)) & 0xff;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    return read_hvipriox(env, 0, env->hviprio, val);
> +}
> +
> +static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    return write_hvipriox(env, 0, env->hviprio, val);
> +}
> +
> +static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    return read_hvipriox(env, 4, env->hviprio, val);
> +}
> +
> +static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    return write_hvipriox(env, 4, env->hviprio, val);
> +}
> +
> +static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    return read_hvipriox(env, 8, env->hviprio, val);
> +}
> +
> +static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    return write_hvipriox(env, 8, env->hviprio, val);
> +}
> +
> +static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val)
> +{
> +    return read_hvipriox(env, 12, env->hviprio, val);
> +}
> +
> +static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val)
> +{
> +    return write_hvipriox(env, 12, env->hviprio, val);
> +}
> +
>  /* Virtual CSR Registers */
>  static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
>  {
> @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      [CSR_MBADADDR] = { "mbadaddr", any,  read_mbadaddr, write_mbadaddr },
>      [CSR_MIP]      = { "mip",      any,  NULL,    NULL, rmw_mip        },
>
> +    /* Machine-Level Window to Indirectly Accessed Registers (AIA) */
> +    [CSR_MISELECT] = { "miselect", aia_any,   NULL, NULL,    rmw_xiselect },
> +    [CSR_MIREG]    = { "mireg",    aia_any,   NULL, NULL,    rmw_xireg },
> +
> +    /* Machine-Level Interrupts (AIA) */
> +    [CSR_MTOPI]    = { "mtopi",    aia_any,   read_mtopi },
> +
> +    /* Machine-Level IMSIC Interface (AIA) */
> +    [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_MCLAIMEI]   = { "mclaimei",   aia_any, read_xclaimei },
> +
> +    /* Machine-Level High-Half CSRs (AIA) */
> +    [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh },
> +    [CSR_MIEH]     = { "mieh",     aia_any32, read_mieh,     write_mieh     },
> +    [CSR_MIPH]     = { "miph",     aia_any32, NULL,    NULL, rmw_miph       },
> +
>      /* Supervisor Trap Setup */
>      [CSR_SSTATUS]    = { "sstatus",    smode, read_sstatus,    write_sstatus    },
>      [CSR_SIE]        = { "sie",        smode, read_sie,        write_sie        },
> @@ -1444,6 +2357,24 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      /* Supervisor Protection and Translation */
>      [CSR_SATP]     = { "satp",     smode, read_satp,    write_satp      },
>
> +    /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
> +    [CSR_SISELECT]   = { "siselect",   aia_smode, NULL, NULL, rmw_xiselect },
> +    [CSR_SIREG]      = { "sireg",      aia_smode, NULL, NULL, rmw_xireg },
> +
> +    /* Supervisor-Level Interrupts (AIA) */
> +    [CSR_STOPI]      = { "stopi",      aia_smode, read_stopi },
> +
> +    /* Supervisor-Level IMSIC Interface (AIA) */
> +    [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_SCLAIMEI]   = { "sclaimei",   aia_smode, read_xclaimei },
> +
> +    /* Supervisor-Level High-Half CSRs (AIA) */
> +    [CSR_SIEH]       = { "sieh",       aia_smode32, read_sieh,  write_sieh },
> +    [CSR_SIPH]       = { "siph",       aia_smode32, NULL, NULL, rmw_siph   },
> +
>      [CSR_HSTATUS]     = { "hstatus",     hmode,   read_hstatus,     write_hstatus     },
>      [CSR_HEDELEG]     = { "hedeleg",     hmode,   read_hedeleg,     write_hedeleg     },
>      [CSR_HIDELEG]     = { "hideleg",     hmode,   read_hideleg,     write_hideleg     },
> @@ -1472,6 +2403,32 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
>      [CSR_MTVAL2]      = { "mtval2",      hmode,   read_mtval2,      write_mtval2      },
>      [CSR_MTINST]      = { "mtinst",      hmode,   read_mtinst,      write_mtinst      },
>
> +    /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
> +    [CSR_HVICONTROL]  = { "hvicontrol",  aia_hmode, read_hvicontrol, write_hvicontrol },
> +    [CSR_HVIPRIO1]    = { "hviprio1",    aia_hmode, read_hviprio1,   write_hviprio1 },
> +    [CSR_HVIPRIO2]    = { "hviprio2",    aia_hmode, read_hviprio2,   write_hviprio2 },
> +
> +    /* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
> +    [CSR_VSISELECT]   = { "vsiselect",   aia_hmode, NULL, NULL,      rmw_xiselect },
> +    [CSR_VSIREG]      = { "vsireg",      aia_hmode, NULL, NULL,      rmw_xireg },
> +
> +    /* VS-Level Interrupts (H-extension with AIA) */
> +    [CSR_VSTOPI]      = { "vstopi",      aia_hmode, read_vstopi },
> +
> +    /* VS-Level IMSIC Interface (H-extension with AIA) */
> +    [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> +    [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> +
> +    /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
> +    [CSR_HIDELEGH]    = { "hidelegh",    aia_hmode32, read_hidelegh,  write_hidelegh },
> +    [CSR_HVIPH]       = { "hviph",       aia_hmode32, NULL, NULL,     rmw_hviph },
> +    [CSR_HVIPRIO1H]   = { "hviprio1h",   aia_hmode32, read_hviprio1h, write_hviprio1h },
> +    [CSR_HVIPRIO2H]   = { "hviprio2h",   aia_hmode32, read_hviprio2h, write_hviprio2h },
> +    [CSR_VSIEH]       = { "vsieh",       aia_hmode32, read_vsieh,     write_vsieh },
> +    [CSR_VSIPH]       = { "vsiep",       aia_hmode32, NULL, NULL,     rmw_vsiph },
> +
>      /* Physical Memory Protection */
>      [CSR_PMPCFG0]    = { "pmpcfg0",   pmp, read_pmpcfg,  write_pmpcfg  },
>      [CSR_PMPCFG1]    = { "pmpcfg1",   pmp, read_pmpcfg,  write_pmpcfg  },
> diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> index 44d4015bd6..f7fa48c240 100644
> --- a/target/riscv/machine.c
> +++ b/target/riscv/machine.c
> @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = {
>
>  static const VMStateDescription vmstate_hyper = {
>      .name = "cpu/hyper",
> -    .version_id = 1,
> -    .minimum_version_id = 1,
> +    .version_id = 2,
> +    .minimum_version_id = 2,
>      .needed = hyper_needed,
>      .fields = (VMStateField[]) {
>          VMSTATE_UINTTL(env.hstatus, RISCVCPU),
>          VMSTATE_UINTTL(env.hedeleg, RISCVCPU),
> -        VMSTATE_UINTTL(env.hideleg, RISCVCPU),
> +        VMSTATE_UINT64(env.hideleg, RISCVCPU),
>          VMSTATE_UINTTL(env.hcounteren, RISCVCPU),
>          VMSTATE_UINTTL(env.htval, RISCVCPU),
>          VMSTATE_UINTTL(env.htinst, RISCVCPU),
>          VMSTATE_UINTTL(env.hgatp, RISCVCPU),
>          VMSTATE_UINT64(env.htimedelta, RISCVCPU),
>
> +        VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
> +        VMSTATE_UINTTL(env.hvicontrol, RISCVCPU),
> +
>          VMSTATE_UINT64(env.vsstatus, RISCVCPU),
>          VMSTATE_UINTTL(env.vstvec, RISCVCPU),
>          VMSTATE_UINTTL(env.vsscratch, RISCVCPU),
> @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = {
>          VMSTATE_UINTTL(env.vscause, RISCVCPU),
>          VMSTATE_UINTTL(env.vstval, RISCVCPU),
>          VMSTATE_UINTTL(env.vsatp, RISCVCPU),
> +        VMSTATE_UINTTL(env.vsiselect, RISCVCPU),
>
>          VMSTATE_UINTTL(env.mtval2, RISCVCPU),
>          VMSTATE_UINTTL(env.mtinst, RISCVCPU),
> @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = {
>
>  const VMStateDescription vmstate_riscv_cpu = {
>      .name = "cpu",
> -    .version_id = 1,
> -    .minimum_version_id = 1,
> +    .version_id = 2,
> +    .minimum_version_id = 2,
>      .fields = (VMStateField[]) {
>          VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
>          VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
> +        VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
> +        VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
>          VMSTATE_UINTTL(env.pc, RISCVCPU),
>          VMSTATE_UINTTL(env.load_res, RISCVCPU),
>          VMSTATE_UINTTL(env.load_val, RISCVCPU),
> @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = {
>          VMSTATE_UINTTL(env.resetvec, RISCVCPU),
>          VMSTATE_UINTTL(env.mhartid, RISCVCPU),
>          VMSTATE_UINT64(env.mstatus, RISCVCPU),
> -        VMSTATE_UINTTL(env.mip, RISCVCPU),
> -        VMSTATE_UINT32(env.miclaim, RISCVCPU),
> -        VMSTATE_UINTTL(env.mie, RISCVCPU),
> -        VMSTATE_UINTTL(env.mideleg, RISCVCPU),
> +        VMSTATE_UINT64(env.mip, RISCVCPU),
> +        VMSTATE_UINT64(env.miclaim, RISCVCPU),
> +        VMSTATE_UINT64(env.mie, RISCVCPU),
> +        VMSTATE_UINT64(env.mideleg, RISCVCPU),
>          VMSTATE_UINTTL(env.sptbr, RISCVCPU),
>          VMSTATE_UINTTL(env.satp, RISCVCPU),
>          VMSTATE_UINTTL(env.sbadaddr, RISCVCPU),
> @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = {
>          VMSTATE_UINTTL(env.mepc, RISCVCPU),
>          VMSTATE_UINTTL(env.mcause, RISCVCPU),
>          VMSTATE_UINTTL(env.mtval, RISCVCPU),
> +        VMSTATE_UINTTL(env.miselect, RISCVCPU),
> +        VMSTATE_UINTTL(env.siselect, RISCVCPU),
>          VMSTATE_UINTTL(env.scounteren, RISCVCPU),
>          VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
>          VMSTATE_UINTTL(env.sscratch, RISCVCPU),
> --
> 2.25.1
>
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 4/4] hw/riscv: virt: Use AIA INTC compatible string when available
  2021-05-14 14:32   ` Anup Patel
@ 2021-06-10 23:20     ` Alistair Francis
  -1 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-10 23:20 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Sat, May 15, 2021 at 12:36 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We should use the AIA INTC compatible string in the CPU INTC
> DT nodes when the CPUs support AIA feature. This will allow
> Linux INTC driver to use AIA local interrupt CSRs.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/riscv/virt.c | 11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index c0dc69ff33..981a3a06d5 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -262,8 +262,15 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
>              qemu_fdt_add_subnode(fdt, intc_name);
>              intc_phandle = phandle++;
>              qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
> -            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
> -                "riscv,cpu-intc");
> +            if (riscv_feature(&s->soc[socket].harts[cpu].env,
> +                              RISCV_FEATURE_AIA)) {
> +                const char intcomp[] = "riscv,cpu-intc-aia\0riscv,cpu-intc";
> +                qemu_fdt_setprop(fdt, name, "compatible",
> +                    intcomp, sizeof(intcomp));
> +            } else {
> +                qemu_fdt_setprop_string(fdt, intc_name, "compatible",
> +                    "riscv,cpu-intc");
> +            }
>              qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
>              qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
>
> --
> 2.25.1
>
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 4/4] hw/riscv: virt: Use AIA INTC compatible string when available
@ 2021-06-10 23:20     ` Alistair Francis
  0 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-10 23:20 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers, Anup Patel

On Sat, May 15, 2021 at 12:36 AM Anup Patel <anup.patel@wdc.com> wrote:
>
> We should use the AIA INTC compatible string in the CPU INTC
> DT nodes when the CPUs support AIA feature. This will allow
> Linux INTC driver to use AIA local interrupt CSRs.
>
> Signed-off-by: Anup Patel <anup.patel@wdc.com>

Reviewed-by: Alistair Francis <alistair.francis@wdc.com>

Alistair

> ---
>  hw/riscv/virt.c | 11 +++++++++--
>  1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c
> index c0dc69ff33..981a3a06d5 100644
> --- a/hw/riscv/virt.c
> +++ b/hw/riscv/virt.c
> @@ -262,8 +262,15 @@ static void create_fdt(RISCVVirtState *s, const MemMapEntry *memmap,
>              qemu_fdt_add_subnode(fdt, intc_name);
>              intc_phandle = phandle++;
>              qemu_fdt_setprop_cell(fdt, intc_name, "phandle", intc_phandle);
> -            qemu_fdt_setprop_string(fdt, intc_name, "compatible",
> -                "riscv,cpu-intc");
> +            if (riscv_feature(&s->soc[socket].harts[cpu].env,
> +                              RISCV_FEATURE_AIA)) {
> +                const char intcomp[] = "riscv,cpu-intc-aia\0riscv,cpu-intc";
> +                qemu_fdt_setprop(fdt, name, "compatible",
> +                    intcomp, sizeof(intcomp));
> +            } else {
> +                qemu_fdt_setprop_string(fdt, intc_name, "compatible",
> +                    "riscv,cpu-intc");
> +            }
>              qemu_fdt_setprop(fdt, intc_name, "interrupt-controller", NULL, 0);
>              qemu_fdt_setprop_cell(fdt, intc_name, "#interrupt-cells", 1);
>
> --
> 2.25.1
>
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/4] target/riscv: Add CPU feature for AIA CSRs
  2021-06-10 23:15     ` Alistair Francis
@ 2021-06-11  4:58       ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-11  4:58 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Fri, Jun 11, 2021 at 4:46 AM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Sat, May 15, 2021 at 12:35 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > We add experimental CPU feature to enable AIA CSRs. This experimental
> > feature can be enabled by setting "x-aia=true" for CPU in the QEMU
> > command-line parameters.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  target/riscv/cpu.c | 5 +++++
> >  target/riscv/cpu.h | 4 +++-
> >  2 files changed, 8 insertions(+), 1 deletion(-)
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index 7d6ed80f6b..f3702111ae 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -414,6 +414,10 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
> >          set_feature(env, RISCV_FEATURE_PMP);
> >      }
> >
> > +    if (cpu->cfg.aia) {
> > +        set_feature(env, RISCV_FEATURE_AIA);
> > +    }
> > +
> >      set_resetvec(env, cpu->cfg.resetvec);
> >
> >      /* If only XLEN is set for misa, then set misa from properties */
> > @@ -554,6 +558,7 @@ static Property riscv_cpu_properties[] = {
> >      DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
> >      DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
> >      DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
> > +    DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false),
>
> This line should be a seperate patch at the end of the series.
>
> The idea is that we don't allow users to enable the feature until it
> has been fully implemented.

Okay, I will move this into a separate patch towards the end of the series.

Regards,
Anup

>
> Alistair
>
> >      DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
> >      DEFINE_PROP_END_OF_LIST(),
> >  };
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index 0a33d387ba..f00c60c840 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -80,7 +80,8 @@
> >  enum {
> >      RISCV_FEATURE_MMU,
> >      RISCV_FEATURE_PMP,
> > -    RISCV_FEATURE_MISA
> > +    RISCV_FEATURE_MISA,
> > +    RISCV_FEATURE_AIA
> >  };
> >
> >  #define PRIV_VERSION_1_10_0 0x00011000
> > @@ -303,6 +304,7 @@ struct RISCVCPU {
> >          uint16_t elen;
> >          bool mmu;
> >          bool pmp;
> > +        bool aia;
> >          uint64_t resetvec;
> >      } cfg;
> >  };
> > --
> > 2.25.1
> >
> >


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 2/4] target/riscv: Add CPU feature for AIA CSRs
@ 2021-06-11  4:58       ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-11  4:58 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Fri, Jun 11, 2021 at 4:46 AM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Sat, May 15, 2021 at 12:35 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > We add experimental CPU feature to enable AIA CSRs. This experimental
> > feature can be enabled by setting "x-aia=true" for CPU in the QEMU
> > command-line parameters.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  target/riscv/cpu.c | 5 +++++
> >  target/riscv/cpu.h | 4 +++-
> >  2 files changed, 8 insertions(+), 1 deletion(-)
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index 7d6ed80f6b..f3702111ae 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -414,6 +414,10 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
> >          set_feature(env, RISCV_FEATURE_PMP);
> >      }
> >
> > +    if (cpu->cfg.aia) {
> > +        set_feature(env, RISCV_FEATURE_AIA);
> > +    }
> > +
> >      set_resetvec(env, cpu->cfg.resetvec);
> >
> >      /* If only XLEN is set for misa, then set misa from properties */
> > @@ -554,6 +558,7 @@ static Property riscv_cpu_properties[] = {
> >      DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
> >      DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
> >      DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
> > +    DEFINE_PROP_BOOL("x-aia", RISCVCPU, cfg.aia, false),
>
> This line should be a seperate patch at the end of the series.
>
> The idea is that we don't allow users to enable the feature until it
> has been fully implemented.

Okay, I will move this into a separate patch towards the end of the series.

Regards,
Anup

>
> Alistair
>
> >      DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
> >      DEFINE_PROP_END_OF_LIST(),
> >  };
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index 0a33d387ba..f00c60c840 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -80,7 +80,8 @@
> >  enum {
> >      RISCV_FEATURE_MMU,
> >      RISCV_FEATURE_PMP,
> > -    RISCV_FEATURE_MISA
> > +    RISCV_FEATURE_MISA,
> > +    RISCV_FEATURE_AIA
> >  };
> >
> >  #define PRIV_VERSION_1_10_0 0x00011000
> > @@ -303,6 +304,7 @@ struct RISCVCPU {
> >          uint16_t elen;
> >          bool mmu;
> >          bool pmp;
> > +        bool aia;
> >          uint64_t resetvec;
> >      } cfg;
> >  };
> > --
> > 2.25.1
> >
> >


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
  2021-06-10 23:19     ` Alistair Francis
@ 2021-06-11  5:04       ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-11  5:04 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> > and VS-mode.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  target/riscv/cpu.c        |   27 +-
> >  target/riscv/cpu.h        |   52 +-
> >  target/riscv/cpu_helper.c |  245 ++++++++-
> >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> >  target/riscv/machine.c    |   26 +-
> >  5 files changed, 1309 insertions(+), 100 deletions(-)
>
> I feel this patch could be split up more :)

This is patch is large because I did not want to break functionality.

I try again to break this patch. At the moment, the best I can do is
to break in to two parts.
1) AIA local interrupt CSRs without IMSIC
2) Extend AIA local interrupt CSRs to support IMSIC register access

>
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index f3702111ae..795162834b 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
> >                       (target_ulong)env->vsstatus);
> >      }
> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
> >      if (riscv_has_ext(env, RVH)) {
> > -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> > +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
> >      }
> >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> >      if (riscv_has_ext(env, RVH)) {
> > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
> >
> >  static void riscv_cpu_reset(DeviceState *dev)
> >  {
> > +    uint8_t iprio;
> > +    int i, irq, rdzero;
> >      CPUState *cs = CPU(dev);
> >      RISCVCPU *cpu = RISCV_CPU(cs);
> >      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
> >      env->mcause = 0;
> >      env->pc = env->resetvec;
> >      env->two_stage_lookup = false;
> > +
> > +    /* Initialized default priorities of local interrupts. */
> > +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> > +        iprio = riscv_cpu_default_priority(i);
> > +        env->miprio[i] = iprio;
> > +        env->siprio[i] = iprio;
> > +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> > +    }
> > +    i = 0;
> > +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> > +        if (rdzero) {
> > +            env->hviprio[irq] = 0;
> > +        } else {
> > +            env->hviprio[irq] = env->miprio[irq];
> > +        }
> > +        i++;
> > +    }
> >  #endif
> >      cs->exception_index = EXCP_NONE;
> >      env->load_res = -1;
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index f00c60c840..780d3f9058 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -157,12 +157,12 @@ struct CPURISCVState {
> >       */
> >      uint64_t mstatus;
> >
> > -    target_ulong mip;
> > +    uint64_t mip;
>
> This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
> all the other existing target_ulong CSRs are the same.

When AIA is available the number of local interrupts are 64 for
both RV32 and RV64.

The width of CSRs remain same as target_ulong but we have
new CSRs for RV32 (such as mipH) for the high-half.

Also, this patch changes does not break the case when AIA
is not available (or disabled).

Regards,
Anup

>
> Alistair
>
> >
> > -    uint32_t miclaim;
> > +    uint64_t miclaim;
> >
> > -    target_ulong mie;
> > -    target_ulong mideleg;
> > +    uint64_t mie;
> > +    uint64_t mideleg;
> >
> >      target_ulong sptbr;  /* until: priv-1.9.1 */
> >      target_ulong satp;   /* since: priv-1.10.0 */
> > @@ -179,16 +179,27 @@ struct CPURISCVState {
> >      target_ulong mcause;
> >      target_ulong mtval;  /* since: priv-1.10.0 */
> >
> > +    /* AIA CSRs */
> > +    target_ulong miselect;
> > +    target_ulong siselect;
> > +
> > +    uint8_t miprio[64];
> > +    uint8_t siprio[64];
> > +
> >      /* Hypervisor CSRs */
> >      target_ulong hstatus;
> >      target_ulong hedeleg;
> > -    target_ulong hideleg;
> > +    uint64_t hideleg;
> >      target_ulong hcounteren;
> >      target_ulong htval;
> >      target_ulong htinst;
> >      target_ulong hgatp;
> >      uint64_t htimedelta;
> >
> > +    /* AIA HS-mode CSRs */
> > +    uint8_t hviprio[64];
> > +    target_ulong hvicontrol;
> > +
> >      /* Virtual CSRs */
> >      /*
> >       * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
> > @@ -202,6 +213,9 @@ struct CPURISCVState {
> >      target_ulong vstval;
> >      target_ulong vsatp;
> >
> > +    /* AIA VS-mode CSRs */
> > +    target_ulong vsiselect;
> > +
> >      target_ulong mtval2;
> >      target_ulong mtinst;
> >
> > @@ -236,6 +250,18 @@ struct CPURISCVState {
> >      uint64_t (*rdtime_fn)(uint32_t);
> >      uint32_t rdtime_fn_arg;
> >
> > +    /* machine specific AIA IMSIC read-modify-write callback */
> > +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \
> > +    ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \
> > +     (((__priv) & 0x3) << 16) | (__isel & 0xffff))
> > +#define IMSIC_REG_ISEL(__reg)                  ((__reg) & 0xffff)
> > +#define IMSIC_REG_PRIV(__reg)                  (((__reg) >> 16) & 0x3)
> > +#define IMSIC_REG_VIRT(__reg)                  (((__reg) >> 20) & 0x1)
> > +#define IMSIC_REG_VGEIN(__reg)                 (((__reg) >> 24) & 0x3f)
> > +    int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val,
> > +                        target_ulong new_val, target_ulong write_mask);
> > +    void *imsic_rmw_fn_arg;
> > +
> >      /* True if in debugger mode.  */
> >      bool debugger;
> >  #endif
> > @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
> >                                 int cpuid, void *opaque);
> >  int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
> >  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero);
> > +uint8_t riscv_cpu_default_priority(int irq);
> > +int riscv_cpu_mirq_pending(CPURISCVState *env);
> > +int riscv_cpu_sirq_pending(CPURISCVState *env);
> > +int riscv_cpu_vsirq_pending(CPURISCVState *env);
> >  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
> >  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> >  bool riscv_cpu_virt_enabled(CPURISCVState *env);
> > @@ -364,9 +395,16 @@ void riscv_cpu_list(void);
> >
> >  #ifndef CONFIG_USER_ONLY
> >  void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
> > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
> > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
> > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
> > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value);
> >  #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
> > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > +                                int (*rmw_fn)(void *arg,
> > +                                              target_ulong reg,
> > +                                              target_ulong *val,
> > +                                              target_ulong new_val,
> > +                                              target_ulong write_mask),
> > +                                void *rmw_fn_arg);
> >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> >                               uint32_t arg);
> >  #endif
> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > index 21c54ef561..5b06b4f995 100644
> > --- a/target/riscv/cpu_helper.c
> > +++ b/target/riscv/cpu_helper.c
> > @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
> >  }
> >
> >  #ifndef CONFIG_USER_ONLY
> > -static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > +
> > +/*
> > + * The HS-mode is allowed to configure priority only for the
> > + * following VS-mode local interrupts:
> > + *
> > + * 0  (Reserved interrupt, reads as zero)
> > + * 1  Supervisor software interrupt
> > + * 4  (Reserved interrupt, reads as zero)
> > + * 5  Supervisor timer interrupt
> > + * 8  (Reserved interrupt, reads as zero)
> > + * 13 (Reserved interrupt)
> > + * 14 "
> > + * 15 "
> > + * 16 "
> > + * 18 Debug/trace interrupt
> > + * 20 (Reserved interrupt)
> > + * 22 ”
> > + * 24 ”
> > + * 26 ”
> > + * 28 "
> > + * 30 (Reserved for standard reporting of bus or system errors)
> > + */
> > +
> > +static int hviprio_index2irq[] =
> > +    { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
> > +static int hviprio_index2rdzero[] =
> > +    { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> > +
> > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
> >  {
> > -    target_ulong irqs;
> > +    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
> > +        return -EINVAL;
> > +    }
> >
> > -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> > -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> > -    target_ulong hs_mstatus_sie = get_field(env->mstatus_hs, MSTATUS_SIE);
> > +    if (out_irq) {
> > +        *out_irq = hviprio_index2irq[index];
> > +    }
> > +
> > +    if (out_rdzero) {
> > +        *out_rdzero = hviprio_index2rdzero[index];
> > +    }
> >
> > -    target_ulong pending = env->mip & env->mie &
> > -                               ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > -    target_ulong vspending = (env->mip & env->mie &
> > -                              (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> > +    return 0;
> > +}
> >
> > -    target_ulong mie    = env->priv < PRV_M ||
> > -                          (env->priv == PRV_M && mstatus_mie);
> > -    target_ulong sie    = env->priv < PRV_S ||
> > -                          (env->priv == PRV_S && mstatus_sie);
> > -    target_ulong hs_sie = env->priv < PRV_S ||
> > -                          (env->priv == PRV_S && hs_mstatus_sie);
> > +uint8_t riscv_cpu_default_priority(int irq)
> > +{
> > +    int u, l;
> > +    uint8_t iprio = IPRIO_MMAXIPRIO;
> >
> > -    if (riscv_cpu_virt_enabled(env)) {
> > -        target_ulong pending_hs_irq = pending & -hs_sie;
> > +    if (irq < 0 || irq > 63) {
> > +        return iprio;
> > +    }
> >
> > -        if (pending_hs_irq) {
> > -            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> > -            return ctz64(pending_hs_irq);
> > +    /*
> > +     * Default priorities of local interrupts are defined in the
> > +     * RISC-V Advanced Interrupt Architecture specification.
> > +     *
> > +     * ----------------------------------------------------------------
> > +     *  Default  |
> > +     *  Priority | Major Interrupt Numbers
> > +     * ----------------------------------------------------------------
> > +     *  Highest  | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c),
> > +     *           | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38),
> > +     *           | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34),
> > +     *           | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30)
> > +     *           |
> > +     *           | 11 (0b),  3 (03),  7 (07)
> > +     *           |  9 (09),  1 (01),  5 (05)
> > +     *           | 12 (0c)
> > +     *           | 10 (0a),  2 (02),  6 (06)
> > +     *           |
> > +     *           | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c),
> > +     *           | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28),
> > +     *           | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24),
> > +     *  Lowest   | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20)
> > +     * ----------------------------------------------------------------
> > +     */
> > +
> > +    u = IPRIO_DEFAULT_U(irq);
> > +    l = IPRIO_DEFAULT_L(irq);
> > +    if (u == 0) {
> > +        if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER ||
> > +            irq == IRQ_VS_SOFT) {
> > +            iprio = IPRIO_DEFAULT_VS;
> > +        } else if (irq == IRQ_S_GEXT) {
> > +            iprio = IPRIO_DEFAULT_SGEXT;
> > +        } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER ||
> > +                   irq == IRQ_S_SOFT) {
> > +            iprio = IPRIO_DEFAULT_S;
> > +        } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER ||
> > +                   irq == IRQ_M_SOFT) {
> > +            iprio = IPRIO_DEFAULT_M;
> > +        } else {
> > +            iprio = IPRIO_DEFAULT_VS;
> >          }
> > +    } else if (u == 1) {
> > +        if (l < 8) {
> > +            iprio = IPRIO_DEFAULT_16_23(irq);
> > +        } else {
> > +            iprio = IPRIO_DEFAULT_24_31(irq);
> > +        }
> > +    } else if (u == 2) {
> > +        iprio = IPRIO_DEFAULT_32_47(irq);
> > +    } else if (u == 3) {
> > +        iprio = IPRIO_DEFAULT_48_63(irq);
> > +    }
> > +
> > +    return iprio;
> > +}
> > +
> > +static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> > +                                    uint64_t pending, uint8_t *iprio)
> > +{
> > +    int irq, best_irq = EXCP_NONE;
> > +    unsigned int prio, best_prio = UINT_MAX;
> >
> > -        pending = vspending;
> > +    if (!pending) {
> > +        return EXCP_NONE;
> >      }
> >
> > -    irqs = (pending & ~env->mideleg & -mie) | (pending &  env->mideleg & -sie);
> > +    irq = ctz64(pending);
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return irq;
> > +    }
> >
> > -    if (irqs) {
> > -        return ctz64(irqs); /* since non-zero */
> > +    pending = pending >> irq;
> > +    while (pending) {
> > +        prio = iprio[irq];
> > +        if (!prio) {
> > +            prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ?
> > +                   1 : IPRIO_MMAXIPRIO;
> > +        }
> > +        if ((pending & 0x1) && (prio < best_prio)) {
> > +            best_irq = irq;
> > +            best_prio = prio;
> > +        }
> > +        irq++;
> > +        pending = pending >> 1;
> > +    }
> > +
> > +    return best_irq;
> > +}
> > +
> > +int riscv_cpu_mirq_pending(CPURISCVState *env)
> > +{
> > +    uint64_t irqs = env->mip & env->mie & ~env->mideleg &
> > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +
> > +    return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > +}
> > +
> > +int riscv_cpu_sirq_pending(CPURISCVState *env)
> > +{
> > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +
> > +    return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > +}
> > +
> > +int riscv_cpu_vsirq_pending(CPURISCVState *env)
> > +{
> > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > +                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +
> > +    return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > +}
> > +
> > +static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > +{
> > +    int virq;
> > +    uint64_t irqs, mie, sie, vsie;
> > +    uint64_t pending, vspending;
> > +
> > +    /* Determine interrupt enable state of all privilege modes */
> > +    if (riscv_cpu_virt_enabled(env)) {
> > +        mie = 1;
> > +        sie = 1;
> > +        vsie = (env->priv < PRV_S) ||
> > +               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> >      } else {
> > -        return EXCP_NONE; /* indicates no pending interrupt */
> > +        mie = (env->priv < PRV_M) ||
> > +              (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
> > +        sie = (env->priv < PRV_S) ||
> > +              (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> > +        vsie = 0;
> > +    }
> > +
> > +    /* Check M-mode interrupts */
> > +    pending = env->mip & env->mie &
> > +              ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +    irqs = pending & ~env->mideleg & -mie;
> > +    if (irqs) {
> > +        return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > +    }
> > +
> > +    /* Check HS-mode interrupts */
> > +    irqs = pending & env->mideleg & -sie;
> > +    if (irqs) {
> > +        return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > +    }
> > +
> > +    /* Check VS-mode interrupts */
> > +    vspending = env->mip & env->mie &
> > +                (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +    irqs = vspending & env->hideleg & -vsie;
> > +    if (irqs) {
> > +        virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > +        return (virq <= 0) ? virq : virq + 1;
> >      }
> > +
> > +    /* Indicates no pending interrupt */
> > +    return EXCP_NONE;
> >  }
> >  #endif
> >
> > @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx)
> >      return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
> >  }
> >
> > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
> >  {
> >      CPURISCVState *env = &cpu->env;
> >      if (env->miclaim & interrupts) {
> > @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> >      }
> >  }
> >
> > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
> >  {
> >      CPURISCVState *env = &cpu->env;
> >      CPUState *cs = CPU(cpu);
> > -    uint32_t old = env->mip;
> > +    uint64_t old = env->mip;
> >      bool locked = false;
> >
> >      if (!qemu_mutex_iothread_locked()) {
> > @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> >      return old;
> >  }
> >
> > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > +                                int (*rmw_fn)(void *arg,
> > +                                              target_ulong reg,
> > +                                              target_ulong *val,
> > +                                              target_ulong new_val,
> > +                                              target_ulong write_mask),
> > +                                void *rmw_fn_arg)
> > +{
> > +    env->imsic_rmw_fn = rmw_fn;
> > +    env->imsic_rmw_fn_arg = rmw_fn_arg;
> > +}
> > +
> >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> >                               uint32_t arg)
> >  {
> > @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> >       */
> >      bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
> >      target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
> > -    target_ulong deleg = async ? env->mideleg : env->medeleg;
> > +    uint64_t deleg = async ? env->mideleg : env->medeleg;
> >      bool write_tval = false;
> >      target_ulong tval = 0;
> >      target_ulong htval = 0;
> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > index d2585395bf..3c016d7452 100644
> > --- a/target/riscv/csr.c
> > +++ b/target/riscv/csr.c
> > @@ -153,11 +153,56 @@ static int any32(CPURISCVState *env, int csrno)
> >
> >  }
> >
> > +static int aia_any(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return any(env, csrno);
> > +}
> > +
> > +static int aia_any32(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return any32(env, csrno);
> > +}
> > +
> >  static int smode(CPURISCVState *env, int csrno)
> >  {
> >      return -!riscv_has_ext(env, RVS);
> >  }
> >
> > +static int smode32(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_cpu_is_32bit(env)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return smode(env, csrno);
> > +}
> > +
> > +static int aia_smode(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return smode(env, csrno);
> > +}
> > +
> > +static int aia_smode32(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return smode32(env, csrno);
> > +}
> > +
> >  static int hmode(CPURISCVState *env, int csrno)
> >  {
> >      if (riscv_has_ext(env, RVS) &&
> > @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno)
> >  static int hmode32(CPURISCVState *env, int csrno)
> >  {
> >      if (!riscv_cpu_is_32bit(env)) {
> > -        return 0;
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return hmode(env, csrno);
> > +}
> > +
> > +static int aia_hmode(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> >      }
> >
> >      return hmode(env, csrno);
> > +}
> >
> > +static int aia_hmode32(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return hmode32(env, csrno);
> >  }
> >
> >  static int pmp(CPURISCVState *env, int csrno)
> > @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
> >
> >  /* Machine constants */
> >
> > -#define M_MODE_INTERRUPTS  (MIP_MSIP | MIP_MTIP | MIP_MEIP)
> > -#define S_MODE_INTERRUPTS  (MIP_SSIP | MIP_STIP | MIP_SEIP)
> > -#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)
> > +#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
> > +#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
> > +#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
> > +
> > +#define TLOWBITS64         ((uint64_t)((target_ulong)-1))
> >
> > -static const target_ulong delegable_ints = S_MODE_INTERRUPTS |
> > -                                           VS_MODE_INTERRUPTS;
> > -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > -                                     VS_MODE_INTERRUPTS;
> > +static const uint64_t delegable_ints = S_MODE_INTERRUPTS |
> > +                                       VS_MODE_INTERRUPTS;
> > +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > +                                 VS_MODE_INTERRUPTS;
> >  static const target_ulong delegable_excps =
> >      (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) |
> >      (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) |
> > @@ -419,10 +483,10 @@ static const target_ulong delegable_excps =
> >  static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
> >      SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
> >      SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
> > -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > -static const target_ulong hip_writable_mask = MIP_VSSIP;
> > -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > -static const target_ulong vsip_writable_mask = MIP_VSSIP;
> > +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > +static const uint64_t hip_writable_mask = MIP_VSSIP;
> > +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > +static const uint64_t vsip_writable_mask = MIP_VSSIP;
> >
> >  static const char valid_vm_1_10_32[16] = {
> >      [VM_1_10_MBARE] = 1,
> > @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val)
> >
> >  static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > -    env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
> > +    uint64_t mask = delegable_ints & TLOWBITS64;
> > +
> > +    env->mideleg = (env->mideleg & ~mask) | (val & mask);
> > +    if (riscv_has_ext(env, RVH)) {
> > +        env->mideleg |= VS_MODE_INTERRUPTS;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_cpu_virt_enabled(env)) {
> > +        return csrno;
> > +    }
> > +
> > +    switch (csrno) {
> > +    case CSR_SISELECT:
> > +        return CSR_VSISELECT;
> > +    case CSR_SIREG:
> > +        return CSR_VSIREG;
> > +    case CSR_STOPI:
> > +        return CSR_VSTOPI;
> > +    case CSR_SSETEIPNUM:
> > +        return CSR_VSSETEIPNUM;
> > +    case CSR_SCLREIPNUM:
> > +        return CSR_VSCLREIPNUM;
> > +    case CSR_SSETEIENUM:
> > +        return CSR_VSSETEIENUM;
> > +    case CSR_SCLREIENUM:
> > +        return CSR_VSCLREIENUM;
> > +    default:
> > +        return csrno;
> > +    };
> > +}
> > +
> > +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val,
> > +                        target_ulong new_val, target_ulong write_mask)
> > +{
> > +    target_ulong *iselect;
> > +
> > +    switch (csrno) {
> > +    case CSR_MISELECT:
> > +        iselect = &env->miselect;
> > +        break;
> > +    case CSR_SISELECT:
> > +        iselect = riscv_cpu_virt_enabled(env) ?
> > +                  &env->vsiselect : &env->siselect;
> > +        break;
> > +    case CSR_VSISELECT:
> > +        iselect = &env->vsiselect;
> > +        break;
> > +    default:
> > +         return -RISCV_EXCP_ILLEGAL_INST;
> > +    };
> > +
> > +    if (val) {
> > +        *val = *iselect;
> > +    }
> > +
> > +    if (write_mask) {
> > +        *iselect = (*iselect & ~write_mask) | (new_val & write_mask);
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int rmw_iprio(target_ulong iselect, uint8_t *iprio,
> > +                     target_ulong *val, target_ulong new_val,
> > +                     target_ulong write_mask)
> > +{
> > +    int i, firq, nirqs;
> > +    target_ulong old_val;
> > +
> > +    if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) {
> > +        return -EINVAL;
> > +    }
> > +#if TARGET_LONG_BITS == 64
> > +    if (iselect & 0x1) {
> > +        return -EINVAL;
> > +    }
> > +#endif
> > +
> > +    nirqs = 4 * (TARGET_LONG_BITS / 32);
> > +    firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 32)) * (nirqs);
> > +
> > +    old_val = 0;
> > +    for (i = 0; i < nirqs; i++) {
> > +        old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i);
> > +    }
> > +
> > +    if (val) {
> > +        *val = old_val;
> > +    }
> > +
> > +    if (write_mask) {
> > +        new_val = (old_val & ~write_mask) | (new_val & write_mask);
> > +        for (i = 0; i < nirqs; i++) {
> > +            iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff;
> > +        }
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
> > +                     target_ulong new_val, target_ulong write_mask)
> > +{
> > +    bool virt;
> > +    uint8_t *iprio;
> > +    int ret = -EINVAL;
> > +    target_ulong priv, isel, vgein;
> > +
> > +    /* Translate CSR number for VS-mode */
> > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > +
> > +    /* Decode register details from CSR number */
> > +    virt = false;
> > +    switch (csrno) {
> > +    case CSR_MIREG:
> > +        iprio = env->miprio;
> > +        isel = env->miselect;
> > +        priv = PRV_M;
> > +        break;
> > +    case CSR_SIREG:
> > +        iprio = env->siprio;
> > +        isel = env->siselect;
> > +        priv = PRV_S;
> > +        break;
> > +    case CSR_VSIREG:
> > +        iprio = env->hviprio;
> > +        isel = env->vsiselect;
> > +        priv = PRV_S;
> > +        virt = true;
> > +        break;
> > +    default:
> > +         goto done;
> > +    };
> > +
> > +    /* Find the selected guest interrupt file */
> > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > +
> > +    if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) {
> > +        /* Local interrupt priority registers not available for VS-mode */
> > +        if (!virt) {
> > +            ret = rmw_iprio(isel, iprio, val, new_val, write_mask);
> > +        }
> > +    } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) {
> > +        /* IMSIC registers only available when machine implements it. */
> > +        if (env->imsic_rmw_fn) {
> > +            /* Selected guest interrupt file should not be zero */
> > +            if (virt && !vgein) {
> > +                goto done;
> > +            }
> > +            /* Call machine specific IMSIC register emulation */
> > +            ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > +                                    IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > +                                    val, new_val, write_mask);
> > +        }
> > +    }
> > +
> > +done:
> > +    if (ret) {
> > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    int irq;
> > +
> > +    irq = riscv_cpu_mirq_pending(env);
> > +    if (irq <= 0 || irq > 63) {
> > +       *val = 0;
> > +    } else {
> > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > +       *val |= env->miprio[irq];
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    bool virt;
> > +    int ret = -EINVAL;
> > +    target_ulong vgein;
> > +
> > +    /* Translate CSR number for VS-mode */
> > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > +
> > +    /* Decode register details from CSR number */
> > +    virt = false;
> > +    switch (csrno) {
> > +    case CSR_MSETEIPNUM:
> > +    case CSR_MCLREIPNUM:
> > +    case CSR_MSETEIENUM:
> > +    case CSR_MCLREIENUM:
> > +    case CSR_SSETEIPNUM:
> > +    case CSR_SCLREIPNUM:
> > +    case CSR_SSETEIENUM:
> > +    case CSR_SCLREIENUM:
> > +        break;
> > +    case CSR_VSSETEIPNUM:
> > +    case CSR_VSCLREIPNUM:
> > +    case CSR_VSSETEIENUM:
> > +    case CSR_VSCLREIENUM:
> > +        virt = true;
> > +        break;
> > +    default:
> > +         goto done;
> > +    };
> > +
> > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > +    if (!env->imsic_rmw_fn) {
> > +        goto done;
> > +    }
> > +
> > +    /* Find the selected guest interrupt file */
> > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > +
> > +    /* Selected guest interrupt file should not be zero */
> > +    if (virt && !vgein) {
> > +        goto done;
> > +    }
> > +
> > +    /* Set/Clear CSRs always read zero */
> > +    ret = 0;
> > +    if (val) {
> > +        *val = 0;
> > +    }
> > +
> > +done:
> > +    if (ret) {
> > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    int ret = -EINVAL;
> > +    bool set, pend, virt;
> > +    target_ulong priv, isel, vgein;
> > +    target_ulong new_val, write_mask;
> > +
> > +    /* Translate CSR number for VS-mode */
> > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > +
> > +    /* Decode register details from CSR number */
> > +    virt = set = pend = false;
> > +    switch (csrno) {
> > +    case CSR_MSETEIPNUM:
> > +        priv = PRV_M;
> > +        set = true;
> > +        break;
> > +    case CSR_MCLREIPNUM:
> > +        priv = PRV_M;
> > +        pend = true;
> > +        break;
> > +    case CSR_MSETEIENUM:
> > +        priv = PRV_M;
> > +        set = true;
> > +        break;
> > +    case CSR_MCLREIENUM:
> > +        priv = PRV_M;
> > +        break;
> > +    case CSR_SSETEIPNUM:
> > +        priv = PRV_S;
> > +        set = true;
> > +        pend = true;
> > +        break;
> > +    case CSR_SCLREIPNUM:
> > +        priv = PRV_S;
> > +        pend = true;
> > +        break;
> > +    case CSR_SSETEIENUM:
> > +        priv = PRV_S;
> > +        set = true;
> > +        break;
> > +    case CSR_SCLREIENUM:
> > +        priv = PRV_S;
> > +        break;
> > +    case CSR_VSSETEIPNUM:
> > +        priv = PRV_S;
> > +        virt = true;
> > +        set = true;
> > +        pend = true;
> > +        break;
> > +    case CSR_VSCLREIPNUM:
> > +        priv = PRV_S;
> > +        virt = true;
> > +        pend = true;
> > +        break;
> > +    case CSR_VSSETEIENUM:
> > +        priv = PRV_S;
> > +        virt = true;
> > +        set = true;
> > +        break;
> > +    case CSR_VSCLREIENUM:
> > +        priv = PRV_S;
> > +        virt = true;
> > +        break;
> > +    default:
> > +         goto done;
> > +    };
> > +
> > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > +    if (!env->imsic_rmw_fn) {
> > +        goto done;
> > +    }
> > +
> > +    /* Find target interrupt pending/enable register */
> > +    if (pend) {
> > +        isel = ISELECT_IMSIC_EIP0;
> > +    } else {
> > +        isel = ISELECT_IMSIC_EIE0;
> > +    }
> > +    isel += val / IMSIC_EIPx_BITS;
> > +
> > +    /* Find the interrupt bit to be set/clear */
> > +    write_mask = 1 << (val % IMSIC_EIPx_BITS);
> > +    new_val = (set) ? write_mask : 0;
> > +
> > +    /* Find the selected guest interrupt file */
> > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > +
> > +    /* Selected guest interrupt file should not be zero */
> > +    if (virt && !vgein) {
> > +        goto done;
> > +    }
> > +
> > +    /* Call machine specific IMSIC register emulation */
> > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > +                            NULL, new_val, write_mask);
> > +
> > +done:
> > +    if (ret) {
> > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    bool virt;
> > +    int ret = -EINVAL;
> > +    target_ulong priv, isel, vgein;
> > +    target_ulong topei, write_mask;
> > +
> > +    /* Decode register details from CSR number */
> > +    virt = false;
> > +    switch (csrno) {
> > +    case CSR_MCLAIMEI:
> > +        priv = PRV_M;
> > +        break;
> > +    case CSR_SCLAIMEI:
> > +        priv = PRV_S;
> > +        virt = riscv_cpu_virt_enabled(env);
> > +        break;
> > +    default:
> > +        goto done;
> > +    };
> > +
> > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > +    if (!env->imsic_rmw_fn) {
> > +        goto done;
> > +    }
> > +
> > +    /* Find the selected guest interrupt file */
> > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > +
> > +    /* Selected guest interrupt file should not be zero */
> > +    if (virt && !vgein) {
> > +        goto done;
> > +    }
> > +
> > +    /* Call machine specific IMSIC register emulation for reading TOPEI */
> > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > +                            IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein),
> > +                            &topei, -1, 0);
> > +    if (ret) {
> > +        goto done;
> > +    }
> > +
> > +    /* If no interrupt pending then we are done */
> > +    if (!topei) {
> > +        goto done;
> > +    }
> > +
> > +    /* Find target interrupt pending register */
> > +    isel = ISELECT_IMSIC_EIP0;
> > +    isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS);
> > +
> > +    /* Find the interrupt bit to be cleared */
> > +    write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS);
> > +
> > +    /* Call machine specific IMSIC register emulation to clear pending bit */
> > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > +                            NULL, 0, write_mask);
> > +
> > +    /* Update return value */
> > +    if (val) {
> > +        *val = topei;
> > +    }
> > +
> > +done:
> > +    if (ret) {
> > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    *val = (env->mideleg >> 32);
> > +    return 0;
> > +}
> > +
> > +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    uint64_t mask = delegable_ints & ~TLOWBITS64;
> > +    uint64_t newval = ((uint64_t)val) << 32;
> > +
> > +    env->mideleg = (env->mideleg & ~mask) | (newval & mask);
> >      if (riscv_has_ext(env, RVH)) {
> >          env->mideleg |= VS_MODE_INTERRUPTS;
> >      }
> > @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
> >
> >  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> > +    uint64_t mask = all_ints & TLOWBITS64;
> > +
> > +    env->mie = (env->mie & ~mask) | (val & mask);
> > +    return 0;
> > +}
> > +
> > +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    *val = (env->mie >> 32);
> > +    return 0;
> > +}
> > +
> > +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    uint64_t mask = all_ints & ~TLOWBITS64;
> > +    uint64_t newval = ((uint64_t)val) << 32;
> > +
> > +    env->mie = (env->mie & ~mask) | (newval & mask);
> >      return 0;
> >  }
> >
> > @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >  {
> >      RISCVCPU *cpu = env_archcpu(env);
> >      /* Allow software control of delegable interrupts not claimed by hardware */
> > -    target_ulong mask = write_mask & delegable_ints & ~env->miclaim;
> > -    uint32_t old_mip;
> > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > +                    ~env->miclaim & TLOWBITS64;
> > +    uint64_t old_mip;
> >
> >      if (mask) {
> >          old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >      return 0;
> >  }
> >
> > +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > +                    target_ulong new_value, target_ulong write_mask)
> > +{
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > +                    ~env->miclaim & ~TLOWBITS64;
> > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > +    uint64_t old_mip;
> > +
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> > +
> > +    if (ret_value) {
> > +        *ret_value = old_mip >> 32;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> >  /* Supervisor Trap Setup */
> >  static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> > @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
> >
> >  static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64;
> > +
> >      /* Shift the VS bits to their S bit location in vsie */
> > -    *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
> > +    *val = (env->mie & mask) >> 1;
> > +    return 0;
> > +}
> > +
> > +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64;
> > +
> > +    /* Shift the VS bits to their S bit location in vsieh */
> > +    *val = (env->mie & mask) >> (32 + 1);
> >      return 0;
> >  }
> >
> >  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> >      if (riscv_cpu_virt_enabled(env)) {
> > -        read_vsie(env, CSR_VSIE, val);
> > -    } else {
> > -        *val = env->mie & env->mideleg;
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return read_vsie(env, CSR_VSIE, val);
> >      }
> > +
> > +    *val = env->mie & env->mideleg;
> >      return 0;
> >  }
> >
> >  static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > +                    all_ints & TLOWBITS64;
> > +
> >      /* Shift the S bits to their VS bit location in mie */
> > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
> > -                          ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS);
> > -    return write_mie(env, CSR_MIE, newval);
> > +    env->mie = (env->mie & ~mask) | ((val << 1) & mask);
> > +
> > +    return 0;
> > +}
> > +
> > +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > +                    all_ints & ~TLOWBITS64;
> > +    uint64_t newval = (uint64_t)val << 32;
> > +
> > +    /* Shift the S bits to their VS bit location in mie */
> > +    env->mie = (env->mie & ~mask) | ((newval << 1) & mask);
> > +
> > +    return 0;
> >  }
> >
> >  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > +    uint64_t mask;
> > +
> >      if (riscv_cpu_virt_enabled(env)) {
> > -        write_vsie(env, CSR_VSIE, val);
> > -    } else {
> > -        target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) |
> > -                              (val & S_MODE_INTERRUPTS);
> > -        write_mie(env, CSR_MIE, newval);
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return write_vsie(env, CSR_VSIE, val);
> > +    }
> > +
> > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64;
> > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > +
> > +    return 0;
> > +}
> > +
> > +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    if (riscv_cpu_virt_enabled(env)) {
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return read_vsieh(env, CSR_VSIEH, val);
> > +    }
> > +
> > +    *val = ((env->mie & env->mideleg) >> 32);
> > +    return 0;
> > +}
> > +
> > +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    uint64_t mask, newval;
> > +
> > +    if (riscv_cpu_virt_enabled(env)) {
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return write_vsieh(env, CSR_VSIEH, val);
> >      }
> >
> > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64;
> > +    newval = (uint64_t)val << 32;
> > +
> > +    env->mie = (env->mie & ~mask) | (newval & mask);
> >      return 0;
> >  }
> >
> > @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
> >  static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >                      target_ulong new_value, target_ulong write_mask)
> >  {
> > -    /* Shift the S bits to their VS bit location in mip */
> > -    int ret = rmw_mip(env, 0, ret_value, new_value << 1,
> > -                      (write_mask << 1) & vsip_writable_mask & env->hideleg);
> > -    *ret_value &= VS_MODE_INTERRUPTS;
> > -    /* Shift the VS bits to their S bit location in vsip */
> > -    *ret_value >>= 1;
> > -    return ret;
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints &
> > +                    vsip_writable_mask & env->hideleg &
> > +                    ~env->miclaim & TLOWBITS64;
> > +    uint64_t old_mip;
> > +
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> > +
> > +    if (ret_value) {
> > +        *ret_value = old_mip & VS_MODE_INTERRUPTS;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > +                     target_ulong new_value, target_ulong write_mask)
> > +{
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints &
> > +                    vsip_writable_mask & env->hideleg &
> > +                    ~env->miclaim & ~TLOWBITS64;
> > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > +    uint64_t old_mip;
> > +
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> > +
> > +    if (ret_value) {
> > +        *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32;
> > +    }
> > +
> > +    return 0;
> >  }
> >
> >  static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >                     target_ulong new_value, target_ulong write_mask)
> >  {
> > -    int ret;
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    uint64_t mask, old_mip;
> >
> >      if (riscv_cpu_virt_enabled(env)) {
> > -        ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > +    }
> > +
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    mask = ((uint64_t)write_mask) & delegable_ints &
> > +           env->mideleg & sip_writable_mask &
> > +           ~env->miclaim & TLOWBITS64;
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> >      } else {
> > -        ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
> > -                      write_mask & env->mideleg & sip_writable_mask);
> > +        old_mip = env->mip;
> >      }
> >
> > -    *ret_value &= env->mideleg;
> > -    return ret;
> > +    if (ret_value) {
> > +        *ret_value = old_mip;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > +                    target_ulong new_value, target_ulong write_mask)
> > +{
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    uint64_t mask, new_value64;
> > +    uint64_t old_mip;
> > +
> > +    if (riscv_cpu_virt_enabled(env)) {
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask);
> > +    }
> > +
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > +           env->mideleg & sip_writable_mask &
> > +           ~env->miclaim & ~TLOWBITS64;
> > +    new_value64 = (uint64_t)new_value << 32;
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> > +
> > +    if (ret_value) {
> > +        *ret_value = (old_mip & env->mideleg) >> 32;
> > +    }
> > +
> > +    return 0;
> >  }
> >
> >  /* Supervisor Protection and Translation */
> > @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
> >      return 0;
> >  }
> >
> > +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    int irq, hiid;
> > +    uint8_t hiprio, iprio;
> > +
> > +    irq = riscv_cpu_vsirq_pending(env);
> > +    if (irq <= 0 || irq > 63) {
> > +       *val = 0;
> > +    } else {
> > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > +       iprio = env->hviprio[irq];
> > +       /* TODO: This needs to improve in specification */
> > +       if (!(env->hstatus & HSTATUS_VGEIN)) {
> > +           hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >>
> > +                 HVICONTROL_IID_SHIFT;
> > +           hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK;
> > +           if (irq == hiid && hiprio) {
> > +               iprio = hiprio;
> > +           }
> > +       }
> > +       *val |= iprio;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    int irq;
> > +
> > +    if (riscv_cpu_virt_enabled(env)) {
> > +        return read_vstopi(env, CSR_VSTOPI, val);
> > +    }
> > +
> > +    irq = riscv_cpu_sirq_pending(env);
> > +    if (irq <= 0 || irq > 63) {
> > +       *val = 0;
> > +    } else {
> > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > +       *val |= env->siprio[irq];
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> >  /* Hypervisor Extensions */
> >  static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> > @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
> >      return 0;
> >  }
> >
> > +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    *val = env->hideleg >> 32;
> > +    return 0;
> > +}
> > +
> > +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    uint64_t mask = ~TLOWBITS64;
> > +    uint64_t newval = ((uint64_t)val) << 32;
> > +
> > +    env->hideleg = (env->hideleg & ~mask) | (newval & mask);
> > +
> > +    return 0;
> > +}
> > +
> >  static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >                     target_ulong new_value, target_ulong write_mask)
> >  {
> > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > -                      write_mask & hvip_writable_mask);
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > +                    hvip_writable_mask &
> > +                    ~env->miclaim & TLOWBITS64;
> > +    uint64_t old_mip;
> > +
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> >
> > -    *ret_value &= hvip_writable_mask;
> > +    if (ret_value) {
> > +        *ret_value = old_mip & hvip_writable_mask;
> > +    }
> >
> > -    return ret;
> > +    return 0;
> > +}
> > +
> > +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > +                    target_ulong new_value, target_ulong write_mask)
> > +{
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > +                    hvip_writable_mask &
> > +                    ~env->miclaim & ~TLOWBITS64;
> > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > +    uint64_t old_mip;
> > +
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> > +
> > +    if (ret_value) {
> > +        *ret_value = (old_mip & hvip_writable_mask) >> 32;
> > +    }
> > +
> > +    return 0;
> >  }
> >
> >  static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >                     target_ulong new_value, target_ulong write_mask)
> >  {
> > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > -                      write_mask & hip_writable_mask);
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > +                    hip_writable_mask &
> > +                    ~env->miclaim & TLOWBITS64;
> > +    uint64_t old_mip;
> >
> > -    *ret_value &= hip_writable_mask;
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> >
> > -    return ret;
> > +    if (ret_value) {
> > +        *ret_value = old_mip & hip_writable_mask;
> > +    }
> > +
> > +    return 0;
> >  }
> >
> >  static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> > @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> >
> >  static int write_hie(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS);
> > -    return write_mie(env, CSR_MIE, newval);
> > +    uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64;
> > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > +    return 0;
> >  }
> >
> >  static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val)
> > @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val)
> >      return 0;
> >  }
> >
> > +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    *val = env->hvicontrol;
> > +    return 0;
> > +}
> > +
> > +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    env->hvicontrol = val & HVICONTROL_VALID_MASK;
> > +    return 0;
> > +}
> > +
> > +static int read_hvipriox(CPURISCVState *env, int first_index,
> > +                         uint8_t *iprio, target_ulong *val)
> > +{
> > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > +
> > +    /* First index has to be multiple of numbe of irqs per register */
> > +    if (first_index % num_irqs) {
> > +        return (riscv_cpu_virt_enabled(env)) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    /* Fill-up return value */
> > +    *val = 0;
> > +    for (i = 0; i < num_irqs; i++) {
> > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > +            continue;
> > +        }
> > +        if (rdzero) {
> > +            continue;
> > +        }
> > +        *val |= ((target_ulong)iprio[irq]) << (i * 8);
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int write_hvipriox(CPURISCVState *env, int first_index,
> > +                          uint8_t *iprio, target_ulong val)
> > +{
> > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > +
> > +    /* First index has to be multiple of numbe of irqs per register */
> > +    if (first_index % num_irqs) {
> > +        return (riscv_cpu_virt_enabled(env)) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    /* Fill-up priority arrary */
> > +    for (i = 0; i < num_irqs; i++) {
> > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > +            continue;
> > +        }
> > +        if (rdzero) {
> > +            iprio[irq] = 0;
> > +        } else {
> > +            iprio[irq] = (val >> (i * 8)) & 0xff;
> > +        }
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    return read_hvipriox(env, 0, env->hviprio, val);
> > +}
> > +
> > +static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    return write_hvipriox(env, 0, env->hviprio, val);
> > +}
> > +
> > +static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    return read_hvipriox(env, 4, env->hviprio, val);
> > +}
> > +
> > +static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    return write_hvipriox(env, 4, env->hviprio, val);
> > +}
> > +
> > +static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    return read_hvipriox(env, 8, env->hviprio, val);
> > +}
> > +
> > +static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    return write_hvipriox(env, 8, env->hviprio, val);
> > +}
> > +
> > +static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    return read_hvipriox(env, 12, env->hviprio, val);
> > +}
> > +
> > +static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    return write_hvipriox(env, 12, env->hviprio, val);
> > +}
> > +
> >  /* Virtual CSR Registers */
> >  static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> > @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> >      [CSR_MBADADDR] = { "mbadaddr", any,  read_mbadaddr, write_mbadaddr },
> >      [CSR_MIP]      = { "mip",      any,  NULL,    NULL, rmw_mip        },
> >
> > +    /* Machine-Level Window to Indirectly Accessed Registers (AIA) */
> > +    [CSR_MISELECT] = { "miselect", aia_any,   NULL, NULL,    rmw_xiselect },
> > +    [CSR_MIREG]    = { "mireg",    aia_any,   NULL, NULL,    rmw_xireg },
> > +
> > +    /* Machine-Level Interrupts (AIA) */
> > +    [CSR_MTOPI]    = { "mtopi",    aia_any,   read_mtopi },
> > +
> > +    /* Machine-Level IMSIC Interface (AIA) */
> > +    [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_MCLAIMEI]   = { "mclaimei",   aia_any, read_xclaimei },
> > +
> > +    /* Machine-Level High-Half CSRs (AIA) */
> > +    [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh },
> > +    [CSR_MIEH]     = { "mieh",     aia_any32, read_mieh,     write_mieh     },
> > +    [CSR_MIPH]     = { "miph",     aia_any32, NULL,    NULL, rmw_miph       },
> > +
> >      /* Supervisor Trap Setup */
> >      [CSR_SSTATUS]    = { "sstatus",    smode, read_sstatus,    write_sstatus    },
> >      [CSR_SIE]        = { "sie",        smode, read_sie,        write_sie        },
> > @@ -1444,6 +2357,24 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> >      /* Supervisor Protection and Translation */
> >      [CSR_SATP]     = { "satp",     smode, read_satp,    write_satp      },
> >
> > +    /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
> > +    [CSR_SISELECT]   = { "siselect",   aia_smode, NULL, NULL, rmw_xiselect },
> > +    [CSR_SIREG]      = { "sireg",      aia_smode, NULL, NULL, rmw_xireg },
> > +
> > +    /* Supervisor-Level Interrupts (AIA) */
> > +    [CSR_STOPI]      = { "stopi",      aia_smode, read_stopi },
> > +
> > +    /* Supervisor-Level IMSIC Interface (AIA) */
> > +    [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_SCLAIMEI]   = { "sclaimei",   aia_smode, read_xclaimei },
> > +
> > +    /* Supervisor-Level High-Half CSRs (AIA) */
> > +    [CSR_SIEH]       = { "sieh",       aia_smode32, read_sieh,  write_sieh },
> > +    [CSR_SIPH]       = { "siph",       aia_smode32, NULL, NULL, rmw_siph   },
> > +
> >      [CSR_HSTATUS]     = { "hstatus",     hmode,   read_hstatus,     write_hstatus     },
> >      [CSR_HEDELEG]     = { "hedeleg",     hmode,   read_hedeleg,     write_hedeleg     },
> >      [CSR_HIDELEG]     = { "hideleg",     hmode,   read_hideleg,     write_hideleg     },
> > @@ -1472,6 +2403,32 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> >      [CSR_MTVAL2]      = { "mtval2",      hmode,   read_mtval2,      write_mtval2      },
> >      [CSR_MTINST]      = { "mtinst",      hmode,   read_mtinst,      write_mtinst      },
> >
> > +    /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
> > +    [CSR_HVICONTROL]  = { "hvicontrol",  aia_hmode, read_hvicontrol, write_hvicontrol },
> > +    [CSR_HVIPRIO1]    = { "hviprio1",    aia_hmode, read_hviprio1,   write_hviprio1 },
> > +    [CSR_HVIPRIO2]    = { "hviprio2",    aia_hmode, read_hviprio2,   write_hviprio2 },
> > +
> > +    /* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
> > +    [CSR_VSISELECT]   = { "vsiselect",   aia_hmode, NULL, NULL,      rmw_xiselect },
> > +    [CSR_VSIREG]      = { "vsireg",      aia_hmode, NULL, NULL,      rmw_xireg },
> > +
> > +    /* VS-Level Interrupts (H-extension with AIA) */
> > +    [CSR_VSTOPI]      = { "vstopi",      aia_hmode, read_vstopi },
> > +
> > +    /* VS-Level IMSIC Interface (H-extension with AIA) */
> > +    [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > +
> > +    /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
> > +    [CSR_HIDELEGH]    = { "hidelegh",    aia_hmode32, read_hidelegh,  write_hidelegh },
> > +    [CSR_HVIPH]       = { "hviph",       aia_hmode32, NULL, NULL,     rmw_hviph },
> > +    [CSR_HVIPRIO1H]   = { "hviprio1h",   aia_hmode32, read_hviprio1h, write_hviprio1h },
> > +    [CSR_HVIPRIO2H]   = { "hviprio2h",   aia_hmode32, read_hviprio2h, write_hviprio2h },
> > +    [CSR_VSIEH]       = { "vsieh",       aia_hmode32, read_vsieh,     write_vsieh },
> > +    [CSR_VSIPH]       = { "vsiep",       aia_hmode32, NULL, NULL,     rmw_vsiph },
> > +
> >      /* Physical Memory Protection */
> >      [CSR_PMPCFG0]    = { "pmpcfg0",   pmp, read_pmpcfg,  write_pmpcfg  },
> >      [CSR_PMPCFG1]    = { "pmpcfg1",   pmp, read_pmpcfg,  write_pmpcfg  },
> > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> > index 44d4015bd6..f7fa48c240 100644
> > --- a/target/riscv/machine.c
> > +++ b/target/riscv/machine.c
> > @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = {
> >
> >  static const VMStateDescription vmstate_hyper = {
> >      .name = "cpu/hyper",
> > -    .version_id = 1,
> > -    .minimum_version_id = 1,
> > +    .version_id = 2,
> > +    .minimum_version_id = 2,
> >      .needed = hyper_needed,
> >      .fields = (VMStateField[]) {
> >          VMSTATE_UINTTL(env.hstatus, RISCVCPU),
> >          VMSTATE_UINTTL(env.hedeleg, RISCVCPU),
> > -        VMSTATE_UINTTL(env.hideleg, RISCVCPU),
> > +        VMSTATE_UINT64(env.hideleg, RISCVCPU),
> >          VMSTATE_UINTTL(env.hcounteren, RISCVCPU),
> >          VMSTATE_UINTTL(env.htval, RISCVCPU),
> >          VMSTATE_UINTTL(env.htinst, RISCVCPU),
> >          VMSTATE_UINTTL(env.hgatp, RISCVCPU),
> >          VMSTATE_UINT64(env.htimedelta, RISCVCPU),
> >
> > +        VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
> > +        VMSTATE_UINTTL(env.hvicontrol, RISCVCPU),
> > +
> >          VMSTATE_UINT64(env.vsstatus, RISCVCPU),
> >          VMSTATE_UINTTL(env.vstvec, RISCVCPU),
> >          VMSTATE_UINTTL(env.vsscratch, RISCVCPU),
> > @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = {
> >          VMSTATE_UINTTL(env.vscause, RISCVCPU),
> >          VMSTATE_UINTTL(env.vstval, RISCVCPU),
> >          VMSTATE_UINTTL(env.vsatp, RISCVCPU),
> > +        VMSTATE_UINTTL(env.vsiselect, RISCVCPU),
> >
> >          VMSTATE_UINTTL(env.mtval2, RISCVCPU),
> >          VMSTATE_UINTTL(env.mtinst, RISCVCPU),
> > @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = {
> >
> >  const VMStateDescription vmstate_riscv_cpu = {
> >      .name = "cpu",
> > -    .version_id = 1,
> > -    .minimum_version_id = 1,
> > +    .version_id = 2,
> > +    .minimum_version_id = 2,
> >      .fields = (VMStateField[]) {
> >          VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
> >          VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
> > +        VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
> > +        VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
> >          VMSTATE_UINTTL(env.pc, RISCVCPU),
> >          VMSTATE_UINTTL(env.load_res, RISCVCPU),
> >          VMSTATE_UINTTL(env.load_val, RISCVCPU),
> > @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = {
> >          VMSTATE_UINTTL(env.resetvec, RISCVCPU),
> >          VMSTATE_UINTTL(env.mhartid, RISCVCPU),
> >          VMSTATE_UINT64(env.mstatus, RISCVCPU),
> > -        VMSTATE_UINTTL(env.mip, RISCVCPU),
> > -        VMSTATE_UINT32(env.miclaim, RISCVCPU),
> > -        VMSTATE_UINTTL(env.mie, RISCVCPU),
> > -        VMSTATE_UINTTL(env.mideleg, RISCVCPU),
> > +        VMSTATE_UINT64(env.mip, RISCVCPU),
> > +        VMSTATE_UINT64(env.miclaim, RISCVCPU),
> > +        VMSTATE_UINT64(env.mie, RISCVCPU),
> > +        VMSTATE_UINT64(env.mideleg, RISCVCPU),
> >          VMSTATE_UINTTL(env.sptbr, RISCVCPU),
> >          VMSTATE_UINTTL(env.satp, RISCVCPU),
> >          VMSTATE_UINTTL(env.sbadaddr, RISCVCPU),
> > @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = {
> >          VMSTATE_UINTTL(env.mepc, RISCVCPU),
> >          VMSTATE_UINTTL(env.mcause, RISCVCPU),
> >          VMSTATE_UINTTL(env.mtval, RISCVCPU),
> > +        VMSTATE_UINTTL(env.miselect, RISCVCPU),
> > +        VMSTATE_UINTTL(env.siselect, RISCVCPU),
> >          VMSTATE_UINTTL(env.scounteren, RISCVCPU),
> >          VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
> >          VMSTATE_UINTTL(env.sscratch, RISCVCPU),
> > --
> > 2.25.1
> >
> >


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
@ 2021-06-11  5:04       ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-11  5:04 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> > and VS-mode.
> >
> > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > ---
> >  target/riscv/cpu.c        |   27 +-
> >  target/riscv/cpu.h        |   52 +-
> >  target/riscv/cpu_helper.c |  245 ++++++++-
> >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> >  target/riscv/machine.c    |   26 +-
> >  5 files changed, 1309 insertions(+), 100 deletions(-)
>
> I feel this patch could be split up more :)

This is patch is large because I did not want to break functionality.

I try again to break this patch. At the moment, the best I can do is
to break in to two parts.
1) AIA local interrupt CSRs without IMSIC
2) Extend AIA local interrupt CSRs to support IMSIC register access

>
> >
> > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > index f3702111ae..795162834b 100644
> > --- a/target/riscv/cpu.c
> > +++ b/target/riscv/cpu.c
> > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
> >                       (target_ulong)env->vsstatus);
> >      }
> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
> >      if (riscv_has_ext(env, RVH)) {
> > -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> > +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
> >      }
> >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> >      if (riscv_has_ext(env, RVH)) {
> > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
> >
> >  static void riscv_cpu_reset(DeviceState *dev)
> >  {
> > +    uint8_t iprio;
> > +    int i, irq, rdzero;
> >      CPUState *cs = CPU(dev);
> >      RISCVCPU *cpu = RISCV_CPU(cs);
> >      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
> >      env->mcause = 0;
> >      env->pc = env->resetvec;
> >      env->two_stage_lookup = false;
> > +
> > +    /* Initialized default priorities of local interrupts. */
> > +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> > +        iprio = riscv_cpu_default_priority(i);
> > +        env->miprio[i] = iprio;
> > +        env->siprio[i] = iprio;
> > +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> > +    }
> > +    i = 0;
> > +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> > +        if (rdzero) {
> > +            env->hviprio[irq] = 0;
> > +        } else {
> > +            env->hviprio[irq] = env->miprio[irq];
> > +        }
> > +        i++;
> > +    }
> >  #endif
> >      cs->exception_index = EXCP_NONE;
> >      env->load_res = -1;
> > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > index f00c60c840..780d3f9058 100644
> > --- a/target/riscv/cpu.h
> > +++ b/target/riscv/cpu.h
> > @@ -157,12 +157,12 @@ struct CPURISCVState {
> >       */
> >      uint64_t mstatus;
> >
> > -    target_ulong mip;
> > +    uint64_t mip;
>
> This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
> all the other existing target_ulong CSRs are the same.

When AIA is available the number of local interrupts are 64 for
both RV32 and RV64.

The width of CSRs remain same as target_ulong but we have
new CSRs for RV32 (such as mipH) for the high-half.

Also, this patch changes does not break the case when AIA
is not available (or disabled).

Regards,
Anup

>
> Alistair
>
> >
> > -    uint32_t miclaim;
> > +    uint64_t miclaim;
> >
> > -    target_ulong mie;
> > -    target_ulong mideleg;
> > +    uint64_t mie;
> > +    uint64_t mideleg;
> >
> >      target_ulong sptbr;  /* until: priv-1.9.1 */
> >      target_ulong satp;   /* since: priv-1.10.0 */
> > @@ -179,16 +179,27 @@ struct CPURISCVState {
> >      target_ulong mcause;
> >      target_ulong mtval;  /* since: priv-1.10.0 */
> >
> > +    /* AIA CSRs */
> > +    target_ulong miselect;
> > +    target_ulong siselect;
> > +
> > +    uint8_t miprio[64];
> > +    uint8_t siprio[64];
> > +
> >      /* Hypervisor CSRs */
> >      target_ulong hstatus;
> >      target_ulong hedeleg;
> > -    target_ulong hideleg;
> > +    uint64_t hideleg;
> >      target_ulong hcounteren;
> >      target_ulong htval;
> >      target_ulong htinst;
> >      target_ulong hgatp;
> >      uint64_t htimedelta;
> >
> > +    /* AIA HS-mode CSRs */
> > +    uint8_t hviprio[64];
> > +    target_ulong hvicontrol;
> > +
> >      /* Virtual CSRs */
> >      /*
> >       * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
> > @@ -202,6 +213,9 @@ struct CPURISCVState {
> >      target_ulong vstval;
> >      target_ulong vsatp;
> >
> > +    /* AIA VS-mode CSRs */
> > +    target_ulong vsiselect;
> > +
> >      target_ulong mtval2;
> >      target_ulong mtinst;
> >
> > @@ -236,6 +250,18 @@ struct CPURISCVState {
> >      uint64_t (*rdtime_fn)(uint32_t);
> >      uint32_t rdtime_fn_arg;
> >
> > +    /* machine specific AIA IMSIC read-modify-write callback */
> > +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \
> > +    ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \
> > +     (((__priv) & 0x3) << 16) | (__isel & 0xffff))
> > +#define IMSIC_REG_ISEL(__reg)                  ((__reg) & 0xffff)
> > +#define IMSIC_REG_PRIV(__reg)                  (((__reg) >> 16) & 0x3)
> > +#define IMSIC_REG_VIRT(__reg)                  (((__reg) >> 20) & 0x1)
> > +#define IMSIC_REG_VGEIN(__reg)                 (((__reg) >> 24) & 0x3f)
> > +    int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val,
> > +                        target_ulong new_val, target_ulong write_mask);
> > +    void *imsic_rmw_fn_arg;
> > +
> >      /* True if in debugger mode.  */
> >      bool debugger;
> >  #endif
> > @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
> >                                 int cpuid, void *opaque);
> >  int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
> >  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero);
> > +uint8_t riscv_cpu_default_priority(int irq);
> > +int riscv_cpu_mirq_pending(CPURISCVState *env);
> > +int riscv_cpu_sirq_pending(CPURISCVState *env);
> > +int riscv_cpu_vsirq_pending(CPURISCVState *env);
> >  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
> >  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> >  bool riscv_cpu_virt_enabled(CPURISCVState *env);
> > @@ -364,9 +395,16 @@ void riscv_cpu_list(void);
> >
> >  #ifndef CONFIG_USER_ONLY
> >  void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
> > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
> > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
> > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
> > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value);
> >  #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
> > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > +                                int (*rmw_fn)(void *arg,
> > +                                              target_ulong reg,
> > +                                              target_ulong *val,
> > +                                              target_ulong new_val,
> > +                                              target_ulong write_mask),
> > +                                void *rmw_fn_arg);
> >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> >                               uint32_t arg);
> >  #endif
> > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > index 21c54ef561..5b06b4f995 100644
> > --- a/target/riscv/cpu_helper.c
> > +++ b/target/riscv/cpu_helper.c
> > @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
> >  }
> >
> >  #ifndef CONFIG_USER_ONLY
> > -static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > +
> > +/*
> > + * The HS-mode is allowed to configure priority only for the
> > + * following VS-mode local interrupts:
> > + *
> > + * 0  (Reserved interrupt, reads as zero)
> > + * 1  Supervisor software interrupt
> > + * 4  (Reserved interrupt, reads as zero)
> > + * 5  Supervisor timer interrupt
> > + * 8  (Reserved interrupt, reads as zero)
> > + * 13 (Reserved interrupt)
> > + * 14 "
> > + * 15 "
> > + * 16 "
> > + * 18 Debug/trace interrupt
> > + * 20 (Reserved interrupt)
> > + * 22 ”
> > + * 24 ”
> > + * 26 ”
> > + * 28 "
> > + * 30 (Reserved for standard reporting of bus or system errors)
> > + */
> > +
> > +static int hviprio_index2irq[] =
> > +    { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
> > +static int hviprio_index2rdzero[] =
> > +    { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> > +
> > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
> >  {
> > -    target_ulong irqs;
> > +    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
> > +        return -EINVAL;
> > +    }
> >
> > -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> > -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> > -    target_ulong hs_mstatus_sie = get_field(env->mstatus_hs, MSTATUS_SIE);
> > +    if (out_irq) {
> > +        *out_irq = hviprio_index2irq[index];
> > +    }
> > +
> > +    if (out_rdzero) {
> > +        *out_rdzero = hviprio_index2rdzero[index];
> > +    }
> >
> > -    target_ulong pending = env->mip & env->mie &
> > -                               ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > -    target_ulong vspending = (env->mip & env->mie &
> > -                              (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> > +    return 0;
> > +}
> >
> > -    target_ulong mie    = env->priv < PRV_M ||
> > -                          (env->priv == PRV_M && mstatus_mie);
> > -    target_ulong sie    = env->priv < PRV_S ||
> > -                          (env->priv == PRV_S && mstatus_sie);
> > -    target_ulong hs_sie = env->priv < PRV_S ||
> > -                          (env->priv == PRV_S && hs_mstatus_sie);
> > +uint8_t riscv_cpu_default_priority(int irq)
> > +{
> > +    int u, l;
> > +    uint8_t iprio = IPRIO_MMAXIPRIO;
> >
> > -    if (riscv_cpu_virt_enabled(env)) {
> > -        target_ulong pending_hs_irq = pending & -hs_sie;
> > +    if (irq < 0 || irq > 63) {
> > +        return iprio;
> > +    }
> >
> > -        if (pending_hs_irq) {
> > -            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> > -            return ctz64(pending_hs_irq);
> > +    /*
> > +     * Default priorities of local interrupts are defined in the
> > +     * RISC-V Advanced Interrupt Architecture specification.
> > +     *
> > +     * ----------------------------------------------------------------
> > +     *  Default  |
> > +     *  Priority | Major Interrupt Numbers
> > +     * ----------------------------------------------------------------
> > +     *  Highest  | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c),
> > +     *           | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38),
> > +     *           | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34),
> > +     *           | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30)
> > +     *           |
> > +     *           | 11 (0b),  3 (03),  7 (07)
> > +     *           |  9 (09),  1 (01),  5 (05)
> > +     *           | 12 (0c)
> > +     *           | 10 (0a),  2 (02),  6 (06)
> > +     *           |
> > +     *           | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c),
> > +     *           | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28),
> > +     *           | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24),
> > +     *  Lowest   | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20)
> > +     * ----------------------------------------------------------------
> > +     */
> > +
> > +    u = IPRIO_DEFAULT_U(irq);
> > +    l = IPRIO_DEFAULT_L(irq);
> > +    if (u == 0) {
> > +        if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER ||
> > +            irq == IRQ_VS_SOFT) {
> > +            iprio = IPRIO_DEFAULT_VS;
> > +        } else if (irq == IRQ_S_GEXT) {
> > +            iprio = IPRIO_DEFAULT_SGEXT;
> > +        } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER ||
> > +                   irq == IRQ_S_SOFT) {
> > +            iprio = IPRIO_DEFAULT_S;
> > +        } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER ||
> > +                   irq == IRQ_M_SOFT) {
> > +            iprio = IPRIO_DEFAULT_M;
> > +        } else {
> > +            iprio = IPRIO_DEFAULT_VS;
> >          }
> > +    } else if (u == 1) {
> > +        if (l < 8) {
> > +            iprio = IPRIO_DEFAULT_16_23(irq);
> > +        } else {
> > +            iprio = IPRIO_DEFAULT_24_31(irq);
> > +        }
> > +    } else if (u == 2) {
> > +        iprio = IPRIO_DEFAULT_32_47(irq);
> > +    } else if (u == 3) {
> > +        iprio = IPRIO_DEFAULT_48_63(irq);
> > +    }
> > +
> > +    return iprio;
> > +}
> > +
> > +static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> > +                                    uint64_t pending, uint8_t *iprio)
> > +{
> > +    int irq, best_irq = EXCP_NONE;
> > +    unsigned int prio, best_prio = UINT_MAX;
> >
> > -        pending = vspending;
> > +    if (!pending) {
> > +        return EXCP_NONE;
> >      }
> >
> > -    irqs = (pending & ~env->mideleg & -mie) | (pending &  env->mideleg & -sie);
> > +    irq = ctz64(pending);
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return irq;
> > +    }
> >
> > -    if (irqs) {
> > -        return ctz64(irqs); /* since non-zero */
> > +    pending = pending >> irq;
> > +    while (pending) {
> > +        prio = iprio[irq];
> > +        if (!prio) {
> > +            prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ?
> > +                   1 : IPRIO_MMAXIPRIO;
> > +        }
> > +        if ((pending & 0x1) && (prio < best_prio)) {
> > +            best_irq = irq;
> > +            best_prio = prio;
> > +        }
> > +        irq++;
> > +        pending = pending >> 1;
> > +    }
> > +
> > +    return best_irq;
> > +}
> > +
> > +int riscv_cpu_mirq_pending(CPURISCVState *env)
> > +{
> > +    uint64_t irqs = env->mip & env->mie & ~env->mideleg &
> > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +
> > +    return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > +}
> > +
> > +int riscv_cpu_sirq_pending(CPURISCVState *env)
> > +{
> > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +
> > +    return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > +}
> > +
> > +int riscv_cpu_vsirq_pending(CPURISCVState *env)
> > +{
> > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > +                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +
> > +    return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > +}
> > +
> > +static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > +{
> > +    int virq;
> > +    uint64_t irqs, mie, sie, vsie;
> > +    uint64_t pending, vspending;
> > +
> > +    /* Determine interrupt enable state of all privilege modes */
> > +    if (riscv_cpu_virt_enabled(env)) {
> > +        mie = 1;
> > +        sie = 1;
> > +        vsie = (env->priv < PRV_S) ||
> > +               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> >      } else {
> > -        return EXCP_NONE; /* indicates no pending interrupt */
> > +        mie = (env->priv < PRV_M) ||
> > +              (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
> > +        sie = (env->priv < PRV_S) ||
> > +              (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> > +        vsie = 0;
> > +    }
> > +
> > +    /* Check M-mode interrupts */
> > +    pending = env->mip & env->mie &
> > +              ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +    irqs = pending & ~env->mideleg & -mie;
> > +    if (irqs) {
> > +        return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > +    }
> > +
> > +    /* Check HS-mode interrupts */
> > +    irqs = pending & env->mideleg & -sie;
> > +    if (irqs) {
> > +        return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > +    }
> > +
> > +    /* Check VS-mode interrupts */
> > +    vspending = env->mip & env->mie &
> > +                (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > +    irqs = vspending & env->hideleg & -vsie;
> > +    if (irqs) {
> > +        virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > +        return (virq <= 0) ? virq : virq + 1;
> >      }
> > +
> > +    /* Indicates no pending interrupt */
> > +    return EXCP_NONE;
> >  }
> >  #endif
> >
> > @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx)
> >      return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
> >  }
> >
> > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
> >  {
> >      CPURISCVState *env = &cpu->env;
> >      if (env->miclaim & interrupts) {
> > @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> >      }
> >  }
> >
> > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
> >  {
> >      CPURISCVState *env = &cpu->env;
> >      CPUState *cs = CPU(cpu);
> > -    uint32_t old = env->mip;
> > +    uint64_t old = env->mip;
> >      bool locked = false;
> >
> >      if (!qemu_mutex_iothread_locked()) {
> > @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> >      return old;
> >  }
> >
> > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > +                                int (*rmw_fn)(void *arg,
> > +                                              target_ulong reg,
> > +                                              target_ulong *val,
> > +                                              target_ulong new_val,
> > +                                              target_ulong write_mask),
> > +                                void *rmw_fn_arg)
> > +{
> > +    env->imsic_rmw_fn = rmw_fn;
> > +    env->imsic_rmw_fn_arg = rmw_fn_arg;
> > +}
> > +
> >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> >                               uint32_t arg)
> >  {
> > @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> >       */
> >      bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
> >      target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
> > -    target_ulong deleg = async ? env->mideleg : env->medeleg;
> > +    uint64_t deleg = async ? env->mideleg : env->medeleg;
> >      bool write_tval = false;
> >      target_ulong tval = 0;
> >      target_ulong htval = 0;
> > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > index d2585395bf..3c016d7452 100644
> > --- a/target/riscv/csr.c
> > +++ b/target/riscv/csr.c
> > @@ -153,11 +153,56 @@ static int any32(CPURISCVState *env, int csrno)
> >
> >  }
> >
> > +static int aia_any(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return any(env, csrno);
> > +}
> > +
> > +static int aia_any32(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return any32(env, csrno);
> > +}
> > +
> >  static int smode(CPURISCVState *env, int csrno)
> >  {
> >      return -!riscv_has_ext(env, RVS);
> >  }
> >
> > +static int smode32(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_cpu_is_32bit(env)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return smode(env, csrno);
> > +}
> > +
> > +static int aia_smode(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return smode(env, csrno);
> > +}
> > +
> > +static int aia_smode32(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return smode32(env, csrno);
> > +}
> > +
> >  static int hmode(CPURISCVState *env, int csrno)
> >  {
> >      if (riscv_has_ext(env, RVS) &&
> > @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno)
> >  static int hmode32(CPURISCVState *env, int csrno)
> >  {
> >      if (!riscv_cpu_is_32bit(env)) {
> > -        return 0;
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return hmode(env, csrno);
> > +}
> > +
> > +static int aia_hmode(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> >      }
> >
> >      return hmode(env, csrno);
> > +}
> >
> > +static int aia_hmode32(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > +        return -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    return hmode32(env, csrno);
> >  }
> >
> >  static int pmp(CPURISCVState *env, int csrno)
> > @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
> >
> >  /* Machine constants */
> >
> > -#define M_MODE_INTERRUPTS  (MIP_MSIP | MIP_MTIP | MIP_MEIP)
> > -#define S_MODE_INTERRUPTS  (MIP_SSIP | MIP_STIP | MIP_SEIP)
> > -#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)
> > +#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
> > +#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
> > +#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
> > +
> > +#define TLOWBITS64         ((uint64_t)((target_ulong)-1))
> >
> > -static const target_ulong delegable_ints = S_MODE_INTERRUPTS |
> > -                                           VS_MODE_INTERRUPTS;
> > -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > -                                     VS_MODE_INTERRUPTS;
> > +static const uint64_t delegable_ints = S_MODE_INTERRUPTS |
> > +                                       VS_MODE_INTERRUPTS;
> > +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > +                                 VS_MODE_INTERRUPTS;
> >  static const target_ulong delegable_excps =
> >      (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) |
> >      (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) |
> > @@ -419,10 +483,10 @@ static const target_ulong delegable_excps =
> >  static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
> >      SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
> >      SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
> > -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > -static const target_ulong hip_writable_mask = MIP_VSSIP;
> > -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > -static const target_ulong vsip_writable_mask = MIP_VSSIP;
> > +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > +static const uint64_t hip_writable_mask = MIP_VSSIP;
> > +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > +static const uint64_t vsip_writable_mask = MIP_VSSIP;
> >
> >  static const char valid_vm_1_10_32[16] = {
> >      [VM_1_10_MBARE] = 1,
> > @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val)
> >
> >  static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > -    env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
> > +    uint64_t mask = delegable_ints & TLOWBITS64;
> > +
> > +    env->mideleg = (env->mideleg & ~mask) | (val & mask);
> > +    if (riscv_has_ext(env, RVH)) {
> > +        env->mideleg |= VS_MODE_INTERRUPTS;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
> > +{
> > +    if (!riscv_cpu_virt_enabled(env)) {
> > +        return csrno;
> > +    }
> > +
> > +    switch (csrno) {
> > +    case CSR_SISELECT:
> > +        return CSR_VSISELECT;
> > +    case CSR_SIREG:
> > +        return CSR_VSIREG;
> > +    case CSR_STOPI:
> > +        return CSR_VSTOPI;
> > +    case CSR_SSETEIPNUM:
> > +        return CSR_VSSETEIPNUM;
> > +    case CSR_SCLREIPNUM:
> > +        return CSR_VSCLREIPNUM;
> > +    case CSR_SSETEIENUM:
> > +        return CSR_VSSETEIENUM;
> > +    case CSR_SCLREIENUM:
> > +        return CSR_VSCLREIENUM;
> > +    default:
> > +        return csrno;
> > +    };
> > +}
> > +
> > +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val,
> > +                        target_ulong new_val, target_ulong write_mask)
> > +{
> > +    target_ulong *iselect;
> > +
> > +    switch (csrno) {
> > +    case CSR_MISELECT:
> > +        iselect = &env->miselect;
> > +        break;
> > +    case CSR_SISELECT:
> > +        iselect = riscv_cpu_virt_enabled(env) ?
> > +                  &env->vsiselect : &env->siselect;
> > +        break;
> > +    case CSR_VSISELECT:
> > +        iselect = &env->vsiselect;
> > +        break;
> > +    default:
> > +         return -RISCV_EXCP_ILLEGAL_INST;
> > +    };
> > +
> > +    if (val) {
> > +        *val = *iselect;
> > +    }
> > +
> > +    if (write_mask) {
> > +        *iselect = (*iselect & ~write_mask) | (new_val & write_mask);
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int rmw_iprio(target_ulong iselect, uint8_t *iprio,
> > +                     target_ulong *val, target_ulong new_val,
> > +                     target_ulong write_mask)
> > +{
> > +    int i, firq, nirqs;
> > +    target_ulong old_val;
> > +
> > +    if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) {
> > +        return -EINVAL;
> > +    }
> > +#if TARGET_LONG_BITS == 64
> > +    if (iselect & 0x1) {
> > +        return -EINVAL;
> > +    }
> > +#endif
> > +
> > +    nirqs = 4 * (TARGET_LONG_BITS / 32);
> > +    firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 32)) * (nirqs);
> > +
> > +    old_val = 0;
> > +    for (i = 0; i < nirqs; i++) {
> > +        old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i);
> > +    }
> > +
> > +    if (val) {
> > +        *val = old_val;
> > +    }
> > +
> > +    if (write_mask) {
> > +        new_val = (old_val & ~write_mask) | (new_val & write_mask);
> > +        for (i = 0; i < nirqs; i++) {
> > +            iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff;
> > +        }
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
> > +                     target_ulong new_val, target_ulong write_mask)
> > +{
> > +    bool virt;
> > +    uint8_t *iprio;
> > +    int ret = -EINVAL;
> > +    target_ulong priv, isel, vgein;
> > +
> > +    /* Translate CSR number for VS-mode */
> > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > +
> > +    /* Decode register details from CSR number */
> > +    virt = false;
> > +    switch (csrno) {
> > +    case CSR_MIREG:
> > +        iprio = env->miprio;
> > +        isel = env->miselect;
> > +        priv = PRV_M;
> > +        break;
> > +    case CSR_SIREG:
> > +        iprio = env->siprio;
> > +        isel = env->siselect;
> > +        priv = PRV_S;
> > +        break;
> > +    case CSR_VSIREG:
> > +        iprio = env->hviprio;
> > +        isel = env->vsiselect;
> > +        priv = PRV_S;
> > +        virt = true;
> > +        break;
> > +    default:
> > +         goto done;
> > +    };
> > +
> > +    /* Find the selected guest interrupt file */
> > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > +
> > +    if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) {
> > +        /* Local interrupt priority registers not available for VS-mode */
> > +        if (!virt) {
> > +            ret = rmw_iprio(isel, iprio, val, new_val, write_mask);
> > +        }
> > +    } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) {
> > +        /* IMSIC registers only available when machine implements it. */
> > +        if (env->imsic_rmw_fn) {
> > +            /* Selected guest interrupt file should not be zero */
> > +            if (virt && !vgein) {
> > +                goto done;
> > +            }
> > +            /* Call machine specific IMSIC register emulation */
> > +            ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > +                                    IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > +                                    val, new_val, write_mask);
> > +        }
> > +    }
> > +
> > +done:
> > +    if (ret) {
> > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    int irq;
> > +
> > +    irq = riscv_cpu_mirq_pending(env);
> > +    if (irq <= 0 || irq > 63) {
> > +       *val = 0;
> > +    } else {
> > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > +       *val |= env->miprio[irq];
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    bool virt;
> > +    int ret = -EINVAL;
> > +    target_ulong vgein;
> > +
> > +    /* Translate CSR number for VS-mode */
> > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > +
> > +    /* Decode register details from CSR number */
> > +    virt = false;
> > +    switch (csrno) {
> > +    case CSR_MSETEIPNUM:
> > +    case CSR_MCLREIPNUM:
> > +    case CSR_MSETEIENUM:
> > +    case CSR_MCLREIENUM:
> > +    case CSR_SSETEIPNUM:
> > +    case CSR_SCLREIPNUM:
> > +    case CSR_SSETEIENUM:
> > +    case CSR_SCLREIENUM:
> > +        break;
> > +    case CSR_VSSETEIPNUM:
> > +    case CSR_VSCLREIPNUM:
> > +    case CSR_VSSETEIENUM:
> > +    case CSR_VSCLREIENUM:
> > +        virt = true;
> > +        break;
> > +    default:
> > +         goto done;
> > +    };
> > +
> > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > +    if (!env->imsic_rmw_fn) {
> > +        goto done;
> > +    }
> > +
> > +    /* Find the selected guest interrupt file */
> > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > +
> > +    /* Selected guest interrupt file should not be zero */
> > +    if (virt && !vgein) {
> > +        goto done;
> > +    }
> > +
> > +    /* Set/Clear CSRs always read zero */
> > +    ret = 0;
> > +    if (val) {
> > +        *val = 0;
> > +    }
> > +
> > +done:
> > +    if (ret) {
> > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    int ret = -EINVAL;
> > +    bool set, pend, virt;
> > +    target_ulong priv, isel, vgein;
> > +    target_ulong new_val, write_mask;
> > +
> > +    /* Translate CSR number for VS-mode */
> > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > +
> > +    /* Decode register details from CSR number */
> > +    virt = set = pend = false;
> > +    switch (csrno) {
> > +    case CSR_MSETEIPNUM:
> > +        priv = PRV_M;
> > +        set = true;
> > +        break;
> > +    case CSR_MCLREIPNUM:
> > +        priv = PRV_M;
> > +        pend = true;
> > +        break;
> > +    case CSR_MSETEIENUM:
> > +        priv = PRV_M;
> > +        set = true;
> > +        break;
> > +    case CSR_MCLREIENUM:
> > +        priv = PRV_M;
> > +        break;
> > +    case CSR_SSETEIPNUM:
> > +        priv = PRV_S;
> > +        set = true;
> > +        pend = true;
> > +        break;
> > +    case CSR_SCLREIPNUM:
> > +        priv = PRV_S;
> > +        pend = true;
> > +        break;
> > +    case CSR_SSETEIENUM:
> > +        priv = PRV_S;
> > +        set = true;
> > +        break;
> > +    case CSR_SCLREIENUM:
> > +        priv = PRV_S;
> > +        break;
> > +    case CSR_VSSETEIPNUM:
> > +        priv = PRV_S;
> > +        virt = true;
> > +        set = true;
> > +        pend = true;
> > +        break;
> > +    case CSR_VSCLREIPNUM:
> > +        priv = PRV_S;
> > +        virt = true;
> > +        pend = true;
> > +        break;
> > +    case CSR_VSSETEIENUM:
> > +        priv = PRV_S;
> > +        virt = true;
> > +        set = true;
> > +        break;
> > +    case CSR_VSCLREIENUM:
> > +        priv = PRV_S;
> > +        virt = true;
> > +        break;
> > +    default:
> > +         goto done;
> > +    };
> > +
> > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > +    if (!env->imsic_rmw_fn) {
> > +        goto done;
> > +    }
> > +
> > +    /* Find target interrupt pending/enable register */
> > +    if (pend) {
> > +        isel = ISELECT_IMSIC_EIP0;
> > +    } else {
> > +        isel = ISELECT_IMSIC_EIE0;
> > +    }
> > +    isel += val / IMSIC_EIPx_BITS;
> > +
> > +    /* Find the interrupt bit to be set/clear */
> > +    write_mask = 1 << (val % IMSIC_EIPx_BITS);
> > +    new_val = (set) ? write_mask : 0;
> > +
> > +    /* Find the selected guest interrupt file */
> > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > +
> > +    /* Selected guest interrupt file should not be zero */
> > +    if (virt && !vgein) {
> > +        goto done;
> > +    }
> > +
> > +    /* Call machine specific IMSIC register emulation */
> > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > +                            NULL, new_val, write_mask);
> > +
> > +done:
> > +    if (ret) {
> > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    bool virt;
> > +    int ret = -EINVAL;
> > +    target_ulong priv, isel, vgein;
> > +    target_ulong topei, write_mask;
> > +
> > +    /* Decode register details from CSR number */
> > +    virt = false;
> > +    switch (csrno) {
> > +    case CSR_MCLAIMEI:
> > +        priv = PRV_M;
> > +        break;
> > +    case CSR_SCLAIMEI:
> > +        priv = PRV_S;
> > +        virt = riscv_cpu_virt_enabled(env);
> > +        break;
> > +    default:
> > +        goto done;
> > +    };
> > +
> > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > +    if (!env->imsic_rmw_fn) {
> > +        goto done;
> > +    }
> > +
> > +    /* Find the selected guest interrupt file */
> > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > +
> > +    /* Selected guest interrupt file should not be zero */
> > +    if (virt && !vgein) {
> > +        goto done;
> > +    }
> > +
> > +    /* Call machine specific IMSIC register emulation for reading TOPEI */
> > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > +                            IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein),
> > +                            &topei, -1, 0);
> > +    if (ret) {
> > +        goto done;
> > +    }
> > +
> > +    /* If no interrupt pending then we are done */
> > +    if (!topei) {
> > +        goto done;
> > +    }
> > +
> > +    /* Find target interrupt pending register */
> > +    isel = ISELECT_IMSIC_EIP0;
> > +    isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS);
> > +
> > +    /* Find the interrupt bit to be cleared */
> > +    write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS);
> > +
> > +    /* Call machine specific IMSIC register emulation to clear pending bit */
> > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > +                            NULL, 0, write_mask);
> > +
> > +    /* Update return value */
> > +    if (val) {
> > +        *val = topei;
> > +    }
> > +
> > +done:
> > +    if (ret) {
> > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +    return 0;
> > +}
> > +
> > +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    *val = (env->mideleg >> 32);
> > +    return 0;
> > +}
> > +
> > +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    uint64_t mask = delegable_ints & ~TLOWBITS64;
> > +    uint64_t newval = ((uint64_t)val) << 32;
> > +
> > +    env->mideleg = (env->mideleg & ~mask) | (newval & mask);
> >      if (riscv_has_ext(env, RVH)) {
> >          env->mideleg |= VS_MODE_INTERRUPTS;
> >      }
> > @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
> >
> >  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> > +    uint64_t mask = all_ints & TLOWBITS64;
> > +
> > +    env->mie = (env->mie & ~mask) | (val & mask);
> > +    return 0;
> > +}
> > +
> > +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    *val = (env->mie >> 32);
> > +    return 0;
> > +}
> > +
> > +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    uint64_t mask = all_ints & ~TLOWBITS64;
> > +    uint64_t newval = ((uint64_t)val) << 32;
> > +
> > +    env->mie = (env->mie & ~mask) | (newval & mask);
> >      return 0;
> >  }
> >
> > @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >  {
> >      RISCVCPU *cpu = env_archcpu(env);
> >      /* Allow software control of delegable interrupts not claimed by hardware */
> > -    target_ulong mask = write_mask & delegable_ints & ~env->miclaim;
> > -    uint32_t old_mip;
> > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > +                    ~env->miclaim & TLOWBITS64;
> > +    uint64_t old_mip;
> >
> >      if (mask) {
> >          old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >      return 0;
> >  }
> >
> > +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > +                    target_ulong new_value, target_ulong write_mask)
> > +{
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > +                    ~env->miclaim & ~TLOWBITS64;
> > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > +    uint64_t old_mip;
> > +
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> > +
> > +    if (ret_value) {
> > +        *ret_value = old_mip >> 32;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> >  /* Supervisor Trap Setup */
> >  static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> > @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
> >
> >  static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64;
> > +
> >      /* Shift the VS bits to their S bit location in vsie */
> > -    *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
> > +    *val = (env->mie & mask) >> 1;
> > +    return 0;
> > +}
> > +
> > +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64;
> > +
> > +    /* Shift the VS bits to their S bit location in vsieh */
> > +    *val = (env->mie & mask) >> (32 + 1);
> >      return 0;
> >  }
> >
> >  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> >      if (riscv_cpu_virt_enabled(env)) {
> > -        read_vsie(env, CSR_VSIE, val);
> > -    } else {
> > -        *val = env->mie & env->mideleg;
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return read_vsie(env, CSR_VSIE, val);
> >      }
> > +
> > +    *val = env->mie & env->mideleg;
> >      return 0;
> >  }
> >
> >  static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > +                    all_ints & TLOWBITS64;
> > +
> >      /* Shift the S bits to their VS bit location in mie */
> > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
> > -                          ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS);
> > -    return write_mie(env, CSR_MIE, newval);
> > +    env->mie = (env->mie & ~mask) | ((val << 1) & mask);
> > +
> > +    return 0;
> > +}
> > +
> > +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > +                    all_ints & ~TLOWBITS64;
> > +    uint64_t newval = (uint64_t)val << 32;
> > +
> > +    /* Shift the S bits to their VS bit location in mie */
> > +    env->mie = (env->mie & ~mask) | ((newval << 1) & mask);
> > +
> > +    return 0;
> >  }
> >
> >  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > +    uint64_t mask;
> > +
> >      if (riscv_cpu_virt_enabled(env)) {
> > -        write_vsie(env, CSR_VSIE, val);
> > -    } else {
> > -        target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) |
> > -                              (val & S_MODE_INTERRUPTS);
> > -        write_mie(env, CSR_MIE, newval);
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return write_vsie(env, CSR_VSIE, val);
> > +    }
> > +
> > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64;
> > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > +
> > +    return 0;
> > +}
> > +
> > +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    if (riscv_cpu_virt_enabled(env)) {
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return read_vsieh(env, CSR_VSIEH, val);
> > +    }
> > +
> > +    *val = ((env->mie & env->mideleg) >> 32);
> > +    return 0;
> > +}
> > +
> > +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    uint64_t mask, newval;
> > +
> > +    if (riscv_cpu_virt_enabled(env)) {
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return write_vsieh(env, CSR_VSIEH, val);
> >      }
> >
> > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64;
> > +    newval = (uint64_t)val << 32;
> > +
> > +    env->mie = (env->mie & ~mask) | (newval & mask);
> >      return 0;
> >  }
> >
> > @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
> >  static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >                      target_ulong new_value, target_ulong write_mask)
> >  {
> > -    /* Shift the S bits to their VS bit location in mip */
> > -    int ret = rmw_mip(env, 0, ret_value, new_value << 1,
> > -                      (write_mask << 1) & vsip_writable_mask & env->hideleg);
> > -    *ret_value &= VS_MODE_INTERRUPTS;
> > -    /* Shift the VS bits to their S bit location in vsip */
> > -    *ret_value >>= 1;
> > -    return ret;
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints &
> > +                    vsip_writable_mask & env->hideleg &
> > +                    ~env->miclaim & TLOWBITS64;
> > +    uint64_t old_mip;
> > +
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> > +
> > +    if (ret_value) {
> > +        *ret_value = old_mip & VS_MODE_INTERRUPTS;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > +                     target_ulong new_value, target_ulong write_mask)
> > +{
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints &
> > +                    vsip_writable_mask & env->hideleg &
> > +                    ~env->miclaim & ~TLOWBITS64;
> > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > +    uint64_t old_mip;
> > +
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> > +
> > +    if (ret_value) {
> > +        *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32;
> > +    }
> > +
> > +    return 0;
> >  }
> >
> >  static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >                     target_ulong new_value, target_ulong write_mask)
> >  {
> > -    int ret;
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    uint64_t mask, old_mip;
> >
> >      if (riscv_cpu_virt_enabled(env)) {
> > -        ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > +    }
> > +
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    mask = ((uint64_t)write_mask) & delegable_ints &
> > +           env->mideleg & sip_writable_mask &
> > +           ~env->miclaim & TLOWBITS64;
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> >      } else {
> > -        ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
> > -                      write_mask & env->mideleg & sip_writable_mask);
> > +        old_mip = env->mip;
> >      }
> >
> > -    *ret_value &= env->mideleg;
> > -    return ret;
> > +    if (ret_value) {
> > +        *ret_value = old_mip;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > +                    target_ulong new_value, target_ulong write_mask)
> > +{
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    uint64_t mask, new_value64;
> > +    uint64_t old_mip;
> > +
> > +    if (riscv_cpu_virt_enabled(env)) {
> > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > +        }
> > +        return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask);
> > +    }
> > +
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > +           env->mideleg & sip_writable_mask &
> > +           ~env->miclaim & ~TLOWBITS64;
> > +    new_value64 = (uint64_t)new_value << 32;
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> > +
> > +    if (ret_value) {
> > +        *ret_value = (old_mip & env->mideleg) >> 32;
> > +    }
> > +
> > +    return 0;
> >  }
> >
> >  /* Supervisor Protection and Translation */
> > @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
> >      return 0;
> >  }
> >
> > +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    int irq, hiid;
> > +    uint8_t hiprio, iprio;
> > +
> > +    irq = riscv_cpu_vsirq_pending(env);
> > +    if (irq <= 0 || irq > 63) {
> > +       *val = 0;
> > +    } else {
> > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > +       iprio = env->hviprio[irq];
> > +       /* TODO: This needs to improve in specification */
> > +       if (!(env->hstatus & HSTATUS_VGEIN)) {
> > +           hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >>
> > +                 HVICONTROL_IID_SHIFT;
> > +           hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK;
> > +           if (irq == hiid && hiprio) {
> > +               iprio = hiprio;
> > +           }
> > +       }
> > +       *val |= iprio;
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    int irq;
> > +
> > +    if (riscv_cpu_virt_enabled(env)) {
> > +        return read_vstopi(env, CSR_VSTOPI, val);
> > +    }
> > +
> > +    irq = riscv_cpu_sirq_pending(env);
> > +    if (irq <= 0 || irq > 63) {
> > +       *val = 0;
> > +    } else {
> > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > +       *val |= env->siprio[irq];
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> >  /* Hypervisor Extensions */
> >  static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> > @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
> >      return 0;
> >  }
> >
> > +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    *val = env->hideleg >> 32;
> > +    return 0;
> > +}
> > +
> > +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    uint64_t mask = ~TLOWBITS64;
> > +    uint64_t newval = ((uint64_t)val) << 32;
> > +
> > +    env->hideleg = (env->hideleg & ~mask) | (newval & mask);
> > +
> > +    return 0;
> > +}
> > +
> >  static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >                     target_ulong new_value, target_ulong write_mask)
> >  {
> > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > -                      write_mask & hvip_writable_mask);
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > +                    hvip_writable_mask &
> > +                    ~env->miclaim & TLOWBITS64;
> > +    uint64_t old_mip;
> > +
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> >
> > -    *ret_value &= hvip_writable_mask;
> > +    if (ret_value) {
> > +        *ret_value = old_mip & hvip_writable_mask;
> > +    }
> >
> > -    return ret;
> > +    return 0;
> > +}
> > +
> > +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > +                    target_ulong new_value, target_ulong write_mask)
> > +{
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > +                    hvip_writable_mask &
> > +                    ~env->miclaim & ~TLOWBITS64;
> > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > +    uint64_t old_mip;
> > +
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> > +
> > +    if (ret_value) {
> > +        *ret_value = (old_mip & hvip_writable_mask) >> 32;
> > +    }
> > +
> > +    return 0;
> >  }
> >
> >  static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> >                     target_ulong new_value, target_ulong write_mask)
> >  {
> > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > -                      write_mask & hip_writable_mask);
> > +    RISCVCPU *cpu = env_archcpu(env);
> > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > +                    hip_writable_mask &
> > +                    ~env->miclaim & TLOWBITS64;
> > +    uint64_t old_mip;
> >
> > -    *ret_value &= hip_writable_mask;
> > +    if (mask) {
> > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > +    } else {
> > +        old_mip = env->mip;
> > +    }
> >
> > -    return ret;
> > +    if (ret_value) {
> > +        *ret_value = old_mip & hip_writable_mask;
> > +    }
> > +
> > +    return 0;
> >  }
> >
> >  static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> > @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> >
> >  static int write_hie(CPURISCVState *env, int csrno, target_ulong val)
> >  {
> > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS);
> > -    return write_mie(env, CSR_MIE, newval);
> > +    uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64;
> > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > +    return 0;
> >  }
> >
> >  static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val)
> > @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val)
> >      return 0;
> >  }
> >
> > +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    *val = env->hvicontrol;
> > +    return 0;
> > +}
> > +
> > +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    env->hvicontrol = val & HVICONTROL_VALID_MASK;
> > +    return 0;
> > +}
> > +
> > +static int read_hvipriox(CPURISCVState *env, int first_index,
> > +                         uint8_t *iprio, target_ulong *val)
> > +{
> > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > +
> > +    /* First index has to be multiple of numbe of irqs per register */
> > +    if (first_index % num_irqs) {
> > +        return (riscv_cpu_virt_enabled(env)) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    /* Fill-up return value */
> > +    *val = 0;
> > +    for (i = 0; i < num_irqs; i++) {
> > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > +            continue;
> > +        }
> > +        if (rdzero) {
> > +            continue;
> > +        }
> > +        *val |= ((target_ulong)iprio[irq]) << (i * 8);
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int write_hvipriox(CPURISCVState *env, int first_index,
> > +                          uint8_t *iprio, target_ulong val)
> > +{
> > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > +
> > +    /* First index has to be multiple of numbe of irqs per register */
> > +    if (first_index % num_irqs) {
> > +        return (riscv_cpu_virt_enabled(env)) ?
> > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > +    }
> > +
> > +    /* Fill-up priority arrary */
> > +    for (i = 0; i < num_irqs; i++) {
> > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > +            continue;
> > +        }
> > +        if (rdzero) {
> > +            iprio[irq] = 0;
> > +        } else {
> > +            iprio[irq] = (val >> (i * 8)) & 0xff;
> > +        }
> > +    }
> > +
> > +    return 0;
> > +}
> > +
> > +static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    return read_hvipriox(env, 0, env->hviprio, val);
> > +}
> > +
> > +static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    return write_hvipriox(env, 0, env->hviprio, val);
> > +}
> > +
> > +static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    return read_hvipriox(env, 4, env->hviprio, val);
> > +}
> > +
> > +static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    return write_hvipriox(env, 4, env->hviprio, val);
> > +}
> > +
> > +static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    return read_hvipriox(env, 8, env->hviprio, val);
> > +}
> > +
> > +static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    return write_hvipriox(env, 8, env->hviprio, val);
> > +}
> > +
> > +static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val)
> > +{
> > +    return read_hvipriox(env, 12, env->hviprio, val);
> > +}
> > +
> > +static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val)
> > +{
> > +    return write_hvipriox(env, 12, env->hviprio, val);
> > +}
> > +
> >  /* Virtual CSR Registers */
> >  static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
> >  {
> > @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> >      [CSR_MBADADDR] = { "mbadaddr", any,  read_mbadaddr, write_mbadaddr },
> >      [CSR_MIP]      = { "mip",      any,  NULL,    NULL, rmw_mip        },
> >
> > +    /* Machine-Level Window to Indirectly Accessed Registers (AIA) */
> > +    [CSR_MISELECT] = { "miselect", aia_any,   NULL, NULL,    rmw_xiselect },
> > +    [CSR_MIREG]    = { "mireg",    aia_any,   NULL, NULL,    rmw_xireg },
> > +
> > +    /* Machine-Level Interrupts (AIA) */
> > +    [CSR_MTOPI]    = { "mtopi",    aia_any,   read_mtopi },
> > +
> > +    /* Machine-Level IMSIC Interface (AIA) */
> > +    [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_MCLAIMEI]   = { "mclaimei",   aia_any, read_xclaimei },
> > +
> > +    /* Machine-Level High-Half CSRs (AIA) */
> > +    [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh },
> > +    [CSR_MIEH]     = { "mieh",     aia_any32, read_mieh,     write_mieh     },
> > +    [CSR_MIPH]     = { "miph",     aia_any32, NULL,    NULL, rmw_miph       },
> > +
> >      /* Supervisor Trap Setup */
> >      [CSR_SSTATUS]    = { "sstatus",    smode, read_sstatus,    write_sstatus    },
> >      [CSR_SIE]        = { "sie",        smode, read_sie,        write_sie        },
> > @@ -1444,6 +2357,24 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> >      /* Supervisor Protection and Translation */
> >      [CSR_SATP]     = { "satp",     smode, read_satp,    write_satp      },
> >
> > +    /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
> > +    [CSR_SISELECT]   = { "siselect",   aia_smode, NULL, NULL, rmw_xiselect },
> > +    [CSR_SIREG]      = { "sireg",      aia_smode, NULL, NULL, rmw_xireg },
> > +
> > +    /* Supervisor-Level Interrupts (AIA) */
> > +    [CSR_STOPI]      = { "stopi",      aia_smode, read_stopi },
> > +
> > +    /* Supervisor-Level IMSIC Interface (AIA) */
> > +    [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_SCLAIMEI]   = { "sclaimei",   aia_smode, read_xclaimei },
> > +
> > +    /* Supervisor-Level High-Half CSRs (AIA) */
> > +    [CSR_SIEH]       = { "sieh",       aia_smode32, read_sieh,  write_sieh },
> > +    [CSR_SIPH]       = { "siph",       aia_smode32, NULL, NULL, rmw_siph   },
> > +
> >      [CSR_HSTATUS]     = { "hstatus",     hmode,   read_hstatus,     write_hstatus     },
> >      [CSR_HEDELEG]     = { "hedeleg",     hmode,   read_hedeleg,     write_hedeleg     },
> >      [CSR_HIDELEG]     = { "hideleg",     hmode,   read_hideleg,     write_hideleg     },
> > @@ -1472,6 +2403,32 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> >      [CSR_MTVAL2]      = { "mtval2",      hmode,   read_mtval2,      write_mtval2      },
> >      [CSR_MTINST]      = { "mtinst",      hmode,   read_mtinst,      write_mtinst      },
> >
> > +    /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
> > +    [CSR_HVICONTROL]  = { "hvicontrol",  aia_hmode, read_hvicontrol, write_hvicontrol },
> > +    [CSR_HVIPRIO1]    = { "hviprio1",    aia_hmode, read_hviprio1,   write_hviprio1 },
> > +    [CSR_HVIPRIO2]    = { "hviprio2",    aia_hmode, read_hviprio2,   write_hviprio2 },
> > +
> > +    /* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
> > +    [CSR_VSISELECT]   = { "vsiselect",   aia_hmode, NULL, NULL,      rmw_xiselect },
> > +    [CSR_VSIREG]      = { "vsireg",      aia_hmode, NULL, NULL,      rmw_xireg },
> > +
> > +    /* VS-Level Interrupts (H-extension with AIA) */
> > +    [CSR_VSTOPI]      = { "vstopi",      aia_hmode, read_vstopi },
> > +
> > +    /* VS-Level IMSIC Interface (H-extension with AIA) */
> > +    [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > +    [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > +
> > +    /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
> > +    [CSR_HIDELEGH]    = { "hidelegh",    aia_hmode32, read_hidelegh,  write_hidelegh },
> > +    [CSR_HVIPH]       = { "hviph",       aia_hmode32, NULL, NULL,     rmw_hviph },
> > +    [CSR_HVIPRIO1H]   = { "hviprio1h",   aia_hmode32, read_hviprio1h, write_hviprio1h },
> > +    [CSR_HVIPRIO2H]   = { "hviprio2h",   aia_hmode32, read_hviprio2h, write_hviprio2h },
> > +    [CSR_VSIEH]       = { "vsieh",       aia_hmode32, read_vsieh,     write_vsieh },
> > +    [CSR_VSIPH]       = { "vsiep",       aia_hmode32, NULL, NULL,     rmw_vsiph },
> > +
> >      /* Physical Memory Protection */
> >      [CSR_PMPCFG0]    = { "pmpcfg0",   pmp, read_pmpcfg,  write_pmpcfg  },
> >      [CSR_PMPCFG1]    = { "pmpcfg1",   pmp, read_pmpcfg,  write_pmpcfg  },
> > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> > index 44d4015bd6..f7fa48c240 100644
> > --- a/target/riscv/machine.c
> > +++ b/target/riscv/machine.c
> > @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = {
> >
> >  static const VMStateDescription vmstate_hyper = {
> >      .name = "cpu/hyper",
> > -    .version_id = 1,
> > -    .minimum_version_id = 1,
> > +    .version_id = 2,
> > +    .minimum_version_id = 2,
> >      .needed = hyper_needed,
> >      .fields = (VMStateField[]) {
> >          VMSTATE_UINTTL(env.hstatus, RISCVCPU),
> >          VMSTATE_UINTTL(env.hedeleg, RISCVCPU),
> > -        VMSTATE_UINTTL(env.hideleg, RISCVCPU),
> > +        VMSTATE_UINT64(env.hideleg, RISCVCPU),
> >          VMSTATE_UINTTL(env.hcounteren, RISCVCPU),
> >          VMSTATE_UINTTL(env.htval, RISCVCPU),
> >          VMSTATE_UINTTL(env.htinst, RISCVCPU),
> >          VMSTATE_UINTTL(env.hgatp, RISCVCPU),
> >          VMSTATE_UINT64(env.htimedelta, RISCVCPU),
> >
> > +        VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
> > +        VMSTATE_UINTTL(env.hvicontrol, RISCVCPU),
> > +
> >          VMSTATE_UINT64(env.vsstatus, RISCVCPU),
> >          VMSTATE_UINTTL(env.vstvec, RISCVCPU),
> >          VMSTATE_UINTTL(env.vsscratch, RISCVCPU),
> > @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = {
> >          VMSTATE_UINTTL(env.vscause, RISCVCPU),
> >          VMSTATE_UINTTL(env.vstval, RISCVCPU),
> >          VMSTATE_UINTTL(env.vsatp, RISCVCPU),
> > +        VMSTATE_UINTTL(env.vsiselect, RISCVCPU),
> >
> >          VMSTATE_UINTTL(env.mtval2, RISCVCPU),
> >          VMSTATE_UINTTL(env.mtinst, RISCVCPU),
> > @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = {
> >
> >  const VMStateDescription vmstate_riscv_cpu = {
> >      .name = "cpu",
> > -    .version_id = 1,
> > -    .minimum_version_id = 1,
> > +    .version_id = 2,
> > +    .minimum_version_id = 2,
> >      .fields = (VMStateField[]) {
> >          VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
> >          VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
> > +        VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
> > +        VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
> >          VMSTATE_UINTTL(env.pc, RISCVCPU),
> >          VMSTATE_UINTTL(env.load_res, RISCVCPU),
> >          VMSTATE_UINTTL(env.load_val, RISCVCPU),
> > @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = {
> >          VMSTATE_UINTTL(env.resetvec, RISCVCPU),
> >          VMSTATE_UINTTL(env.mhartid, RISCVCPU),
> >          VMSTATE_UINT64(env.mstatus, RISCVCPU),
> > -        VMSTATE_UINTTL(env.mip, RISCVCPU),
> > -        VMSTATE_UINT32(env.miclaim, RISCVCPU),
> > -        VMSTATE_UINTTL(env.mie, RISCVCPU),
> > -        VMSTATE_UINTTL(env.mideleg, RISCVCPU),
> > +        VMSTATE_UINT64(env.mip, RISCVCPU),
> > +        VMSTATE_UINT64(env.miclaim, RISCVCPU),
> > +        VMSTATE_UINT64(env.mie, RISCVCPU),
> > +        VMSTATE_UINT64(env.mideleg, RISCVCPU),
> >          VMSTATE_UINTTL(env.sptbr, RISCVCPU),
> >          VMSTATE_UINTTL(env.satp, RISCVCPU),
> >          VMSTATE_UINTTL(env.sbadaddr, RISCVCPU),
> > @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = {
> >          VMSTATE_UINTTL(env.mepc, RISCVCPU),
> >          VMSTATE_UINTTL(env.mcause, RISCVCPU),
> >          VMSTATE_UINTTL(env.mtval, RISCVCPU),
> > +        VMSTATE_UINTTL(env.miselect, RISCVCPU),
> > +        VMSTATE_UINTTL(env.siselect, RISCVCPU),
> >          VMSTATE_UINTTL(env.scounteren, RISCVCPU),
> >          VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
> >          VMSTATE_UINTTL(env.sscratch, RISCVCPU),
> > --
> > 2.25.1
> >
> >


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/4] AIA local interrupt CSR support
  2021-05-14 14:32 ` Anup Patel
@ 2021-06-11  6:47   ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-11  6:47 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	QEMU Developers, Atish Patra, Palmer Dabbelt

Hi Alistair,

On Fri, May 14, 2021 at 8:03 PM Anup Patel <anup.patel@wdc.com> wrote:
>
> The advanced interrupt architecture (AIA) extends the per-HART local
> interrupt support. Along with this, it also adds IMSIC (MSI contrllor)
> and Advanced PLIC (wired interrupt controller).
>
> The latest AIA draft specification can be found here:
> http://jhauser.us/private/RISCV-AIA/riscv-interrupts-021.pdf
>
> This series adds initial AIA support in QEMU which includes emulating all
> AIA local CSR. To enable AIA in QEMU, we just need to pass "x-aia=true"
> paramenter in "-cpu" QEMU command-line.
>
> To test series, we require OpenSBI and Linux with AIA support which
> can be found in riscv_aia_v1 branch at:
> https://github.com/avpatel/opensbi.git
> https://github.com/avpatel/linux.git
>
> Anup Patel (4):
>   target/riscv: Add defines for AIA local interrupt CSRs
>   target/riscv: Add CPU feature for AIA CSRs
>   target/riscv: Implement AIA local interrupt CSRs
>   hw/riscv: virt: Use AIA INTC compatible string when available

The ACLINT specification will be frozen soon (probably early next
month). The ACLINT QEMU support patches are also ready and don't
depend on the AIA QEMU support patches.

Is it okay to target ACLINT support in QEMU first ?

I can rebase this series on ACLINT support patches and also include
more AIA emulation patches (APLIC and IMSIC) in the AIA series.

Regards,
Anup

>
>  hw/riscv/virt.c           |   11 +-
>  target/riscv/cpu.c        |   32 +-
>  target/riscv/cpu.h        |   56 +-
>  target/riscv/cpu_bits.h   |  128 +++++
>  target/riscv/cpu_helper.c |  245 ++++++++-
>  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
>  target/riscv/machine.c    |   26 +-
>  7 files changed, 1454 insertions(+), 103 deletions(-)
>
> --
> 2.25.1
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/4] AIA local interrupt CSR support
@ 2021-06-11  6:47   ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-11  6:47 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Peter Maydell, Palmer Dabbelt, Sagar Karandikar, Atish Patra,
	open list:RISC-V, QEMU Developers, Anup Patel

Hi Alistair,

On Fri, May 14, 2021 at 8:03 PM Anup Patel <anup.patel@wdc.com> wrote:
>
> The advanced interrupt architecture (AIA) extends the per-HART local
> interrupt support. Along with this, it also adds IMSIC (MSI contrllor)
> and Advanced PLIC (wired interrupt controller).
>
> The latest AIA draft specification can be found here:
> http://jhauser.us/private/RISCV-AIA/riscv-interrupts-021.pdf
>
> This series adds initial AIA support in QEMU which includes emulating all
> AIA local CSR. To enable AIA in QEMU, we just need to pass "x-aia=true"
> paramenter in "-cpu" QEMU command-line.
>
> To test series, we require OpenSBI and Linux with AIA support which
> can be found in riscv_aia_v1 branch at:
> https://github.com/avpatel/opensbi.git
> https://github.com/avpatel/linux.git
>
> Anup Patel (4):
>   target/riscv: Add defines for AIA local interrupt CSRs
>   target/riscv: Add CPU feature for AIA CSRs
>   target/riscv: Implement AIA local interrupt CSRs
>   hw/riscv: virt: Use AIA INTC compatible string when available

The ACLINT specification will be frozen soon (probably early next
month). The ACLINT QEMU support patches are also ready and don't
depend on the AIA QEMU support patches.

Is it okay to target ACLINT support in QEMU first ?

I can rebase this series on ACLINT support patches and also include
more AIA emulation patches (APLIC and IMSIC) in the AIA series.

Regards,
Anup

>
>  hw/riscv/virt.c           |   11 +-
>  target/riscv/cpu.c        |   32 +-
>  target/riscv/cpu.h        |   56 +-
>  target/riscv/cpu_bits.h   |  128 +++++
>  target/riscv/cpu_helper.c |  245 ++++++++-
>  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
>  target/riscv/machine.c    |   26 +-
>  7 files changed, 1454 insertions(+), 103 deletions(-)
>
> --
> 2.25.1
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/4] AIA local interrupt CSR support
  2021-06-11  6:47   ` Anup Patel
@ 2021-06-11  8:40     ` Alistair Francis
  -1 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-11  8:40 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	QEMU Developers, Atish Patra, Alistair Francis, Palmer Dabbelt

On Fri, Jun 11, 2021 at 4:48 PM Anup Patel <anup@brainfault.org> wrote:
>
> Hi Alistair,
>
> On Fri, May 14, 2021 at 8:03 PM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > The advanced interrupt architecture (AIA) extends the per-HART local
> > interrupt support. Along with this, it also adds IMSIC (MSI contrllor)
> > and Advanced PLIC (wired interrupt controller).
> >
> > The latest AIA draft specification can be found here:
> > http://jhauser.us/private/RISCV-AIA/riscv-interrupts-021.pdf
> >
> > This series adds initial AIA support in QEMU which includes emulating all
> > AIA local CSR. To enable AIA in QEMU, we just need to pass "x-aia=true"
> > paramenter in "-cpu" QEMU command-line.
> >
> > To test series, we require OpenSBI and Linux with AIA support which
> > can be found in riscv_aia_v1 branch at:
> > https://github.com/avpatel/opensbi.git
> > https://github.com/avpatel/linux.git
> >
> > Anup Patel (4):
> >   target/riscv: Add defines for AIA local interrupt CSRs
> >   target/riscv: Add CPU feature for AIA CSRs
> >   target/riscv: Implement AIA local interrupt CSRs
> >   hw/riscv: virt: Use AIA INTC compatible string when available
>
> The ACLINT specification will be frozen soon (probably early next
> month). The ACLINT QEMU support patches are also ready and don't
> depend on the AIA QEMU support patches.
>
> Is it okay to target ACLINT support in QEMU first ?

Yeah, go for it.

Alistair

>
> I can rebase this series on ACLINT support patches and also include
> more AIA emulation patches (APLIC and IMSIC) in the AIA series.
>
> Regards,
> Anup
>
> >
> >  hw/riscv/virt.c           |   11 +-
> >  target/riscv/cpu.c        |   32 +-
> >  target/riscv/cpu.h        |   56 +-
> >  target/riscv/cpu_bits.h   |  128 +++++
> >  target/riscv/cpu_helper.c |  245 ++++++++-
> >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> >  target/riscv/machine.c    |   26 +-
> >  7 files changed, 1454 insertions(+), 103 deletions(-)
> >
> > --
> > 2.25.1
> >
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 0/4] AIA local interrupt CSR support
@ 2021-06-11  8:40     ` Alistair Francis
  0 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-11  8:40 UTC (permalink / raw)
  To: Anup Patel
  Cc: Alistair Francis, Peter Maydell, open list:RISC-V,
	Sagar Karandikar, Anup Patel, QEMU Developers, Atish Patra,
	Palmer Dabbelt

On Fri, Jun 11, 2021 at 4:48 PM Anup Patel <anup@brainfault.org> wrote:
>
> Hi Alistair,
>
> On Fri, May 14, 2021 at 8:03 PM Anup Patel <anup.patel@wdc.com> wrote:
> >
> > The advanced interrupt architecture (AIA) extends the per-HART local
> > interrupt support. Along with this, it also adds IMSIC (MSI contrllor)
> > and Advanced PLIC (wired interrupt controller).
> >
> > The latest AIA draft specification can be found here:
> > http://jhauser.us/private/RISCV-AIA/riscv-interrupts-021.pdf
> >
> > This series adds initial AIA support in QEMU which includes emulating all
> > AIA local CSR. To enable AIA in QEMU, we just need to pass "x-aia=true"
> > paramenter in "-cpu" QEMU command-line.
> >
> > To test series, we require OpenSBI and Linux with AIA support which
> > can be found in riscv_aia_v1 branch at:
> > https://github.com/avpatel/opensbi.git
> > https://github.com/avpatel/linux.git
> >
> > Anup Patel (4):
> >   target/riscv: Add defines for AIA local interrupt CSRs
> >   target/riscv: Add CPU feature for AIA CSRs
> >   target/riscv: Implement AIA local interrupt CSRs
> >   hw/riscv: virt: Use AIA INTC compatible string when available
>
> The ACLINT specification will be frozen soon (probably early next
> month). The ACLINT QEMU support patches are also ready and don't
> depend on the AIA QEMU support patches.
>
> Is it okay to target ACLINT support in QEMU first ?

Yeah, go for it.

Alistair

>
> I can rebase this series on ACLINT support patches and also include
> more AIA emulation patches (APLIC and IMSIC) in the AIA series.
>
> Regards,
> Anup
>
> >
> >  hw/riscv/virt.c           |   11 +-
> >  target/riscv/cpu.c        |   32 +-
> >  target/riscv/cpu.h        |   56 +-
> >  target/riscv/cpu_bits.h   |  128 +++++
> >  target/riscv/cpu_helper.c |  245 ++++++++-
> >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> >  target/riscv/machine.c    |   26 +-
> >  7 files changed, 1454 insertions(+), 103 deletions(-)
> >
> > --
> > 2.25.1
> >
>


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
  2021-06-11  5:04       ` Anup Patel
@ 2021-06-11  8:45         ` Alistair Francis
  -1 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-11  8:45 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote:
>
> On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote:
> >
> > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
> > >
> > > We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> > > and VS-mode.
> > >
> > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > ---
> > >  target/riscv/cpu.c        |   27 +-
> > >  target/riscv/cpu.h        |   52 +-
> > >  target/riscv/cpu_helper.c |  245 ++++++++-
> > >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> > >  target/riscv/machine.c    |   26 +-
> > >  5 files changed, 1309 insertions(+), 100 deletions(-)
> >
> > I feel this patch could be split up more :)
>
> This is patch is large because I did not want to break functionality.
>
> I try again to break this patch. At the moment, the best I can do is
> to break in to two parts.
> 1) AIA local interrupt CSRs without IMSIC
> 2) Extend AIA local interrupt CSRs to support IMSIC register access

As the patch is being added while AIA isn't enabled you are able to
add the AIA in breaking stages. That is the AIA isn't fully
functional, you still have to make sure not to break existing users.

>
> >
> > >
> > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > > index f3702111ae..795162834b 100644
> > > --- a/target/riscv/cpu.c
> > > +++ b/target/riscv/cpu.c
> > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> > >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
> > >                       (target_ulong)env->vsstatus);
> > >      }
> > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
> > >      if (riscv_has_ext(env, RVH)) {
> > > -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> > > +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
> > >      }
> > >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> > >      if (riscv_has_ext(env, RVH)) {
> > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
> > >
> > >  static void riscv_cpu_reset(DeviceState *dev)
> > >  {
> > > +    uint8_t iprio;
> > > +    int i, irq, rdzero;
> > >      CPUState *cs = CPU(dev);
> > >      RISCVCPU *cpu = RISCV_CPU(cs);
> > >      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
> > >      env->mcause = 0;
> > >      env->pc = env->resetvec;
> > >      env->two_stage_lookup = false;
> > > +
> > > +    /* Initialized default priorities of local interrupts. */
> > > +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> > > +        iprio = riscv_cpu_default_priority(i);
> > > +        env->miprio[i] = iprio;
> > > +        env->siprio[i] = iprio;
> > > +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> > > +    }
> > > +    i = 0;
> > > +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> > > +        if (rdzero) {
> > > +            env->hviprio[irq] = 0;
> > > +        } else {
> > > +            env->hviprio[irq] = env->miprio[irq];
> > > +        }
> > > +        i++;
> > > +    }
> > >  #endif
> > >      cs->exception_index = EXCP_NONE;
> > >      env->load_res = -1;
> > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > > index f00c60c840..780d3f9058 100644
> > > --- a/target/riscv/cpu.h
> > > +++ b/target/riscv/cpu.h
> > > @@ -157,12 +157,12 @@ struct CPURISCVState {
> > >       */
> > >      uint64_t mstatus;
> > >
> > > -    target_ulong mip;
> > > +    uint64_t mip;
> >
> > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
> > all the other existing target_ulong CSRs are the same.
>
> When AIA is available the number of local interrupts are 64 for
> both RV32 and RV64.

Is that going to be reflected in the priv spec?

>
> The width of CSRs remain same as target_ulong but we have
> new CSRs for RV32 (such as mipH) for the high-half.

Ah! Sorry I missed that.

This change should be in a seperate patch then.

>
> Also, this patch changes does not break the case when AIA
> is not available (or disabled).

Good, we need to make sure we don't.

Alistair

>
> Regards,
> Anup
>
> >
> > Alistair
> >
> > >
> > > -    uint32_t miclaim;
> > > +    uint64_t miclaim;
> > >
> > > -    target_ulong mie;
> > > -    target_ulong mideleg;
> > > +    uint64_t mie;
> > > +    uint64_t mideleg;
> > >
> > >      target_ulong sptbr;  /* until: priv-1.9.1 */
> > >      target_ulong satp;   /* since: priv-1.10.0 */
> > > @@ -179,16 +179,27 @@ struct CPURISCVState {
> > >      target_ulong mcause;
> > >      target_ulong mtval;  /* since: priv-1.10.0 */
> > >
> > > +    /* AIA CSRs */
> > > +    target_ulong miselect;
> > > +    target_ulong siselect;
> > > +
> > > +    uint8_t miprio[64];
> > > +    uint8_t siprio[64];
> > > +
> > >      /* Hypervisor CSRs */
> > >      target_ulong hstatus;
> > >      target_ulong hedeleg;
> > > -    target_ulong hideleg;
> > > +    uint64_t hideleg;
> > >      target_ulong hcounteren;
> > >      target_ulong htval;
> > >      target_ulong htinst;
> > >      target_ulong hgatp;
> > >      uint64_t htimedelta;
> > >
> > > +    /* AIA HS-mode CSRs */
> > > +    uint8_t hviprio[64];
> > > +    target_ulong hvicontrol;
> > > +
> > >      /* Virtual CSRs */
> > >      /*
> > >       * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
> > > @@ -202,6 +213,9 @@ struct CPURISCVState {
> > >      target_ulong vstval;
> > >      target_ulong vsatp;
> > >
> > > +    /* AIA VS-mode CSRs */
> > > +    target_ulong vsiselect;
> > > +
> > >      target_ulong mtval2;
> > >      target_ulong mtinst;
> > >
> > > @@ -236,6 +250,18 @@ struct CPURISCVState {
> > >      uint64_t (*rdtime_fn)(uint32_t);
> > >      uint32_t rdtime_fn_arg;
> > >
> > > +    /* machine specific AIA IMSIC read-modify-write callback */
> > > +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \
> > > +    ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \
> > > +     (((__priv) & 0x3) << 16) | (__isel & 0xffff))
> > > +#define IMSIC_REG_ISEL(__reg)                  ((__reg) & 0xffff)
> > > +#define IMSIC_REG_PRIV(__reg)                  (((__reg) >> 16) & 0x3)
> > > +#define IMSIC_REG_VIRT(__reg)                  (((__reg) >> 20) & 0x1)
> > > +#define IMSIC_REG_VGEIN(__reg)                 (((__reg) >> 24) & 0x3f)
> > > +    int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val,
> > > +                        target_ulong new_val, target_ulong write_mask);
> > > +    void *imsic_rmw_fn_arg;
> > > +
> > >      /* True if in debugger mode.  */
> > >      bool debugger;
> > >  #endif
> > > @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
> > >                                 int cpuid, void *opaque);
> > >  int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
> > >  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero);
> > > +uint8_t riscv_cpu_default_priority(int irq);
> > > +int riscv_cpu_mirq_pending(CPURISCVState *env);
> > > +int riscv_cpu_sirq_pending(CPURISCVState *env);
> > > +int riscv_cpu_vsirq_pending(CPURISCVState *env);
> > >  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
> > >  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> > >  bool riscv_cpu_virt_enabled(CPURISCVState *env);
> > > @@ -364,9 +395,16 @@ void riscv_cpu_list(void);
> > >
> > >  #ifndef CONFIG_USER_ONLY
> > >  void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
> > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
> > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
> > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
> > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value);
> > >  #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
> > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > > +                                int (*rmw_fn)(void *arg,
> > > +                                              target_ulong reg,
> > > +                                              target_ulong *val,
> > > +                                              target_ulong new_val,
> > > +                                              target_ulong write_mask),
> > > +                                void *rmw_fn_arg);
> > >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> > >                               uint32_t arg);
> > >  #endif
> > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > > index 21c54ef561..5b06b4f995 100644
> > > --- a/target/riscv/cpu_helper.c
> > > +++ b/target/riscv/cpu_helper.c
> > > @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
> > >  }
> > >
> > >  #ifndef CONFIG_USER_ONLY
> > > -static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > > +
> > > +/*
> > > + * The HS-mode is allowed to configure priority only for the
> > > + * following VS-mode local interrupts:
> > > + *
> > > + * 0  (Reserved interrupt, reads as zero)
> > > + * 1  Supervisor software interrupt
> > > + * 4  (Reserved interrupt, reads as zero)
> > > + * 5  Supervisor timer interrupt
> > > + * 8  (Reserved interrupt, reads as zero)
> > > + * 13 (Reserved interrupt)
> > > + * 14 "
> > > + * 15 "
> > > + * 16 "
> > > + * 18 Debug/trace interrupt
> > > + * 20 (Reserved interrupt)
> > > + * 22 ”
> > > + * 24 ”
> > > + * 26 ”
> > > + * 28 "
> > > + * 30 (Reserved for standard reporting of bus or system errors)
> > > + */
> > > +
> > > +static int hviprio_index2irq[] =
> > > +    { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
> > > +static int hviprio_index2rdzero[] =
> > > +    { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> > > +
> > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
> > >  {
> > > -    target_ulong irqs;
> > > +    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
> > > +        return -EINVAL;
> > > +    }
> > >
> > > -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> > > -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> > > -    target_ulong hs_mstatus_sie = get_field(env->mstatus_hs, MSTATUS_SIE);
> > > +    if (out_irq) {
> > > +        *out_irq = hviprio_index2irq[index];
> > > +    }
> > > +
> > > +    if (out_rdzero) {
> > > +        *out_rdzero = hviprio_index2rdzero[index];
> > > +    }
> > >
> > > -    target_ulong pending = env->mip & env->mie &
> > > -                               ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > -    target_ulong vspending = (env->mip & env->mie &
> > > -                              (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> > > +    return 0;
> > > +}
> > >
> > > -    target_ulong mie    = env->priv < PRV_M ||
> > > -                          (env->priv == PRV_M && mstatus_mie);
> > > -    target_ulong sie    = env->priv < PRV_S ||
> > > -                          (env->priv == PRV_S && mstatus_sie);
> > > -    target_ulong hs_sie = env->priv < PRV_S ||
> > > -                          (env->priv == PRV_S && hs_mstatus_sie);
> > > +uint8_t riscv_cpu_default_priority(int irq)
> > > +{
> > > +    int u, l;
> > > +    uint8_t iprio = IPRIO_MMAXIPRIO;
> > >
> > > -    if (riscv_cpu_virt_enabled(env)) {
> > > -        target_ulong pending_hs_irq = pending & -hs_sie;
> > > +    if (irq < 0 || irq > 63) {
> > > +        return iprio;
> > > +    }
> > >
> > > -        if (pending_hs_irq) {
> > > -            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> > > -            return ctz64(pending_hs_irq);
> > > +    /*
> > > +     * Default priorities of local interrupts are defined in the
> > > +     * RISC-V Advanced Interrupt Architecture specification.
> > > +     *
> > > +     * ----------------------------------------------------------------
> > > +     *  Default  |
> > > +     *  Priority | Major Interrupt Numbers
> > > +     * ----------------------------------------------------------------
> > > +     *  Highest  | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c),
> > > +     *           | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38),
> > > +     *           | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34),
> > > +     *           | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30)
> > > +     *           |
> > > +     *           | 11 (0b),  3 (03),  7 (07)
> > > +     *           |  9 (09),  1 (01),  5 (05)
> > > +     *           | 12 (0c)
> > > +     *           | 10 (0a),  2 (02),  6 (06)
> > > +     *           |
> > > +     *           | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c),
> > > +     *           | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28),
> > > +     *           | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24),
> > > +     *  Lowest   | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20)
> > > +     * ----------------------------------------------------------------
> > > +     */
> > > +
> > > +    u = IPRIO_DEFAULT_U(irq);
> > > +    l = IPRIO_DEFAULT_L(irq);
> > > +    if (u == 0) {
> > > +        if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER ||
> > > +            irq == IRQ_VS_SOFT) {
> > > +            iprio = IPRIO_DEFAULT_VS;
> > > +        } else if (irq == IRQ_S_GEXT) {
> > > +            iprio = IPRIO_DEFAULT_SGEXT;
> > > +        } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER ||
> > > +                   irq == IRQ_S_SOFT) {
> > > +            iprio = IPRIO_DEFAULT_S;
> > > +        } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER ||
> > > +                   irq == IRQ_M_SOFT) {
> > > +            iprio = IPRIO_DEFAULT_M;
> > > +        } else {
> > > +            iprio = IPRIO_DEFAULT_VS;
> > >          }
> > > +    } else if (u == 1) {
> > > +        if (l < 8) {
> > > +            iprio = IPRIO_DEFAULT_16_23(irq);
> > > +        } else {
> > > +            iprio = IPRIO_DEFAULT_24_31(irq);
> > > +        }
> > > +    } else if (u == 2) {
> > > +        iprio = IPRIO_DEFAULT_32_47(irq);
> > > +    } else if (u == 3) {
> > > +        iprio = IPRIO_DEFAULT_48_63(irq);
> > > +    }
> > > +
> > > +    return iprio;
> > > +}
> > > +
> > > +static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> > > +                                    uint64_t pending, uint8_t *iprio)
> > > +{
> > > +    int irq, best_irq = EXCP_NONE;
> > > +    unsigned int prio, best_prio = UINT_MAX;
> > >
> > > -        pending = vspending;
> > > +    if (!pending) {
> > > +        return EXCP_NONE;
> > >      }
> > >
> > > -    irqs = (pending & ~env->mideleg & -mie) | (pending &  env->mideleg & -sie);
> > > +    irq = ctz64(pending);
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return irq;
> > > +    }
> > >
> > > -    if (irqs) {
> > > -        return ctz64(irqs); /* since non-zero */
> > > +    pending = pending >> irq;
> > > +    while (pending) {
> > > +        prio = iprio[irq];
> > > +        if (!prio) {
> > > +            prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ?
> > > +                   1 : IPRIO_MMAXIPRIO;
> > > +        }
> > > +        if ((pending & 0x1) && (prio < best_prio)) {
> > > +            best_irq = irq;
> > > +            best_prio = prio;
> > > +        }
> > > +        irq++;
> > > +        pending = pending >> 1;
> > > +    }
> > > +
> > > +    return best_irq;
> > > +}
> > > +
> > > +int riscv_cpu_mirq_pending(CPURISCVState *env)
> > > +{
> > > +    uint64_t irqs = env->mip & env->mie & ~env->mideleg &
> > > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > +
> > > +    return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > > +}
> > > +
> > > +int riscv_cpu_sirq_pending(CPURISCVState *env)
> > > +{
> > > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > +
> > > +    return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > > +}
> > > +
> > > +int riscv_cpu_vsirq_pending(CPURISCVState *env)
> > > +{
> > > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > > +                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > +
> > > +    return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > > +}
> > > +
> > > +static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > > +{
> > > +    int virq;
> > > +    uint64_t irqs, mie, sie, vsie;
> > > +    uint64_t pending, vspending;
> > > +
> > > +    /* Determine interrupt enable state of all privilege modes */
> > > +    if (riscv_cpu_virt_enabled(env)) {
> > > +        mie = 1;
> > > +        sie = 1;
> > > +        vsie = (env->priv < PRV_S) ||
> > > +               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> > >      } else {
> > > -        return EXCP_NONE; /* indicates no pending interrupt */
> > > +        mie = (env->priv < PRV_M) ||
> > > +              (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
> > > +        sie = (env->priv < PRV_S) ||
> > > +              (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> > > +        vsie = 0;
> > > +    }
> > > +
> > > +    /* Check M-mode interrupts */
> > > +    pending = env->mip & env->mie &
> > > +              ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > +    irqs = pending & ~env->mideleg & -mie;
> > > +    if (irqs) {
> > > +        return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > > +    }
> > > +
> > > +    /* Check HS-mode interrupts */
> > > +    irqs = pending & env->mideleg & -sie;
> > > +    if (irqs) {
> > > +        return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > > +    }
> > > +
> > > +    /* Check VS-mode interrupts */
> > > +    vspending = env->mip & env->mie &
> > > +                (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > +    irqs = vspending & env->hideleg & -vsie;
> > > +    if (irqs) {
> > > +        virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > > +        return (virq <= 0) ? virq : virq + 1;
> > >      }
> > > +
> > > +    /* Indicates no pending interrupt */
> > > +    return EXCP_NONE;
> > >  }
> > >  #endif
> > >
> > > @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx)
> > >      return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
> > >  }
> > >
> > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
> > >  {
> > >      CPURISCVState *env = &cpu->env;
> > >      if (env->miclaim & interrupts) {
> > > @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> > >      }
> > >  }
> > >
> > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
> > >  {
> > >      CPURISCVState *env = &cpu->env;
> > >      CPUState *cs = CPU(cpu);
> > > -    uint32_t old = env->mip;
> > > +    uint64_t old = env->mip;
> > >      bool locked = false;
> > >
> > >      if (!qemu_mutex_iothread_locked()) {
> > > @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> > >      return old;
> > >  }
> > >
> > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > > +                                int (*rmw_fn)(void *arg,
> > > +                                              target_ulong reg,
> > > +                                              target_ulong *val,
> > > +                                              target_ulong new_val,
> > > +                                              target_ulong write_mask),
> > > +                                void *rmw_fn_arg)
> > > +{
> > > +    env->imsic_rmw_fn = rmw_fn;
> > > +    env->imsic_rmw_fn_arg = rmw_fn_arg;
> > > +}
> > > +
> > >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> > >                               uint32_t arg)
> > >  {
> > > @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> > >       */
> > >      bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
> > >      target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
> > > -    target_ulong deleg = async ? env->mideleg : env->medeleg;
> > > +    uint64_t deleg = async ? env->mideleg : env->medeleg;
> > >      bool write_tval = false;
> > >      target_ulong tval = 0;
> > >      target_ulong htval = 0;
> > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > > index d2585395bf..3c016d7452 100644
> > > --- a/target/riscv/csr.c
> > > +++ b/target/riscv/csr.c
> > > @@ -153,11 +153,56 @@ static int any32(CPURISCVState *env, int csrno)
> > >
> > >  }
> > >
> > > +static int aia_any(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return any(env, csrno);
> > > +}
> > > +
> > > +static int aia_any32(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return any32(env, csrno);
> > > +}
> > > +
> > >  static int smode(CPURISCVState *env, int csrno)
> > >  {
> > >      return -!riscv_has_ext(env, RVS);
> > >  }
> > >
> > > +static int smode32(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_cpu_is_32bit(env)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return smode(env, csrno);
> > > +}
> > > +
> > > +static int aia_smode(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return smode(env, csrno);
> > > +}
> > > +
> > > +static int aia_smode32(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return smode32(env, csrno);
> > > +}
> > > +
> > >  static int hmode(CPURISCVState *env, int csrno)
> > >  {
> > >      if (riscv_has_ext(env, RVS) &&
> > > @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno)
> > >  static int hmode32(CPURISCVState *env, int csrno)
> > >  {
> > >      if (!riscv_cpu_is_32bit(env)) {
> > > -        return 0;
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return hmode(env, csrno);
> > > +}
> > > +
> > > +static int aia_hmode(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > >      }
> > >
> > >      return hmode(env, csrno);
> > > +}
> > >
> > > +static int aia_hmode32(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return hmode32(env, csrno);
> > >  }
> > >
> > >  static int pmp(CPURISCVState *env, int csrno)
> > > @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
> > >
> > >  /* Machine constants */
> > >
> > > -#define M_MODE_INTERRUPTS  (MIP_MSIP | MIP_MTIP | MIP_MEIP)
> > > -#define S_MODE_INTERRUPTS  (MIP_SSIP | MIP_STIP | MIP_SEIP)
> > > -#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)
> > > +#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
> > > +#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
> > > +#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
> > > +
> > > +#define TLOWBITS64         ((uint64_t)((target_ulong)-1))
> > >
> > > -static const target_ulong delegable_ints = S_MODE_INTERRUPTS |
> > > -                                           VS_MODE_INTERRUPTS;
> > > -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > > -                                     VS_MODE_INTERRUPTS;
> > > +static const uint64_t delegable_ints = S_MODE_INTERRUPTS |
> > > +                                       VS_MODE_INTERRUPTS;
> > > +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > > +                                 VS_MODE_INTERRUPTS;
> > >  static const target_ulong delegable_excps =
> > >      (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) |
> > >      (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) |
> > > @@ -419,10 +483,10 @@ static const target_ulong delegable_excps =
> > >  static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
> > >      SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
> > >      SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
> > > -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > > -static const target_ulong hip_writable_mask = MIP_VSSIP;
> > > -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > > -static const target_ulong vsip_writable_mask = MIP_VSSIP;
> > > +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > > +static const uint64_t hip_writable_mask = MIP_VSSIP;
> > > +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > > +static const uint64_t vsip_writable_mask = MIP_VSSIP;
> > >
> > >  static const char valid_vm_1_10_32[16] = {
> > >      [VM_1_10_MBARE] = 1,
> > > @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val)
> > >
> > >  static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
> > >  {
> > > -    env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
> > > +    uint64_t mask = delegable_ints & TLOWBITS64;
> > > +
> > > +    env->mideleg = (env->mideleg & ~mask) | (val & mask);
> > > +    if (riscv_has_ext(env, RVH)) {
> > > +        env->mideleg |= VS_MODE_INTERRUPTS;
> > > +    }
> > > +    return 0;
> > > +}
> > > +
> > > +static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_cpu_virt_enabled(env)) {
> > > +        return csrno;
> > > +    }
> > > +
> > > +    switch (csrno) {
> > > +    case CSR_SISELECT:
> > > +        return CSR_VSISELECT;
> > > +    case CSR_SIREG:
> > > +        return CSR_VSIREG;
> > > +    case CSR_STOPI:
> > > +        return CSR_VSTOPI;
> > > +    case CSR_SSETEIPNUM:
> > > +        return CSR_VSSETEIPNUM;
> > > +    case CSR_SCLREIPNUM:
> > > +        return CSR_VSCLREIPNUM;
> > > +    case CSR_SSETEIENUM:
> > > +        return CSR_VSSETEIENUM;
> > > +    case CSR_SCLREIENUM:
> > > +        return CSR_VSCLREIENUM;
> > > +    default:
> > > +        return csrno;
> > > +    };
> > > +}
> > > +
> > > +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val,
> > > +                        target_ulong new_val, target_ulong write_mask)
> > > +{
> > > +    target_ulong *iselect;
> > > +
> > > +    switch (csrno) {
> > > +    case CSR_MISELECT:
> > > +        iselect = &env->miselect;
> > > +        break;
> > > +    case CSR_SISELECT:
> > > +        iselect = riscv_cpu_virt_enabled(env) ?
> > > +                  &env->vsiselect : &env->siselect;
> > > +        break;
> > > +    case CSR_VSISELECT:
> > > +        iselect = &env->vsiselect;
> > > +        break;
> > > +    default:
> > > +         return -RISCV_EXCP_ILLEGAL_INST;
> > > +    };
> > > +
> > > +    if (val) {
> > > +        *val = *iselect;
> > > +    }
> > > +
> > > +    if (write_mask) {
> > > +        *iselect = (*iselect & ~write_mask) | (new_val & write_mask);
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int rmw_iprio(target_ulong iselect, uint8_t *iprio,
> > > +                     target_ulong *val, target_ulong new_val,
> > > +                     target_ulong write_mask)
> > > +{
> > > +    int i, firq, nirqs;
> > > +    target_ulong old_val;
> > > +
> > > +    if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) {
> > > +        return -EINVAL;
> > > +    }
> > > +#if TARGET_LONG_BITS == 64
> > > +    if (iselect & 0x1) {
> > > +        return -EINVAL;
> > > +    }
> > > +#endif
> > > +
> > > +    nirqs = 4 * (TARGET_LONG_BITS / 32);
> > > +    firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 32)) * (nirqs);
> > > +
> > > +    old_val = 0;
> > > +    for (i = 0; i < nirqs; i++) {
> > > +        old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i);
> > > +    }
> > > +
> > > +    if (val) {
> > > +        *val = old_val;
> > > +    }
> > > +
> > > +    if (write_mask) {
> > > +        new_val = (old_val & ~write_mask) | (new_val & write_mask);
> > > +        for (i = 0; i < nirqs; i++) {
> > > +            iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff;
> > > +        }
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
> > > +                     target_ulong new_val, target_ulong write_mask)
> > > +{
> > > +    bool virt;
> > > +    uint8_t *iprio;
> > > +    int ret = -EINVAL;
> > > +    target_ulong priv, isel, vgein;
> > > +
> > > +    /* Translate CSR number for VS-mode */
> > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > +
> > > +    /* Decode register details from CSR number */
> > > +    virt = false;
> > > +    switch (csrno) {
> > > +    case CSR_MIREG:
> > > +        iprio = env->miprio;
> > > +        isel = env->miselect;
> > > +        priv = PRV_M;
> > > +        break;
> > > +    case CSR_SIREG:
> > > +        iprio = env->siprio;
> > > +        isel = env->siselect;
> > > +        priv = PRV_S;
> > > +        break;
> > > +    case CSR_VSIREG:
> > > +        iprio = env->hviprio;
> > > +        isel = env->vsiselect;
> > > +        priv = PRV_S;
> > > +        virt = true;
> > > +        break;
> > > +    default:
> > > +         goto done;
> > > +    };
> > > +
> > > +    /* Find the selected guest interrupt file */
> > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > +
> > > +    if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) {
> > > +        /* Local interrupt priority registers not available for VS-mode */
> > > +        if (!virt) {
> > > +            ret = rmw_iprio(isel, iprio, val, new_val, write_mask);
> > > +        }
> > > +    } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) {
> > > +        /* IMSIC registers only available when machine implements it. */
> > > +        if (env->imsic_rmw_fn) {
> > > +            /* Selected guest interrupt file should not be zero */
> > > +            if (virt && !vgein) {
> > > +                goto done;
> > > +            }
> > > +            /* Call machine specific IMSIC register emulation */
> > > +            ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > +                                    IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > +                                    val, new_val, write_mask);
> > > +        }
> > > +    }
> > > +
> > > +done:
> > > +    if (ret) {
> > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    int irq;
> > > +
> > > +    irq = riscv_cpu_mirq_pending(env);
> > > +    if (irq <= 0 || irq > 63) {
> > > +       *val = 0;
> > > +    } else {
> > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > +       *val |= env->miprio[irq];
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    bool virt;
> > > +    int ret = -EINVAL;
> > > +    target_ulong vgein;
> > > +
> > > +    /* Translate CSR number for VS-mode */
> > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > +
> > > +    /* Decode register details from CSR number */
> > > +    virt = false;
> > > +    switch (csrno) {
> > > +    case CSR_MSETEIPNUM:
> > > +    case CSR_MCLREIPNUM:
> > > +    case CSR_MSETEIENUM:
> > > +    case CSR_MCLREIENUM:
> > > +    case CSR_SSETEIPNUM:
> > > +    case CSR_SCLREIPNUM:
> > > +    case CSR_SSETEIENUM:
> > > +    case CSR_SCLREIENUM:
> > > +        break;
> > > +    case CSR_VSSETEIPNUM:
> > > +    case CSR_VSCLREIPNUM:
> > > +    case CSR_VSSETEIENUM:
> > > +    case CSR_VSCLREIENUM:
> > > +        virt = true;
> > > +        break;
> > > +    default:
> > > +         goto done;
> > > +    };
> > > +
> > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > +    if (!env->imsic_rmw_fn) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Find the selected guest interrupt file */
> > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > +
> > > +    /* Selected guest interrupt file should not be zero */
> > > +    if (virt && !vgein) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Set/Clear CSRs always read zero */
> > > +    ret = 0;
> > > +    if (val) {
> > > +        *val = 0;
> > > +    }
> > > +
> > > +done:
> > > +    if (ret) {
> > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    int ret = -EINVAL;
> > > +    bool set, pend, virt;
> > > +    target_ulong priv, isel, vgein;
> > > +    target_ulong new_val, write_mask;
> > > +
> > > +    /* Translate CSR number for VS-mode */
> > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > +
> > > +    /* Decode register details from CSR number */
> > > +    virt = set = pend = false;
> > > +    switch (csrno) {
> > > +    case CSR_MSETEIPNUM:
> > > +        priv = PRV_M;
> > > +        set = true;
> > > +        break;
> > > +    case CSR_MCLREIPNUM:
> > > +        priv = PRV_M;
> > > +        pend = true;
> > > +        break;
> > > +    case CSR_MSETEIENUM:
> > > +        priv = PRV_M;
> > > +        set = true;
> > > +        break;
> > > +    case CSR_MCLREIENUM:
> > > +        priv = PRV_M;
> > > +        break;
> > > +    case CSR_SSETEIPNUM:
> > > +        priv = PRV_S;
> > > +        set = true;
> > > +        pend = true;
> > > +        break;
> > > +    case CSR_SCLREIPNUM:
> > > +        priv = PRV_S;
> > > +        pend = true;
> > > +        break;
> > > +    case CSR_SSETEIENUM:
> > > +        priv = PRV_S;
> > > +        set = true;
> > > +        break;
> > > +    case CSR_SCLREIENUM:
> > > +        priv = PRV_S;
> > > +        break;
> > > +    case CSR_VSSETEIPNUM:
> > > +        priv = PRV_S;
> > > +        virt = true;
> > > +        set = true;
> > > +        pend = true;
> > > +        break;
> > > +    case CSR_VSCLREIPNUM:
> > > +        priv = PRV_S;
> > > +        virt = true;
> > > +        pend = true;
> > > +        break;
> > > +    case CSR_VSSETEIENUM:
> > > +        priv = PRV_S;
> > > +        virt = true;
> > > +        set = true;
> > > +        break;
> > > +    case CSR_VSCLREIENUM:
> > > +        priv = PRV_S;
> > > +        virt = true;
> > > +        break;
> > > +    default:
> > > +         goto done;
> > > +    };
> > > +
> > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > +    if (!env->imsic_rmw_fn) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Find target interrupt pending/enable register */
> > > +    if (pend) {
> > > +        isel = ISELECT_IMSIC_EIP0;
> > > +    } else {
> > > +        isel = ISELECT_IMSIC_EIE0;
> > > +    }
> > > +    isel += val / IMSIC_EIPx_BITS;
> > > +
> > > +    /* Find the interrupt bit to be set/clear */
> > > +    write_mask = 1 << (val % IMSIC_EIPx_BITS);
> > > +    new_val = (set) ? write_mask : 0;
> > > +
> > > +    /* Find the selected guest interrupt file */
> > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > +
> > > +    /* Selected guest interrupt file should not be zero */
> > > +    if (virt && !vgein) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Call machine specific IMSIC register emulation */
> > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > +                            NULL, new_val, write_mask);
> > > +
> > > +done:
> > > +    if (ret) {
> > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    bool virt;
> > > +    int ret = -EINVAL;
> > > +    target_ulong priv, isel, vgein;
> > > +    target_ulong topei, write_mask;
> > > +
> > > +    /* Decode register details from CSR number */
> > > +    virt = false;
> > > +    switch (csrno) {
> > > +    case CSR_MCLAIMEI:
> > > +        priv = PRV_M;
> > > +        break;
> > > +    case CSR_SCLAIMEI:
> > > +        priv = PRV_S;
> > > +        virt = riscv_cpu_virt_enabled(env);
> > > +        break;
> > > +    default:
> > > +        goto done;
> > > +    };
> > > +
> > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > +    if (!env->imsic_rmw_fn) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Find the selected guest interrupt file */
> > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > +
> > > +    /* Selected guest interrupt file should not be zero */
> > > +    if (virt && !vgein) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Call machine specific IMSIC register emulation for reading TOPEI */
> > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > +                            IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein),
> > > +                            &topei, -1, 0);
> > > +    if (ret) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* If no interrupt pending then we are done */
> > > +    if (!topei) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Find target interrupt pending register */
> > > +    isel = ISELECT_IMSIC_EIP0;
> > > +    isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS);
> > > +
> > > +    /* Find the interrupt bit to be cleared */
> > > +    write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS);
> > > +
> > > +    /* Call machine specific IMSIC register emulation to clear pending bit */
> > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > +                            NULL, 0, write_mask);
> > > +
> > > +    /* Update return value */
> > > +    if (val) {
> > > +        *val = topei;
> > > +    }
> > > +
> > > +done:
> > > +    if (ret) {
> > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    *val = (env->mideleg >> 32);
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    uint64_t mask = delegable_ints & ~TLOWBITS64;
> > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > +
> > > +    env->mideleg = (env->mideleg & ~mask) | (newval & mask);
> > >      if (riscv_has_ext(env, RVH)) {
> > >          env->mideleg |= VS_MODE_INTERRUPTS;
> > >      }
> > > @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
> > >
> > >  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
> > >  {
> > > -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> > > +    uint64_t mask = all_ints & TLOWBITS64;
> > > +
> > > +    env->mie = (env->mie & ~mask) | (val & mask);
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    *val = (env->mie >> 32);
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    uint64_t mask = all_ints & ~TLOWBITS64;
> > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > +
> > > +    env->mie = (env->mie & ~mask) | (newval & mask);
> > >      return 0;
> > >  }
> > >
> > > @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >  {
> > >      RISCVCPU *cpu = env_archcpu(env);
> > >      /* Allow software control of delegable interrupts not claimed by hardware */
> > > -    target_ulong mask = write_mask & delegable_ints & ~env->miclaim;
> > > -    uint32_t old_mip;
> > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > +                    ~env->miclaim & TLOWBITS64;
> > > +    uint64_t old_mip;
> > >
> > >      if (mask) {
> > >          old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >      return 0;
> > >  }
> > >
> > > +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > +                    target_ulong new_value, target_ulong write_mask)
> > > +{
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > +                    ~env->miclaim & ~TLOWBITS64;
> > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > > +
> > > +    if (ret_value) {
> > > +        *ret_value = old_mip >> 32;
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > >  /* Supervisor Trap Setup */
> > >  static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > >  {
> > > @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
> > >
> > >  static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
> > >  {
> > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64;
> > > +
> > >      /* Shift the VS bits to their S bit location in vsie */
> > > -    *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
> > > +    *val = (env->mie & mask) >> 1;
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64;
> > > +
> > > +    /* Shift the VS bits to their S bit location in vsieh */
> > > +    *val = (env->mie & mask) >> (32 + 1);
> > >      return 0;
> > >  }
> > >
> > >  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
> > >  {
> > >      if (riscv_cpu_virt_enabled(env)) {
> > > -        read_vsie(env, CSR_VSIE, val);
> > > -    } else {
> > > -        *val = env->mie & env->mideleg;
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return read_vsie(env, CSR_VSIE, val);
> > >      }
> > > +
> > > +    *val = env->mie & env->mideleg;
> > >      return 0;
> > >  }
> > >
> > >  static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
> > >  {
> > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > > +                    all_ints & TLOWBITS64;
> > > +
> > >      /* Shift the S bits to their VS bit location in mie */
> > > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
> > > -                          ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS);
> > > -    return write_mie(env, CSR_MIE, newval);
> > > +    env->mie = (env->mie & ~mask) | ((val << 1) & mask);
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > > +                    all_ints & ~TLOWBITS64;
> > > +    uint64_t newval = (uint64_t)val << 32;
> > > +
> > > +    /* Shift the S bits to their VS bit location in mie */
> > > +    env->mie = (env->mie & ~mask) | ((newval << 1) & mask);
> > > +
> > > +    return 0;
> > >  }
> > >
> > >  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
> > >  {
> > > +    uint64_t mask;
> > > +
> > >      if (riscv_cpu_virt_enabled(env)) {
> > > -        write_vsie(env, CSR_VSIE, val);
> > > -    } else {
> > > -        target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) |
> > > -                              (val & S_MODE_INTERRUPTS);
> > > -        write_mie(env, CSR_MIE, newval);
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return write_vsie(env, CSR_VSIE, val);
> > > +    }
> > > +
> > > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64;
> > > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    if (riscv_cpu_virt_enabled(env)) {
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return read_vsieh(env, CSR_VSIEH, val);
> > > +    }
> > > +
> > > +    *val = ((env->mie & env->mideleg) >> 32);
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    uint64_t mask, newval;
> > > +
> > > +    if (riscv_cpu_virt_enabled(env)) {
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return write_vsieh(env, CSR_VSIEH, val);
> > >      }
> > >
> > > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64;
> > > +    newval = (uint64_t)val << 32;
> > > +
> > > +    env->mie = (env->mie & ~mask) | (newval & mask);
> > >      return 0;
> > >  }
> > >
> > > @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
> > >  static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >                      target_ulong new_value, target_ulong write_mask)
> > >  {
> > > -    /* Shift the S bits to their VS bit location in mip */
> > > -    int ret = rmw_mip(env, 0, ret_value, new_value << 1,
> > > -                      (write_mask << 1) & vsip_writable_mask & env->hideleg);
> > > -    *ret_value &= VS_MODE_INTERRUPTS;
> > > -    /* Shift the VS bits to their S bit location in vsip */
> > > -    *ret_value >>= 1;
> > > -    return ret;
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints &
> > > +                    vsip_writable_mask & env->hideleg &
> > > +                    ~env->miclaim & TLOWBITS64;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > > +
> > > +    if (ret_value) {
> > > +        *ret_value = old_mip & VS_MODE_INTERRUPTS;
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > +                     target_ulong new_value, target_ulong write_mask)
> > > +{
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints &
> > > +                    vsip_writable_mask & env->hideleg &
> > > +                    ~env->miclaim & ~TLOWBITS64;
> > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > > +
> > > +    if (ret_value) {
> > > +        *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32;
> > > +    }
> > > +
> > > +    return 0;
> > >  }
> > >
> > >  static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >                     target_ulong new_value, target_ulong write_mask)
> > >  {
> > > -    int ret;
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    uint64_t mask, old_mip;
> > >
> > >      if (riscv_cpu_virt_enabled(env)) {
> > > -        ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > > +    }
> > > +
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    mask = ((uint64_t)write_mask) & delegable_ints &
> > > +           env->mideleg & sip_writable_mask &
> > > +           ~env->miclaim & TLOWBITS64;
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > >      } else {
> > > -        ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
> > > -                      write_mask & env->mideleg & sip_writable_mask);
> > > +        old_mip = env->mip;
> > >      }
> > >
> > > -    *ret_value &= env->mideleg;
> > > -    return ret;
> > > +    if (ret_value) {
> > > +        *ret_value = old_mip;
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > +                    target_ulong new_value, target_ulong write_mask)
> > > +{
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    uint64_t mask, new_value64;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (riscv_cpu_virt_enabled(env)) {
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask);
> > > +    }
> > > +
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > +           env->mideleg & sip_writable_mask &
> > > +           ~env->miclaim & ~TLOWBITS64;
> > > +    new_value64 = (uint64_t)new_value << 32;
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > > +
> > > +    if (ret_value) {
> > > +        *ret_value = (old_mip & env->mideleg) >> 32;
> > > +    }
> > > +
> > > +    return 0;
> > >  }
> > >
> > >  /* Supervisor Protection and Translation */
> > > @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
> > >      return 0;
> > >  }
> > >
> > > +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    int irq, hiid;
> > > +    uint8_t hiprio, iprio;
> > > +
> > > +    irq = riscv_cpu_vsirq_pending(env);
> > > +    if (irq <= 0 || irq > 63) {
> > > +       *val = 0;
> > > +    } else {
> > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > +       iprio = env->hviprio[irq];
> > > +       /* TODO: This needs to improve in specification */
> > > +       if (!(env->hstatus & HSTATUS_VGEIN)) {
> > > +           hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >>
> > > +                 HVICONTROL_IID_SHIFT;
> > > +           hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK;
> > > +           if (irq == hiid && hiprio) {
> > > +               iprio = hiprio;
> > > +           }
> > > +       }
> > > +       *val |= iprio;
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    int irq;
> > > +
> > > +    if (riscv_cpu_virt_enabled(env)) {
> > > +        return read_vstopi(env, CSR_VSTOPI, val);
> > > +    }
> > > +
> > > +    irq = riscv_cpu_sirq_pending(env);
> > > +    if (irq <= 0 || irq > 63) {
> > > +       *val = 0;
> > > +    } else {
> > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > +       *val |= env->siprio[irq];
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > >  /* Hypervisor Extensions */
> > >  static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > >  {
> > > @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
> > >      return 0;
> > >  }
> > >
> > > +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    *val = env->hideleg >> 32;
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    uint64_t mask = ~TLOWBITS64;
> > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > +
> > > +    env->hideleg = (env->hideleg & ~mask) | (newval & mask);
> > > +
> > > +    return 0;
> > > +}
> > > +
> > >  static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >                     target_ulong new_value, target_ulong write_mask)
> > >  {
> > > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > > -                      write_mask & hvip_writable_mask);
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > +                    hvip_writable_mask &
> > > +                    ~env->miclaim & TLOWBITS64;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > >
> > > -    *ret_value &= hvip_writable_mask;
> > > +    if (ret_value) {
> > > +        *ret_value = old_mip & hvip_writable_mask;
> > > +    }
> > >
> > > -    return ret;
> > > +    return 0;
> > > +}
> > > +
> > > +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > +                    target_ulong new_value, target_ulong write_mask)
> > > +{
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > +                    hvip_writable_mask &
> > > +                    ~env->miclaim & ~TLOWBITS64;
> > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > > +
> > > +    if (ret_value) {
> > > +        *ret_value = (old_mip & hvip_writable_mask) >> 32;
> > > +    }
> > > +
> > > +    return 0;
> > >  }
> > >
> > >  static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >                     target_ulong new_value, target_ulong write_mask)
> > >  {
> > > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > > -                      write_mask & hip_writable_mask);
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > +                    hip_writable_mask &
> > > +                    ~env->miclaim & TLOWBITS64;
> > > +    uint64_t old_mip;
> > >
> > > -    *ret_value &= hip_writable_mask;
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > >
> > > -    return ret;
> > > +    if (ret_value) {
> > > +        *ret_value = old_mip & hip_writable_mask;
> > > +    }
> > > +
> > > +    return 0;
> > >  }
> > >
> > >  static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> > > @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> > >
> > >  static int write_hie(CPURISCVState *env, int csrno, target_ulong val)
> > >  {
> > > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS);
> > > -    return write_mie(env, CSR_MIE, newval);
> > > +    uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64;
> > > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > > +    return 0;
> > >  }
> > >
> > >  static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val)
> > > @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val)
> > >      return 0;
> > >  }
> > >
> > > +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    *val = env->hvicontrol;
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    env->hvicontrol = val & HVICONTROL_VALID_MASK;
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_hvipriox(CPURISCVState *env, int first_index,
> > > +                         uint8_t *iprio, target_ulong *val)
> > > +{
> > > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > > +
> > > +    /* First index has to be multiple of numbe of irqs per register */
> > > +    if (first_index % num_irqs) {
> > > +        return (riscv_cpu_virt_enabled(env)) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    /* Fill-up return value */
> > > +    *val = 0;
> > > +    for (i = 0; i < num_irqs; i++) {
> > > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > > +            continue;
> > > +        }
> > > +        if (rdzero) {
> > > +            continue;
> > > +        }
> > > +        *val |= ((target_ulong)iprio[irq]) << (i * 8);
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_hvipriox(CPURISCVState *env, int first_index,
> > > +                          uint8_t *iprio, target_ulong val)
> > > +{
> > > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > > +
> > > +    /* First index has to be multiple of numbe of irqs per register */
> > > +    if (first_index % num_irqs) {
> > > +        return (riscv_cpu_virt_enabled(env)) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    /* Fill-up priority arrary */
> > > +    for (i = 0; i < num_irqs; i++) {
> > > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > > +            continue;
> > > +        }
> > > +        if (rdzero) {
> > > +            iprio[irq] = 0;
> > > +        } else {
> > > +            iprio[irq] = (val >> (i * 8)) & 0xff;
> > > +        }
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    return read_hvipriox(env, 0, env->hviprio, val);
> > > +}
> > > +
> > > +static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    return write_hvipriox(env, 0, env->hviprio, val);
> > > +}
> > > +
> > > +static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    return read_hvipriox(env, 4, env->hviprio, val);
> > > +}
> > > +
> > > +static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    return write_hvipriox(env, 4, env->hviprio, val);
> > > +}
> > > +
> > > +static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    return read_hvipriox(env, 8, env->hviprio, val);
> > > +}
> > > +
> > > +static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    return write_hvipriox(env, 8, env->hviprio, val);
> > > +}
> > > +
> > > +static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    return read_hvipriox(env, 12, env->hviprio, val);
> > > +}
> > > +
> > > +static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    return write_hvipriox(env, 12, env->hviprio, val);
> > > +}
> > > +
> > >  /* Virtual CSR Registers */
> > >  static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > >  {
> > > @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > >      [CSR_MBADADDR] = { "mbadaddr", any,  read_mbadaddr, write_mbadaddr },
> > >      [CSR_MIP]      = { "mip",      any,  NULL,    NULL, rmw_mip        },
> > >
> > > +    /* Machine-Level Window to Indirectly Accessed Registers (AIA) */
> > > +    [CSR_MISELECT] = { "miselect", aia_any,   NULL, NULL,    rmw_xiselect },
> > > +    [CSR_MIREG]    = { "mireg",    aia_any,   NULL, NULL,    rmw_xireg },
> > > +
> > > +    /* Machine-Level Interrupts (AIA) */
> > > +    [CSR_MTOPI]    = { "mtopi",    aia_any,   read_mtopi },
> > > +
> > > +    /* Machine-Level IMSIC Interface (AIA) */
> > > +    [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_MCLAIMEI]   = { "mclaimei",   aia_any, read_xclaimei },
> > > +
> > > +    /* Machine-Level High-Half CSRs (AIA) */
> > > +    [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh },
> > > +    [CSR_MIEH]     = { "mieh",     aia_any32, read_mieh,     write_mieh     },
> > > +    [CSR_MIPH]     = { "miph",     aia_any32, NULL,    NULL, rmw_miph       },
> > > +
> > >      /* Supervisor Trap Setup */
> > >      [CSR_SSTATUS]    = { "sstatus",    smode, read_sstatus,    write_sstatus    },
> > >      [CSR_SIE]        = { "sie",        smode, read_sie,        write_sie        },
> > > @@ -1444,6 +2357,24 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > >      /* Supervisor Protection and Translation */
> > >      [CSR_SATP]     = { "satp",     smode, read_satp,    write_satp      },
> > >
> > > +    /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
> > > +    [CSR_SISELECT]   = { "siselect",   aia_smode, NULL, NULL, rmw_xiselect },
> > > +    [CSR_SIREG]      = { "sireg",      aia_smode, NULL, NULL, rmw_xireg },
> > > +
> > > +    /* Supervisor-Level Interrupts (AIA) */
> > > +    [CSR_STOPI]      = { "stopi",      aia_smode, read_stopi },
> > > +
> > > +    /* Supervisor-Level IMSIC Interface (AIA) */
> > > +    [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_SCLAIMEI]   = { "sclaimei",   aia_smode, read_xclaimei },
> > > +
> > > +    /* Supervisor-Level High-Half CSRs (AIA) */
> > > +    [CSR_SIEH]       = { "sieh",       aia_smode32, read_sieh,  write_sieh },
> > > +    [CSR_SIPH]       = { "siph",       aia_smode32, NULL, NULL, rmw_siph   },
> > > +
> > >      [CSR_HSTATUS]     = { "hstatus",     hmode,   read_hstatus,     write_hstatus     },
> > >      [CSR_HEDELEG]     = { "hedeleg",     hmode,   read_hedeleg,     write_hedeleg     },
> > >      [CSR_HIDELEG]     = { "hideleg",     hmode,   read_hideleg,     write_hideleg     },
> > > @@ -1472,6 +2403,32 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > >      [CSR_MTVAL2]      = { "mtval2",      hmode,   read_mtval2,      write_mtval2      },
> > >      [CSR_MTINST]      = { "mtinst",      hmode,   read_mtinst,      write_mtinst      },
> > >
> > > +    /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
> > > +    [CSR_HVICONTROL]  = { "hvicontrol",  aia_hmode, read_hvicontrol, write_hvicontrol },
> > > +    [CSR_HVIPRIO1]    = { "hviprio1",    aia_hmode, read_hviprio1,   write_hviprio1 },
> > > +    [CSR_HVIPRIO2]    = { "hviprio2",    aia_hmode, read_hviprio2,   write_hviprio2 },
> > > +
> > > +    /* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
> > > +    [CSR_VSISELECT]   = { "vsiselect",   aia_hmode, NULL, NULL,      rmw_xiselect },
> > > +    [CSR_VSIREG]      = { "vsireg",      aia_hmode, NULL, NULL,      rmw_xireg },
> > > +
> > > +    /* VS-Level Interrupts (H-extension with AIA) */
> > > +    [CSR_VSTOPI]      = { "vstopi",      aia_hmode, read_vstopi },
> > > +
> > > +    /* VS-Level IMSIC Interface (H-extension with AIA) */
> > > +    [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > +
> > > +    /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
> > > +    [CSR_HIDELEGH]    = { "hidelegh",    aia_hmode32, read_hidelegh,  write_hidelegh },
> > > +    [CSR_HVIPH]       = { "hviph",       aia_hmode32, NULL, NULL,     rmw_hviph },
> > > +    [CSR_HVIPRIO1H]   = { "hviprio1h",   aia_hmode32, read_hviprio1h, write_hviprio1h },
> > > +    [CSR_HVIPRIO2H]   = { "hviprio2h",   aia_hmode32, read_hviprio2h, write_hviprio2h },
> > > +    [CSR_VSIEH]       = { "vsieh",       aia_hmode32, read_vsieh,     write_vsieh },
> > > +    [CSR_VSIPH]       = { "vsiep",       aia_hmode32, NULL, NULL,     rmw_vsiph },
> > > +
> > >      /* Physical Memory Protection */
> > >      [CSR_PMPCFG0]    = { "pmpcfg0",   pmp, read_pmpcfg,  write_pmpcfg  },
> > >      [CSR_PMPCFG1]    = { "pmpcfg1",   pmp, read_pmpcfg,  write_pmpcfg  },
> > > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> > > index 44d4015bd6..f7fa48c240 100644
> > > --- a/target/riscv/machine.c
> > > +++ b/target/riscv/machine.c
> > > @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = {
> > >
> > >  static const VMStateDescription vmstate_hyper = {
> > >      .name = "cpu/hyper",
> > > -    .version_id = 1,
> > > -    .minimum_version_id = 1,
> > > +    .version_id = 2,
> > > +    .minimum_version_id = 2,
> > >      .needed = hyper_needed,
> > >      .fields = (VMStateField[]) {
> > >          VMSTATE_UINTTL(env.hstatus, RISCVCPU),
> > >          VMSTATE_UINTTL(env.hedeleg, RISCVCPU),
> > > -        VMSTATE_UINTTL(env.hideleg, RISCVCPU),
> > > +        VMSTATE_UINT64(env.hideleg, RISCVCPU),
> > >          VMSTATE_UINTTL(env.hcounteren, RISCVCPU),
> > >          VMSTATE_UINTTL(env.htval, RISCVCPU),
> > >          VMSTATE_UINTTL(env.htinst, RISCVCPU),
> > >          VMSTATE_UINTTL(env.hgatp, RISCVCPU),
> > >          VMSTATE_UINT64(env.htimedelta, RISCVCPU),
> > >
> > > +        VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
> > > +        VMSTATE_UINTTL(env.hvicontrol, RISCVCPU),
> > > +
> > >          VMSTATE_UINT64(env.vsstatus, RISCVCPU),
> > >          VMSTATE_UINTTL(env.vstvec, RISCVCPU),
> > >          VMSTATE_UINTTL(env.vsscratch, RISCVCPU),
> > > @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = {
> > >          VMSTATE_UINTTL(env.vscause, RISCVCPU),
> > >          VMSTATE_UINTTL(env.vstval, RISCVCPU),
> > >          VMSTATE_UINTTL(env.vsatp, RISCVCPU),
> > > +        VMSTATE_UINTTL(env.vsiselect, RISCVCPU),
> > >
> > >          VMSTATE_UINTTL(env.mtval2, RISCVCPU),
> > >          VMSTATE_UINTTL(env.mtinst, RISCVCPU),
> > > @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = {
> > >
> > >  const VMStateDescription vmstate_riscv_cpu = {
> > >      .name = "cpu",
> > > -    .version_id = 1,
> > > -    .minimum_version_id = 1,
> > > +    .version_id = 2,
> > > +    .minimum_version_id = 2,
> > >      .fields = (VMStateField[]) {
> > >          VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
> > >          VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
> > > +        VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
> > > +        VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
> > >          VMSTATE_UINTTL(env.pc, RISCVCPU),
> > >          VMSTATE_UINTTL(env.load_res, RISCVCPU),
> > >          VMSTATE_UINTTL(env.load_val, RISCVCPU),
> > > @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = {
> > >          VMSTATE_UINTTL(env.resetvec, RISCVCPU),
> > >          VMSTATE_UINTTL(env.mhartid, RISCVCPU),
> > >          VMSTATE_UINT64(env.mstatus, RISCVCPU),
> > > -        VMSTATE_UINTTL(env.mip, RISCVCPU),
> > > -        VMSTATE_UINT32(env.miclaim, RISCVCPU),
> > > -        VMSTATE_UINTTL(env.mie, RISCVCPU),
> > > -        VMSTATE_UINTTL(env.mideleg, RISCVCPU),
> > > +        VMSTATE_UINT64(env.mip, RISCVCPU),
> > > +        VMSTATE_UINT64(env.miclaim, RISCVCPU),
> > > +        VMSTATE_UINT64(env.mie, RISCVCPU),
> > > +        VMSTATE_UINT64(env.mideleg, RISCVCPU),
> > >          VMSTATE_UINTTL(env.sptbr, RISCVCPU),
> > >          VMSTATE_UINTTL(env.satp, RISCVCPU),
> > >          VMSTATE_UINTTL(env.sbadaddr, RISCVCPU),
> > > @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = {
> > >          VMSTATE_UINTTL(env.mepc, RISCVCPU),
> > >          VMSTATE_UINTTL(env.mcause, RISCVCPU),
> > >          VMSTATE_UINTTL(env.mtval, RISCVCPU),
> > > +        VMSTATE_UINTTL(env.miselect, RISCVCPU),
> > > +        VMSTATE_UINTTL(env.siselect, RISCVCPU),
> > >          VMSTATE_UINTTL(env.scounteren, RISCVCPU),
> > >          VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
> > >          VMSTATE_UINTTL(env.sscratch, RISCVCPU),
> > > --
> > > 2.25.1
> > >
> > >


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
@ 2021-06-11  8:45         ` Alistair Francis
  0 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-11  8:45 UTC (permalink / raw)
  To: Anup Patel
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote:
>
> On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote:
> >
> > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
> > >
> > > We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> > > and VS-mode.
> > >
> > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > ---
> > >  target/riscv/cpu.c        |   27 +-
> > >  target/riscv/cpu.h        |   52 +-
> > >  target/riscv/cpu_helper.c |  245 ++++++++-
> > >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> > >  target/riscv/machine.c    |   26 +-
> > >  5 files changed, 1309 insertions(+), 100 deletions(-)
> >
> > I feel this patch could be split up more :)
>
> This is patch is large because I did not want to break functionality.
>
> I try again to break this patch. At the moment, the best I can do is
> to break in to two parts.
> 1) AIA local interrupt CSRs without IMSIC
> 2) Extend AIA local interrupt CSRs to support IMSIC register access

As the patch is being added while AIA isn't enabled you are able to
add the AIA in breaking stages. That is the AIA isn't fully
functional, you still have to make sure not to break existing users.

>
> >
> > >
> > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > > index f3702111ae..795162834b 100644
> > > --- a/target/riscv/cpu.c
> > > +++ b/target/riscv/cpu.c
> > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> > >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
> > >                       (target_ulong)env->vsstatus);
> > >      }
> > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
> > >      if (riscv_has_ext(env, RVH)) {
> > > -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> > > +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
> > >      }
> > >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> > >      if (riscv_has_ext(env, RVH)) {
> > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
> > >
> > >  static void riscv_cpu_reset(DeviceState *dev)
> > >  {
> > > +    uint8_t iprio;
> > > +    int i, irq, rdzero;
> > >      CPUState *cs = CPU(dev);
> > >      RISCVCPU *cpu = RISCV_CPU(cs);
> > >      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
> > >      env->mcause = 0;
> > >      env->pc = env->resetvec;
> > >      env->two_stage_lookup = false;
> > > +
> > > +    /* Initialized default priorities of local interrupts. */
> > > +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> > > +        iprio = riscv_cpu_default_priority(i);
> > > +        env->miprio[i] = iprio;
> > > +        env->siprio[i] = iprio;
> > > +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> > > +    }
> > > +    i = 0;
> > > +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> > > +        if (rdzero) {
> > > +            env->hviprio[irq] = 0;
> > > +        } else {
> > > +            env->hviprio[irq] = env->miprio[irq];
> > > +        }
> > > +        i++;
> > > +    }
> > >  #endif
> > >      cs->exception_index = EXCP_NONE;
> > >      env->load_res = -1;
> > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > > index f00c60c840..780d3f9058 100644
> > > --- a/target/riscv/cpu.h
> > > +++ b/target/riscv/cpu.h
> > > @@ -157,12 +157,12 @@ struct CPURISCVState {
> > >       */
> > >      uint64_t mstatus;
> > >
> > > -    target_ulong mip;
> > > +    uint64_t mip;
> >
> > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
> > all the other existing target_ulong CSRs are the same.
>
> When AIA is available the number of local interrupts are 64 for
> both RV32 and RV64.

Is that going to be reflected in the priv spec?

>
> The width of CSRs remain same as target_ulong but we have
> new CSRs for RV32 (such as mipH) for the high-half.

Ah! Sorry I missed that.

This change should be in a seperate patch then.

>
> Also, this patch changes does not break the case when AIA
> is not available (or disabled).

Good, we need to make sure we don't.

Alistair

>
> Regards,
> Anup
>
> >
> > Alistair
> >
> > >
> > > -    uint32_t miclaim;
> > > +    uint64_t miclaim;
> > >
> > > -    target_ulong mie;
> > > -    target_ulong mideleg;
> > > +    uint64_t mie;
> > > +    uint64_t mideleg;
> > >
> > >      target_ulong sptbr;  /* until: priv-1.9.1 */
> > >      target_ulong satp;   /* since: priv-1.10.0 */
> > > @@ -179,16 +179,27 @@ struct CPURISCVState {
> > >      target_ulong mcause;
> > >      target_ulong mtval;  /* since: priv-1.10.0 */
> > >
> > > +    /* AIA CSRs */
> > > +    target_ulong miselect;
> > > +    target_ulong siselect;
> > > +
> > > +    uint8_t miprio[64];
> > > +    uint8_t siprio[64];
> > > +
> > >      /* Hypervisor CSRs */
> > >      target_ulong hstatus;
> > >      target_ulong hedeleg;
> > > -    target_ulong hideleg;
> > > +    uint64_t hideleg;
> > >      target_ulong hcounteren;
> > >      target_ulong htval;
> > >      target_ulong htinst;
> > >      target_ulong hgatp;
> > >      uint64_t htimedelta;
> > >
> > > +    /* AIA HS-mode CSRs */
> > > +    uint8_t hviprio[64];
> > > +    target_ulong hvicontrol;
> > > +
> > >      /* Virtual CSRs */
> > >      /*
> > >       * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
> > > @@ -202,6 +213,9 @@ struct CPURISCVState {
> > >      target_ulong vstval;
> > >      target_ulong vsatp;
> > >
> > > +    /* AIA VS-mode CSRs */
> > > +    target_ulong vsiselect;
> > > +
> > >      target_ulong mtval2;
> > >      target_ulong mtinst;
> > >
> > > @@ -236,6 +250,18 @@ struct CPURISCVState {
> > >      uint64_t (*rdtime_fn)(uint32_t);
> > >      uint32_t rdtime_fn_arg;
> > >
> > > +    /* machine specific AIA IMSIC read-modify-write callback */
> > > +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \
> > > +    ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \
> > > +     (((__priv) & 0x3) << 16) | (__isel & 0xffff))
> > > +#define IMSIC_REG_ISEL(__reg)                  ((__reg) & 0xffff)
> > > +#define IMSIC_REG_PRIV(__reg)                  (((__reg) >> 16) & 0x3)
> > > +#define IMSIC_REG_VIRT(__reg)                  (((__reg) >> 20) & 0x1)
> > > +#define IMSIC_REG_VGEIN(__reg)                 (((__reg) >> 24) & 0x3f)
> > > +    int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val,
> > > +                        target_ulong new_val, target_ulong write_mask);
> > > +    void *imsic_rmw_fn_arg;
> > > +
> > >      /* True if in debugger mode.  */
> > >      bool debugger;
> > >  #endif
> > > @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
> > >                                 int cpuid, void *opaque);
> > >  int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
> > >  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero);
> > > +uint8_t riscv_cpu_default_priority(int irq);
> > > +int riscv_cpu_mirq_pending(CPURISCVState *env);
> > > +int riscv_cpu_sirq_pending(CPURISCVState *env);
> > > +int riscv_cpu_vsirq_pending(CPURISCVState *env);
> > >  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
> > >  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> > >  bool riscv_cpu_virt_enabled(CPURISCVState *env);
> > > @@ -364,9 +395,16 @@ void riscv_cpu_list(void);
> > >
> > >  #ifndef CONFIG_USER_ONLY
> > >  void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
> > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
> > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
> > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
> > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value);
> > >  #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
> > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > > +                                int (*rmw_fn)(void *arg,
> > > +                                              target_ulong reg,
> > > +                                              target_ulong *val,
> > > +                                              target_ulong new_val,
> > > +                                              target_ulong write_mask),
> > > +                                void *rmw_fn_arg);
> > >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> > >                               uint32_t arg);
> > >  #endif
> > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > > index 21c54ef561..5b06b4f995 100644
> > > --- a/target/riscv/cpu_helper.c
> > > +++ b/target/riscv/cpu_helper.c
> > > @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
> > >  }
> > >
> > >  #ifndef CONFIG_USER_ONLY
> > > -static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > > +
> > > +/*
> > > + * The HS-mode is allowed to configure priority only for the
> > > + * following VS-mode local interrupts:
> > > + *
> > > + * 0  (Reserved interrupt, reads as zero)
> > > + * 1  Supervisor software interrupt
> > > + * 4  (Reserved interrupt, reads as zero)
> > > + * 5  Supervisor timer interrupt
> > > + * 8  (Reserved interrupt, reads as zero)
> > > + * 13 (Reserved interrupt)
> > > + * 14 "
> > > + * 15 "
> > > + * 16 "
> > > + * 18 Debug/trace interrupt
> > > + * 20 (Reserved interrupt)
> > > + * 22 ”
> > > + * 24 ”
> > > + * 26 ”
> > > + * 28 "
> > > + * 30 (Reserved for standard reporting of bus or system errors)
> > > + */
> > > +
> > > +static int hviprio_index2irq[] =
> > > +    { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
> > > +static int hviprio_index2rdzero[] =
> > > +    { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> > > +
> > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
> > >  {
> > > -    target_ulong irqs;
> > > +    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
> > > +        return -EINVAL;
> > > +    }
> > >
> > > -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> > > -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> > > -    target_ulong hs_mstatus_sie = get_field(env->mstatus_hs, MSTATUS_SIE);
> > > +    if (out_irq) {
> > > +        *out_irq = hviprio_index2irq[index];
> > > +    }
> > > +
> > > +    if (out_rdzero) {
> > > +        *out_rdzero = hviprio_index2rdzero[index];
> > > +    }
> > >
> > > -    target_ulong pending = env->mip & env->mie &
> > > -                               ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > -    target_ulong vspending = (env->mip & env->mie &
> > > -                              (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> > > +    return 0;
> > > +}
> > >
> > > -    target_ulong mie    = env->priv < PRV_M ||
> > > -                          (env->priv == PRV_M && mstatus_mie);
> > > -    target_ulong sie    = env->priv < PRV_S ||
> > > -                          (env->priv == PRV_S && mstatus_sie);
> > > -    target_ulong hs_sie = env->priv < PRV_S ||
> > > -                          (env->priv == PRV_S && hs_mstatus_sie);
> > > +uint8_t riscv_cpu_default_priority(int irq)
> > > +{
> > > +    int u, l;
> > > +    uint8_t iprio = IPRIO_MMAXIPRIO;
> > >
> > > -    if (riscv_cpu_virt_enabled(env)) {
> > > -        target_ulong pending_hs_irq = pending & -hs_sie;
> > > +    if (irq < 0 || irq > 63) {
> > > +        return iprio;
> > > +    }
> > >
> > > -        if (pending_hs_irq) {
> > > -            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> > > -            return ctz64(pending_hs_irq);
> > > +    /*
> > > +     * Default priorities of local interrupts are defined in the
> > > +     * RISC-V Advanced Interrupt Architecture specification.
> > > +     *
> > > +     * ----------------------------------------------------------------
> > > +     *  Default  |
> > > +     *  Priority | Major Interrupt Numbers
> > > +     * ----------------------------------------------------------------
> > > +     *  Highest  | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c),
> > > +     *           | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38),
> > > +     *           | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34),
> > > +     *           | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30)
> > > +     *           |
> > > +     *           | 11 (0b),  3 (03),  7 (07)
> > > +     *           |  9 (09),  1 (01),  5 (05)
> > > +     *           | 12 (0c)
> > > +     *           | 10 (0a),  2 (02),  6 (06)
> > > +     *           |
> > > +     *           | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c),
> > > +     *           | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28),
> > > +     *           | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24),
> > > +     *  Lowest   | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20)
> > > +     * ----------------------------------------------------------------
> > > +     */
> > > +
> > > +    u = IPRIO_DEFAULT_U(irq);
> > > +    l = IPRIO_DEFAULT_L(irq);
> > > +    if (u == 0) {
> > > +        if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER ||
> > > +            irq == IRQ_VS_SOFT) {
> > > +            iprio = IPRIO_DEFAULT_VS;
> > > +        } else if (irq == IRQ_S_GEXT) {
> > > +            iprio = IPRIO_DEFAULT_SGEXT;
> > > +        } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER ||
> > > +                   irq == IRQ_S_SOFT) {
> > > +            iprio = IPRIO_DEFAULT_S;
> > > +        } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER ||
> > > +                   irq == IRQ_M_SOFT) {
> > > +            iprio = IPRIO_DEFAULT_M;
> > > +        } else {
> > > +            iprio = IPRIO_DEFAULT_VS;
> > >          }
> > > +    } else if (u == 1) {
> > > +        if (l < 8) {
> > > +            iprio = IPRIO_DEFAULT_16_23(irq);
> > > +        } else {
> > > +            iprio = IPRIO_DEFAULT_24_31(irq);
> > > +        }
> > > +    } else if (u == 2) {
> > > +        iprio = IPRIO_DEFAULT_32_47(irq);
> > > +    } else if (u == 3) {
> > > +        iprio = IPRIO_DEFAULT_48_63(irq);
> > > +    }
> > > +
> > > +    return iprio;
> > > +}
> > > +
> > > +static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> > > +                                    uint64_t pending, uint8_t *iprio)
> > > +{
> > > +    int irq, best_irq = EXCP_NONE;
> > > +    unsigned int prio, best_prio = UINT_MAX;
> > >
> > > -        pending = vspending;
> > > +    if (!pending) {
> > > +        return EXCP_NONE;
> > >      }
> > >
> > > -    irqs = (pending & ~env->mideleg & -mie) | (pending &  env->mideleg & -sie);
> > > +    irq = ctz64(pending);
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return irq;
> > > +    }
> > >
> > > -    if (irqs) {
> > > -        return ctz64(irqs); /* since non-zero */
> > > +    pending = pending >> irq;
> > > +    while (pending) {
> > > +        prio = iprio[irq];
> > > +        if (!prio) {
> > > +            prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ?
> > > +                   1 : IPRIO_MMAXIPRIO;
> > > +        }
> > > +        if ((pending & 0x1) && (prio < best_prio)) {
> > > +            best_irq = irq;
> > > +            best_prio = prio;
> > > +        }
> > > +        irq++;
> > > +        pending = pending >> 1;
> > > +    }
> > > +
> > > +    return best_irq;
> > > +}
> > > +
> > > +int riscv_cpu_mirq_pending(CPURISCVState *env)
> > > +{
> > > +    uint64_t irqs = env->mip & env->mie & ~env->mideleg &
> > > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > +
> > > +    return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > > +}
> > > +
> > > +int riscv_cpu_sirq_pending(CPURISCVState *env)
> > > +{
> > > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > +
> > > +    return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > > +}
> > > +
> > > +int riscv_cpu_vsirq_pending(CPURISCVState *env)
> > > +{
> > > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > > +                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > +
> > > +    return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > > +}
> > > +
> > > +static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > > +{
> > > +    int virq;
> > > +    uint64_t irqs, mie, sie, vsie;
> > > +    uint64_t pending, vspending;
> > > +
> > > +    /* Determine interrupt enable state of all privilege modes */
> > > +    if (riscv_cpu_virt_enabled(env)) {
> > > +        mie = 1;
> > > +        sie = 1;
> > > +        vsie = (env->priv < PRV_S) ||
> > > +               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> > >      } else {
> > > -        return EXCP_NONE; /* indicates no pending interrupt */
> > > +        mie = (env->priv < PRV_M) ||
> > > +              (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
> > > +        sie = (env->priv < PRV_S) ||
> > > +              (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> > > +        vsie = 0;
> > > +    }
> > > +
> > > +    /* Check M-mode interrupts */
> > > +    pending = env->mip & env->mie &
> > > +              ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > +    irqs = pending & ~env->mideleg & -mie;
> > > +    if (irqs) {
> > > +        return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > > +    }
> > > +
> > > +    /* Check HS-mode interrupts */
> > > +    irqs = pending & env->mideleg & -sie;
> > > +    if (irqs) {
> > > +        return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > > +    }
> > > +
> > > +    /* Check VS-mode interrupts */
> > > +    vspending = env->mip & env->mie &
> > > +                (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > +    irqs = vspending & env->hideleg & -vsie;
> > > +    if (irqs) {
> > > +        virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > > +        return (virq <= 0) ? virq : virq + 1;
> > >      }
> > > +
> > > +    /* Indicates no pending interrupt */
> > > +    return EXCP_NONE;
> > >  }
> > >  #endif
> > >
> > > @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx)
> > >      return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
> > >  }
> > >
> > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
> > >  {
> > >      CPURISCVState *env = &cpu->env;
> > >      if (env->miclaim & interrupts) {
> > > @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> > >      }
> > >  }
> > >
> > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
> > >  {
> > >      CPURISCVState *env = &cpu->env;
> > >      CPUState *cs = CPU(cpu);
> > > -    uint32_t old = env->mip;
> > > +    uint64_t old = env->mip;
> > >      bool locked = false;
> > >
> > >      if (!qemu_mutex_iothread_locked()) {
> > > @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> > >      return old;
> > >  }
> > >
> > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > > +                                int (*rmw_fn)(void *arg,
> > > +                                              target_ulong reg,
> > > +                                              target_ulong *val,
> > > +                                              target_ulong new_val,
> > > +                                              target_ulong write_mask),
> > > +                                void *rmw_fn_arg)
> > > +{
> > > +    env->imsic_rmw_fn = rmw_fn;
> > > +    env->imsic_rmw_fn_arg = rmw_fn_arg;
> > > +}
> > > +
> > >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> > >                               uint32_t arg)
> > >  {
> > > @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> > >       */
> > >      bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
> > >      target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
> > > -    target_ulong deleg = async ? env->mideleg : env->medeleg;
> > > +    uint64_t deleg = async ? env->mideleg : env->medeleg;
> > >      bool write_tval = false;
> > >      target_ulong tval = 0;
> > >      target_ulong htval = 0;
> > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > > index d2585395bf..3c016d7452 100644
> > > --- a/target/riscv/csr.c
> > > +++ b/target/riscv/csr.c
> > > @@ -153,11 +153,56 @@ static int any32(CPURISCVState *env, int csrno)
> > >
> > >  }
> > >
> > > +static int aia_any(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return any(env, csrno);
> > > +}
> > > +
> > > +static int aia_any32(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return any32(env, csrno);
> > > +}
> > > +
> > >  static int smode(CPURISCVState *env, int csrno)
> > >  {
> > >      return -!riscv_has_ext(env, RVS);
> > >  }
> > >
> > > +static int smode32(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_cpu_is_32bit(env)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return smode(env, csrno);
> > > +}
> > > +
> > > +static int aia_smode(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return smode(env, csrno);
> > > +}
> > > +
> > > +static int aia_smode32(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return smode32(env, csrno);
> > > +}
> > > +
> > >  static int hmode(CPURISCVState *env, int csrno)
> > >  {
> > >      if (riscv_has_ext(env, RVS) &&
> > > @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno)
> > >  static int hmode32(CPURISCVState *env, int csrno)
> > >  {
> > >      if (!riscv_cpu_is_32bit(env)) {
> > > -        return 0;
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return hmode(env, csrno);
> > > +}
> > > +
> > > +static int aia_hmode(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > >      }
> > >
> > >      return hmode(env, csrno);
> > > +}
> > >
> > > +static int aia_hmode32(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    return hmode32(env, csrno);
> > >  }
> > >
> > >  static int pmp(CPURISCVState *env, int csrno)
> > > @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
> > >
> > >  /* Machine constants */
> > >
> > > -#define M_MODE_INTERRUPTS  (MIP_MSIP | MIP_MTIP | MIP_MEIP)
> > > -#define S_MODE_INTERRUPTS  (MIP_SSIP | MIP_STIP | MIP_SEIP)
> > > -#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)
> > > +#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
> > > +#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
> > > +#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
> > > +
> > > +#define TLOWBITS64         ((uint64_t)((target_ulong)-1))
> > >
> > > -static const target_ulong delegable_ints = S_MODE_INTERRUPTS |
> > > -                                           VS_MODE_INTERRUPTS;
> > > -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > > -                                     VS_MODE_INTERRUPTS;
> > > +static const uint64_t delegable_ints = S_MODE_INTERRUPTS |
> > > +                                       VS_MODE_INTERRUPTS;
> > > +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > > +                                 VS_MODE_INTERRUPTS;
> > >  static const target_ulong delegable_excps =
> > >      (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) |
> > >      (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) |
> > > @@ -419,10 +483,10 @@ static const target_ulong delegable_excps =
> > >  static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
> > >      SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
> > >      SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
> > > -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > > -static const target_ulong hip_writable_mask = MIP_VSSIP;
> > > -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > > -static const target_ulong vsip_writable_mask = MIP_VSSIP;
> > > +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > > +static const uint64_t hip_writable_mask = MIP_VSSIP;
> > > +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > > +static const uint64_t vsip_writable_mask = MIP_VSSIP;
> > >
> > >  static const char valid_vm_1_10_32[16] = {
> > >      [VM_1_10_MBARE] = 1,
> > > @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val)
> > >
> > >  static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
> > >  {
> > > -    env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
> > > +    uint64_t mask = delegable_ints & TLOWBITS64;
> > > +
> > > +    env->mideleg = (env->mideleg & ~mask) | (val & mask);
> > > +    if (riscv_has_ext(env, RVH)) {
> > > +        env->mideleg |= VS_MODE_INTERRUPTS;
> > > +    }
> > > +    return 0;
> > > +}
> > > +
> > > +static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
> > > +{
> > > +    if (!riscv_cpu_virt_enabled(env)) {
> > > +        return csrno;
> > > +    }
> > > +
> > > +    switch (csrno) {
> > > +    case CSR_SISELECT:
> > > +        return CSR_VSISELECT;
> > > +    case CSR_SIREG:
> > > +        return CSR_VSIREG;
> > > +    case CSR_STOPI:
> > > +        return CSR_VSTOPI;
> > > +    case CSR_SSETEIPNUM:
> > > +        return CSR_VSSETEIPNUM;
> > > +    case CSR_SCLREIPNUM:
> > > +        return CSR_VSCLREIPNUM;
> > > +    case CSR_SSETEIENUM:
> > > +        return CSR_VSSETEIENUM;
> > > +    case CSR_SCLREIENUM:
> > > +        return CSR_VSCLREIENUM;
> > > +    default:
> > > +        return csrno;
> > > +    };
> > > +}
> > > +
> > > +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val,
> > > +                        target_ulong new_val, target_ulong write_mask)
> > > +{
> > > +    target_ulong *iselect;
> > > +
> > > +    switch (csrno) {
> > > +    case CSR_MISELECT:
> > > +        iselect = &env->miselect;
> > > +        break;
> > > +    case CSR_SISELECT:
> > > +        iselect = riscv_cpu_virt_enabled(env) ?
> > > +                  &env->vsiselect : &env->siselect;
> > > +        break;
> > > +    case CSR_VSISELECT:
> > > +        iselect = &env->vsiselect;
> > > +        break;
> > > +    default:
> > > +         return -RISCV_EXCP_ILLEGAL_INST;
> > > +    };
> > > +
> > > +    if (val) {
> > > +        *val = *iselect;
> > > +    }
> > > +
> > > +    if (write_mask) {
> > > +        *iselect = (*iselect & ~write_mask) | (new_val & write_mask);
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int rmw_iprio(target_ulong iselect, uint8_t *iprio,
> > > +                     target_ulong *val, target_ulong new_val,
> > > +                     target_ulong write_mask)
> > > +{
> > > +    int i, firq, nirqs;
> > > +    target_ulong old_val;
> > > +
> > > +    if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) {
> > > +        return -EINVAL;
> > > +    }
> > > +#if TARGET_LONG_BITS == 64
> > > +    if (iselect & 0x1) {
> > > +        return -EINVAL;
> > > +    }
> > > +#endif
> > > +
> > > +    nirqs = 4 * (TARGET_LONG_BITS / 32);
> > > +    firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 32)) * (nirqs);
> > > +
> > > +    old_val = 0;
> > > +    for (i = 0; i < nirqs; i++) {
> > > +        old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i);
> > > +    }
> > > +
> > > +    if (val) {
> > > +        *val = old_val;
> > > +    }
> > > +
> > > +    if (write_mask) {
> > > +        new_val = (old_val & ~write_mask) | (new_val & write_mask);
> > > +        for (i = 0; i < nirqs; i++) {
> > > +            iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff;
> > > +        }
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
> > > +                     target_ulong new_val, target_ulong write_mask)
> > > +{
> > > +    bool virt;
> > > +    uint8_t *iprio;
> > > +    int ret = -EINVAL;
> > > +    target_ulong priv, isel, vgein;
> > > +
> > > +    /* Translate CSR number for VS-mode */
> > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > +
> > > +    /* Decode register details from CSR number */
> > > +    virt = false;
> > > +    switch (csrno) {
> > > +    case CSR_MIREG:
> > > +        iprio = env->miprio;
> > > +        isel = env->miselect;
> > > +        priv = PRV_M;
> > > +        break;
> > > +    case CSR_SIREG:
> > > +        iprio = env->siprio;
> > > +        isel = env->siselect;
> > > +        priv = PRV_S;
> > > +        break;
> > > +    case CSR_VSIREG:
> > > +        iprio = env->hviprio;
> > > +        isel = env->vsiselect;
> > > +        priv = PRV_S;
> > > +        virt = true;
> > > +        break;
> > > +    default:
> > > +         goto done;
> > > +    };
> > > +
> > > +    /* Find the selected guest interrupt file */
> > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > +
> > > +    if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) {
> > > +        /* Local interrupt priority registers not available for VS-mode */
> > > +        if (!virt) {
> > > +            ret = rmw_iprio(isel, iprio, val, new_val, write_mask);
> > > +        }
> > > +    } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) {
> > > +        /* IMSIC registers only available when machine implements it. */
> > > +        if (env->imsic_rmw_fn) {
> > > +            /* Selected guest interrupt file should not be zero */
> > > +            if (virt && !vgein) {
> > > +                goto done;
> > > +            }
> > > +            /* Call machine specific IMSIC register emulation */
> > > +            ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > +                                    IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > +                                    val, new_val, write_mask);
> > > +        }
> > > +    }
> > > +
> > > +done:
> > > +    if (ret) {
> > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    int irq;
> > > +
> > > +    irq = riscv_cpu_mirq_pending(env);
> > > +    if (irq <= 0 || irq > 63) {
> > > +       *val = 0;
> > > +    } else {
> > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > +       *val |= env->miprio[irq];
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    bool virt;
> > > +    int ret = -EINVAL;
> > > +    target_ulong vgein;
> > > +
> > > +    /* Translate CSR number for VS-mode */
> > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > +
> > > +    /* Decode register details from CSR number */
> > > +    virt = false;
> > > +    switch (csrno) {
> > > +    case CSR_MSETEIPNUM:
> > > +    case CSR_MCLREIPNUM:
> > > +    case CSR_MSETEIENUM:
> > > +    case CSR_MCLREIENUM:
> > > +    case CSR_SSETEIPNUM:
> > > +    case CSR_SCLREIPNUM:
> > > +    case CSR_SSETEIENUM:
> > > +    case CSR_SCLREIENUM:
> > > +        break;
> > > +    case CSR_VSSETEIPNUM:
> > > +    case CSR_VSCLREIPNUM:
> > > +    case CSR_VSSETEIENUM:
> > > +    case CSR_VSCLREIENUM:
> > > +        virt = true;
> > > +        break;
> > > +    default:
> > > +         goto done;
> > > +    };
> > > +
> > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > +    if (!env->imsic_rmw_fn) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Find the selected guest interrupt file */
> > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > +
> > > +    /* Selected guest interrupt file should not be zero */
> > > +    if (virt && !vgein) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Set/Clear CSRs always read zero */
> > > +    ret = 0;
> > > +    if (val) {
> > > +        *val = 0;
> > > +    }
> > > +
> > > +done:
> > > +    if (ret) {
> > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    int ret = -EINVAL;
> > > +    bool set, pend, virt;
> > > +    target_ulong priv, isel, vgein;
> > > +    target_ulong new_val, write_mask;
> > > +
> > > +    /* Translate CSR number for VS-mode */
> > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > +
> > > +    /* Decode register details from CSR number */
> > > +    virt = set = pend = false;
> > > +    switch (csrno) {
> > > +    case CSR_MSETEIPNUM:
> > > +        priv = PRV_M;
> > > +        set = true;
> > > +        break;
> > > +    case CSR_MCLREIPNUM:
> > > +        priv = PRV_M;
> > > +        pend = true;
> > > +        break;
> > > +    case CSR_MSETEIENUM:
> > > +        priv = PRV_M;
> > > +        set = true;
> > > +        break;
> > > +    case CSR_MCLREIENUM:
> > > +        priv = PRV_M;
> > > +        break;
> > > +    case CSR_SSETEIPNUM:
> > > +        priv = PRV_S;
> > > +        set = true;
> > > +        pend = true;
> > > +        break;
> > > +    case CSR_SCLREIPNUM:
> > > +        priv = PRV_S;
> > > +        pend = true;
> > > +        break;
> > > +    case CSR_SSETEIENUM:
> > > +        priv = PRV_S;
> > > +        set = true;
> > > +        break;
> > > +    case CSR_SCLREIENUM:
> > > +        priv = PRV_S;
> > > +        break;
> > > +    case CSR_VSSETEIPNUM:
> > > +        priv = PRV_S;
> > > +        virt = true;
> > > +        set = true;
> > > +        pend = true;
> > > +        break;
> > > +    case CSR_VSCLREIPNUM:
> > > +        priv = PRV_S;
> > > +        virt = true;
> > > +        pend = true;
> > > +        break;
> > > +    case CSR_VSSETEIENUM:
> > > +        priv = PRV_S;
> > > +        virt = true;
> > > +        set = true;
> > > +        break;
> > > +    case CSR_VSCLREIENUM:
> > > +        priv = PRV_S;
> > > +        virt = true;
> > > +        break;
> > > +    default:
> > > +         goto done;
> > > +    };
> > > +
> > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > +    if (!env->imsic_rmw_fn) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Find target interrupt pending/enable register */
> > > +    if (pend) {
> > > +        isel = ISELECT_IMSIC_EIP0;
> > > +    } else {
> > > +        isel = ISELECT_IMSIC_EIE0;
> > > +    }
> > > +    isel += val / IMSIC_EIPx_BITS;
> > > +
> > > +    /* Find the interrupt bit to be set/clear */
> > > +    write_mask = 1 << (val % IMSIC_EIPx_BITS);
> > > +    new_val = (set) ? write_mask : 0;
> > > +
> > > +    /* Find the selected guest interrupt file */
> > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > +
> > > +    /* Selected guest interrupt file should not be zero */
> > > +    if (virt && !vgein) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Call machine specific IMSIC register emulation */
> > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > +                            NULL, new_val, write_mask);
> > > +
> > > +done:
> > > +    if (ret) {
> > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    bool virt;
> > > +    int ret = -EINVAL;
> > > +    target_ulong priv, isel, vgein;
> > > +    target_ulong topei, write_mask;
> > > +
> > > +    /* Decode register details from CSR number */
> > > +    virt = false;
> > > +    switch (csrno) {
> > > +    case CSR_MCLAIMEI:
> > > +        priv = PRV_M;
> > > +        break;
> > > +    case CSR_SCLAIMEI:
> > > +        priv = PRV_S;
> > > +        virt = riscv_cpu_virt_enabled(env);
> > > +        break;
> > > +    default:
> > > +        goto done;
> > > +    };
> > > +
> > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > +    if (!env->imsic_rmw_fn) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Find the selected guest interrupt file */
> > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > +
> > > +    /* Selected guest interrupt file should not be zero */
> > > +    if (virt && !vgein) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Call machine specific IMSIC register emulation for reading TOPEI */
> > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > +                            IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein),
> > > +                            &topei, -1, 0);
> > > +    if (ret) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* If no interrupt pending then we are done */
> > > +    if (!topei) {
> > > +        goto done;
> > > +    }
> > > +
> > > +    /* Find target interrupt pending register */
> > > +    isel = ISELECT_IMSIC_EIP0;
> > > +    isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS);
> > > +
> > > +    /* Find the interrupt bit to be cleared */
> > > +    write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS);
> > > +
> > > +    /* Call machine specific IMSIC register emulation to clear pending bit */
> > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > +                            NULL, 0, write_mask);
> > > +
> > > +    /* Update return value */
> > > +    if (val) {
> > > +        *val = topei;
> > > +    }
> > > +
> > > +done:
> > > +    if (ret) {
> > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    *val = (env->mideleg >> 32);
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    uint64_t mask = delegable_ints & ~TLOWBITS64;
> > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > +
> > > +    env->mideleg = (env->mideleg & ~mask) | (newval & mask);
> > >      if (riscv_has_ext(env, RVH)) {
> > >          env->mideleg |= VS_MODE_INTERRUPTS;
> > >      }
> > > @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
> > >
> > >  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
> > >  {
> > > -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> > > +    uint64_t mask = all_ints & TLOWBITS64;
> > > +
> > > +    env->mie = (env->mie & ~mask) | (val & mask);
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    *val = (env->mie >> 32);
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    uint64_t mask = all_ints & ~TLOWBITS64;
> > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > +
> > > +    env->mie = (env->mie & ~mask) | (newval & mask);
> > >      return 0;
> > >  }
> > >
> > > @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >  {
> > >      RISCVCPU *cpu = env_archcpu(env);
> > >      /* Allow software control of delegable interrupts not claimed by hardware */
> > > -    target_ulong mask = write_mask & delegable_ints & ~env->miclaim;
> > > -    uint32_t old_mip;
> > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > +                    ~env->miclaim & TLOWBITS64;
> > > +    uint64_t old_mip;
> > >
> > >      if (mask) {
> > >          old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >      return 0;
> > >  }
> > >
> > > +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > +                    target_ulong new_value, target_ulong write_mask)
> > > +{
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > +                    ~env->miclaim & ~TLOWBITS64;
> > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > > +
> > > +    if (ret_value) {
> > > +        *ret_value = old_mip >> 32;
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > >  /* Supervisor Trap Setup */
> > >  static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > >  {
> > > @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
> > >
> > >  static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
> > >  {
> > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64;
> > > +
> > >      /* Shift the VS bits to their S bit location in vsie */
> > > -    *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
> > > +    *val = (env->mie & mask) >> 1;
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64;
> > > +
> > > +    /* Shift the VS bits to their S bit location in vsieh */
> > > +    *val = (env->mie & mask) >> (32 + 1);
> > >      return 0;
> > >  }
> > >
> > >  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
> > >  {
> > >      if (riscv_cpu_virt_enabled(env)) {
> > > -        read_vsie(env, CSR_VSIE, val);
> > > -    } else {
> > > -        *val = env->mie & env->mideleg;
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return read_vsie(env, CSR_VSIE, val);
> > >      }
> > > +
> > > +    *val = env->mie & env->mideleg;
> > >      return 0;
> > >  }
> > >
> > >  static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
> > >  {
> > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > > +                    all_ints & TLOWBITS64;
> > > +
> > >      /* Shift the S bits to their VS bit location in mie */
> > > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
> > > -                          ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS);
> > > -    return write_mie(env, CSR_MIE, newval);
> > > +    env->mie = (env->mie & ~mask) | ((val << 1) & mask);
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > > +                    all_ints & ~TLOWBITS64;
> > > +    uint64_t newval = (uint64_t)val << 32;
> > > +
> > > +    /* Shift the S bits to their VS bit location in mie */
> > > +    env->mie = (env->mie & ~mask) | ((newval << 1) & mask);
> > > +
> > > +    return 0;
> > >  }
> > >
> > >  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
> > >  {
> > > +    uint64_t mask;
> > > +
> > >      if (riscv_cpu_virt_enabled(env)) {
> > > -        write_vsie(env, CSR_VSIE, val);
> > > -    } else {
> > > -        target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) |
> > > -                              (val & S_MODE_INTERRUPTS);
> > > -        write_mie(env, CSR_MIE, newval);
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return write_vsie(env, CSR_VSIE, val);
> > > +    }
> > > +
> > > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64;
> > > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    if (riscv_cpu_virt_enabled(env)) {
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return read_vsieh(env, CSR_VSIEH, val);
> > > +    }
> > > +
> > > +    *val = ((env->mie & env->mideleg) >> 32);
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    uint64_t mask, newval;
> > > +
> > > +    if (riscv_cpu_virt_enabled(env)) {
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return write_vsieh(env, CSR_VSIEH, val);
> > >      }
> > >
> > > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64;
> > > +    newval = (uint64_t)val << 32;
> > > +
> > > +    env->mie = (env->mie & ~mask) | (newval & mask);
> > >      return 0;
> > >  }
> > >
> > > @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
> > >  static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >                      target_ulong new_value, target_ulong write_mask)
> > >  {
> > > -    /* Shift the S bits to their VS bit location in mip */
> > > -    int ret = rmw_mip(env, 0, ret_value, new_value << 1,
> > > -                      (write_mask << 1) & vsip_writable_mask & env->hideleg);
> > > -    *ret_value &= VS_MODE_INTERRUPTS;
> > > -    /* Shift the VS bits to their S bit location in vsip */
> > > -    *ret_value >>= 1;
> > > -    return ret;
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints &
> > > +                    vsip_writable_mask & env->hideleg &
> > > +                    ~env->miclaim & TLOWBITS64;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > > +
> > > +    if (ret_value) {
> > > +        *ret_value = old_mip & VS_MODE_INTERRUPTS;
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > +                     target_ulong new_value, target_ulong write_mask)
> > > +{
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints &
> > > +                    vsip_writable_mask & env->hideleg &
> > > +                    ~env->miclaim & ~TLOWBITS64;
> > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > > +
> > > +    if (ret_value) {
> > > +        *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32;
> > > +    }
> > > +
> > > +    return 0;
> > >  }
> > >
> > >  static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >                     target_ulong new_value, target_ulong write_mask)
> > >  {
> > > -    int ret;
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    uint64_t mask, old_mip;
> > >
> > >      if (riscv_cpu_virt_enabled(env)) {
> > > -        ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > > +    }
> > > +
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    mask = ((uint64_t)write_mask) & delegable_ints &
> > > +           env->mideleg & sip_writable_mask &
> > > +           ~env->miclaim & TLOWBITS64;
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > >      } else {
> > > -        ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
> > > -                      write_mask & env->mideleg & sip_writable_mask);
> > > +        old_mip = env->mip;
> > >      }
> > >
> > > -    *ret_value &= env->mideleg;
> > > -    return ret;
> > > +    if (ret_value) {
> > > +        *ret_value = old_mip;
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > +                    target_ulong new_value, target_ulong write_mask)
> > > +{
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    uint64_t mask, new_value64;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (riscv_cpu_virt_enabled(env)) {
> > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > +        }
> > > +        return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask);
> > > +    }
> > > +
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > +           env->mideleg & sip_writable_mask &
> > > +           ~env->miclaim & ~TLOWBITS64;
> > > +    new_value64 = (uint64_t)new_value << 32;
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > > +
> > > +    if (ret_value) {
> > > +        *ret_value = (old_mip & env->mideleg) >> 32;
> > > +    }
> > > +
> > > +    return 0;
> > >  }
> > >
> > >  /* Supervisor Protection and Translation */
> > > @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
> > >      return 0;
> > >  }
> > >
> > > +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    int irq, hiid;
> > > +    uint8_t hiprio, iprio;
> > > +
> > > +    irq = riscv_cpu_vsirq_pending(env);
> > > +    if (irq <= 0 || irq > 63) {
> > > +       *val = 0;
> > > +    } else {
> > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > +       iprio = env->hviprio[irq];
> > > +       /* TODO: This needs to improve in specification */
> > > +       if (!(env->hstatus & HSTATUS_VGEIN)) {
> > > +           hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >>
> > > +                 HVICONTROL_IID_SHIFT;
> > > +           hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK;
> > > +           if (irq == hiid && hiprio) {
> > > +               iprio = hiprio;
> > > +           }
> > > +       }
> > > +       *val |= iprio;
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    int irq;
> > > +
> > > +    if (riscv_cpu_virt_enabled(env)) {
> > > +        return read_vstopi(env, CSR_VSTOPI, val);
> > > +    }
> > > +
> > > +    irq = riscv_cpu_sirq_pending(env);
> > > +    if (irq <= 0 || irq > 63) {
> > > +       *val = 0;
> > > +    } else {
> > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > +       *val |= env->siprio[irq];
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > >  /* Hypervisor Extensions */
> > >  static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > >  {
> > > @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
> > >      return 0;
> > >  }
> > >
> > > +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    *val = env->hideleg >> 32;
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    uint64_t mask = ~TLOWBITS64;
> > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > +
> > > +    env->hideleg = (env->hideleg & ~mask) | (newval & mask);
> > > +
> > > +    return 0;
> > > +}
> > > +
> > >  static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >                     target_ulong new_value, target_ulong write_mask)
> > >  {
> > > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > > -                      write_mask & hvip_writable_mask);
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > +                    hvip_writable_mask &
> > > +                    ~env->miclaim & TLOWBITS64;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > >
> > > -    *ret_value &= hvip_writable_mask;
> > > +    if (ret_value) {
> > > +        *ret_value = old_mip & hvip_writable_mask;
> > > +    }
> > >
> > > -    return ret;
> > > +    return 0;
> > > +}
> > > +
> > > +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > +                    target_ulong new_value, target_ulong write_mask)
> > > +{
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > +                    hvip_writable_mask &
> > > +                    ~env->miclaim & ~TLOWBITS64;
> > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > +    uint64_t old_mip;
> > > +
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > > +
> > > +    if (ret_value) {
> > > +        *ret_value = (old_mip & hvip_writable_mask) >> 32;
> > > +    }
> > > +
> > > +    return 0;
> > >  }
> > >
> > >  static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > >                     target_ulong new_value, target_ulong write_mask)
> > >  {
> > > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > > -                      write_mask & hip_writable_mask);
> > > +    RISCVCPU *cpu = env_archcpu(env);
> > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > +                    hip_writable_mask &
> > > +                    ~env->miclaim & TLOWBITS64;
> > > +    uint64_t old_mip;
> > >
> > > -    *ret_value &= hip_writable_mask;
> > > +    if (mask) {
> > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > +    } else {
> > > +        old_mip = env->mip;
> > > +    }
> > >
> > > -    return ret;
> > > +    if (ret_value) {
> > > +        *ret_value = old_mip & hip_writable_mask;
> > > +    }
> > > +
> > > +    return 0;
> > >  }
> > >
> > >  static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> > > @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> > >
> > >  static int write_hie(CPURISCVState *env, int csrno, target_ulong val)
> > >  {
> > > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS);
> > > -    return write_mie(env, CSR_MIE, newval);
> > > +    uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64;
> > > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > > +    return 0;
> > >  }
> > >
> > >  static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val)
> > > @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val)
> > >      return 0;
> > >  }
> > >
> > > +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    *val = env->hvicontrol;
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    env->hvicontrol = val & HVICONTROL_VALID_MASK;
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_hvipriox(CPURISCVState *env, int first_index,
> > > +                         uint8_t *iprio, target_ulong *val)
> > > +{
> > > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > > +
> > > +    /* First index has to be multiple of numbe of irqs per register */
> > > +    if (first_index % num_irqs) {
> > > +        return (riscv_cpu_virt_enabled(env)) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    /* Fill-up return value */
> > > +    *val = 0;
> > > +    for (i = 0; i < num_irqs; i++) {
> > > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > > +            continue;
> > > +        }
> > > +        if (rdzero) {
> > > +            continue;
> > > +        }
> > > +        *val |= ((target_ulong)iprio[irq]) << (i * 8);
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int write_hvipriox(CPURISCVState *env, int first_index,
> > > +                          uint8_t *iprio, target_ulong val)
> > > +{
> > > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > > +
> > > +    /* First index has to be multiple of numbe of irqs per register */
> > > +    if (first_index % num_irqs) {
> > > +        return (riscv_cpu_virt_enabled(env)) ?
> > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > +    }
> > > +
> > > +    /* Fill-up priority arrary */
> > > +    for (i = 0; i < num_irqs; i++) {
> > > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > > +            continue;
> > > +        }
> > > +        if (rdzero) {
> > > +            iprio[irq] = 0;
> > > +        } else {
> > > +            iprio[irq] = (val >> (i * 8)) & 0xff;
> > > +        }
> > > +    }
> > > +
> > > +    return 0;
> > > +}
> > > +
> > > +static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    return read_hvipriox(env, 0, env->hviprio, val);
> > > +}
> > > +
> > > +static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    return write_hvipriox(env, 0, env->hviprio, val);
> > > +}
> > > +
> > > +static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    return read_hvipriox(env, 4, env->hviprio, val);
> > > +}
> > > +
> > > +static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    return write_hvipriox(env, 4, env->hviprio, val);
> > > +}
> > > +
> > > +static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    return read_hvipriox(env, 8, env->hviprio, val);
> > > +}
> > > +
> > > +static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    return write_hvipriox(env, 8, env->hviprio, val);
> > > +}
> > > +
> > > +static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val)
> > > +{
> > > +    return read_hvipriox(env, 12, env->hviprio, val);
> > > +}
> > > +
> > > +static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val)
> > > +{
> > > +    return write_hvipriox(env, 12, env->hviprio, val);
> > > +}
> > > +
> > >  /* Virtual CSR Registers */
> > >  static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > >  {
> > > @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > >      [CSR_MBADADDR] = { "mbadaddr", any,  read_mbadaddr, write_mbadaddr },
> > >      [CSR_MIP]      = { "mip",      any,  NULL,    NULL, rmw_mip        },
> > >
> > > +    /* Machine-Level Window to Indirectly Accessed Registers (AIA) */
> > > +    [CSR_MISELECT] = { "miselect", aia_any,   NULL, NULL,    rmw_xiselect },
> > > +    [CSR_MIREG]    = { "mireg",    aia_any,   NULL, NULL,    rmw_xireg },
> > > +
> > > +    /* Machine-Level Interrupts (AIA) */
> > > +    [CSR_MTOPI]    = { "mtopi",    aia_any,   read_mtopi },
> > > +
> > > +    /* Machine-Level IMSIC Interface (AIA) */
> > > +    [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_MCLAIMEI]   = { "mclaimei",   aia_any, read_xclaimei },
> > > +
> > > +    /* Machine-Level High-Half CSRs (AIA) */
> > > +    [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh },
> > > +    [CSR_MIEH]     = { "mieh",     aia_any32, read_mieh,     write_mieh     },
> > > +    [CSR_MIPH]     = { "miph",     aia_any32, NULL,    NULL, rmw_miph       },
> > > +
> > >      /* Supervisor Trap Setup */
> > >      [CSR_SSTATUS]    = { "sstatus",    smode, read_sstatus,    write_sstatus    },
> > >      [CSR_SIE]        = { "sie",        smode, read_sie,        write_sie        },
> > > @@ -1444,6 +2357,24 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > >      /* Supervisor Protection and Translation */
> > >      [CSR_SATP]     = { "satp",     smode, read_satp,    write_satp      },
> > >
> > > +    /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
> > > +    [CSR_SISELECT]   = { "siselect",   aia_smode, NULL, NULL, rmw_xiselect },
> > > +    [CSR_SIREG]      = { "sireg",      aia_smode, NULL, NULL, rmw_xireg },
> > > +
> > > +    /* Supervisor-Level Interrupts (AIA) */
> > > +    [CSR_STOPI]      = { "stopi",      aia_smode, read_stopi },
> > > +
> > > +    /* Supervisor-Level IMSIC Interface (AIA) */
> > > +    [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_SCLAIMEI]   = { "sclaimei",   aia_smode, read_xclaimei },
> > > +
> > > +    /* Supervisor-Level High-Half CSRs (AIA) */
> > > +    [CSR_SIEH]       = { "sieh",       aia_smode32, read_sieh,  write_sieh },
> > > +    [CSR_SIPH]       = { "siph",       aia_smode32, NULL, NULL, rmw_siph   },
> > > +
> > >      [CSR_HSTATUS]     = { "hstatus",     hmode,   read_hstatus,     write_hstatus     },
> > >      [CSR_HEDELEG]     = { "hedeleg",     hmode,   read_hedeleg,     write_hedeleg     },
> > >      [CSR_HIDELEG]     = { "hideleg",     hmode,   read_hideleg,     write_hideleg     },
> > > @@ -1472,6 +2403,32 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > >      [CSR_MTVAL2]      = { "mtval2",      hmode,   read_mtval2,      write_mtval2      },
> > >      [CSR_MTINST]      = { "mtinst",      hmode,   read_mtinst,      write_mtinst      },
> > >
> > > +    /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
> > > +    [CSR_HVICONTROL]  = { "hvicontrol",  aia_hmode, read_hvicontrol, write_hvicontrol },
> > > +    [CSR_HVIPRIO1]    = { "hviprio1",    aia_hmode, read_hviprio1,   write_hviprio1 },
> > > +    [CSR_HVIPRIO2]    = { "hviprio2",    aia_hmode, read_hviprio2,   write_hviprio2 },
> > > +
> > > +    /* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
> > > +    [CSR_VSISELECT]   = { "vsiselect",   aia_hmode, NULL, NULL,      rmw_xiselect },
> > > +    [CSR_VSIREG]      = { "vsireg",      aia_hmode, NULL, NULL,      rmw_xireg },
> > > +
> > > +    /* VS-Level Interrupts (H-extension with AIA) */
> > > +    [CSR_VSTOPI]      = { "vstopi",      aia_hmode, read_vstopi },
> > > +
> > > +    /* VS-Level IMSIC Interface (H-extension with AIA) */
> > > +    [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > +    [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > +
> > > +    /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
> > > +    [CSR_HIDELEGH]    = { "hidelegh",    aia_hmode32, read_hidelegh,  write_hidelegh },
> > > +    [CSR_HVIPH]       = { "hviph",       aia_hmode32, NULL, NULL,     rmw_hviph },
> > > +    [CSR_HVIPRIO1H]   = { "hviprio1h",   aia_hmode32, read_hviprio1h, write_hviprio1h },
> > > +    [CSR_HVIPRIO2H]   = { "hviprio2h",   aia_hmode32, read_hviprio2h, write_hviprio2h },
> > > +    [CSR_VSIEH]       = { "vsieh",       aia_hmode32, read_vsieh,     write_vsieh },
> > > +    [CSR_VSIPH]       = { "vsiep",       aia_hmode32, NULL, NULL,     rmw_vsiph },
> > > +
> > >      /* Physical Memory Protection */
> > >      [CSR_PMPCFG0]    = { "pmpcfg0",   pmp, read_pmpcfg,  write_pmpcfg  },
> > >      [CSR_PMPCFG1]    = { "pmpcfg1",   pmp, read_pmpcfg,  write_pmpcfg  },
> > > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> > > index 44d4015bd6..f7fa48c240 100644
> > > --- a/target/riscv/machine.c
> > > +++ b/target/riscv/machine.c
> > > @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = {
> > >
> > >  static const VMStateDescription vmstate_hyper = {
> > >      .name = "cpu/hyper",
> > > -    .version_id = 1,
> > > -    .minimum_version_id = 1,
> > > +    .version_id = 2,
> > > +    .minimum_version_id = 2,
> > >      .needed = hyper_needed,
> > >      .fields = (VMStateField[]) {
> > >          VMSTATE_UINTTL(env.hstatus, RISCVCPU),
> > >          VMSTATE_UINTTL(env.hedeleg, RISCVCPU),
> > > -        VMSTATE_UINTTL(env.hideleg, RISCVCPU),
> > > +        VMSTATE_UINT64(env.hideleg, RISCVCPU),
> > >          VMSTATE_UINTTL(env.hcounteren, RISCVCPU),
> > >          VMSTATE_UINTTL(env.htval, RISCVCPU),
> > >          VMSTATE_UINTTL(env.htinst, RISCVCPU),
> > >          VMSTATE_UINTTL(env.hgatp, RISCVCPU),
> > >          VMSTATE_UINT64(env.htimedelta, RISCVCPU),
> > >
> > > +        VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
> > > +        VMSTATE_UINTTL(env.hvicontrol, RISCVCPU),
> > > +
> > >          VMSTATE_UINT64(env.vsstatus, RISCVCPU),
> > >          VMSTATE_UINTTL(env.vstvec, RISCVCPU),
> > >          VMSTATE_UINTTL(env.vsscratch, RISCVCPU),
> > > @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = {
> > >          VMSTATE_UINTTL(env.vscause, RISCVCPU),
> > >          VMSTATE_UINTTL(env.vstval, RISCVCPU),
> > >          VMSTATE_UINTTL(env.vsatp, RISCVCPU),
> > > +        VMSTATE_UINTTL(env.vsiselect, RISCVCPU),
> > >
> > >          VMSTATE_UINTTL(env.mtval2, RISCVCPU),
> > >          VMSTATE_UINTTL(env.mtinst, RISCVCPU),
> > > @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = {
> > >
> > >  const VMStateDescription vmstate_riscv_cpu = {
> > >      .name = "cpu",
> > > -    .version_id = 1,
> > > -    .minimum_version_id = 1,
> > > +    .version_id = 2,
> > > +    .minimum_version_id = 2,
> > >      .fields = (VMStateField[]) {
> > >          VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
> > >          VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
> > > +        VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
> > > +        VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
> > >          VMSTATE_UINTTL(env.pc, RISCVCPU),
> > >          VMSTATE_UINTTL(env.load_res, RISCVCPU),
> > >          VMSTATE_UINTTL(env.load_val, RISCVCPU),
> > > @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = {
> > >          VMSTATE_UINTTL(env.resetvec, RISCVCPU),
> > >          VMSTATE_UINTTL(env.mhartid, RISCVCPU),
> > >          VMSTATE_UINT64(env.mstatus, RISCVCPU),
> > > -        VMSTATE_UINTTL(env.mip, RISCVCPU),
> > > -        VMSTATE_UINT32(env.miclaim, RISCVCPU),
> > > -        VMSTATE_UINTTL(env.mie, RISCVCPU),
> > > -        VMSTATE_UINTTL(env.mideleg, RISCVCPU),
> > > +        VMSTATE_UINT64(env.mip, RISCVCPU),
> > > +        VMSTATE_UINT64(env.miclaim, RISCVCPU),
> > > +        VMSTATE_UINT64(env.mie, RISCVCPU),
> > > +        VMSTATE_UINT64(env.mideleg, RISCVCPU),
> > >          VMSTATE_UINTTL(env.sptbr, RISCVCPU),
> > >          VMSTATE_UINTTL(env.satp, RISCVCPU),
> > >          VMSTATE_UINTTL(env.sbadaddr, RISCVCPU),
> > > @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = {
> > >          VMSTATE_UINTTL(env.mepc, RISCVCPU),
> > >          VMSTATE_UINTTL(env.mcause, RISCVCPU),
> > >          VMSTATE_UINTTL(env.mtval, RISCVCPU),
> > > +        VMSTATE_UINTTL(env.miselect, RISCVCPU),
> > > +        VMSTATE_UINTTL(env.siselect, RISCVCPU),
> > >          VMSTATE_UINTTL(env.scounteren, RISCVCPU),
> > >          VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
> > >          VMSTATE_UINTTL(env.sscratch, RISCVCPU),
> > > --
> > > 2.25.1
> > >
> > >


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
  2021-06-11  8:45         ` Alistair Francis
@ 2021-06-11 14:04           ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-11 14:04 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Fri, Jun 11, 2021 at 2:16 PM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote:
> >
> > On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote:
> > >
> > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > >
> > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> > > > and VS-mode.
> > > >
> > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > ---
> > > >  target/riscv/cpu.c        |   27 +-
> > > >  target/riscv/cpu.h        |   52 +-
> > > >  target/riscv/cpu_helper.c |  245 ++++++++-
> > > >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> > > >  target/riscv/machine.c    |   26 +-
> > > >  5 files changed, 1309 insertions(+), 100 deletions(-)
> > >
> > > I feel this patch could be split up more :)
> >
> > This is patch is large because I did not want to break functionality.
> >
> > I try again to break this patch. At the moment, the best I can do is
> > to break in to two parts.
> > 1) AIA local interrupt CSRs without IMSIC
> > 2) Extend AIA local interrupt CSRs to support IMSIC register access
>
> As the patch is being added while AIA isn't enabled you are able to
> add the AIA in breaking stages. That is the AIA isn't fully
> functional, you still have to make sure not to break existing users.
>
> >
> > >
> > > >
> > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > > > index f3702111ae..795162834b 100644
> > > > --- a/target/riscv/cpu.c
> > > > +++ b/target/riscv/cpu.c
> > > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> > > >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
> > > >                       (target_ulong)env->vsstatus);
> > > >      }
> > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
> > > >      if (riscv_has_ext(env, RVH)) {
> > > > -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> > > > +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
> > > >      }
> > > >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> > > >      if (riscv_has_ext(env, RVH)) {
> > > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
> > > >
> > > >  static void riscv_cpu_reset(DeviceState *dev)
> > > >  {
> > > > +    uint8_t iprio;
> > > > +    int i, irq, rdzero;
> > > >      CPUState *cs = CPU(dev);
> > > >      RISCVCPU *cpu = RISCV_CPU(cs);
> > > >      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> > > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
> > > >      env->mcause = 0;
> > > >      env->pc = env->resetvec;
> > > >      env->two_stage_lookup = false;
> > > > +
> > > > +    /* Initialized default priorities of local interrupts. */
> > > > +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> > > > +        iprio = riscv_cpu_default_priority(i);
> > > > +        env->miprio[i] = iprio;
> > > > +        env->siprio[i] = iprio;
> > > > +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> > > > +    }
> > > > +    i = 0;
> > > > +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> > > > +        if (rdzero) {
> > > > +            env->hviprio[irq] = 0;
> > > > +        } else {
> > > > +            env->hviprio[irq] = env->miprio[irq];
> > > > +        }
> > > > +        i++;
> > > > +    }
> > > >  #endif
> > > >      cs->exception_index = EXCP_NONE;
> > > >      env->load_res = -1;
> > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > > > index f00c60c840..780d3f9058 100644
> > > > --- a/target/riscv/cpu.h
> > > > +++ b/target/riscv/cpu.h
> > > > @@ -157,12 +157,12 @@ struct CPURISCVState {
> > > >       */
> > > >      uint64_t mstatus;
> > > >
> > > > -    target_ulong mip;
> > > > +    uint64_t mip;
> > >
> > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
> > > all the other existing target_ulong CSRs are the same.
> >
> > When AIA is available the number of local interrupts are 64 for
> > both RV32 and RV64.
>
> Is that going to be reflected in the priv spec?

The AIA spec is going to be separate from priv spec since
it is totally optional.

This AIA local interrupt CSRs will be part of AIA spec and should
only be implemented if a RISC-V implementations wants to use
AIA.

We have four types of changes as far as CSRs go:
1) RV32 CSRs to support 64 local interrupts on RV32
2) Indirect CSRs to access local interrupt priorities
3) Interrupt filtering CSRs
4) IMSIC support CSRs

From above #3 is totally optional and not implemented by this
patch whereas #4 is only required when platform has RISC-V IMSIC.

A platform can skip all four changes mentioned above, if the
platform only wants AIA APLIC to manage wired interrupts.

Regards,
Anup

>
> >
> > The width of CSRs remain same as target_ulong but we have
> > new CSRs for RV32 (such as mipH) for the high-half.
>
> Ah! Sorry I missed that.
>
> This change should be in a seperate patch then.
>
> >
> > Also, this patch changes does not break the case when AIA
> > is not available (or disabled).
>
> Good, we need to make sure we don't.
>
> Alistair
>
> >
> > Regards,
> > Anup
> >
> > >
> > > Alistair
> > >
> > > >
> > > > -    uint32_t miclaim;
> > > > +    uint64_t miclaim;
> > > >
> > > > -    target_ulong mie;
> > > > -    target_ulong mideleg;
> > > > +    uint64_t mie;
> > > > +    uint64_t mideleg;
> > > >
> > > >      target_ulong sptbr;  /* until: priv-1.9.1 */
> > > >      target_ulong satp;   /* since: priv-1.10.0 */
> > > > @@ -179,16 +179,27 @@ struct CPURISCVState {
> > > >      target_ulong mcause;
> > > >      target_ulong mtval;  /* since: priv-1.10.0 */
> > > >
> > > > +    /* AIA CSRs */
> > > > +    target_ulong miselect;
> > > > +    target_ulong siselect;
> > > > +
> > > > +    uint8_t miprio[64];
> > > > +    uint8_t siprio[64];
> > > > +
> > > >      /* Hypervisor CSRs */
> > > >      target_ulong hstatus;
> > > >      target_ulong hedeleg;
> > > > -    target_ulong hideleg;
> > > > +    uint64_t hideleg;
> > > >      target_ulong hcounteren;
> > > >      target_ulong htval;
> > > >      target_ulong htinst;
> > > >      target_ulong hgatp;
> > > >      uint64_t htimedelta;
> > > >
> > > > +    /* AIA HS-mode CSRs */
> > > > +    uint8_t hviprio[64];
> > > > +    target_ulong hvicontrol;
> > > > +
> > > >      /* Virtual CSRs */
> > > >      /*
> > > >       * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
> > > > @@ -202,6 +213,9 @@ struct CPURISCVState {
> > > >      target_ulong vstval;
> > > >      target_ulong vsatp;
> > > >
> > > > +    /* AIA VS-mode CSRs */
> > > > +    target_ulong vsiselect;
> > > > +
> > > >      target_ulong mtval2;
> > > >      target_ulong mtinst;
> > > >
> > > > @@ -236,6 +250,18 @@ struct CPURISCVState {
> > > >      uint64_t (*rdtime_fn)(uint32_t);
> > > >      uint32_t rdtime_fn_arg;
> > > >
> > > > +    /* machine specific AIA IMSIC read-modify-write callback */
> > > > +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \
> > > > +    ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \
> > > > +     (((__priv) & 0x3) << 16) | (__isel & 0xffff))
> > > > +#define IMSIC_REG_ISEL(__reg)                  ((__reg) & 0xffff)
> > > > +#define IMSIC_REG_PRIV(__reg)                  (((__reg) >> 16) & 0x3)
> > > > +#define IMSIC_REG_VIRT(__reg)                  (((__reg) >> 20) & 0x1)
> > > > +#define IMSIC_REG_VGEIN(__reg)                 (((__reg) >> 24) & 0x3f)
> > > > +    int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val,
> > > > +                        target_ulong new_val, target_ulong write_mask);
> > > > +    void *imsic_rmw_fn_arg;
> > > > +
> > > >      /* True if in debugger mode.  */
> > > >      bool debugger;
> > > >  #endif
> > > > @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
> > > >                                 int cpuid, void *opaque);
> > > >  int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
> > > >  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> > > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero);
> > > > +uint8_t riscv_cpu_default_priority(int irq);
> > > > +int riscv_cpu_mirq_pending(CPURISCVState *env);
> > > > +int riscv_cpu_sirq_pending(CPURISCVState *env);
> > > > +int riscv_cpu_vsirq_pending(CPURISCVState *env);
> > > >  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
> > > >  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> > > >  bool riscv_cpu_virt_enabled(CPURISCVState *env);
> > > > @@ -364,9 +395,16 @@ void riscv_cpu_list(void);
> > > >
> > > >  #ifndef CONFIG_USER_ONLY
> > > >  void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
> > > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
> > > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
> > > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
> > > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value);
> > > >  #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
> > > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > > > +                                int (*rmw_fn)(void *arg,
> > > > +                                              target_ulong reg,
> > > > +                                              target_ulong *val,
> > > > +                                              target_ulong new_val,
> > > > +                                              target_ulong write_mask),
> > > > +                                void *rmw_fn_arg);
> > > >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> > > >                               uint32_t arg);
> > > >  #endif
> > > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > > > index 21c54ef561..5b06b4f995 100644
> > > > --- a/target/riscv/cpu_helper.c
> > > > +++ b/target/riscv/cpu_helper.c
> > > > @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
> > > >  }
> > > >
> > > >  #ifndef CONFIG_USER_ONLY
> > > > -static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > > > +
> > > > +/*
> > > > + * The HS-mode is allowed to configure priority only for the
> > > > + * following VS-mode local interrupts:
> > > > + *
> > > > + * 0  (Reserved interrupt, reads as zero)
> > > > + * 1  Supervisor software interrupt
> > > > + * 4  (Reserved interrupt, reads as zero)
> > > > + * 5  Supervisor timer interrupt
> > > > + * 8  (Reserved interrupt, reads as zero)
> > > > + * 13 (Reserved interrupt)
> > > > + * 14 "
> > > > + * 15 "
> > > > + * 16 "
> > > > + * 18 Debug/trace interrupt
> > > > + * 20 (Reserved interrupt)
> > > > + * 22 ”
> > > > + * 24 ”
> > > > + * 26 ”
> > > > + * 28 "
> > > > + * 30 (Reserved for standard reporting of bus or system errors)
> > > > + */
> > > > +
> > > > +static int hviprio_index2irq[] =
> > > > +    { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
> > > > +static int hviprio_index2rdzero[] =
> > > > +    { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> > > > +
> > > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
> > > >  {
> > > > -    target_ulong irqs;
> > > > +    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
> > > > +        return -EINVAL;
> > > > +    }
> > > >
> > > > -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> > > > -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> > > > -    target_ulong hs_mstatus_sie = get_field(env->mstatus_hs, MSTATUS_SIE);
> > > > +    if (out_irq) {
> > > > +        *out_irq = hviprio_index2irq[index];
> > > > +    }
> > > > +
> > > > +    if (out_rdzero) {
> > > > +        *out_rdzero = hviprio_index2rdzero[index];
> > > > +    }
> > > >
> > > > -    target_ulong pending = env->mip & env->mie &
> > > > -                               ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > -    target_ulong vspending = (env->mip & env->mie &
> > > > -                              (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> > > > +    return 0;
> > > > +}
> > > >
> > > > -    target_ulong mie    = env->priv < PRV_M ||
> > > > -                          (env->priv == PRV_M && mstatus_mie);
> > > > -    target_ulong sie    = env->priv < PRV_S ||
> > > > -                          (env->priv == PRV_S && mstatus_sie);
> > > > -    target_ulong hs_sie = env->priv < PRV_S ||
> > > > -                          (env->priv == PRV_S && hs_mstatus_sie);
> > > > +uint8_t riscv_cpu_default_priority(int irq)
> > > > +{
> > > > +    int u, l;
> > > > +    uint8_t iprio = IPRIO_MMAXIPRIO;
> > > >
> > > > -    if (riscv_cpu_virt_enabled(env)) {
> > > > -        target_ulong pending_hs_irq = pending & -hs_sie;
> > > > +    if (irq < 0 || irq > 63) {
> > > > +        return iprio;
> > > > +    }
> > > >
> > > > -        if (pending_hs_irq) {
> > > > -            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> > > > -            return ctz64(pending_hs_irq);
> > > > +    /*
> > > > +     * Default priorities of local interrupts are defined in the
> > > > +     * RISC-V Advanced Interrupt Architecture specification.
> > > > +     *
> > > > +     * ----------------------------------------------------------------
> > > > +     *  Default  |
> > > > +     *  Priority | Major Interrupt Numbers
> > > > +     * ----------------------------------------------------------------
> > > > +     *  Highest  | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c),
> > > > +     *           | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38),
> > > > +     *           | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34),
> > > > +     *           | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30)
> > > > +     *           |
> > > > +     *           | 11 (0b),  3 (03),  7 (07)
> > > > +     *           |  9 (09),  1 (01),  5 (05)
> > > > +     *           | 12 (0c)
> > > > +     *           | 10 (0a),  2 (02),  6 (06)
> > > > +     *           |
> > > > +     *           | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c),
> > > > +     *           | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28),
> > > > +     *           | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24),
> > > > +     *  Lowest   | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20)
> > > > +     * ----------------------------------------------------------------
> > > > +     */
> > > > +
> > > > +    u = IPRIO_DEFAULT_U(irq);
> > > > +    l = IPRIO_DEFAULT_L(irq);
> > > > +    if (u == 0) {
> > > > +        if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER ||
> > > > +            irq == IRQ_VS_SOFT) {
> > > > +            iprio = IPRIO_DEFAULT_VS;
> > > > +        } else if (irq == IRQ_S_GEXT) {
> > > > +            iprio = IPRIO_DEFAULT_SGEXT;
> > > > +        } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER ||
> > > > +                   irq == IRQ_S_SOFT) {
> > > > +            iprio = IPRIO_DEFAULT_S;
> > > > +        } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER ||
> > > > +                   irq == IRQ_M_SOFT) {
> > > > +            iprio = IPRIO_DEFAULT_M;
> > > > +        } else {
> > > > +            iprio = IPRIO_DEFAULT_VS;
> > > >          }
> > > > +    } else if (u == 1) {
> > > > +        if (l < 8) {
> > > > +            iprio = IPRIO_DEFAULT_16_23(irq);
> > > > +        } else {
> > > > +            iprio = IPRIO_DEFAULT_24_31(irq);
> > > > +        }
> > > > +    } else if (u == 2) {
> > > > +        iprio = IPRIO_DEFAULT_32_47(irq);
> > > > +    } else if (u == 3) {
> > > > +        iprio = IPRIO_DEFAULT_48_63(irq);
> > > > +    }
> > > > +
> > > > +    return iprio;
> > > > +}
> > > > +
> > > > +static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> > > > +                                    uint64_t pending, uint8_t *iprio)
> > > > +{
> > > > +    int irq, best_irq = EXCP_NONE;
> > > > +    unsigned int prio, best_prio = UINT_MAX;
> > > >
> > > > -        pending = vspending;
> > > > +    if (!pending) {
> > > > +        return EXCP_NONE;
> > > >      }
> > > >
> > > > -    irqs = (pending & ~env->mideleg & -mie) | (pending &  env->mideleg & -sie);
> > > > +    irq = ctz64(pending);
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return irq;
> > > > +    }
> > > >
> > > > -    if (irqs) {
> > > > -        return ctz64(irqs); /* since non-zero */
> > > > +    pending = pending >> irq;
> > > > +    while (pending) {
> > > > +        prio = iprio[irq];
> > > > +        if (!prio) {
> > > > +            prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ?
> > > > +                   1 : IPRIO_MMAXIPRIO;
> > > > +        }
> > > > +        if ((pending & 0x1) && (prio < best_prio)) {
> > > > +            best_irq = irq;
> > > > +            best_prio = prio;
> > > > +        }
> > > > +        irq++;
> > > > +        pending = pending >> 1;
> > > > +    }
> > > > +
> > > > +    return best_irq;
> > > > +}
> > > > +
> > > > +int riscv_cpu_mirq_pending(CPURISCVState *env)
> > > > +{
> > > > +    uint64_t irqs = env->mip & env->mie & ~env->mideleg &
> > > > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > +
> > > > +    return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > > > +}
> > > > +
> > > > +int riscv_cpu_sirq_pending(CPURISCVState *env)
> > > > +{
> > > > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > > > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > +
> > > > +    return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > > > +}
> > > > +
> > > > +int riscv_cpu_vsirq_pending(CPURISCVState *env)
> > > > +{
> > > > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > > > +                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > +
> > > > +    return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > > > +}
> > > > +
> > > > +static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > > > +{
> > > > +    int virq;
> > > > +    uint64_t irqs, mie, sie, vsie;
> > > > +    uint64_t pending, vspending;
> > > > +
> > > > +    /* Determine interrupt enable state of all privilege modes */
> > > > +    if (riscv_cpu_virt_enabled(env)) {
> > > > +        mie = 1;
> > > > +        sie = 1;
> > > > +        vsie = (env->priv < PRV_S) ||
> > > > +               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> > > >      } else {
> > > > -        return EXCP_NONE; /* indicates no pending interrupt */
> > > > +        mie = (env->priv < PRV_M) ||
> > > > +              (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
> > > > +        sie = (env->priv < PRV_S) ||
> > > > +              (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> > > > +        vsie = 0;
> > > > +    }
> > > > +
> > > > +    /* Check M-mode interrupts */
> > > > +    pending = env->mip & env->mie &
> > > > +              ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > +    irqs = pending & ~env->mideleg & -mie;
> > > > +    if (irqs) {
> > > > +        return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > > > +    }
> > > > +
> > > > +    /* Check HS-mode interrupts */
> > > > +    irqs = pending & env->mideleg & -sie;
> > > > +    if (irqs) {
> > > > +        return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > > > +    }
> > > > +
> > > > +    /* Check VS-mode interrupts */
> > > > +    vspending = env->mip & env->mie &
> > > > +                (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > +    irqs = vspending & env->hideleg & -vsie;
> > > > +    if (irqs) {
> > > > +        virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > > > +        return (virq <= 0) ? virq : virq + 1;
> > > >      }
> > > > +
> > > > +    /* Indicates no pending interrupt */
> > > > +    return EXCP_NONE;
> > > >  }
> > > >  #endif
> > > >
> > > > @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx)
> > > >      return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
> > > >  }
> > > >
> > > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> > > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
> > > >  {
> > > >      CPURISCVState *env = &cpu->env;
> > > >      if (env->miclaim & interrupts) {
> > > > @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> > > >      }
> > > >  }
> > > >
> > > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> > > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
> > > >  {
> > > >      CPURISCVState *env = &cpu->env;
> > > >      CPUState *cs = CPU(cpu);
> > > > -    uint32_t old = env->mip;
> > > > +    uint64_t old = env->mip;
> > > >      bool locked = false;
> > > >
> > > >      if (!qemu_mutex_iothread_locked()) {
> > > > @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> > > >      return old;
> > > >  }
> > > >
> > > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > > > +                                int (*rmw_fn)(void *arg,
> > > > +                                              target_ulong reg,
> > > > +                                              target_ulong *val,
> > > > +                                              target_ulong new_val,
> > > > +                                              target_ulong write_mask),
> > > > +                                void *rmw_fn_arg)
> > > > +{
> > > > +    env->imsic_rmw_fn = rmw_fn;
> > > > +    env->imsic_rmw_fn_arg = rmw_fn_arg;
> > > > +}
> > > > +
> > > >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> > > >                               uint32_t arg)
> > > >  {
> > > > @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> > > >       */
> > > >      bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
> > > >      target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
> > > > -    target_ulong deleg = async ? env->mideleg : env->medeleg;
> > > > +    uint64_t deleg = async ? env->mideleg : env->medeleg;
> > > >      bool write_tval = false;
> > > >      target_ulong tval = 0;
> > > >      target_ulong htval = 0;
> > > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > > > index d2585395bf..3c016d7452 100644
> > > > --- a/target/riscv/csr.c
> > > > +++ b/target/riscv/csr.c
> > > > @@ -153,11 +153,56 @@ static int any32(CPURISCVState *env, int csrno)
> > > >
> > > >  }
> > > >
> > > > +static int aia_any(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return any(env, csrno);
> > > > +}
> > > > +
> > > > +static int aia_any32(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return any32(env, csrno);
> > > > +}
> > > > +
> > > >  static int smode(CPURISCVState *env, int csrno)
> > > >  {
> > > >      return -!riscv_has_ext(env, RVS);
> > > >  }
> > > >
> > > > +static int smode32(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_cpu_is_32bit(env)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return smode(env, csrno);
> > > > +}
> > > > +
> > > > +static int aia_smode(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return smode(env, csrno);
> > > > +}
> > > > +
> > > > +static int aia_smode32(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return smode32(env, csrno);
> > > > +}
> > > > +
> > > >  static int hmode(CPURISCVState *env, int csrno)
> > > >  {
> > > >      if (riscv_has_ext(env, RVS) &&
> > > > @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno)
> > > >  static int hmode32(CPURISCVState *env, int csrno)
> > > >  {
> > > >      if (!riscv_cpu_is_32bit(env)) {
> > > > -        return 0;
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return hmode(env, csrno);
> > > > +}
> > > > +
> > > > +static int aia_hmode(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > >      }
> > > >
> > > >      return hmode(env, csrno);
> > > > +}
> > > >
> > > > +static int aia_hmode32(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return hmode32(env, csrno);
> > > >  }
> > > >
> > > >  static int pmp(CPURISCVState *env, int csrno)
> > > > @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
> > > >
> > > >  /* Machine constants */
> > > >
> > > > -#define M_MODE_INTERRUPTS  (MIP_MSIP | MIP_MTIP | MIP_MEIP)
> > > > -#define S_MODE_INTERRUPTS  (MIP_SSIP | MIP_STIP | MIP_SEIP)
> > > > -#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)
> > > > +#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
> > > > +#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
> > > > +#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
> > > > +
> > > > +#define TLOWBITS64         ((uint64_t)((target_ulong)-1))
> > > >
> > > > -static const target_ulong delegable_ints = S_MODE_INTERRUPTS |
> > > > -                                           VS_MODE_INTERRUPTS;
> > > > -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > > > -                                     VS_MODE_INTERRUPTS;
> > > > +static const uint64_t delegable_ints = S_MODE_INTERRUPTS |
> > > > +                                       VS_MODE_INTERRUPTS;
> > > > +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > > > +                                 VS_MODE_INTERRUPTS;
> > > >  static const target_ulong delegable_excps =
> > > >      (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) |
> > > >      (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) |
> > > > @@ -419,10 +483,10 @@ static const target_ulong delegable_excps =
> > > >  static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
> > > >      SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
> > > >      SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
> > > > -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > > > -static const target_ulong hip_writable_mask = MIP_VSSIP;
> > > > -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > > > -static const target_ulong vsip_writable_mask = MIP_VSSIP;
> > > > +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > > > +static const uint64_t hip_writable_mask = MIP_VSSIP;
> > > > +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > > > +static const uint64_t vsip_writable_mask = MIP_VSSIP;
> > > >
> > > >  static const char valid_vm_1_10_32[16] = {
> > > >      [VM_1_10_MBARE] = 1,
> > > > @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val)
> > > >
> > > >  static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
> > > >  {
> > > > -    env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
> > > > +    uint64_t mask = delegable_ints & TLOWBITS64;
> > > > +
> > > > +    env->mideleg = (env->mideleg & ~mask) | (val & mask);
> > > > +    if (riscv_has_ext(env, RVH)) {
> > > > +        env->mideleg |= VS_MODE_INTERRUPTS;
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_cpu_virt_enabled(env)) {
> > > > +        return csrno;
> > > > +    }
> > > > +
> > > > +    switch (csrno) {
> > > > +    case CSR_SISELECT:
> > > > +        return CSR_VSISELECT;
> > > > +    case CSR_SIREG:
> > > > +        return CSR_VSIREG;
> > > > +    case CSR_STOPI:
> > > > +        return CSR_VSTOPI;
> > > > +    case CSR_SSETEIPNUM:
> > > > +        return CSR_VSSETEIPNUM;
> > > > +    case CSR_SCLREIPNUM:
> > > > +        return CSR_VSCLREIPNUM;
> > > > +    case CSR_SSETEIENUM:
> > > > +        return CSR_VSSETEIENUM;
> > > > +    case CSR_SCLREIENUM:
> > > > +        return CSR_VSCLREIENUM;
> > > > +    default:
> > > > +        return csrno;
> > > > +    };
> > > > +}
> > > > +
> > > > +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val,
> > > > +                        target_ulong new_val, target_ulong write_mask)
> > > > +{
> > > > +    target_ulong *iselect;
> > > > +
> > > > +    switch (csrno) {
> > > > +    case CSR_MISELECT:
> > > > +        iselect = &env->miselect;
> > > > +        break;
> > > > +    case CSR_SISELECT:
> > > > +        iselect = riscv_cpu_virt_enabled(env) ?
> > > > +                  &env->vsiselect : &env->siselect;
> > > > +        break;
> > > > +    case CSR_VSISELECT:
> > > > +        iselect = &env->vsiselect;
> > > > +        break;
> > > > +    default:
> > > > +         return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    };
> > > > +
> > > > +    if (val) {
> > > > +        *val = *iselect;
> > > > +    }
> > > > +
> > > > +    if (write_mask) {
> > > > +        *iselect = (*iselect & ~write_mask) | (new_val & write_mask);
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int rmw_iprio(target_ulong iselect, uint8_t *iprio,
> > > > +                     target_ulong *val, target_ulong new_val,
> > > > +                     target_ulong write_mask)
> > > > +{
> > > > +    int i, firq, nirqs;
> > > > +    target_ulong old_val;
> > > > +
> > > > +    if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) {
> > > > +        return -EINVAL;
> > > > +    }
> > > > +#if TARGET_LONG_BITS == 64
> > > > +    if (iselect & 0x1) {
> > > > +        return -EINVAL;
> > > > +    }
> > > > +#endif
> > > > +
> > > > +    nirqs = 4 * (TARGET_LONG_BITS / 32);
> > > > +    firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 32)) * (nirqs);
> > > > +
> > > > +    old_val = 0;
> > > > +    for (i = 0; i < nirqs; i++) {
> > > > +        old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i);
> > > > +    }
> > > > +
> > > > +    if (val) {
> > > > +        *val = old_val;
> > > > +    }
> > > > +
> > > > +    if (write_mask) {
> > > > +        new_val = (old_val & ~write_mask) | (new_val & write_mask);
> > > > +        for (i = 0; i < nirqs; i++) {
> > > > +            iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff;
> > > > +        }
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
> > > > +                     target_ulong new_val, target_ulong write_mask)
> > > > +{
> > > > +    bool virt;
> > > > +    uint8_t *iprio;
> > > > +    int ret = -EINVAL;
> > > > +    target_ulong priv, isel, vgein;
> > > > +
> > > > +    /* Translate CSR number for VS-mode */
> > > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > > +
> > > > +    /* Decode register details from CSR number */
> > > > +    virt = false;
> > > > +    switch (csrno) {
> > > > +    case CSR_MIREG:
> > > > +        iprio = env->miprio;
> > > > +        isel = env->miselect;
> > > > +        priv = PRV_M;
> > > > +        break;
> > > > +    case CSR_SIREG:
> > > > +        iprio = env->siprio;
> > > > +        isel = env->siselect;
> > > > +        priv = PRV_S;
> > > > +        break;
> > > > +    case CSR_VSIREG:
> > > > +        iprio = env->hviprio;
> > > > +        isel = env->vsiselect;
> > > > +        priv = PRV_S;
> > > > +        virt = true;
> > > > +        break;
> > > > +    default:
> > > > +         goto done;
> > > > +    };
> > > > +
> > > > +    /* Find the selected guest interrupt file */
> > > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > > +
> > > > +    if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) {
> > > > +        /* Local interrupt priority registers not available for VS-mode */
> > > > +        if (!virt) {
> > > > +            ret = rmw_iprio(isel, iprio, val, new_val, write_mask);
> > > > +        }
> > > > +    } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) {
> > > > +        /* IMSIC registers only available when machine implements it. */
> > > > +        if (env->imsic_rmw_fn) {
> > > > +            /* Selected guest interrupt file should not be zero */
> > > > +            if (virt && !vgein) {
> > > > +                goto done;
> > > > +            }
> > > > +            /* Call machine specific IMSIC register emulation */
> > > > +            ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > > +                                    IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > > +                                    val, new_val, write_mask);
> > > > +        }
> > > > +    }
> > > > +
> > > > +done:
> > > > +    if (ret) {
> > > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    int irq;
> > > > +
> > > > +    irq = riscv_cpu_mirq_pending(env);
> > > > +    if (irq <= 0 || irq > 63) {
> > > > +       *val = 0;
> > > > +    } else {
> > > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > > +       *val |= env->miprio[irq];
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    bool virt;
> > > > +    int ret = -EINVAL;
> > > > +    target_ulong vgein;
> > > > +
> > > > +    /* Translate CSR number for VS-mode */
> > > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > > +
> > > > +    /* Decode register details from CSR number */
> > > > +    virt = false;
> > > > +    switch (csrno) {
> > > > +    case CSR_MSETEIPNUM:
> > > > +    case CSR_MCLREIPNUM:
> > > > +    case CSR_MSETEIENUM:
> > > > +    case CSR_MCLREIENUM:
> > > > +    case CSR_SSETEIPNUM:
> > > > +    case CSR_SCLREIPNUM:
> > > > +    case CSR_SSETEIENUM:
> > > > +    case CSR_SCLREIENUM:
> > > > +        break;
> > > > +    case CSR_VSSETEIPNUM:
> > > > +    case CSR_VSCLREIPNUM:
> > > > +    case CSR_VSSETEIENUM:
> > > > +    case CSR_VSCLREIENUM:
> > > > +        virt = true;
> > > > +        break;
> > > > +    default:
> > > > +         goto done;
> > > > +    };
> > > > +
> > > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > > +    if (!env->imsic_rmw_fn) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Find the selected guest interrupt file */
> > > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > > +
> > > > +    /* Selected guest interrupt file should not be zero */
> > > > +    if (virt && !vgein) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Set/Clear CSRs always read zero */
> > > > +    ret = 0;
> > > > +    if (val) {
> > > > +        *val = 0;
> > > > +    }
> > > > +
> > > > +done:
> > > > +    if (ret) {
> > > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    int ret = -EINVAL;
> > > > +    bool set, pend, virt;
> > > > +    target_ulong priv, isel, vgein;
> > > > +    target_ulong new_val, write_mask;
> > > > +
> > > > +    /* Translate CSR number for VS-mode */
> > > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > > +
> > > > +    /* Decode register details from CSR number */
> > > > +    virt = set = pend = false;
> > > > +    switch (csrno) {
> > > > +    case CSR_MSETEIPNUM:
> > > > +        priv = PRV_M;
> > > > +        set = true;
> > > > +        break;
> > > > +    case CSR_MCLREIPNUM:
> > > > +        priv = PRV_M;
> > > > +        pend = true;
> > > > +        break;
> > > > +    case CSR_MSETEIENUM:
> > > > +        priv = PRV_M;
> > > > +        set = true;
> > > > +        break;
> > > > +    case CSR_MCLREIENUM:
> > > > +        priv = PRV_M;
> > > > +        break;
> > > > +    case CSR_SSETEIPNUM:
> > > > +        priv = PRV_S;
> > > > +        set = true;
> > > > +        pend = true;
> > > > +        break;
> > > > +    case CSR_SCLREIPNUM:
> > > > +        priv = PRV_S;
> > > > +        pend = true;
> > > > +        break;
> > > > +    case CSR_SSETEIENUM:
> > > > +        priv = PRV_S;
> > > > +        set = true;
> > > > +        break;
> > > > +    case CSR_SCLREIENUM:
> > > > +        priv = PRV_S;
> > > > +        break;
> > > > +    case CSR_VSSETEIPNUM:
> > > > +        priv = PRV_S;
> > > > +        virt = true;
> > > > +        set = true;
> > > > +        pend = true;
> > > > +        break;
> > > > +    case CSR_VSCLREIPNUM:
> > > > +        priv = PRV_S;
> > > > +        virt = true;
> > > > +        pend = true;
> > > > +        break;
> > > > +    case CSR_VSSETEIENUM:
> > > > +        priv = PRV_S;
> > > > +        virt = true;
> > > > +        set = true;
> > > > +        break;
> > > > +    case CSR_VSCLREIENUM:
> > > > +        priv = PRV_S;
> > > > +        virt = true;
> > > > +        break;
> > > > +    default:
> > > > +         goto done;
> > > > +    };
> > > > +
> > > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > > +    if (!env->imsic_rmw_fn) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Find target interrupt pending/enable register */
> > > > +    if (pend) {
> > > > +        isel = ISELECT_IMSIC_EIP0;
> > > > +    } else {
> > > > +        isel = ISELECT_IMSIC_EIE0;
> > > > +    }
> > > > +    isel += val / IMSIC_EIPx_BITS;
> > > > +
> > > > +    /* Find the interrupt bit to be set/clear */
> > > > +    write_mask = 1 << (val % IMSIC_EIPx_BITS);
> > > > +    new_val = (set) ? write_mask : 0;
> > > > +
> > > > +    /* Find the selected guest interrupt file */
> > > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > > +
> > > > +    /* Selected guest interrupt file should not be zero */
> > > > +    if (virt && !vgein) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Call machine specific IMSIC register emulation */
> > > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > > +                            NULL, new_val, write_mask);
> > > > +
> > > > +done:
> > > > +    if (ret) {
> > > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    bool virt;
> > > > +    int ret = -EINVAL;
> > > > +    target_ulong priv, isel, vgein;
> > > > +    target_ulong topei, write_mask;
> > > > +
> > > > +    /* Decode register details from CSR number */
> > > > +    virt = false;
> > > > +    switch (csrno) {
> > > > +    case CSR_MCLAIMEI:
> > > > +        priv = PRV_M;
> > > > +        break;
> > > > +    case CSR_SCLAIMEI:
> > > > +        priv = PRV_S;
> > > > +        virt = riscv_cpu_virt_enabled(env);
> > > > +        break;
> > > > +    default:
> > > > +        goto done;
> > > > +    };
> > > > +
> > > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > > +    if (!env->imsic_rmw_fn) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Find the selected guest interrupt file */
> > > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > > +
> > > > +    /* Selected guest interrupt file should not be zero */
> > > > +    if (virt && !vgein) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Call machine specific IMSIC register emulation for reading TOPEI */
> > > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > > +                            IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein),
> > > > +                            &topei, -1, 0);
> > > > +    if (ret) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* If no interrupt pending then we are done */
> > > > +    if (!topei) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Find target interrupt pending register */
> > > > +    isel = ISELECT_IMSIC_EIP0;
> > > > +    isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS);
> > > > +
> > > > +    /* Find the interrupt bit to be cleared */
> > > > +    write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS);
> > > > +
> > > > +    /* Call machine specific IMSIC register emulation to clear pending bit */
> > > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > > +                            NULL, 0, write_mask);
> > > > +
> > > > +    /* Update return value */
> > > > +    if (val) {
> > > > +        *val = topei;
> > > > +    }
> > > > +
> > > > +done:
> > > > +    if (ret) {
> > > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    *val = (env->mideleg >> 32);
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    uint64_t mask = delegable_ints & ~TLOWBITS64;
> > > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > > +
> > > > +    env->mideleg = (env->mideleg & ~mask) | (newval & mask);
> > > >      if (riscv_has_ext(env, RVH)) {
> > > >          env->mideleg |= VS_MODE_INTERRUPTS;
> > > >      }
> > > > @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
> > > >
> > > >  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
> > > >  {
> > > > -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> > > > +    uint64_t mask = all_ints & TLOWBITS64;
> > > > +
> > > > +    env->mie = (env->mie & ~mask) | (val & mask);
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    *val = (env->mie >> 32);
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    uint64_t mask = all_ints & ~TLOWBITS64;
> > > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > > +
> > > > +    env->mie = (env->mie & ~mask) | (newval & mask);
> > > >      return 0;
> > > >  }
> > > >
> > > > @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >  {
> > > >      RISCVCPU *cpu = env_archcpu(env);
> > > >      /* Allow software control of delegable interrupts not claimed by hardware */
> > > > -    target_ulong mask = write_mask & delegable_ints & ~env->miclaim;
> > > > -    uint32_t old_mip;
> > > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > > +                    ~env->miclaim & TLOWBITS64;
> > > > +    uint64_t old_mip;
> > > >
> > > >      if (mask) {
> > > >          old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > > @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >      return 0;
> > > >  }
> > > >
> > > > +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > > +                    target_ulong new_value, target_ulong write_mask)
> > > > +{
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > > +                    ~env->miclaim & ~TLOWBITS64;
> > > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > > +
> > > > +    if (ret_value) {
> > > > +        *ret_value = old_mip >> 32;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > >  /* Supervisor Trap Setup */
> > > >  static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > > >  {
> > > > @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
> > > >
> > > >  static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
> > > >  {
> > > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64;
> > > > +
> > > >      /* Shift the VS bits to their S bit location in vsie */
> > > > -    *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
> > > > +    *val = (env->mie & mask) >> 1;
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64;
> > > > +
> > > > +    /* Shift the VS bits to their S bit location in vsieh */
> > > > +    *val = (env->mie & mask) >> (32 + 1);
> > > >      return 0;
> > > >  }
> > > >
> > > >  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
> > > >  {
> > > >      if (riscv_cpu_virt_enabled(env)) {
> > > > -        read_vsie(env, CSR_VSIE, val);
> > > > -    } else {
> > > > -        *val = env->mie & env->mideleg;
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return read_vsie(env, CSR_VSIE, val);
> > > >      }
> > > > +
> > > > +    *val = env->mie & env->mideleg;
> > > >      return 0;
> > > >  }
> > > >
> > > >  static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
> > > >  {
> > > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > > > +                    all_ints & TLOWBITS64;
> > > > +
> > > >      /* Shift the S bits to their VS bit location in mie */
> > > > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
> > > > -                          ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS);
> > > > -    return write_mie(env, CSR_MIE, newval);
> > > > +    env->mie = (env->mie & ~mask) | ((val << 1) & mask);
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > > > +                    all_ints & ~TLOWBITS64;
> > > > +    uint64_t newval = (uint64_t)val << 32;
> > > > +
> > > > +    /* Shift the S bits to their VS bit location in mie */
> > > > +    env->mie = (env->mie & ~mask) | ((newval << 1) & mask);
> > > > +
> > > > +    return 0;
> > > >  }
> > > >
> > > >  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
> > > >  {
> > > > +    uint64_t mask;
> > > > +
> > > >      if (riscv_cpu_virt_enabled(env)) {
> > > > -        write_vsie(env, CSR_VSIE, val);
> > > > -    } else {
> > > > -        target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) |
> > > > -                              (val & S_MODE_INTERRUPTS);
> > > > -        write_mie(env, CSR_MIE, newval);
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return write_vsie(env, CSR_VSIE, val);
> > > > +    }
> > > > +
> > > > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64;
> > > > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    if (riscv_cpu_virt_enabled(env)) {
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return read_vsieh(env, CSR_VSIEH, val);
> > > > +    }
> > > > +
> > > > +    *val = ((env->mie & env->mideleg) >> 32);
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    uint64_t mask, newval;
> > > > +
> > > > +    if (riscv_cpu_virt_enabled(env)) {
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return write_vsieh(env, CSR_VSIEH, val);
> > > >      }
> > > >
> > > > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64;
> > > > +    newval = (uint64_t)val << 32;
> > > > +
> > > > +    env->mie = (env->mie & ~mask) | (newval & mask);
> > > >      return 0;
> > > >  }
> > > >
> > > > @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
> > > >  static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >                      target_ulong new_value, target_ulong write_mask)
> > > >  {
> > > > -    /* Shift the S bits to their VS bit location in mip */
> > > > -    int ret = rmw_mip(env, 0, ret_value, new_value << 1,
> > > > -                      (write_mask << 1) & vsip_writable_mask & env->hideleg);
> > > > -    *ret_value &= VS_MODE_INTERRUPTS;
> > > > -    /* Shift the VS bits to their S bit location in vsip */
> > > > -    *ret_value >>= 1;
> > > > -    return ret;
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints &
> > > > +                    vsip_writable_mask & env->hideleg &
> > > > +                    ~env->miclaim & TLOWBITS64;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > > +
> > > > +    if (ret_value) {
> > > > +        *ret_value = old_mip & VS_MODE_INTERRUPTS;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > > +                     target_ulong new_value, target_ulong write_mask)
> > > > +{
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints &
> > > > +                    vsip_writable_mask & env->hideleg &
> > > > +                    ~env->miclaim & ~TLOWBITS64;
> > > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > > +
> > > > +    if (ret_value) {
> > > > +        *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > >  }
> > > >
> > > >  static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >                     target_ulong new_value, target_ulong write_mask)
> > > >  {
> > > > -    int ret;
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    uint64_t mask, old_mip;
> > > >
> > > >      if (riscv_cpu_virt_enabled(env)) {
> > > > -        ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > > > +    }
> > > > +
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    mask = ((uint64_t)write_mask) & delegable_ints &
> > > > +           env->mideleg & sip_writable_mask &
> > > > +           ~env->miclaim & TLOWBITS64;
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > >      } else {
> > > > -        ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
> > > > -                      write_mask & env->mideleg & sip_writable_mask);
> > > > +        old_mip = env->mip;
> > > >      }
> > > >
> > > > -    *ret_value &= env->mideleg;
> > > > -    return ret;
> > > > +    if (ret_value) {
> > > > +        *ret_value = old_mip;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > > +                    target_ulong new_value, target_ulong write_mask)
> > > > +{
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    uint64_t mask, new_value64;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (riscv_cpu_virt_enabled(env)) {
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask);
> > > > +    }
> > > > +
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > > +           env->mideleg & sip_writable_mask &
> > > > +           ~env->miclaim & ~TLOWBITS64;
> > > > +    new_value64 = (uint64_t)new_value << 32;
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > > +
> > > > +    if (ret_value) {
> > > > +        *ret_value = (old_mip & env->mideleg) >> 32;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > >  }
> > > >
> > > >  /* Supervisor Protection and Translation */
> > > > @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
> > > >      return 0;
> > > >  }
> > > >
> > > > +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    int irq, hiid;
> > > > +    uint8_t hiprio, iprio;
> > > > +
> > > > +    irq = riscv_cpu_vsirq_pending(env);
> > > > +    if (irq <= 0 || irq > 63) {
> > > > +       *val = 0;
> > > > +    } else {
> > > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > > +       iprio = env->hviprio[irq];
> > > > +       /* TODO: This needs to improve in specification */
> > > > +       if (!(env->hstatus & HSTATUS_VGEIN)) {
> > > > +           hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >>
> > > > +                 HVICONTROL_IID_SHIFT;
> > > > +           hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK;
> > > > +           if (irq == hiid && hiprio) {
> > > > +               iprio = hiprio;
> > > > +           }
> > > > +       }
> > > > +       *val |= iprio;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    int irq;
> > > > +
> > > > +    if (riscv_cpu_virt_enabled(env)) {
> > > > +        return read_vstopi(env, CSR_VSTOPI, val);
> > > > +    }
> > > > +
> > > > +    irq = riscv_cpu_sirq_pending(env);
> > > > +    if (irq <= 0 || irq > 63) {
> > > > +       *val = 0;
> > > > +    } else {
> > > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > > +       *val |= env->siprio[irq];
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > >  /* Hypervisor Extensions */
> > > >  static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > > >  {
> > > > @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
> > > >      return 0;
> > > >  }
> > > >
> > > > +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    *val = env->hideleg >> 32;
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    uint64_t mask = ~TLOWBITS64;
> > > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > > +
> > > > +    env->hideleg = (env->hideleg & ~mask) | (newval & mask);
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > >  static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >                     target_ulong new_value, target_ulong write_mask)
> > > >  {
> > > > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > > > -                      write_mask & hvip_writable_mask);
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > > +                    hvip_writable_mask &
> > > > +                    ~env->miclaim & TLOWBITS64;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > >
> > > > -    *ret_value &= hvip_writable_mask;
> > > > +    if (ret_value) {
> > > > +        *ret_value = old_mip & hvip_writable_mask;
> > > > +    }
> > > >
> > > > -    return ret;
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > > +                    target_ulong new_value, target_ulong write_mask)
> > > > +{
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > > +                    hvip_writable_mask &
> > > > +                    ~env->miclaim & ~TLOWBITS64;
> > > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > > +
> > > > +    if (ret_value) {
> > > > +        *ret_value = (old_mip & hvip_writable_mask) >> 32;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > >  }
> > > >
> > > >  static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >                     target_ulong new_value, target_ulong write_mask)
> > > >  {
> > > > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > > > -                      write_mask & hip_writable_mask);
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > > +                    hip_writable_mask &
> > > > +                    ~env->miclaim & TLOWBITS64;
> > > > +    uint64_t old_mip;
> > > >
> > > > -    *ret_value &= hip_writable_mask;
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > >
> > > > -    return ret;
> > > > +    if (ret_value) {
> > > > +        *ret_value = old_mip & hip_writable_mask;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > >  }
> > > >
> > > >  static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> > > > @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> > > >
> > > >  static int write_hie(CPURISCVState *env, int csrno, target_ulong val)
> > > >  {
> > > > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS);
> > > > -    return write_mie(env, CSR_MIE, newval);
> > > > +    uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64;
> > > > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > > > +    return 0;
> > > >  }
> > > >
> > > >  static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val)
> > > > @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val)
> > > >      return 0;
> > > >  }
> > > >
> > > > +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    *val = env->hvicontrol;
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    env->hvicontrol = val & HVICONTROL_VALID_MASK;
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_hvipriox(CPURISCVState *env, int first_index,
> > > > +                         uint8_t *iprio, target_ulong *val)
> > > > +{
> > > > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > > > +
> > > > +    /* First index has to be multiple of numbe of irqs per register */
> > > > +    if (first_index % num_irqs) {
> > > > +        return (riscv_cpu_virt_enabled(env)) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    /* Fill-up return value */
> > > > +    *val = 0;
> > > > +    for (i = 0; i < num_irqs; i++) {
> > > > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > > > +            continue;
> > > > +        }
> > > > +        if (rdzero) {
> > > > +            continue;
> > > > +        }
> > > > +        *val |= ((target_ulong)iprio[irq]) << (i * 8);
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_hvipriox(CPURISCVState *env, int first_index,
> > > > +                          uint8_t *iprio, target_ulong val)
> > > > +{
> > > > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > > > +
> > > > +    /* First index has to be multiple of numbe of irqs per register */
> > > > +    if (first_index % num_irqs) {
> > > > +        return (riscv_cpu_virt_enabled(env)) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    /* Fill-up priority arrary */
> > > > +    for (i = 0; i < num_irqs; i++) {
> > > > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > > > +            continue;
> > > > +        }
> > > > +        if (rdzero) {
> > > > +            iprio[irq] = 0;
> > > > +        } else {
> > > > +            iprio[irq] = (val >> (i * 8)) & 0xff;
> > > > +        }
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    return read_hvipriox(env, 0, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    return write_hvipriox(env, 0, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    return read_hvipriox(env, 4, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    return write_hvipriox(env, 4, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    return read_hvipriox(env, 8, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    return write_hvipriox(env, 8, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    return read_hvipriox(env, 12, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    return write_hvipriox(env, 12, env->hviprio, val);
> > > > +}
> > > > +
> > > >  /* Virtual CSR Registers */
> > > >  static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > > >  {
> > > > @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > > >      [CSR_MBADADDR] = { "mbadaddr", any,  read_mbadaddr, write_mbadaddr },
> > > >      [CSR_MIP]      = { "mip",      any,  NULL,    NULL, rmw_mip        },
> > > >
> > > > +    /* Machine-Level Window to Indirectly Accessed Registers (AIA) */
> > > > +    [CSR_MISELECT] = { "miselect", aia_any,   NULL, NULL,    rmw_xiselect },
> > > > +    [CSR_MIREG]    = { "mireg",    aia_any,   NULL, NULL,    rmw_xireg },
> > > > +
> > > > +    /* Machine-Level Interrupts (AIA) */
> > > > +    [CSR_MTOPI]    = { "mtopi",    aia_any,   read_mtopi },
> > > > +
> > > > +    /* Machine-Level IMSIC Interface (AIA) */
> > > > +    [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_MCLAIMEI]   = { "mclaimei",   aia_any, read_xclaimei },
> > > > +
> > > > +    /* Machine-Level High-Half CSRs (AIA) */
> > > > +    [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh },
> > > > +    [CSR_MIEH]     = { "mieh",     aia_any32, read_mieh,     write_mieh     },
> > > > +    [CSR_MIPH]     = { "miph",     aia_any32, NULL,    NULL, rmw_miph       },
> > > > +
> > > >      /* Supervisor Trap Setup */
> > > >      [CSR_SSTATUS]    = { "sstatus",    smode, read_sstatus,    write_sstatus    },
> > > >      [CSR_SIE]        = { "sie",        smode, read_sie,        write_sie        },
> > > > @@ -1444,6 +2357,24 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > > >      /* Supervisor Protection and Translation */
> > > >      [CSR_SATP]     = { "satp",     smode, read_satp,    write_satp      },
> > > >
> > > > +    /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
> > > > +    [CSR_SISELECT]   = { "siselect",   aia_smode, NULL, NULL, rmw_xiselect },
> > > > +    [CSR_SIREG]      = { "sireg",      aia_smode, NULL, NULL, rmw_xireg },
> > > > +
> > > > +    /* Supervisor-Level Interrupts (AIA) */
> > > > +    [CSR_STOPI]      = { "stopi",      aia_smode, read_stopi },
> > > > +
> > > > +    /* Supervisor-Level IMSIC Interface (AIA) */
> > > > +    [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_SCLAIMEI]   = { "sclaimei",   aia_smode, read_xclaimei },
> > > > +
> > > > +    /* Supervisor-Level High-Half CSRs (AIA) */
> > > > +    [CSR_SIEH]       = { "sieh",       aia_smode32, read_sieh,  write_sieh },
> > > > +    [CSR_SIPH]       = { "siph",       aia_smode32, NULL, NULL, rmw_siph   },
> > > > +
> > > >      [CSR_HSTATUS]     = { "hstatus",     hmode,   read_hstatus,     write_hstatus     },
> > > >      [CSR_HEDELEG]     = { "hedeleg",     hmode,   read_hedeleg,     write_hedeleg     },
> > > >      [CSR_HIDELEG]     = { "hideleg",     hmode,   read_hideleg,     write_hideleg     },
> > > > @@ -1472,6 +2403,32 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > > >      [CSR_MTVAL2]      = { "mtval2",      hmode,   read_mtval2,      write_mtval2      },
> > > >      [CSR_MTINST]      = { "mtinst",      hmode,   read_mtinst,      write_mtinst      },
> > > >
> > > > +    /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
> > > > +    [CSR_HVICONTROL]  = { "hvicontrol",  aia_hmode, read_hvicontrol, write_hvicontrol },
> > > > +    [CSR_HVIPRIO1]    = { "hviprio1",    aia_hmode, read_hviprio1,   write_hviprio1 },
> > > > +    [CSR_HVIPRIO2]    = { "hviprio2",    aia_hmode, read_hviprio2,   write_hviprio2 },
> > > > +
> > > > +    /* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
> > > > +    [CSR_VSISELECT]   = { "vsiselect",   aia_hmode, NULL, NULL,      rmw_xiselect },
> > > > +    [CSR_VSIREG]      = { "vsireg",      aia_hmode, NULL, NULL,      rmw_xireg },
> > > > +
> > > > +    /* VS-Level Interrupts (H-extension with AIA) */
> > > > +    [CSR_VSTOPI]      = { "vstopi",      aia_hmode, read_vstopi },
> > > > +
> > > > +    /* VS-Level IMSIC Interface (H-extension with AIA) */
> > > > +    [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > > +
> > > > +    /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
> > > > +    [CSR_HIDELEGH]    = { "hidelegh",    aia_hmode32, read_hidelegh,  write_hidelegh },
> > > > +    [CSR_HVIPH]       = { "hviph",       aia_hmode32, NULL, NULL,     rmw_hviph },
> > > > +    [CSR_HVIPRIO1H]   = { "hviprio1h",   aia_hmode32, read_hviprio1h, write_hviprio1h },
> > > > +    [CSR_HVIPRIO2H]   = { "hviprio2h",   aia_hmode32, read_hviprio2h, write_hviprio2h },
> > > > +    [CSR_VSIEH]       = { "vsieh",       aia_hmode32, read_vsieh,     write_vsieh },
> > > > +    [CSR_VSIPH]       = { "vsiep",       aia_hmode32, NULL, NULL,     rmw_vsiph },
> > > > +
> > > >      /* Physical Memory Protection */
> > > >      [CSR_PMPCFG0]    = { "pmpcfg0",   pmp, read_pmpcfg,  write_pmpcfg  },
> > > >      [CSR_PMPCFG1]    = { "pmpcfg1",   pmp, read_pmpcfg,  write_pmpcfg  },
> > > > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> > > > index 44d4015bd6..f7fa48c240 100644
> > > > --- a/target/riscv/machine.c
> > > > +++ b/target/riscv/machine.c
> > > > @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = {
> > > >
> > > >  static const VMStateDescription vmstate_hyper = {
> > > >      .name = "cpu/hyper",
> > > > -    .version_id = 1,
> > > > -    .minimum_version_id = 1,
> > > > +    .version_id = 2,
> > > > +    .minimum_version_id = 2,
> > > >      .needed = hyper_needed,
> > > >      .fields = (VMStateField[]) {
> > > >          VMSTATE_UINTTL(env.hstatus, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.hedeleg, RISCVCPU),
> > > > -        VMSTATE_UINTTL(env.hideleg, RISCVCPU),
> > > > +        VMSTATE_UINT64(env.hideleg, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.hcounteren, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.htval, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.htinst, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.hgatp, RISCVCPU),
> > > >          VMSTATE_UINT64(env.htimedelta, RISCVCPU),
> > > >
> > > > +        VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
> > > > +        VMSTATE_UINTTL(env.hvicontrol, RISCVCPU),
> > > > +
> > > >          VMSTATE_UINT64(env.vsstatus, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.vstvec, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.vsscratch, RISCVCPU),
> > > > @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = {
> > > >          VMSTATE_UINTTL(env.vscause, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.vstval, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.vsatp, RISCVCPU),
> > > > +        VMSTATE_UINTTL(env.vsiselect, RISCVCPU),
> > > >
> > > >          VMSTATE_UINTTL(env.mtval2, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.mtinst, RISCVCPU),
> > > > @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = {
> > > >
> > > >  const VMStateDescription vmstate_riscv_cpu = {
> > > >      .name = "cpu",
> > > > -    .version_id = 1,
> > > > -    .minimum_version_id = 1,
> > > > +    .version_id = 2,
> > > > +    .minimum_version_id = 2,
> > > >      .fields = (VMStateField[]) {
> > > >          VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
> > > >          VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
> > > > +        VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
> > > > +        VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
> > > >          VMSTATE_UINTTL(env.pc, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.load_res, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.load_val, RISCVCPU),
> > > > @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = {
> > > >          VMSTATE_UINTTL(env.resetvec, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.mhartid, RISCVCPU),
> > > >          VMSTATE_UINT64(env.mstatus, RISCVCPU),
> > > > -        VMSTATE_UINTTL(env.mip, RISCVCPU),
> > > > -        VMSTATE_UINT32(env.miclaim, RISCVCPU),
> > > > -        VMSTATE_UINTTL(env.mie, RISCVCPU),
> > > > -        VMSTATE_UINTTL(env.mideleg, RISCVCPU),
> > > > +        VMSTATE_UINT64(env.mip, RISCVCPU),
> > > > +        VMSTATE_UINT64(env.miclaim, RISCVCPU),
> > > > +        VMSTATE_UINT64(env.mie, RISCVCPU),
> > > > +        VMSTATE_UINT64(env.mideleg, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.sptbr, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.satp, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.sbadaddr, RISCVCPU),
> > > > @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = {
> > > >          VMSTATE_UINTTL(env.mepc, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.mcause, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.mtval, RISCVCPU),
> > > > +        VMSTATE_UINTTL(env.miselect, RISCVCPU),
> > > > +        VMSTATE_UINTTL(env.siselect, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.scounteren, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.sscratch, RISCVCPU),
> > > > --
> > > > 2.25.1
> > > >
> > > >


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
@ 2021-06-11 14:04           ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-11 14:04 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Fri, Jun 11, 2021 at 2:16 PM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote:
> >
> > On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote:
> > >
> > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > >
> > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> > > > and VS-mode.
> > > >
> > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > ---
> > > >  target/riscv/cpu.c        |   27 +-
> > > >  target/riscv/cpu.h        |   52 +-
> > > >  target/riscv/cpu_helper.c |  245 ++++++++-
> > > >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> > > >  target/riscv/machine.c    |   26 +-
> > > >  5 files changed, 1309 insertions(+), 100 deletions(-)
> > >
> > > I feel this patch could be split up more :)
> >
> > This is patch is large because I did not want to break functionality.
> >
> > I try again to break this patch. At the moment, the best I can do is
> > to break in to two parts.
> > 1) AIA local interrupt CSRs without IMSIC
> > 2) Extend AIA local interrupt CSRs to support IMSIC register access
>
> As the patch is being added while AIA isn't enabled you are able to
> add the AIA in breaking stages. That is the AIA isn't fully
> functional, you still have to make sure not to break existing users.
>
> >
> > >
> > > >
> > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > > > index f3702111ae..795162834b 100644
> > > > --- a/target/riscv/cpu.c
> > > > +++ b/target/riscv/cpu.c
> > > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> > > >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
> > > >                       (target_ulong)env->vsstatus);
> > > >      }
> > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
> > > >      if (riscv_has_ext(env, RVH)) {
> > > > -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> > > > +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
> > > >      }
> > > >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> > > >      if (riscv_has_ext(env, RVH)) {
> > > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
> > > >
> > > >  static void riscv_cpu_reset(DeviceState *dev)
> > > >  {
> > > > +    uint8_t iprio;
> > > > +    int i, irq, rdzero;
> > > >      CPUState *cs = CPU(dev);
> > > >      RISCVCPU *cpu = RISCV_CPU(cs);
> > > >      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> > > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
> > > >      env->mcause = 0;
> > > >      env->pc = env->resetvec;
> > > >      env->two_stage_lookup = false;
> > > > +
> > > > +    /* Initialized default priorities of local interrupts. */
> > > > +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> > > > +        iprio = riscv_cpu_default_priority(i);
> > > > +        env->miprio[i] = iprio;
> > > > +        env->siprio[i] = iprio;
> > > > +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> > > > +    }
> > > > +    i = 0;
> > > > +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> > > > +        if (rdzero) {
> > > > +            env->hviprio[irq] = 0;
> > > > +        } else {
> > > > +            env->hviprio[irq] = env->miprio[irq];
> > > > +        }
> > > > +        i++;
> > > > +    }
> > > >  #endif
> > > >      cs->exception_index = EXCP_NONE;
> > > >      env->load_res = -1;
> > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > > > index f00c60c840..780d3f9058 100644
> > > > --- a/target/riscv/cpu.h
> > > > +++ b/target/riscv/cpu.h
> > > > @@ -157,12 +157,12 @@ struct CPURISCVState {
> > > >       */
> > > >      uint64_t mstatus;
> > > >
> > > > -    target_ulong mip;
> > > > +    uint64_t mip;
> > >
> > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
> > > all the other existing target_ulong CSRs are the same.
> >
> > When AIA is available the number of local interrupts are 64 for
> > both RV32 and RV64.
>
> Is that going to be reflected in the priv spec?

The AIA spec is going to be separate from priv spec since
it is totally optional.

This AIA local interrupt CSRs will be part of AIA spec and should
only be implemented if a RISC-V implementations wants to use
AIA.

We have four types of changes as far as CSRs go:
1) RV32 CSRs to support 64 local interrupts on RV32
2) Indirect CSRs to access local interrupt priorities
3) Interrupt filtering CSRs
4) IMSIC support CSRs

From above #3 is totally optional and not implemented by this
patch whereas #4 is only required when platform has RISC-V IMSIC.

A platform can skip all four changes mentioned above, if the
platform only wants AIA APLIC to manage wired interrupts.

Regards,
Anup

>
> >
> > The width of CSRs remain same as target_ulong but we have
> > new CSRs for RV32 (such as mipH) for the high-half.
>
> Ah! Sorry I missed that.
>
> This change should be in a seperate patch then.
>
> >
> > Also, this patch changes does not break the case when AIA
> > is not available (or disabled).
>
> Good, we need to make sure we don't.
>
> Alistair
>
> >
> > Regards,
> > Anup
> >
> > >
> > > Alistair
> > >
> > > >
> > > > -    uint32_t miclaim;
> > > > +    uint64_t miclaim;
> > > >
> > > > -    target_ulong mie;
> > > > -    target_ulong mideleg;
> > > > +    uint64_t mie;
> > > > +    uint64_t mideleg;
> > > >
> > > >      target_ulong sptbr;  /* until: priv-1.9.1 */
> > > >      target_ulong satp;   /* since: priv-1.10.0 */
> > > > @@ -179,16 +179,27 @@ struct CPURISCVState {
> > > >      target_ulong mcause;
> > > >      target_ulong mtval;  /* since: priv-1.10.0 */
> > > >
> > > > +    /* AIA CSRs */
> > > > +    target_ulong miselect;
> > > > +    target_ulong siselect;
> > > > +
> > > > +    uint8_t miprio[64];
> > > > +    uint8_t siprio[64];
> > > > +
> > > >      /* Hypervisor CSRs */
> > > >      target_ulong hstatus;
> > > >      target_ulong hedeleg;
> > > > -    target_ulong hideleg;
> > > > +    uint64_t hideleg;
> > > >      target_ulong hcounteren;
> > > >      target_ulong htval;
> > > >      target_ulong htinst;
> > > >      target_ulong hgatp;
> > > >      uint64_t htimedelta;
> > > >
> > > > +    /* AIA HS-mode CSRs */
> > > > +    uint8_t hviprio[64];
> > > > +    target_ulong hvicontrol;
> > > > +
> > > >      /* Virtual CSRs */
> > > >      /*
> > > >       * For RV32 this is 32-bit vsstatus and 32-bit vsstatush.
> > > > @@ -202,6 +213,9 @@ struct CPURISCVState {
> > > >      target_ulong vstval;
> > > >      target_ulong vsatp;
> > > >
> > > > +    /* AIA VS-mode CSRs */
> > > > +    target_ulong vsiselect;
> > > > +
> > > >      target_ulong mtval2;
> > > >      target_ulong mtinst;
> > > >
> > > > @@ -236,6 +250,18 @@ struct CPURISCVState {
> > > >      uint64_t (*rdtime_fn)(uint32_t);
> > > >      uint32_t rdtime_fn_arg;
> > > >
> > > > +    /* machine specific AIA IMSIC read-modify-write callback */
> > > > +#define IMSIC_MAKE_REG(__isel, __priv, __virt, __vgein) \
> > > > +    ((((__vgein) & 0x3f) << 24) | (((__virt) & 0x1) << 20) | \
> > > > +     (((__priv) & 0x3) << 16) | (__isel & 0xffff))
> > > > +#define IMSIC_REG_ISEL(__reg)                  ((__reg) & 0xffff)
> > > > +#define IMSIC_REG_PRIV(__reg)                  (((__reg) >> 16) & 0x3)
> > > > +#define IMSIC_REG_VIRT(__reg)                  (((__reg) >> 20) & 0x1)
> > > > +#define IMSIC_REG_VGEIN(__reg)                 (((__reg) >> 24) & 0x3f)
> > > > +    int (*imsic_rmw_fn)(void *arg, target_ulong reg, target_ulong *val,
> > > > +                        target_ulong new_val, target_ulong write_mask);
> > > > +    void *imsic_rmw_fn_arg;
> > > > +
> > > >      /* True if in debugger mode.  */
> > > >      bool debugger;
> > > >  #endif
> > > > @@ -335,6 +361,11 @@ int riscv_cpu_write_elf32_note(WriteCoreDumpFunction f, CPUState *cs,
> > > >                                 int cpuid, void *opaque);
> > > >  int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
> > > >  int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
> > > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero);
> > > > +uint8_t riscv_cpu_default_priority(int irq);
> > > > +int riscv_cpu_mirq_pending(CPURISCVState *env);
> > > > +int riscv_cpu_sirq_pending(CPURISCVState *env);
> > > > +int riscv_cpu_vsirq_pending(CPURISCVState *env);
> > > >  bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request);
> > > >  bool riscv_cpu_fp_enabled(CPURISCVState *env);
> > > >  bool riscv_cpu_virt_enabled(CPURISCVState *env);
> > > > @@ -364,9 +395,16 @@ void riscv_cpu_list(void);
> > > >
> > > >  #ifndef CONFIG_USER_ONLY
> > > >  void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
> > > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
> > > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
> > > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts);
> > > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value);
> > > >  #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
> > > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > > > +                                int (*rmw_fn)(void *arg,
> > > > +                                              target_ulong reg,
> > > > +                                              target_ulong *val,
> > > > +                                              target_ulong new_val,
> > > > +                                              target_ulong write_mask),
> > > > +                                void *rmw_fn_arg);
> > > >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> > > >                               uint32_t arg);
> > > >  #endif
> > > > diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c
> > > > index 21c54ef561..5b06b4f995 100644
> > > > --- a/target/riscv/cpu_helper.c
> > > > +++ b/target/riscv/cpu_helper.c
> > > > @@ -36,44 +36,219 @@ int riscv_cpu_mmu_index(CPURISCVState *env, bool ifetch)
> > > >  }
> > > >
> > > >  #ifndef CONFIG_USER_ONLY
> > > > -static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > > > +
> > > > +/*
> > > > + * The HS-mode is allowed to configure priority only for the
> > > > + * following VS-mode local interrupts:
> > > > + *
> > > > + * 0  (Reserved interrupt, reads as zero)
> > > > + * 1  Supervisor software interrupt
> > > > + * 4  (Reserved interrupt, reads as zero)
> > > > + * 5  Supervisor timer interrupt
> > > > + * 8  (Reserved interrupt, reads as zero)
> > > > + * 13 (Reserved interrupt)
> > > > + * 14 "
> > > > + * 15 "
> > > > + * 16 "
> > > > + * 18 Debug/trace interrupt
> > > > + * 20 (Reserved interrupt)
> > > > + * 22 ”
> > > > + * 24 ”
> > > > + * 26 ”
> > > > + * 28 "
> > > > + * 30 (Reserved for standard reporting of bus or system errors)
> > > > + */
> > > > +
> > > > +static int hviprio_index2irq[] =
> > > > +    { 0, 1, 4, 5, 8, 13, 14, 15, 16, 18, 20, 22, 24, 26, 28, 30 };
> > > > +static int hviprio_index2rdzero[] =
> > > > +    { 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
> > > > +
> > > > +int riscv_cpu_hviprio_index2irq(int index, int *out_irq, int *out_rdzero)
> > > >  {
> > > > -    target_ulong irqs;
> > > > +    if (index < 0 || ARRAY_SIZE(hviprio_index2irq) <= index) {
> > > > +        return -EINVAL;
> > > > +    }
> > > >
> > > > -    target_ulong mstatus_mie = get_field(env->mstatus, MSTATUS_MIE);
> > > > -    target_ulong mstatus_sie = get_field(env->mstatus, MSTATUS_SIE);
> > > > -    target_ulong hs_mstatus_sie = get_field(env->mstatus_hs, MSTATUS_SIE);
> > > > +    if (out_irq) {
> > > > +        *out_irq = hviprio_index2irq[index];
> > > > +    }
> > > > +
> > > > +    if (out_rdzero) {
> > > > +        *out_rdzero = hviprio_index2rdzero[index];
> > > > +    }
> > > >
> > > > -    target_ulong pending = env->mip & env->mie &
> > > > -                               ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > -    target_ulong vspending = (env->mip & env->mie &
> > > > -                              (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP));
> > > > +    return 0;
> > > > +}
> > > >
> > > > -    target_ulong mie    = env->priv < PRV_M ||
> > > > -                          (env->priv == PRV_M && mstatus_mie);
> > > > -    target_ulong sie    = env->priv < PRV_S ||
> > > > -                          (env->priv == PRV_S && mstatus_sie);
> > > > -    target_ulong hs_sie = env->priv < PRV_S ||
> > > > -                          (env->priv == PRV_S && hs_mstatus_sie);
> > > > +uint8_t riscv_cpu_default_priority(int irq)
> > > > +{
> > > > +    int u, l;
> > > > +    uint8_t iprio = IPRIO_MMAXIPRIO;
> > > >
> > > > -    if (riscv_cpu_virt_enabled(env)) {
> > > > -        target_ulong pending_hs_irq = pending & -hs_sie;
> > > > +    if (irq < 0 || irq > 63) {
> > > > +        return iprio;
> > > > +    }
> > > >
> > > > -        if (pending_hs_irq) {
> > > > -            riscv_cpu_set_force_hs_excep(env, FORCE_HS_EXCEP);
> > > > -            return ctz64(pending_hs_irq);
> > > > +    /*
> > > > +     * Default priorities of local interrupts are defined in the
> > > > +     * RISC-V Advanced Interrupt Architecture specification.
> > > > +     *
> > > > +     * ----------------------------------------------------------------
> > > > +     *  Default  |
> > > > +     *  Priority | Major Interrupt Numbers
> > > > +     * ----------------------------------------------------------------
> > > > +     *  Highest  | 63 (3f), 62 (3e), 31 (1f), 30 (1e), 61 (3d), 60 (3c),
> > > > +     *           | 59 (3b), 58 (3a), 29 (1d), 28 (1c), 57 (39), 56 (38),
> > > > +     *           | 55 (37), 54 (36), 27 (1b), 26 (1a), 53 (35), 52 (34),
> > > > +     *           | 51 (33), 50 (32), 25 (19), 24 (18), 49 (31), 48 (30)
> > > > +     *           |
> > > > +     *           | 11 (0b),  3 (03),  7 (07)
> > > > +     *           |  9 (09),  1 (01),  5 (05)
> > > > +     *           | 12 (0c)
> > > > +     *           | 10 (0a),  2 (02),  6 (06)
> > > > +     *           |
> > > > +     *           | 47 (2f), 46 (2e), 23 (17), 22 (16), 45 (2d), 44 (2c),
> > > > +     *           | 43 (2b), 42 (2a), 21 (15), 20 (14), 41 (29), 40 (28),
> > > > +     *           | 39 (27), 38 (26), 19 (13), 18 (12), 37 (25), 36 (24),
> > > > +     *  Lowest   | 35 (23), 34 (22), 17 (11), 16 (10), 33 (21), 32 (20)
> > > > +     * ----------------------------------------------------------------
> > > > +     */
> > > > +
> > > > +    u = IPRIO_DEFAULT_U(irq);
> > > > +    l = IPRIO_DEFAULT_L(irq);
> > > > +    if (u == 0) {
> > > > +        if (irq == IRQ_VS_EXT || irq == IRQ_VS_TIMER ||
> > > > +            irq == IRQ_VS_SOFT) {
> > > > +            iprio = IPRIO_DEFAULT_VS;
> > > > +        } else if (irq == IRQ_S_GEXT) {
> > > > +            iprio = IPRIO_DEFAULT_SGEXT;
> > > > +        } else if (irq == IRQ_S_EXT || irq == IRQ_S_TIMER ||
> > > > +                   irq == IRQ_S_SOFT) {
> > > > +            iprio = IPRIO_DEFAULT_S;
> > > > +        } else if (irq == IRQ_M_EXT || irq == IRQ_M_TIMER ||
> > > > +                   irq == IRQ_M_SOFT) {
> > > > +            iprio = IPRIO_DEFAULT_M;
> > > > +        } else {
> > > > +            iprio = IPRIO_DEFAULT_VS;
> > > >          }
> > > > +    } else if (u == 1) {
> > > > +        if (l < 8) {
> > > > +            iprio = IPRIO_DEFAULT_16_23(irq);
> > > > +        } else {
> > > > +            iprio = IPRIO_DEFAULT_24_31(irq);
> > > > +        }
> > > > +    } else if (u == 2) {
> > > > +        iprio = IPRIO_DEFAULT_32_47(irq);
> > > > +    } else if (u == 3) {
> > > > +        iprio = IPRIO_DEFAULT_48_63(irq);
> > > > +    }
> > > > +
> > > > +    return iprio;
> > > > +}
> > > > +
> > > > +static int riscv_cpu_pending_to_irq(CPURISCVState *env,
> > > > +                                    uint64_t pending, uint8_t *iprio)
> > > > +{
> > > > +    int irq, best_irq = EXCP_NONE;
> > > > +    unsigned int prio, best_prio = UINT_MAX;
> > > >
> > > > -        pending = vspending;
> > > > +    if (!pending) {
> > > > +        return EXCP_NONE;
> > > >      }
> > > >
> > > > -    irqs = (pending & ~env->mideleg & -mie) | (pending &  env->mideleg & -sie);
> > > > +    irq = ctz64(pending);
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return irq;
> > > > +    }
> > > >
> > > > -    if (irqs) {
> > > > -        return ctz64(irqs); /* since non-zero */
> > > > +    pending = pending >> irq;
> > > > +    while (pending) {
> > > > +        prio = iprio[irq];
> > > > +        if (!prio) {
> > > > +            prio = (riscv_cpu_default_priority(irq) < IPRIO_DEFAULT_M) ?
> > > > +                   1 : IPRIO_MMAXIPRIO;
> > > > +        }
> > > > +        if ((pending & 0x1) && (prio < best_prio)) {
> > > > +            best_irq = irq;
> > > > +            best_prio = prio;
> > > > +        }
> > > > +        irq++;
> > > > +        pending = pending >> 1;
> > > > +    }
> > > > +
> > > > +    return best_irq;
> > > > +}
> > > > +
> > > > +int riscv_cpu_mirq_pending(CPURISCVState *env)
> > > > +{
> > > > +    uint64_t irqs = env->mip & env->mie & ~env->mideleg &
> > > > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > +
> > > > +    return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > > > +}
> > > > +
> > > > +int riscv_cpu_sirq_pending(CPURISCVState *env)
> > > > +{
> > > > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > > > +                    ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > +
> > > > +    return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > > > +}
> > > > +
> > > > +int riscv_cpu_vsirq_pending(CPURISCVState *env)
> > > > +{
> > > > +    uint64_t irqs = env->mip & env->mie & env->mideleg &
> > > > +                    (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > +
> > > > +    return riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > > > +}
> > > > +
> > > > +static int riscv_cpu_local_irq_pending(CPURISCVState *env)
> > > > +{
> > > > +    int virq;
> > > > +    uint64_t irqs, mie, sie, vsie;
> > > > +    uint64_t pending, vspending;
> > > > +
> > > > +    /* Determine interrupt enable state of all privilege modes */
> > > > +    if (riscv_cpu_virt_enabled(env)) {
> > > > +        mie = 1;
> > > > +        sie = 1;
> > > > +        vsie = (env->priv < PRV_S) ||
> > > > +               (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> > > >      } else {
> > > > -        return EXCP_NONE; /* indicates no pending interrupt */
> > > > +        mie = (env->priv < PRV_M) ||
> > > > +              (env->priv == PRV_M && get_field(env->mstatus, MSTATUS_MIE));
> > > > +        sie = (env->priv < PRV_S) ||
> > > > +              (env->priv == PRV_S && get_field(env->mstatus, MSTATUS_SIE));
> > > > +        vsie = 0;
> > > > +    }
> > > > +
> > > > +    /* Check M-mode interrupts */
> > > > +    pending = env->mip & env->mie &
> > > > +              ~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > +    irqs = pending & ~env->mideleg & -mie;
> > > > +    if (irqs) {
> > > > +        return riscv_cpu_pending_to_irq(env, irqs, env->miprio);
> > > > +    }
> > > > +
> > > > +    /* Check HS-mode interrupts */
> > > > +    irqs = pending & env->mideleg & -sie;
> > > > +    if (irqs) {
> > > > +        return riscv_cpu_pending_to_irq(env, irqs, env->siprio);
> > > > +    }
> > > > +
> > > > +    /* Check VS-mode interrupts */
> > > > +    vspending = env->mip & env->mie &
> > > > +                (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
> > > > +    irqs = vspending & env->hideleg & -vsie;
> > > > +    if (irqs) {
> > > > +        virq = riscv_cpu_pending_to_irq(env, irqs >> 1, env->hviprio);
> > > > +        return (virq <= 0) ? virq : virq + 1;
> > > >      }
> > > > +
> > > > +    /* Indicates no pending interrupt */
> > > > +    return EXCP_NONE;
> > > >  }
> > > >  #endif
> > > >
> > > > @@ -213,7 +388,7 @@ bool riscv_cpu_two_stage_lookup(int mmu_idx)
> > > >      return mmu_idx & TB_FLAGS_PRIV_HYP_ACCESS_MASK;
> > > >  }
> > > >
> > > > -int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> > > > +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
> > > >  {
> > > >      CPURISCVState *env = &cpu->env;
> > > >      if (env->miclaim & interrupts) {
> > > > @@ -224,11 +399,11 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts)
> > > >      }
> > > >  }
> > > >
> > > > -uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> > > > +uint64_t riscv_cpu_update_mip(RISCVCPU *cpu, uint64_t mask, uint64_t value)
> > > >  {
> > > >      CPURISCVState *env = &cpu->env;
> > > >      CPUState *cs = CPU(cpu);
> > > > -    uint32_t old = env->mip;
> > > > +    uint64_t old = env->mip;
> > > >      bool locked = false;
> > > >
> > > >      if (!qemu_mutex_iothread_locked()) {
> > > > @@ -251,6 +426,18 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
> > > >      return old;
> > > >  }
> > > >
> > > > +void riscv_cpu_set_imsic_rmw_fn(CPURISCVState *env,
> > > > +                                int (*rmw_fn)(void *arg,
> > > > +                                              target_ulong reg,
> > > > +                                              target_ulong *val,
> > > > +                                              target_ulong new_val,
> > > > +                                              target_ulong write_mask),
> > > > +                                void *rmw_fn_arg)
> > > > +{
> > > > +    env->imsic_rmw_fn = rmw_fn;
> > > > +    env->imsic_rmw_fn_arg = rmw_fn_arg;
> > > > +}
> > > > +
> > > >  void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
> > > >                               uint32_t arg)
> > > >  {
> > > > @@ -904,7 +1091,7 @@ void riscv_cpu_do_interrupt(CPUState *cs)
> > > >       */
> > > >      bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
> > > >      target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
> > > > -    target_ulong deleg = async ? env->mideleg : env->medeleg;
> > > > +    uint64_t deleg = async ? env->mideleg : env->medeleg;
> > > >      bool write_tval = false;
> > > >      target_ulong tval = 0;
> > > >      target_ulong htval = 0;
> > > > diff --git a/target/riscv/csr.c b/target/riscv/csr.c
> > > > index d2585395bf..3c016d7452 100644
> > > > --- a/target/riscv/csr.c
> > > > +++ b/target/riscv/csr.c
> > > > @@ -153,11 +153,56 @@ static int any32(CPURISCVState *env, int csrno)
> > > >
> > > >  }
> > > >
> > > > +static int aia_any(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return any(env, csrno);
> > > > +}
> > > > +
> > > > +static int aia_any32(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return any32(env, csrno);
> > > > +}
> > > > +
> > > >  static int smode(CPURISCVState *env, int csrno)
> > > >  {
> > > >      return -!riscv_has_ext(env, RVS);
> > > >  }
> > > >
> > > > +static int smode32(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_cpu_is_32bit(env)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return smode(env, csrno);
> > > > +}
> > > > +
> > > > +static int aia_smode(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return smode(env, csrno);
> > > > +}
> > > > +
> > > > +static int aia_smode32(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return smode32(env, csrno);
> > > > +}
> > > > +
> > > >  static int hmode(CPURISCVState *env, int csrno)
> > > >  {
> > > >      if (riscv_has_ext(env, RVS) &&
> > > > @@ -177,11 +222,28 @@ static int hmode(CPURISCVState *env, int csrno)
> > > >  static int hmode32(CPURISCVState *env, int csrno)
> > > >  {
> > > >      if (!riscv_cpu_is_32bit(env)) {
> > > > -        return 0;
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return hmode(env, csrno);
> > > > +}
> > > > +
> > > > +static int aia_hmode(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > >      }
> > > >
> > > >      return hmode(env, csrno);
> > > > +}
> > > >
> > > > +static int aia_hmode32(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_feature(env, RISCV_FEATURE_AIA)) {
> > > > +        return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    return hmode32(env, csrno);
> > > >  }
> > > >
> > > >  static int pmp(CPURISCVState *env, int csrno)
> > > > @@ -388,14 +450,16 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
> > > >
> > > >  /* Machine constants */
> > > >
> > > > -#define M_MODE_INTERRUPTS  (MIP_MSIP | MIP_MTIP | MIP_MEIP)
> > > > -#define S_MODE_INTERRUPTS  (MIP_SSIP | MIP_STIP | MIP_SEIP)
> > > > -#define VS_MODE_INTERRUPTS (MIP_VSSIP | MIP_VSTIP | MIP_VSEIP)
> > > > +#define M_MODE_INTERRUPTS  ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
> > > > +#define S_MODE_INTERRUPTS  ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
> > > > +#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
> > > > +
> > > > +#define TLOWBITS64         ((uint64_t)((target_ulong)-1))
> > > >
> > > > -static const target_ulong delegable_ints = S_MODE_INTERRUPTS |
> > > > -                                           VS_MODE_INTERRUPTS;
> > > > -static const target_ulong all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > > > -                                     VS_MODE_INTERRUPTS;
> > > > +static const uint64_t delegable_ints = S_MODE_INTERRUPTS |
> > > > +                                       VS_MODE_INTERRUPTS;
> > > > +static const uint64_t all_ints = M_MODE_INTERRUPTS | S_MODE_INTERRUPTS |
> > > > +                                 VS_MODE_INTERRUPTS;
> > > >  static const target_ulong delegable_excps =
> > > >      (1ULL << (RISCV_EXCP_INST_ADDR_MIS)) |
> > > >      (1ULL << (RISCV_EXCP_INST_ACCESS_FAULT)) |
> > > > @@ -419,10 +483,10 @@ static const target_ulong delegable_excps =
> > > >  static const target_ulong sstatus_v1_10_mask = SSTATUS_SIE | SSTATUS_SPIE |
> > > >      SSTATUS_UIE | SSTATUS_UPIE | SSTATUS_SPP | SSTATUS_FS | SSTATUS_XS |
> > > >      SSTATUS_SUM | SSTATUS_MXR | SSTATUS_SD;
> > > > -static const target_ulong sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > > > -static const target_ulong hip_writable_mask = MIP_VSSIP;
> > > > -static const target_ulong hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > > > -static const target_ulong vsip_writable_mask = MIP_VSSIP;
> > > > +static const uint64_t sip_writable_mask = SIP_SSIP | MIP_USIP | MIP_UEIP;
> > > > +static const uint64_t hip_writable_mask = MIP_VSSIP;
> > > > +static const uint64_t hvip_writable_mask = MIP_VSSIP | MIP_VSTIP | MIP_VSEIP;
> > > > +static const uint64_t vsip_writable_mask = MIP_VSSIP;
> > > >
> > > >  static const char valid_vm_1_10_32[16] = {
> > > >      [VM_1_10_MBARE] = 1,
> > > > @@ -596,7 +660,437 @@ static int read_mideleg(CPURISCVState *env, int csrno, target_ulong *val)
> > > >
> > > >  static int write_mideleg(CPURISCVState *env, int csrno, target_ulong val)
> > > >  {
> > > > -    env->mideleg = (env->mideleg & ~delegable_ints) | (val & delegable_ints);
> > > > +    uint64_t mask = delegable_ints & TLOWBITS64;
> > > > +
> > > > +    env->mideleg = (env->mideleg & ~mask) | (val & mask);
> > > > +    if (riscv_has_ext(env, RVH)) {
> > > > +        env->mideleg |= VS_MODE_INTERRUPTS;
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int aia_xlate_vs_csrno(CPURISCVState *env, int csrno)
> > > > +{
> > > > +    if (!riscv_cpu_virt_enabled(env)) {
> > > > +        return csrno;
> > > > +    }
> > > > +
> > > > +    switch (csrno) {
> > > > +    case CSR_SISELECT:
> > > > +        return CSR_VSISELECT;
> > > > +    case CSR_SIREG:
> > > > +        return CSR_VSIREG;
> > > > +    case CSR_STOPI:
> > > > +        return CSR_VSTOPI;
> > > > +    case CSR_SSETEIPNUM:
> > > > +        return CSR_VSSETEIPNUM;
> > > > +    case CSR_SCLREIPNUM:
> > > > +        return CSR_VSCLREIPNUM;
> > > > +    case CSR_SSETEIENUM:
> > > > +        return CSR_VSSETEIENUM;
> > > > +    case CSR_SCLREIENUM:
> > > > +        return CSR_VSCLREIENUM;
> > > > +    default:
> > > > +        return csrno;
> > > > +    };
> > > > +}
> > > > +
> > > > +static int rmw_xiselect(CPURISCVState *env, int csrno, target_ulong *val,
> > > > +                        target_ulong new_val, target_ulong write_mask)
> > > > +{
> > > > +    target_ulong *iselect;
> > > > +
> > > > +    switch (csrno) {
> > > > +    case CSR_MISELECT:
> > > > +        iselect = &env->miselect;
> > > > +        break;
> > > > +    case CSR_SISELECT:
> > > > +        iselect = riscv_cpu_virt_enabled(env) ?
> > > > +                  &env->vsiselect : &env->siselect;
> > > > +        break;
> > > > +    case CSR_VSISELECT:
> > > > +        iselect = &env->vsiselect;
> > > > +        break;
> > > > +    default:
> > > > +         return -RISCV_EXCP_ILLEGAL_INST;
> > > > +    };
> > > > +
> > > > +    if (val) {
> > > > +        *val = *iselect;
> > > > +    }
> > > > +
> > > > +    if (write_mask) {
> > > > +        *iselect = (*iselect & ~write_mask) | (new_val & write_mask);
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int rmw_iprio(target_ulong iselect, uint8_t *iprio,
> > > > +                     target_ulong *val, target_ulong new_val,
> > > > +                     target_ulong write_mask)
> > > > +{
> > > > +    int i, firq, nirqs;
> > > > +    target_ulong old_val;
> > > > +
> > > > +    if (iselect < ISELECT_IPRIO0 || ISELECT_IPRIO15 < iselect) {
> > > > +        return -EINVAL;
> > > > +    }
> > > > +#if TARGET_LONG_BITS == 64
> > > > +    if (iselect & 0x1) {
> > > > +        return -EINVAL;
> > > > +    }
> > > > +#endif
> > > > +
> > > > +    nirqs = 4 * (TARGET_LONG_BITS / 32);
> > > > +    firq = ((iselect - ISELECT_IPRIO0) / (TARGET_LONG_BITS / 32)) * (nirqs);
> > > > +
> > > > +    old_val = 0;
> > > > +    for (i = 0; i < nirqs; i++) {
> > > > +        old_val |= ((target_ulong)iprio[firq + i]) << (IPRIO_IRQ_BITS * i);
> > > > +    }
> > > > +
> > > > +    if (val) {
> > > > +        *val = old_val;
> > > > +    }
> > > > +
> > > > +    if (write_mask) {
> > > > +        new_val = (old_val & ~write_mask) | (new_val & write_mask);
> > > > +        for (i = 0; i < nirqs; i++) {
> > > > +            iprio[firq + i] = (new_val >> (IPRIO_IRQ_BITS * i)) & 0xff;
> > > > +        }
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int rmw_xireg(CPURISCVState *env, int csrno, target_ulong *val,
> > > > +                     target_ulong new_val, target_ulong write_mask)
> > > > +{
> > > > +    bool virt;
> > > > +    uint8_t *iprio;
> > > > +    int ret = -EINVAL;
> > > > +    target_ulong priv, isel, vgein;
> > > > +
> > > > +    /* Translate CSR number for VS-mode */
> > > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > > +
> > > > +    /* Decode register details from CSR number */
> > > > +    virt = false;
> > > > +    switch (csrno) {
> > > > +    case CSR_MIREG:
> > > > +        iprio = env->miprio;
> > > > +        isel = env->miselect;
> > > > +        priv = PRV_M;
> > > > +        break;
> > > > +    case CSR_SIREG:
> > > > +        iprio = env->siprio;
> > > > +        isel = env->siselect;
> > > > +        priv = PRV_S;
> > > > +        break;
> > > > +    case CSR_VSIREG:
> > > > +        iprio = env->hviprio;
> > > > +        isel = env->vsiselect;
> > > > +        priv = PRV_S;
> > > > +        virt = true;
> > > > +        break;
> > > > +    default:
> > > > +         goto done;
> > > > +    };
> > > > +
> > > > +    /* Find the selected guest interrupt file */
> > > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > > +
> > > > +    if (ISELECT_IPRIO0 <= isel && isel <= ISELECT_IPRIO15) {
> > > > +        /* Local interrupt priority registers not available for VS-mode */
> > > > +        if (!virt) {
> > > > +            ret = rmw_iprio(isel, iprio, val, new_val, write_mask);
> > > > +        }
> > > > +    } else if (ISELECT_IMSIC_FIRST <= isel && isel <= ISELECT_IMSIC_LAST) {
> > > > +        /* IMSIC registers only available when machine implements it. */
> > > > +        if (env->imsic_rmw_fn) {
> > > > +            /* Selected guest interrupt file should not be zero */
> > > > +            if (virt && !vgein) {
> > > > +                goto done;
> > > > +            }
> > > > +            /* Call machine specific IMSIC register emulation */
> > > > +            ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > > +                                    IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > > +                                    val, new_val, write_mask);
> > > > +        }
> > > > +    }
> > > > +
> > > > +done:
> > > > +    if (ret) {
> > > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_mtopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    int irq;
> > > > +
> > > > +    irq = riscv_cpu_mirq_pending(env);
> > > > +    if (irq <= 0 || irq > 63) {
> > > > +       *val = 0;
> > > > +    } else {
> > > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > > +       *val |= env->miprio[irq];
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_xsetclreinum(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    bool virt;
> > > > +    int ret = -EINVAL;
> > > > +    target_ulong vgein;
> > > > +
> > > > +    /* Translate CSR number for VS-mode */
> > > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > > +
> > > > +    /* Decode register details from CSR number */
> > > > +    virt = false;
> > > > +    switch (csrno) {
> > > > +    case CSR_MSETEIPNUM:
> > > > +    case CSR_MCLREIPNUM:
> > > > +    case CSR_MSETEIENUM:
> > > > +    case CSR_MCLREIENUM:
> > > > +    case CSR_SSETEIPNUM:
> > > > +    case CSR_SCLREIPNUM:
> > > > +    case CSR_SSETEIENUM:
> > > > +    case CSR_SCLREIENUM:
> > > > +        break;
> > > > +    case CSR_VSSETEIPNUM:
> > > > +    case CSR_VSCLREIPNUM:
> > > > +    case CSR_VSSETEIENUM:
> > > > +    case CSR_VSCLREIENUM:
> > > > +        virt = true;
> > > > +        break;
> > > > +    default:
> > > > +         goto done;
> > > > +    };
> > > > +
> > > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > > +    if (!env->imsic_rmw_fn) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Find the selected guest interrupt file */
> > > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > > +
> > > > +    /* Selected guest interrupt file should not be zero */
> > > > +    if (virt && !vgein) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Set/Clear CSRs always read zero */
> > > > +    ret = 0;
> > > > +    if (val) {
> > > > +        *val = 0;
> > > > +    }
> > > > +
> > > > +done:
> > > > +    if (ret) {
> > > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_xsetclreinum(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    int ret = -EINVAL;
> > > > +    bool set, pend, virt;
> > > > +    target_ulong priv, isel, vgein;
> > > > +    target_ulong new_val, write_mask;
> > > > +
> > > > +    /* Translate CSR number for VS-mode */
> > > > +    csrno = aia_xlate_vs_csrno(env, csrno);
> > > > +
> > > > +    /* Decode register details from CSR number */
> > > > +    virt = set = pend = false;
> > > > +    switch (csrno) {
> > > > +    case CSR_MSETEIPNUM:
> > > > +        priv = PRV_M;
> > > > +        set = true;
> > > > +        break;
> > > > +    case CSR_MCLREIPNUM:
> > > > +        priv = PRV_M;
> > > > +        pend = true;
> > > > +        break;
> > > > +    case CSR_MSETEIENUM:
> > > > +        priv = PRV_M;
> > > > +        set = true;
> > > > +        break;
> > > > +    case CSR_MCLREIENUM:
> > > > +        priv = PRV_M;
> > > > +        break;
> > > > +    case CSR_SSETEIPNUM:
> > > > +        priv = PRV_S;
> > > > +        set = true;
> > > > +        pend = true;
> > > > +        break;
> > > > +    case CSR_SCLREIPNUM:
> > > > +        priv = PRV_S;
> > > > +        pend = true;
> > > > +        break;
> > > > +    case CSR_SSETEIENUM:
> > > > +        priv = PRV_S;
> > > > +        set = true;
> > > > +        break;
> > > > +    case CSR_SCLREIENUM:
> > > > +        priv = PRV_S;
> > > > +        break;
> > > > +    case CSR_VSSETEIPNUM:
> > > > +        priv = PRV_S;
> > > > +        virt = true;
> > > > +        set = true;
> > > > +        pend = true;
> > > > +        break;
> > > > +    case CSR_VSCLREIPNUM:
> > > > +        priv = PRV_S;
> > > > +        virt = true;
> > > > +        pend = true;
> > > > +        break;
> > > > +    case CSR_VSSETEIENUM:
> > > > +        priv = PRV_S;
> > > > +        virt = true;
> > > > +        set = true;
> > > > +        break;
> > > > +    case CSR_VSCLREIENUM:
> > > > +        priv = PRV_S;
> > > > +        virt = true;
> > > > +        break;
> > > > +    default:
> > > > +         goto done;
> > > > +    };
> > > > +
> > > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > > +    if (!env->imsic_rmw_fn) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Find target interrupt pending/enable register */
> > > > +    if (pend) {
> > > > +        isel = ISELECT_IMSIC_EIP0;
> > > > +    } else {
> > > > +        isel = ISELECT_IMSIC_EIE0;
> > > > +    }
> > > > +    isel += val / IMSIC_EIPx_BITS;
> > > > +
> > > > +    /* Find the interrupt bit to be set/clear */
> > > > +    write_mask = 1 << (val % IMSIC_EIPx_BITS);
> > > > +    new_val = (set) ? write_mask : 0;
> > > > +
> > > > +    /* Find the selected guest interrupt file */
> > > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > > +
> > > > +    /* Selected guest interrupt file should not be zero */
> > > > +    if (virt && !vgein) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Call machine specific IMSIC register emulation */
> > > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > > +                            NULL, new_val, write_mask);
> > > > +
> > > > +done:
> > > > +    if (ret) {
> > > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_xclaimei(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    bool virt;
> > > > +    int ret = -EINVAL;
> > > > +    target_ulong priv, isel, vgein;
> > > > +    target_ulong topei, write_mask;
> > > > +
> > > > +    /* Decode register details from CSR number */
> > > > +    virt = false;
> > > > +    switch (csrno) {
> > > > +    case CSR_MCLAIMEI:
> > > > +        priv = PRV_M;
> > > > +        break;
> > > > +    case CSR_SCLAIMEI:
> > > > +        priv = PRV_S;
> > > > +        virt = riscv_cpu_virt_enabled(env);
> > > > +        break;
> > > > +    default:
> > > > +        goto done;
> > > > +    };
> > > > +
> > > > +    /* IMSIC CSRs only available when machine implements IMSIC. */
> > > > +    if (!env->imsic_rmw_fn) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Find the selected guest interrupt file */
> > > > +    vgein = (virt) ? (env->hstatus & HSTATUS_VGEIN) >> HSTATUS_VGEIN_SHIFT : 0;
> > > > +
> > > > +    /* Selected guest interrupt file should not be zero */
> > > > +    if (virt && !vgein) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Call machine specific IMSIC register emulation for reading TOPEI */
> > > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > > +                            IMSIC_MAKE_REG(ISELECT_IMSIC_TOPEI, priv, virt, vgein),
> > > > +                            &topei, -1, 0);
> > > > +    if (ret) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* If no interrupt pending then we are done */
> > > > +    if (!topei) {
> > > > +        goto done;
> > > > +    }
> > > > +
> > > > +    /* Find target interrupt pending register */
> > > > +    isel = ISELECT_IMSIC_EIP0;
> > > > +    isel += ((topei >> TOPI_IID_SHIFT) / IMSIC_EIPx_BITS);
> > > > +
> > > > +    /* Find the interrupt bit to be cleared */
> > > > +    write_mask = 1 << ((topei >> TOPI_IID_SHIFT) % IMSIC_EIPx_BITS);
> > > > +
> > > > +    /* Call machine specific IMSIC register emulation to clear pending bit */
> > > > +    ret = env->imsic_rmw_fn(env->imsic_rmw_fn_arg,
> > > > +                            IMSIC_MAKE_REG(isel, priv, virt, vgein),
> > > > +                            NULL, 0, write_mask);
> > > > +
> > > > +    /* Update return value */
> > > > +    if (val) {
> > > > +        *val = topei;
> > > > +    }
> > > > +
> > > > +done:
> > > > +    if (ret) {
> > > > +        return (riscv_cpu_virt_enabled(env) && virt) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_midelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    *val = (env->mideleg >> 32);
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_midelegh(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    uint64_t mask = delegable_ints & ~TLOWBITS64;
> > > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > > +
> > > > +    env->mideleg = (env->mideleg & ~mask) | (newval & mask);
> > > >      if (riscv_has_ext(env, RVH)) {
> > > >          env->mideleg |= VS_MODE_INTERRUPTS;
> > > >      }
> > > > @@ -611,7 +1105,24 @@ static int read_mie(CPURISCVState *env, int csrno, target_ulong *val)
> > > >
> > > >  static int write_mie(CPURISCVState *env, int csrno, target_ulong val)
> > > >  {
> > > > -    env->mie = (env->mie & ~all_ints) | (val & all_ints);
> > > > +    uint64_t mask = all_ints & TLOWBITS64;
> > > > +
> > > > +    env->mie = (env->mie & ~mask) | (val & mask);
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_mieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    *val = (env->mie >> 32);
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_mieh(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    uint64_t mask = all_ints & ~TLOWBITS64;
> > > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > > +
> > > > +    env->mie = (env->mie & ~mask) | (newval & mask);
> > > >      return 0;
> > > >  }
> > > >
> > > > @@ -718,8 +1229,9 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >  {
> > > >      RISCVCPU *cpu = env_archcpu(env);
> > > >      /* Allow software control of delegable interrupts not claimed by hardware */
> > > > -    target_ulong mask = write_mask & delegable_ints & ~env->miclaim;
> > > > -    uint32_t old_mip;
> > > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > > +                    ~env->miclaim & TLOWBITS64;
> > > > +    uint64_t old_mip;
> > > >
> > > >      if (mask) {
> > > >          old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > > @@ -734,6 +1246,29 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >      return 0;
> > > >  }
> > > >
> > > > +static int rmw_miph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > > +                    target_ulong new_value, target_ulong write_mask)
> > > > +{
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > > +                    ~env->miclaim & ~TLOWBITS64;
> > > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > > +
> > > > +    if (ret_value) {
> > > > +        *ret_value = old_mip >> 32;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > >  /* Supervisor Trap Setup */
> > > >  static int read_sstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > > >  {
> > > > @@ -751,39 +1286,103 @@ static int write_sstatus(CPURISCVState *env, int csrno, target_ulong val)
> > > >
> > > >  static int read_vsie(CPURISCVState *env, int csrno, target_ulong *val)
> > > >  {
> > > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & TLOWBITS64;
> > > > +
> > > >      /* Shift the VS bits to their S bit location in vsie */
> > > > -    *val = (env->mie & env->hideleg & VS_MODE_INTERRUPTS) >> 1;
> > > > +    *val = (env->mie & mask) >> 1;
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_vsieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg & ~TLOWBITS64;
> > > > +
> > > > +    /* Shift the VS bits to their S bit location in vsieh */
> > > > +    *val = (env->mie & mask) >> (32 + 1);
> > > >      return 0;
> > > >  }
> > > >
> > > >  static int read_sie(CPURISCVState *env, int csrno, target_ulong *val)
> > > >  {
> > > >      if (riscv_cpu_virt_enabled(env)) {
> > > > -        read_vsie(env, CSR_VSIE, val);
> > > > -    } else {
> > > > -        *val = env->mie & env->mideleg;
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return read_vsie(env, CSR_VSIE, val);
> > > >      }
> > > > +
> > > > +    *val = env->mie & env->mideleg;
> > > >      return 0;
> > > >  }
> > > >
> > > >  static int write_vsie(CPURISCVState *env, int csrno, target_ulong val)
> > > >  {
> > > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > > > +                    all_ints & TLOWBITS64;
> > > > +
> > > >      /* Shift the S bits to their VS bit location in mie */
> > > > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) |
> > > > -                          ((val << 1) & env->hideleg & VS_MODE_INTERRUPTS);
> > > > -    return write_mie(env, CSR_MIE, newval);
> > > > +    env->mie = (env->mie & ~mask) | ((val << 1) & mask);
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_vsieh(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    uint64_t mask = VS_MODE_INTERRUPTS & env->hideleg &
> > > > +                    all_ints & ~TLOWBITS64;
> > > > +    uint64_t newval = (uint64_t)val << 32;
> > > > +
> > > > +    /* Shift the S bits to their VS bit location in mie */
> > > > +    env->mie = (env->mie & ~mask) | ((newval << 1) & mask);
> > > > +
> > > > +    return 0;
> > > >  }
> > > >
> > > >  static int write_sie(CPURISCVState *env, int csrno, target_ulong val)
> > > >  {
> > > > +    uint64_t mask;
> > > > +
> > > >      if (riscv_cpu_virt_enabled(env)) {
> > > > -        write_vsie(env, CSR_VSIE, val);
> > > > -    } else {
> > > > -        target_ulong newval = (env->mie & ~S_MODE_INTERRUPTS) |
> > > > -                              (val & S_MODE_INTERRUPTS);
> > > > -        write_mie(env, CSR_MIE, newval);
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return write_vsie(env, CSR_VSIE, val);
> > > > +    }
> > > > +
> > > > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & TLOWBITS64;
> > > > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_sieh(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    if (riscv_cpu_virt_enabled(env)) {
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return read_vsieh(env, CSR_VSIEH, val);
> > > > +    }
> > > > +
> > > > +    *val = ((env->mie & env->mideleg) >> 32);
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_sieh(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    uint64_t mask, newval;
> > > > +
> > > > +    if (riscv_cpu_virt_enabled(env)) {
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return write_vsieh(env, CSR_VSIEH, val);
> > > >      }
> > > >
> > > > +    mask = S_MODE_INTERRUPTS & env->mideleg & all_ints & ~TLOWBITS64;
> > > > +    newval = (uint64_t)val << 32;
> > > > +
> > > > +    env->mie = (env->mie & ~mask) | (newval & mask);
> > > >      return 0;
> > > >  }
> > > >
> > > > @@ -868,29 +1467,110 @@ static int write_sbadaddr(CPURISCVState *env, int csrno, target_ulong val)
> > > >  static int rmw_vsip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >                      target_ulong new_value, target_ulong write_mask)
> > > >  {
> > > > -    /* Shift the S bits to their VS bit location in mip */
> > > > -    int ret = rmw_mip(env, 0, ret_value, new_value << 1,
> > > > -                      (write_mask << 1) & vsip_writable_mask & env->hideleg);
> > > > -    *ret_value &= VS_MODE_INTERRUPTS;
> > > > -    /* Shift the VS bits to their S bit location in vsip */
> > > > -    *ret_value >>= 1;
> > > > -    return ret;
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask << 1) & delegable_ints &
> > > > +                    vsip_writable_mask & env->hideleg &
> > > > +                    ~env->miclaim & TLOWBITS64;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > > +
> > > > +    if (ret_value) {
> > > > +        *ret_value = old_mip & VS_MODE_INTERRUPTS;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int rmw_vsiph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > > +                     target_ulong new_value, target_ulong write_mask)
> > > > +{
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask << (32 + 1)) & delegable_ints &
> > > > +                    vsip_writable_mask & env->hideleg &
> > > > +                    ~env->miclaim & ~TLOWBITS64;
> > > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > > +
> > > > +    if (ret_value) {
> > > > +        *ret_value = (old_mip & VS_MODE_INTERRUPTS) >> 32;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > >  }
> > > >
> > > >  static int rmw_sip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >                     target_ulong new_value, target_ulong write_mask)
> > > >  {
> > > > -    int ret;
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    uint64_t mask, old_mip;
> > > >
> > > >      if (riscv_cpu_virt_enabled(env)) {
> > > > -        ret = rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return rmw_vsip(env, CSR_VSIP, ret_value, new_value, write_mask);
> > > > +    }
> > > > +
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    mask = ((uint64_t)write_mask) & delegable_ints &
> > > > +           env->mideleg & sip_writable_mask &
> > > > +           ~env->miclaim & TLOWBITS64;
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > >      } else {
> > > > -        ret = rmw_mip(env, CSR_MSTATUS, ret_value, new_value,
> > > > -                      write_mask & env->mideleg & sip_writable_mask);
> > > > +        old_mip = env->mip;
> > > >      }
> > > >
> > > > -    *ret_value &= env->mideleg;
> > > > -    return ret;
> > > > +    if (ret_value) {
> > > > +        *ret_value = old_mip;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int rmw_siph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > > +                    target_ulong new_value, target_ulong write_mask)
> > > > +{
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    uint64_t mask, new_value64;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (riscv_cpu_virt_enabled(env)) {
> > > > +        if (env->hvicontrol & HVICONTROL_VTI) {
> > > > +            return -RISCV_EXCP_VIRT_INSTRUCTION_FAULT;
> > > > +        }
> > > > +        return rmw_vsiph(env, CSR_VSIPH, ret_value, new_value, write_mask);
> > > > +    }
> > > > +
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > > +           env->mideleg & sip_writable_mask &
> > > > +           ~env->miclaim & ~TLOWBITS64;
> > > > +    new_value64 = (uint64_t)new_value << 32;
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > > +
> > > > +    if (ret_value) {
> > > > +        *ret_value = (old_mip & env->mideleg) >> 32;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > >  }
> > > >
> > > >  /* Supervisor Protection and Translation */
> > > > @@ -930,6 +1610,51 @@ static int write_satp(CPURISCVState *env, int csrno, target_ulong val)
> > > >      return 0;
> > > >  }
> > > >
> > > > +static int read_vstopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    int irq, hiid;
> > > > +    uint8_t hiprio, iprio;
> > > > +
> > > > +    irq = riscv_cpu_vsirq_pending(env);
> > > > +    if (irq <= 0 || irq > 63) {
> > > > +       *val = 0;
> > > > +    } else {
> > > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > > +       iprio = env->hviprio[irq];
> > > > +       /* TODO: This needs to improve in specification */
> > > > +       if (!(env->hstatus & HSTATUS_VGEIN)) {
> > > > +           hiid = (env->hvicontrol & HVICONTROL_IID_MASK) >>
> > > > +                 HVICONTROL_IID_SHIFT;
> > > > +           hiprio = env->hvicontrol & HVICONTROL_IPRIO_MASK;
> > > > +           if (irq == hiid && hiprio) {
> > > > +               iprio = hiprio;
> > > > +           }
> > > > +       }
> > > > +       *val |= iprio;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_stopi(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    int irq;
> > > > +
> > > > +    if (riscv_cpu_virt_enabled(env)) {
> > > > +        return read_vstopi(env, CSR_VSTOPI, val);
> > > > +    }
> > > > +
> > > > +    irq = riscv_cpu_sirq_pending(env);
> > > > +    if (irq <= 0 || irq > 63) {
> > > > +       *val = 0;
> > > > +    } else {
> > > > +       *val = (irq & TOPI_IID_MASK) << TOPI_IID_SHIFT;
> > > > +       *val |= env->siprio[irq];
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > >  /* Hypervisor Extensions */
> > > >  static int read_hstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > > >  {
> > > > @@ -979,26 +1704,90 @@ static int write_hideleg(CPURISCVState *env, int csrno, target_ulong val)
> > > >      return 0;
> > > >  }
> > > >
> > > > +static int read_hidelegh(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    *val = env->hideleg >> 32;
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_hidelegh(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    uint64_t mask = ~TLOWBITS64;
> > > > +    uint64_t newval = ((uint64_t)val) << 32;
> > > > +
> > > > +    env->hideleg = (env->hideleg & ~mask) | (newval & mask);
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > >  static int rmw_hvip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >                     target_ulong new_value, target_ulong write_mask)
> > > >  {
> > > > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > > > -                      write_mask & hvip_writable_mask);
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > > +                    hvip_writable_mask &
> > > > +                    ~env->miclaim & TLOWBITS64;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > >
> > > > -    *ret_value &= hvip_writable_mask;
> > > > +    if (ret_value) {
> > > > +        *ret_value = old_mip & hvip_writable_mask;
> > > > +    }
> > > >
> > > > -    return ret;
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int rmw_hviph(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > > +                    target_ulong new_value, target_ulong write_mask)
> > > > +{
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask << 32) & delegable_ints &
> > > > +                    hvip_writable_mask &
> > > > +                    ~env->miclaim & ~TLOWBITS64;
> > > > +    uint64_t new_value64 = (uint64_t)new_value << 32;
> > > > +    uint64_t old_mip;
> > > > +
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value64 & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > > +
> > > > +    if (ret_value) {
> > > > +        *ret_value = (old_mip & hvip_writable_mask) >> 32;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > >  }
> > > >
> > > >  static int rmw_hip(CPURISCVState *env, int csrno, target_ulong *ret_value,
> > > >                     target_ulong new_value, target_ulong write_mask)
> > > >  {
> > > > -    int ret = rmw_mip(env, 0, ret_value, new_value,
> > > > -                      write_mask & hip_writable_mask);
> > > > +    RISCVCPU *cpu = env_archcpu(env);
> > > > +    /* Allow software control of delegable interrupts not claimed by hardware */
> > > > +    uint64_t mask = ((uint64_t)write_mask) & delegable_ints &
> > > > +                    hip_writable_mask &
> > > > +                    ~env->miclaim & TLOWBITS64;
> > > > +    uint64_t old_mip;
> > > >
> > > > -    *ret_value &= hip_writable_mask;
> > > > +    if (mask) {
> > > > +        old_mip = riscv_cpu_update_mip(cpu, mask, (new_value & mask));
> > > > +    } else {
> > > > +        old_mip = env->mip;
> > > > +    }
> > > >
> > > > -    return ret;
> > > > +    if (ret_value) {
> > > > +        *ret_value = old_mip & hip_writable_mask;
> > > > +    }
> > > > +
> > > > +    return 0;
> > > >  }
> > > >
> > > >  static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> > > > @@ -1009,8 +1798,9 @@ static int read_hie(CPURISCVState *env, int csrno, target_ulong *val)
> > > >
> > > >  static int write_hie(CPURISCVState *env, int csrno, target_ulong val)
> > > >  {
> > > > -    target_ulong newval = (env->mie & ~VS_MODE_INTERRUPTS) | (val & VS_MODE_INTERRUPTS);
> > > > -    return write_mie(env, CSR_MIE, newval);
> > > > +    uint64_t mask = VS_MODE_INTERRUPTS & all_ints & TLOWBITS64;
> > > > +    env->mie = (env->mie & ~mask) | ((uint64_t)val & mask);
> > > > +    return 0;
> > > >  }
> > > >
> > > >  static int read_hcounteren(CPURISCVState *env, int csrno, target_ulong *val)
> > > > @@ -1128,6 +1918,110 @@ static int write_htimedeltah(CPURISCVState *env, int csrno, target_ulong val)
> > > >      return 0;
> > > >  }
> > > >
> > > > +static int read_hvicontrol(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    *val = env->hvicontrol;
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_hvicontrol(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    env->hvicontrol = val & HVICONTROL_VALID_MASK;
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_hvipriox(CPURISCVState *env, int first_index,
> > > > +                         uint8_t *iprio, target_ulong *val)
> > > > +{
> > > > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > > > +
> > > > +    /* First index has to be multiple of numbe of irqs per register */
> > > > +    if (first_index % num_irqs) {
> > > > +        return (riscv_cpu_virt_enabled(env)) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    /* Fill-up return value */
> > > > +    *val = 0;
> > > > +    for (i = 0; i < num_irqs; i++) {
> > > > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > > > +            continue;
> > > > +        }
> > > > +        if (rdzero) {
> > > > +            continue;
> > > > +        }
> > > > +        *val |= ((target_ulong)iprio[irq]) << (i * 8);
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int write_hvipriox(CPURISCVState *env, int first_index,
> > > > +                          uint8_t *iprio, target_ulong val)
> > > > +{
> > > > +    int i, irq, rdzero, num_irqs = 4 * (TARGET_LONG_BITS / 32);
> > > > +
> > > > +    /* First index has to be multiple of numbe of irqs per register */
> > > > +    if (first_index % num_irqs) {
> > > > +        return (riscv_cpu_virt_enabled(env)) ?
> > > > +               -RISCV_EXCP_VIRT_INSTRUCTION_FAULT : -RISCV_EXCP_ILLEGAL_INST;
> > > > +    }
> > > > +
> > > > +    /* Fill-up priority arrary */
> > > > +    for (i = 0; i < num_irqs; i++) {
> > > > +        if (riscv_cpu_hviprio_index2irq(first_index + i, &irq, &rdzero)) {
> > > > +            continue;
> > > > +        }
> > > > +        if (rdzero) {
> > > > +            iprio[irq] = 0;
> > > > +        } else {
> > > > +            iprio[irq] = (val >> (i * 8)) & 0xff;
> > > > +        }
> > > > +    }
> > > > +
> > > > +    return 0;
> > > > +}
> > > > +
> > > > +static int read_hviprio1(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    return read_hvipriox(env, 0, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int write_hviprio1(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    return write_hvipriox(env, 0, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int read_hviprio1h(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    return read_hvipriox(env, 4, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int write_hviprio1h(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    return write_hvipriox(env, 4, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int read_hviprio2(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    return read_hvipriox(env, 8, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int write_hviprio2(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    return write_hvipriox(env, 8, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int read_hviprio2h(CPURISCVState *env, int csrno, target_ulong *val)
> > > > +{
> > > > +    return read_hvipriox(env, 12, env->hviprio, val);
> > > > +}
> > > > +
> > > > +static int write_hviprio2h(CPURISCVState *env, int csrno, target_ulong val)
> > > > +{
> > > > +    return write_hvipriox(env, 12, env->hviprio, val);
> > > > +}
> > > > +
> > > >  /* Virtual CSR Registers */
> > > >  static int read_vsstatus(CPURISCVState *env, int csrno, target_ulong *val)
> > > >  {
> > > > @@ -1428,6 +2322,25 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > > >      [CSR_MBADADDR] = { "mbadaddr", any,  read_mbadaddr, write_mbadaddr },
> > > >      [CSR_MIP]      = { "mip",      any,  NULL,    NULL, rmw_mip        },
> > > >
> > > > +    /* Machine-Level Window to Indirectly Accessed Registers (AIA) */
> > > > +    [CSR_MISELECT] = { "miselect", aia_any,   NULL, NULL,    rmw_xiselect },
> > > > +    [CSR_MIREG]    = { "mireg",    aia_any,   NULL, NULL,    rmw_xireg },
> > > > +
> > > > +    /* Machine-Level Interrupts (AIA) */
> > > > +    [CSR_MTOPI]    = { "mtopi",    aia_any,   read_mtopi },
> > > > +
> > > > +    /* Machine-Level IMSIC Interface (AIA) */
> > > > +    [CSR_MSETEIPNUM] = { "mseteipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_MCLREIPNUM] = { "mclreipnum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_MSETEIENUM] = { "mseteienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_MCLREIENUM] = { "mclreienum", aia_any, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_MCLAIMEI]   = { "mclaimei",   aia_any, read_xclaimei },
> > > > +
> > > > +    /* Machine-Level High-Half CSRs (AIA) */
> > > > +    [CSR_MIDELEGH] = { "midelegh", aia_any32, read_midelegh, write_midelegh },
> > > > +    [CSR_MIEH]     = { "mieh",     aia_any32, read_mieh,     write_mieh     },
> > > > +    [CSR_MIPH]     = { "miph",     aia_any32, NULL,    NULL, rmw_miph       },
> > > > +
> > > >      /* Supervisor Trap Setup */
> > > >      [CSR_SSTATUS]    = { "sstatus",    smode, read_sstatus,    write_sstatus    },
> > > >      [CSR_SIE]        = { "sie",        smode, read_sie,        write_sie        },
> > > > @@ -1444,6 +2357,24 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > > >      /* Supervisor Protection and Translation */
> > > >      [CSR_SATP]     = { "satp",     smode, read_satp,    write_satp      },
> > > >
> > > > +    /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
> > > > +    [CSR_SISELECT]   = { "siselect",   aia_smode, NULL, NULL, rmw_xiselect },
> > > > +    [CSR_SIREG]      = { "sireg",      aia_smode, NULL, NULL, rmw_xireg },
> > > > +
> > > > +    /* Supervisor-Level Interrupts (AIA) */
> > > > +    [CSR_STOPI]      = { "stopi",      aia_smode, read_stopi },
> > > > +
> > > > +    /* Supervisor-Level IMSIC Interface (AIA) */
> > > > +    [CSR_SSETEIPNUM] = { "sseteipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_SCLREIPNUM] = { "sclreipnum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_SSETEIENUM] = { "sseteienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_SCLREIENUM] = { "sclreienum", aia_smode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_SCLAIMEI]   = { "sclaimei",   aia_smode, read_xclaimei },
> > > > +
> > > > +    /* Supervisor-Level High-Half CSRs (AIA) */
> > > > +    [CSR_SIEH]       = { "sieh",       aia_smode32, read_sieh,  write_sieh },
> > > > +    [CSR_SIPH]       = { "siph",       aia_smode32, NULL, NULL, rmw_siph   },
> > > > +
> > > >      [CSR_HSTATUS]     = { "hstatus",     hmode,   read_hstatus,     write_hstatus     },
> > > >      [CSR_HEDELEG]     = { "hedeleg",     hmode,   read_hedeleg,     write_hedeleg     },
> > > >      [CSR_HIDELEG]     = { "hideleg",     hmode,   read_hideleg,     write_hideleg     },
> > > > @@ -1472,6 +2403,32 @@ riscv_csr_operations csr_ops[CSR_TABLE_SIZE] = {
> > > >      [CSR_MTVAL2]      = { "mtval2",      hmode,   read_mtval2,      write_mtval2      },
> > > >      [CSR_MTINST]      = { "mtinst",      hmode,   read_mtinst,      write_mtinst      },
> > > >
> > > > +    /* Virtual Interrupts and Interrupt Priorities (H-extension with AIA) */
> > > > +    [CSR_HVICONTROL]  = { "hvicontrol",  aia_hmode, read_hvicontrol, write_hvicontrol },
> > > > +    [CSR_HVIPRIO1]    = { "hviprio1",    aia_hmode, read_hviprio1,   write_hviprio1 },
> > > > +    [CSR_HVIPRIO2]    = { "hviprio2",    aia_hmode, read_hviprio2,   write_hviprio2 },
> > > > +
> > > > +    /* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
> > > > +    [CSR_VSISELECT]   = { "vsiselect",   aia_hmode, NULL, NULL,      rmw_xiselect },
> > > > +    [CSR_VSIREG]      = { "vsireg",      aia_hmode, NULL, NULL,      rmw_xireg },
> > > > +
> > > > +    /* VS-Level Interrupts (H-extension with AIA) */
> > > > +    [CSR_VSTOPI]      = { "vstopi",      aia_hmode, read_vstopi },
> > > > +
> > > > +    /* VS-Level IMSIC Interface (H-extension with AIA) */
> > > > +    [CSR_VSSETEIPNUM] = { "vsseteipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_VSCLREIPNUM] = { "vsclreipnum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_VSSETEIENUM] = { "vsseteienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > > +    [CSR_VSCLREIENUM] = { "vsclreienum", aia_hmode, read_xsetclreinum, write_xsetclreinum },
> > > > +
> > > > +    /* Hypervisor and VS-Level High-Half CSRs (H-extension with AIA) */
> > > > +    [CSR_HIDELEGH]    = { "hidelegh",    aia_hmode32, read_hidelegh,  write_hidelegh },
> > > > +    [CSR_HVIPH]       = { "hviph",       aia_hmode32, NULL, NULL,     rmw_hviph },
> > > > +    [CSR_HVIPRIO1H]   = { "hviprio1h",   aia_hmode32, read_hviprio1h, write_hviprio1h },
> > > > +    [CSR_HVIPRIO2H]   = { "hviprio2h",   aia_hmode32, read_hviprio2h, write_hviprio2h },
> > > > +    [CSR_VSIEH]       = { "vsieh",       aia_hmode32, read_vsieh,     write_vsieh },
> > > > +    [CSR_VSIPH]       = { "vsiep",       aia_hmode32, NULL, NULL,     rmw_vsiph },
> > > > +
> > > >      /* Physical Memory Protection */
> > > >      [CSR_PMPCFG0]    = { "pmpcfg0",   pmp, read_pmpcfg,  write_pmpcfg  },
> > > >      [CSR_PMPCFG1]    = { "pmpcfg1",   pmp, read_pmpcfg,  write_pmpcfg  },
> > > > diff --git a/target/riscv/machine.c b/target/riscv/machine.c
> > > > index 44d4015bd6..f7fa48c240 100644
> > > > --- a/target/riscv/machine.c
> > > > +++ b/target/riscv/machine.c
> > > > @@ -102,19 +102,22 @@ static const VMStateDescription vmstate_vector = {
> > > >
> > > >  static const VMStateDescription vmstate_hyper = {
> > > >      .name = "cpu/hyper",
> > > > -    .version_id = 1,
> > > > -    .minimum_version_id = 1,
> > > > +    .version_id = 2,
> > > > +    .minimum_version_id = 2,
> > > >      .needed = hyper_needed,
> > > >      .fields = (VMStateField[]) {
> > > >          VMSTATE_UINTTL(env.hstatus, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.hedeleg, RISCVCPU),
> > > > -        VMSTATE_UINTTL(env.hideleg, RISCVCPU),
> > > > +        VMSTATE_UINT64(env.hideleg, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.hcounteren, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.htval, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.htinst, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.hgatp, RISCVCPU),
> > > >          VMSTATE_UINT64(env.htimedelta, RISCVCPU),
> > > >
> > > > +        VMSTATE_UINT8_ARRAY(env.hviprio, RISCVCPU, 64),
> > > > +        VMSTATE_UINTTL(env.hvicontrol, RISCVCPU),
> > > > +
> > > >          VMSTATE_UINT64(env.vsstatus, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.vstvec, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.vsscratch, RISCVCPU),
> > > > @@ -122,6 +125,7 @@ static const VMStateDescription vmstate_hyper = {
> > > >          VMSTATE_UINTTL(env.vscause, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.vstval, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.vsatp, RISCVCPU),
> > > > +        VMSTATE_UINTTL(env.vsiselect, RISCVCPU),
> > > >
> > > >          VMSTATE_UINTTL(env.mtval2, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.mtinst, RISCVCPU),
> > > > @@ -140,11 +144,13 @@ static const VMStateDescription vmstate_hyper = {
> > > >
> > > >  const VMStateDescription vmstate_riscv_cpu = {
> > > >      .name = "cpu",
> > > > -    .version_id = 1,
> > > > -    .minimum_version_id = 1,
> > > > +    .version_id = 2,
> > > > +    .minimum_version_id = 2,
> > > >      .fields = (VMStateField[]) {
> > > >          VMSTATE_UINTTL_ARRAY(env.gpr, RISCVCPU, 32),
> > > >          VMSTATE_UINT64_ARRAY(env.fpr, RISCVCPU, 32),
> > > > +        VMSTATE_UINT8_ARRAY(env.miprio, RISCVCPU, 64),
> > > > +        VMSTATE_UINT8_ARRAY(env.siprio, RISCVCPU, 64),
> > > >          VMSTATE_UINTTL(env.pc, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.load_res, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.load_val, RISCVCPU),
> > > > @@ -161,10 +167,10 @@ const VMStateDescription vmstate_riscv_cpu = {
> > > >          VMSTATE_UINTTL(env.resetvec, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.mhartid, RISCVCPU),
> > > >          VMSTATE_UINT64(env.mstatus, RISCVCPU),
> > > > -        VMSTATE_UINTTL(env.mip, RISCVCPU),
> > > > -        VMSTATE_UINT32(env.miclaim, RISCVCPU),
> > > > -        VMSTATE_UINTTL(env.mie, RISCVCPU),
> > > > -        VMSTATE_UINTTL(env.mideleg, RISCVCPU),
> > > > +        VMSTATE_UINT64(env.mip, RISCVCPU),
> > > > +        VMSTATE_UINT64(env.miclaim, RISCVCPU),
> > > > +        VMSTATE_UINT64(env.mie, RISCVCPU),
> > > > +        VMSTATE_UINT64(env.mideleg, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.sptbr, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.satp, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.sbadaddr, RISCVCPU),
> > > > @@ -177,6 +183,8 @@ const VMStateDescription vmstate_riscv_cpu = {
> > > >          VMSTATE_UINTTL(env.mepc, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.mcause, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.mtval, RISCVCPU),
> > > > +        VMSTATE_UINTTL(env.miselect, RISCVCPU),
> > > > +        VMSTATE_UINTTL(env.siselect, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.scounteren, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.mcounteren, RISCVCPU),
> > > >          VMSTATE_UINTTL(env.sscratch, RISCVCPU),
> > > > --
> > > > 2.25.1
> > > >
> > > >


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
  2021-06-11 14:04           ` Anup Patel
@ 2021-06-15  8:11             ` Alistair Francis
  -1 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-15  8:11 UTC (permalink / raw)
  To: Anup Patel
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Sat, Jun 12, 2021 at 12:04 AM Anup Patel <anup@brainfault.org> wrote:
>
> On Fri, Jun 11, 2021 at 2:16 PM Alistair Francis <alistair23@gmail.com> wrote:
> >
> > On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote:
> > >
> > > On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote:
> > > >
> > > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > > >
> > > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> > > > > and VS-mode.
> > > > >
> > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > > ---
> > > > >  target/riscv/cpu.c        |   27 +-
> > > > >  target/riscv/cpu.h        |   52 +-
> > > > >  target/riscv/cpu_helper.c |  245 ++++++++-
> > > > >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> > > > >  target/riscv/machine.c    |   26 +-
> > > > >  5 files changed, 1309 insertions(+), 100 deletions(-)
> > > >
> > > > I feel this patch could be split up more :)
> > >
> > > This is patch is large because I did not want to break functionality.
> > >
> > > I try again to break this patch. At the moment, the best I can do is
> > > to break in to two parts.
> > > 1) AIA local interrupt CSRs without IMSIC
> > > 2) Extend AIA local interrupt CSRs to support IMSIC register access
> >
> > As the patch is being added while AIA isn't enabled you are able to
> > add the AIA in breaking stages. That is the AIA isn't fully
> > functional, you still have to make sure not to break existing users.
> >
> > >
> > > >
> > > > >
> > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > > > > index f3702111ae..795162834b 100644
> > > > > --- a/target/riscv/cpu.c
> > > > > +++ b/target/riscv/cpu.c
> > > > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> > > > >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
> > > > >                       (target_ulong)env->vsstatus);
> > > > >      }
> > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
> > > > >      if (riscv_has_ext(env, RVH)) {
> > > > > -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> > > > > +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
> > > > >      }
> > > > >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> > > > >      if (riscv_has_ext(env, RVH)) {
> > > > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
> > > > >
> > > > >  static void riscv_cpu_reset(DeviceState *dev)
> > > > >  {
> > > > > +    uint8_t iprio;
> > > > > +    int i, irq, rdzero;
> > > > >      CPUState *cs = CPU(dev);
> > > > >      RISCVCPU *cpu = RISCV_CPU(cs);
> > > > >      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> > > > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
> > > > >      env->mcause = 0;
> > > > >      env->pc = env->resetvec;
> > > > >      env->two_stage_lookup = false;
> > > > > +
> > > > > +    /* Initialized default priorities of local interrupts. */
> > > > > +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> > > > > +        iprio = riscv_cpu_default_priority(i);
> > > > > +        env->miprio[i] = iprio;
> > > > > +        env->siprio[i] = iprio;
> > > > > +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> > > > > +    }
> > > > > +    i = 0;
> > > > > +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> > > > > +        if (rdzero) {
> > > > > +            env->hviprio[irq] = 0;
> > > > > +        } else {
> > > > > +            env->hviprio[irq] = env->miprio[irq];
> > > > > +        }
> > > > > +        i++;
> > > > > +    }
> > > > >  #endif
> > > > >      cs->exception_index = EXCP_NONE;
> > > > >      env->load_res = -1;
> > > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > > > > index f00c60c840..780d3f9058 100644
> > > > > --- a/target/riscv/cpu.h
> > > > > +++ b/target/riscv/cpu.h
> > > > > @@ -157,12 +157,12 @@ struct CPURISCVState {
> > > > >       */
> > > > >      uint64_t mstatus;
> > > > >
> > > > > -    target_ulong mip;
> > > > > +    uint64_t mip;
> > > >
> > > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
> > > > all the other existing target_ulong CSRs are the same.
> > >
> > > When AIA is available the number of local interrupts are 64 for
> > > both RV32 and RV64.
> >
> > Is that going to be reflected in the priv spec?
>
> The AIA spec is going to be separate from priv spec since
> it is totally optional.
>
> This AIA local interrupt CSRs will be part of AIA spec and should
> only be implemented if a RISC-V implementations wants to use
> AIA.
>
> We have four types of changes as far as CSRs go:
> 1) RV32 CSRs to support 64 local interrupts on RV32

Hmmm... This isn't ideal. So implementations without AIA will have a
Xlen MIP while implementations with AIA will have a 64-bit MIP?

I guess we just don't expose all of MIP, so it isn't that bad. Still
that change should be it's own patch with good justification as why we
aren't following the priv spec.

> 2) Indirect CSRs to access local interrupt priorities
> 3) Interrupt filtering CSRs
> 4) IMSIC support CSRs

New AIA CSRs are fine, it's just core changes that are more of a worry.

Alistair

>
> From above #3 is totally optional and not implemented by this
> patch whereas #4 is only required when platform has RISC-V IMSIC.
>
> A platform can skip all four changes mentioned above, if the
> platform only wants AIA APLIC to manage wired interrupts.
>
> Regards,
> Anup


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
@ 2021-06-15  8:11             ` Alistair Francis
  0 siblings, 0 replies; 34+ messages in thread
From: Alistair Francis @ 2021-06-15  8:11 UTC (permalink / raw)
  To: Anup Patel
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Sat, Jun 12, 2021 at 12:04 AM Anup Patel <anup@brainfault.org> wrote:
>
> On Fri, Jun 11, 2021 at 2:16 PM Alistair Francis <alistair23@gmail.com> wrote:
> >
> > On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote:
> > >
> > > On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote:
> > > >
> > > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > > >
> > > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> > > > > and VS-mode.
> > > > >
> > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > > ---
> > > > >  target/riscv/cpu.c        |   27 +-
> > > > >  target/riscv/cpu.h        |   52 +-
> > > > >  target/riscv/cpu_helper.c |  245 ++++++++-
> > > > >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> > > > >  target/riscv/machine.c    |   26 +-
> > > > >  5 files changed, 1309 insertions(+), 100 deletions(-)
> > > >
> > > > I feel this patch could be split up more :)
> > >
> > > This is patch is large because I did not want to break functionality.
> > >
> > > I try again to break this patch. At the moment, the best I can do is
> > > to break in to two parts.
> > > 1) AIA local interrupt CSRs without IMSIC
> > > 2) Extend AIA local interrupt CSRs to support IMSIC register access
> >
> > As the patch is being added while AIA isn't enabled you are able to
> > add the AIA in breaking stages. That is the AIA isn't fully
> > functional, you still have to make sure not to break existing users.
> >
> > >
> > > >
> > > > >
> > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > > > > index f3702111ae..795162834b 100644
> > > > > --- a/target/riscv/cpu.c
> > > > > +++ b/target/riscv/cpu.c
> > > > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> > > > >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
> > > > >                       (target_ulong)env->vsstatus);
> > > > >      }
> > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
> > > > >      if (riscv_has_ext(env, RVH)) {
> > > > > -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> > > > > +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
> > > > >      }
> > > > >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> > > > >      if (riscv_has_ext(env, RVH)) {
> > > > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
> > > > >
> > > > >  static void riscv_cpu_reset(DeviceState *dev)
> > > > >  {
> > > > > +    uint8_t iprio;
> > > > > +    int i, irq, rdzero;
> > > > >      CPUState *cs = CPU(dev);
> > > > >      RISCVCPU *cpu = RISCV_CPU(cs);
> > > > >      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> > > > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
> > > > >      env->mcause = 0;
> > > > >      env->pc = env->resetvec;
> > > > >      env->two_stage_lookup = false;
> > > > > +
> > > > > +    /* Initialized default priorities of local interrupts. */
> > > > > +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> > > > > +        iprio = riscv_cpu_default_priority(i);
> > > > > +        env->miprio[i] = iprio;
> > > > > +        env->siprio[i] = iprio;
> > > > > +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> > > > > +    }
> > > > > +    i = 0;
> > > > > +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> > > > > +        if (rdzero) {
> > > > > +            env->hviprio[irq] = 0;
> > > > > +        } else {
> > > > > +            env->hviprio[irq] = env->miprio[irq];
> > > > > +        }
> > > > > +        i++;
> > > > > +    }
> > > > >  #endif
> > > > >      cs->exception_index = EXCP_NONE;
> > > > >      env->load_res = -1;
> > > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > > > > index f00c60c840..780d3f9058 100644
> > > > > --- a/target/riscv/cpu.h
> > > > > +++ b/target/riscv/cpu.h
> > > > > @@ -157,12 +157,12 @@ struct CPURISCVState {
> > > > >       */
> > > > >      uint64_t mstatus;
> > > > >
> > > > > -    target_ulong mip;
> > > > > +    uint64_t mip;
> > > >
> > > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
> > > > all the other existing target_ulong CSRs are the same.
> > >
> > > When AIA is available the number of local interrupts are 64 for
> > > both RV32 and RV64.
> >
> > Is that going to be reflected in the priv spec?
>
> The AIA spec is going to be separate from priv spec since
> it is totally optional.
>
> This AIA local interrupt CSRs will be part of AIA spec and should
> only be implemented if a RISC-V implementations wants to use
> AIA.
>
> We have four types of changes as far as CSRs go:
> 1) RV32 CSRs to support 64 local interrupts on RV32

Hmmm... This isn't ideal. So implementations without AIA will have a
Xlen MIP while implementations with AIA will have a 64-bit MIP?

I guess we just don't expose all of MIP, so it isn't that bad. Still
that change should be it's own patch with good justification as why we
aren't following the priv spec.

> 2) Indirect CSRs to access local interrupt priorities
> 3) Interrupt filtering CSRs
> 4) IMSIC support CSRs

New AIA CSRs are fine, it's just core changes that are more of a worry.

Alistair

>
> From above #3 is totally optional and not implemented by this
> patch whereas #4 is only required when platform has RISC-V IMSIC.
>
> A platform can skip all four changes mentioned above, if the
> platform only wants AIA APLIC to manage wired interrupts.
>
> Regards,
> Anup


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
  2021-06-15  8:11             ` Alistair Francis
@ 2021-06-15 12:48               ` Anup Patel
  -1 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-15 12:48 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Peter Maydell, open list:RISC-V, Sagar Karandikar, Anup Patel,
	qemu-devel@nongnu.org Developers, Atish Patra, Alistair Francis,
	Palmer Dabbelt

On Tue, Jun 15, 2021 at 1:41 PM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Sat, Jun 12, 2021 at 12:04 AM Anup Patel <anup@brainfault.org> wrote:
> >
> > On Fri, Jun 11, 2021 at 2:16 PM Alistair Francis <alistair23@gmail.com> wrote:
> > >
> > > On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote:
> > > >
> > > > On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote:
> > > > >
> > > > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > > > >
> > > > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> > > > > > and VS-mode.
> > > > > >
> > > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > > > ---
> > > > > >  target/riscv/cpu.c        |   27 +-
> > > > > >  target/riscv/cpu.h        |   52 +-
> > > > > >  target/riscv/cpu_helper.c |  245 ++++++++-
> > > > > >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> > > > > >  target/riscv/machine.c    |   26 +-
> > > > > >  5 files changed, 1309 insertions(+), 100 deletions(-)
> > > > >
> > > > > I feel this patch could be split up more :)
> > > >
> > > > This is patch is large because I did not want to break functionality.
> > > >
> > > > I try again to break this patch. At the moment, the best I can do is
> > > > to break in to two parts.
> > > > 1) AIA local interrupt CSRs without IMSIC
> > > > 2) Extend AIA local interrupt CSRs to support IMSIC register access
> > >
> > > As the patch is being added while AIA isn't enabled you are able to
> > > add the AIA in breaking stages. That is the AIA isn't fully
> > > functional, you still have to make sure not to break existing users.
> > >
> > > >
> > > > >
> > > > > >
> > > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > > > > > index f3702111ae..795162834b 100644
> > > > > > --- a/target/riscv/cpu.c
> > > > > > +++ b/target/riscv/cpu.c
> > > > > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> > > > > >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
> > > > > >                       (target_ulong)env->vsstatus);
> > > > > >      }
> > > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> > > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> > > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> > > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> > > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
> > > > > >      if (riscv_has_ext(env, RVH)) {
> > > > > > -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> > > > > > +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
> > > > > >      }
> > > > > >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> > > > > >      if (riscv_has_ext(env, RVH)) {
> > > > > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
> > > > > >
> > > > > >  static void riscv_cpu_reset(DeviceState *dev)
> > > > > >  {
> > > > > > +    uint8_t iprio;
> > > > > > +    int i, irq, rdzero;
> > > > > >      CPUState *cs = CPU(dev);
> > > > > >      RISCVCPU *cpu = RISCV_CPU(cs);
> > > > > >      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> > > > > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
> > > > > >      env->mcause = 0;
> > > > > >      env->pc = env->resetvec;
> > > > > >      env->two_stage_lookup = false;
> > > > > > +
> > > > > > +    /* Initialized default priorities of local interrupts. */
> > > > > > +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> > > > > > +        iprio = riscv_cpu_default_priority(i);
> > > > > > +        env->miprio[i] = iprio;
> > > > > > +        env->siprio[i] = iprio;
> > > > > > +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> > > > > > +    }
> > > > > > +    i = 0;
> > > > > > +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> > > > > > +        if (rdzero) {
> > > > > > +            env->hviprio[irq] = 0;
> > > > > > +        } else {
> > > > > > +            env->hviprio[irq] = env->miprio[irq];
> > > > > > +        }
> > > > > > +        i++;
> > > > > > +    }
> > > > > >  #endif
> > > > > >      cs->exception_index = EXCP_NONE;
> > > > > >      env->load_res = -1;
> > > > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > > > > > index f00c60c840..780d3f9058 100644
> > > > > > --- a/target/riscv/cpu.h
> > > > > > +++ b/target/riscv/cpu.h
> > > > > > @@ -157,12 +157,12 @@ struct CPURISCVState {
> > > > > >       */
> > > > > >      uint64_t mstatus;
> > > > > >
> > > > > > -    target_ulong mip;
> > > > > > +    uint64_t mip;
> > > > >
> > > > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
> > > > > all the other existing target_ulong CSRs are the same.
> > > >
> > > > When AIA is available the number of local interrupts are 64 for
> > > > both RV32 and RV64.
> > >
> > > Is that going to be reflected in the priv spec?
> >
> > The AIA spec is going to be separate from priv spec since
> > it is totally optional.
> >
> > This AIA local interrupt CSRs will be part of AIA spec and should
> > only be implemented if a RISC-V implementations wants to use
> > AIA.
> >
> > We have four types of changes as far as CSRs go:
> > 1) RV32 CSRs to support 64 local interrupts on RV32
>
> Hmmm... This isn't ideal. So implementations without AIA will have a
> Xlen MIP while implementations with AIA will have a 64-bit MIP?

That's an inherent limitation of the Priv spec.

>
> I guess we just don't expose all of MIP, so it isn't that bad. Still
> that change should be it's own patch with good justification as why we
> aren't following the priv spec.

The rationale with Priv spec allows implementations to support
32bit mode on RV64 HART so even RV64 HART running in
32bit mode can't use more than 32 local interrupts.

This means we have a hard limit of 32 local interrupts in the
Priv spec for both RV32 and RV64. The lower 13 interrupts
are already standardized by Priv spec but we need to support
good amount of per-HART local interrupts for future needs
hence the AIA spec mandates minimum 64 local interrupts.

Look at it this way, implementations which need future ready
local interrupt support will implement AIA style local interrupts
and implementations which don't can reduce hardware cost
by staying with only XLEN local interrupts.

The AIA style local interrupts are already approved by Andrew,
Greg, and other folks because everyone accepts the local interrupt
limitations of current Priv spec.

>
> > 2) Indirect CSRs to access local interrupt priorities
> > 3) Interrupt filtering CSRs
> > 4) IMSIC support CSRs
>
> New AIA CSRs are fine, it's just core changes that are more of a worry.

Backward compatibility is a key requirement for RISC-V AIA
and if you see this patch we keep the original Priv style
local interrupts as-is with minor improvements.

Regards,
Anup

>
> Alistair
>
> >
> > From above #3 is totally optional and not implemented by this
> > patch whereas #4 is only required when platform has RISC-V IMSIC.
> >
> > A platform can skip all four changes mentioned above, if the
> > platform only wants AIA APLIC to manage wired interrupts.
> >
> > Regards,
> > Anup


^ permalink raw reply	[flat|nested] 34+ messages in thread

* Re: [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
@ 2021-06-15 12:48               ` Anup Patel
  0 siblings, 0 replies; 34+ messages in thread
From: Anup Patel @ 2021-06-15 12:48 UTC (permalink / raw)
  To: Alistair Francis
  Cc: Anup Patel, Peter Maydell, Palmer Dabbelt, Alistair Francis,
	Sagar Karandikar, Atish Patra, open list:RISC-V,
	qemu-devel@nongnu.org Developers

On Tue, Jun 15, 2021 at 1:41 PM Alistair Francis <alistair23@gmail.com> wrote:
>
> On Sat, Jun 12, 2021 at 12:04 AM Anup Patel <anup@brainfault.org> wrote:
> >
> > On Fri, Jun 11, 2021 at 2:16 PM Alistair Francis <alistair23@gmail.com> wrote:
> > >
> > > On Fri, Jun 11, 2021 at 3:04 PM Anup Patel <anup@brainfault.org> wrote:
> > > >
> > > > On Fri, Jun 11, 2021 at 4:49 AM Alistair Francis <alistair23@gmail.com> wrote:
> > > > >
> > > > > On Sat, May 15, 2021 at 12:34 AM Anup Patel <anup.patel@wdc.com> wrote:
> > > > > >
> > > > > > We implement various AIA local interrupt CSRs for M-mode, HS-mode,
> > > > > > and VS-mode.
> > > > > >
> > > > > > Signed-off-by: Anup Patel <anup.patel@wdc.com>
> > > > > > ---
> > > > > >  target/riscv/cpu.c        |   27 +-
> > > > > >  target/riscv/cpu.h        |   52 +-
> > > > > >  target/riscv/cpu_helper.c |  245 ++++++++-
> > > > > >  target/riscv/csr.c        | 1059 +++++++++++++++++++++++++++++++++++--
> > > > > >  target/riscv/machine.c    |   26 +-
> > > > > >  5 files changed, 1309 insertions(+), 100 deletions(-)
> > > > >
> > > > > I feel this patch could be split up more :)
> > > >
> > > > This is patch is large because I did not want to break functionality.
> > > >
> > > > I try again to break this patch. At the moment, the best I can do is
> > > > to break in to two parts.
> > > > 1) AIA local interrupt CSRs without IMSIC
> > > > 2) Extend AIA local interrupt CSRs to support IMSIC register access
> > >
> > > As the patch is being added while AIA isn't enabled you are able to
> > > add the AIA in breaking stages. That is the AIA isn't fully
> > > functional, you still have to make sure not to break existing users.
> > >
> > > >
> > > > >
> > > > > >
> > > > > > diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
> > > > > > index f3702111ae..795162834b 100644
> > > > > > --- a/target/riscv/cpu.c
> > > > > > +++ b/target/riscv/cpu.c
> > > > > > @@ -256,11 +256,11 @@ static void riscv_cpu_dump_state(CPUState *cs, FILE *f, int flags)
> > > > > >          qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "vsstatus ",
> > > > > >                       (target_ulong)env->vsstatus);
> > > > > >      }
> > > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mip     ", env->mip);
> > > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mie     ", env->mie);
> > > > > > -    qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "mideleg ", env->mideleg);
> > > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mip     ", env->mip);
> > > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mie     ", env->mie);
> > > > > > +    qemu_fprintf(f, " %s %016" PRIx64 "\n", "mideleg ", env->mideleg);
> > > > > >      if (riscv_has_ext(env, RVH)) {
> > > > > > -        qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "hideleg ", env->hideleg);
> > > > > > +        qemu_fprintf(f, " %s %016" PRIx64 "\n", "hideleg ", env->hideleg);
> > > > > >      }
> > > > > >      qemu_fprintf(f, " %s " TARGET_FMT_lx "\n", "medeleg ", env->medeleg);
> > > > > >      if (riscv_has_ext(env, RVH)) {
> > > > > > @@ -345,6 +345,8 @@ void restore_state_to_opc(CPURISCVState *env, TranslationBlock *tb,
> > > > > >
> > > > > >  static void riscv_cpu_reset(DeviceState *dev)
> > > > > >  {
> > > > > > +    uint8_t iprio;
> > > > > > +    int i, irq, rdzero;
> > > > > >      CPUState *cs = CPU(dev);
> > > > > >      RISCVCPU *cpu = RISCV_CPU(cs);
> > > > > >      RISCVCPUClass *mcc = RISCV_CPU_GET_CLASS(cpu);
> > > > > > @@ -357,6 +359,23 @@ static void riscv_cpu_reset(DeviceState *dev)
> > > > > >      env->mcause = 0;
> > > > > >      env->pc = env->resetvec;
> > > > > >      env->two_stage_lookup = false;
> > > > > > +
> > > > > > +    /* Initialized default priorities of local interrupts. */
> > > > > > +    for (i = 0; i < ARRAY_SIZE(env->miprio); i++) {
> > > > > > +        iprio = riscv_cpu_default_priority(i);
> > > > > > +        env->miprio[i] = iprio;
> > > > > > +        env->siprio[i] = iprio;
> > > > > > +        env->hviprio[i] = IPRIO_DEFAULT_MMAXIPRIO;
> > > > > > +    }
> > > > > > +    i = 0;
> > > > > > +    while (!riscv_cpu_hviprio_index2irq(i, &irq, &rdzero)) {
> > > > > > +        if (rdzero) {
> > > > > > +            env->hviprio[irq] = 0;
> > > > > > +        } else {
> > > > > > +            env->hviprio[irq] = env->miprio[irq];
> > > > > > +        }
> > > > > > +        i++;
> > > > > > +    }
> > > > > >  #endif
> > > > > >      cs->exception_index = EXCP_NONE;
> > > > > >      env->load_res = -1;
> > > > > > diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
> > > > > > index f00c60c840..780d3f9058 100644
> > > > > > --- a/target/riscv/cpu.h
> > > > > > +++ b/target/riscv/cpu.h
> > > > > > @@ -157,12 +157,12 @@ struct CPURISCVState {
> > > > > >       */
> > > > > >      uint64_t mstatus;
> > > > > >
> > > > > > -    target_ulong mip;
> > > > > > +    uint64_t mip;
> > > > >
> > > > > This isn't right. MIP is a MXLEN-1 CSR. I didn't check but I assume
> > > > > all the other existing target_ulong CSRs are the same.
> > > >
> > > > When AIA is available the number of local interrupts are 64 for
> > > > both RV32 and RV64.
> > >
> > > Is that going to be reflected in the priv spec?
> >
> > The AIA spec is going to be separate from priv spec since
> > it is totally optional.
> >
> > This AIA local interrupt CSRs will be part of AIA spec and should
> > only be implemented if a RISC-V implementations wants to use
> > AIA.
> >
> > We have four types of changes as far as CSRs go:
> > 1) RV32 CSRs to support 64 local interrupts on RV32
>
> Hmmm... This isn't ideal. So implementations without AIA will have a
> Xlen MIP while implementations with AIA will have a 64-bit MIP?

That's an inherent limitation of the Priv spec.

>
> I guess we just don't expose all of MIP, so it isn't that bad. Still
> that change should be it's own patch with good justification as why we
> aren't following the priv spec.

The rationale with Priv spec allows implementations to support
32bit mode on RV64 HART so even RV64 HART running in
32bit mode can't use more than 32 local interrupts.

This means we have a hard limit of 32 local interrupts in the
Priv spec for both RV32 and RV64. The lower 13 interrupts
are already standardized by Priv spec but we need to support
good amount of per-HART local interrupts for future needs
hence the AIA spec mandates minimum 64 local interrupts.

Look at it this way, implementations which need future ready
local interrupt support will implement AIA style local interrupts
and implementations which don't can reduce hardware cost
by staying with only XLEN local interrupts.

The AIA style local interrupts are already approved by Andrew,
Greg, and other folks because everyone accepts the local interrupt
limitations of current Priv spec.

>
> > 2) Indirect CSRs to access local interrupt priorities
> > 3) Interrupt filtering CSRs
> > 4) IMSIC support CSRs
>
> New AIA CSRs are fine, it's just core changes that are more of a worry.

Backward compatibility is a key requirement for RISC-V AIA
and if you see this patch we keep the original Priv style
local interrupts as-is with minor improvements.

Regards,
Anup

>
> Alistair
>
> >
> > From above #3 is totally optional and not implemented by this
> > patch whereas #4 is only required when platform has RISC-V IMSIC.
> >
> > A platform can skip all four changes mentioned above, if the
> > platform only wants AIA APLIC to manage wired interrupts.
> >
> > Regards,
> > Anup


^ permalink raw reply	[flat|nested] 34+ messages in thread

end of thread, other threads:[~2021-06-15 12:50 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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 ` [PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs Anup Patel
2021-05-14 14:32   ` 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

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.