aboutsummaryrefslogtreecommitdiff
path: root/target/riscv
diff options
context:
space:
mode:
authorAlistair Francis <alistair.francis@wdc.com>2022-03-17 16:18:17 +1000
committerAlistair Francis <alistair.francis@wdc.com>2022-04-22 10:35:16 +1000
commit33fe584f7026bfaa13bb8a943f85c879e06bbdc6 (patch)
tree7faea1a6b23444c9a72a726da833cd251d4f994a /target/riscv
parent8b5c807bc07f8def162cbe7689eb1da4e80186ad (diff)
target/riscv: Allow software access to MIP SEIP
The RISC-V specification states that: "Supervisor-level external interrupts are made pending based on the logical-OR of the software-writable SEIP bit and the signal from the external interrupt controller." We currently only allow either the interrupt controller or software to set the bit, which is incorrect. This patch removes the miclaim mask when writing MIP to allow M-mode software to inject interrupts, even with an interrupt controller. We then also need to keep track of which source is setting MIP_SEIP. The final value is a OR of both, so we add two bools and use that to keep track of the current state. This way either source can change without losing the correct value. Resolves: https://gitlab.com/qemu-project/qemu/-/issues/904 Signed-off-by: Alistair Francis <alistair.francis@wdc.com> Reviewed-by: Bin Meng <bmeng.cn@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-Id: <20220317061817.3856850-3-alistair.francis@opensource.wdc.com>
Diffstat (limited to 'target/riscv')
-rw-r--r--target/riscv/cpu.c10
-rw-r--r--target/riscv/cpu.h8
-rw-r--r--target/riscv/csr.c8
3 files changed, 23 insertions, 3 deletions
diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c
index 78fc7b22ed..cfdfe787de 100644
--- a/target/riscv/cpu.c
+++ b/target/riscv/cpu.c
@@ -708,7 +708,6 @@ static void riscv_cpu_set_irq(void *opaque, int irq, int level)
case IRQ_VS_TIMER:
case IRQ_M_TIMER:
case IRQ_U_EXT:
- case IRQ_S_EXT:
case IRQ_VS_EXT:
case IRQ_M_EXT:
if (kvm_enabled()) {
@@ -717,6 +716,15 @@ static void riscv_cpu_set_irq(void *opaque, int irq, int level)
riscv_cpu_update_mip(cpu, 1 << irq, BOOL_TO_MASK(level));
}
break;
+ case IRQ_S_EXT:
+ if (kvm_enabled()) {
+ kvm_riscv_set_irq(cpu, irq, level);
+ } else {
+ env->external_seip = level;
+ riscv_cpu_update_mip(cpu, 1 << irq,
+ BOOL_TO_MASK(level | env->software_seip));
+ }
+ break;
default:
g_assert_not_reached();
}
diff --git a/target/riscv/cpu.h b/target/riscv/cpu.h
index e129c3da7d..b90ca8268e 100644
--- a/target/riscv/cpu.h
+++ b/target/riscv/cpu.h
@@ -177,6 +177,14 @@ struct CPUArchState {
uint64_t mstatus;
uint64_t mip;
+ /*
+ * MIP contains the software writable version of SEIP ORed with the
+ * external interrupt value. The MIP register is always up-to-date.
+ * To keep track of the current source, we also save booleans of the values
+ * here.
+ */
+ bool external_seip;
+ bool software_seip;
uint64_t miclaim;
diff --git a/target/riscv/csr.c b/target/riscv/csr.c
index 8b6a1b90f1..a09126a011 100644
--- a/target/riscv/csr.c
+++ b/target/riscv/csr.c
@@ -1498,10 +1498,14 @@ static RISCVException rmw_mip64(CPURISCVState *env, int csrno,
uint64_t new_val, uint64_t wr_mask)
{
RISCVCPU *cpu = env_archcpu(env);
- /* Allow software control of delegable interrupts not claimed by hardware */
- uint64_t old_mip, mask = wr_mask & delegable_ints & ~env->miclaim;
+ uint64_t old_mip, mask = wr_mask & delegable_ints;
uint32_t gin;
+ if (mask & MIP_SEIP) {
+ env->software_seip = new_val & MIP_SEIP;
+ new_val |= env->external_seip * MIP_SEIP;
+ }
+
if (mask) {
old_mip = riscv_cpu_update_mip(cpu, mask, (new_val & mask));
} else {