[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs
From: |
Anup Patel |
Subject: |
[PATCH 3/4] target/riscv: Implement AIA local interrupt CSRs |
Date: |
Fri, 14 May 2021 20:02:41 +0530 |
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