From 2e0c0400625fa6bdaef377e7b7684ac0a0aadee2 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Tue, 19 Mar 2019 23:47:35 -0400 Subject: [PATCH] RISC-V: Allow interrupt controllers to claim interrupts We can't allow the supervisor to control SEIP as this would allow the supervisor to clear a pending external interrupt which will result in lost a interrupt in the case a PLIC is attached. The SEIP bit must be hardware controlled when a PLIC is attached. This logic was previously hard-coded so SEIP was always masked even if no PLIC was attached. This patch adds riscv_cpu_claim_interrupts so that the PLIC can register control of SEIP. In the case of models without a PLIC (spike), the SEIP bit remains software controlled. This interface allows for hardware control of supervisor timer and software interrupts by other interrupt controller models. Backports commit e3e7039cc24ecf47d81c091e8bb04552d6564ad8 from qemu --- qemu/header_gen.py | 1 + qemu/riscv32.h | 1 + qemu/riscv64.h | 1 + qemu/target/riscv/cpu.h | 2 ++ qemu/target/riscv/cpu_helper.c | 11 +++++++++++ qemu/target/riscv/csr.c | 10 ++-------- 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/qemu/header_gen.py b/qemu/header_gen.py index cc106996..a6246ecf 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -5467,6 +5467,7 @@ riscv_symbols = ( 'pmpaddr_csr_write', 'pmpcfg_csr_read', 'pmpcfg_csr_write', + 'riscv_cpu_claim_interrupts', 'riscv_cpu_do_interrupt', 'riscv_cpu_do_unaligned_access', 'riscv_cpu_exec_interrupt', diff --git a/qemu/riscv32.h b/qemu/riscv32.h index bb203163..01e1b951 100644 --- a/qemu/riscv32.h +++ b/qemu/riscv32.h @@ -3388,6 +3388,7 @@ #define pmpaddr_csr_write pmpaddr_csr_write_riscv32 #define pmpcfg_csr_read pmpcfg_csr_read_riscv32 #define pmpcfg_csr_write pmpcfg_csr_write_riscv32 +#define riscv_cpu_claim_interrupts riscv_cpu_claim_interrupts_riscv32 #define riscv_cpu_do_interrupt riscv_cpu_do_interrupt_riscv32 #define riscv_cpu_do_unaligned_access riscv_cpu_do_unaligned_access_riscv32 #define riscv_cpu_exec_interrupt riscv_cpu_exec_interrupt_riscv32 diff --git a/qemu/riscv64.h b/qemu/riscv64.h index 4245fa30..27530506 100644 --- a/qemu/riscv64.h +++ b/qemu/riscv64.h @@ -3388,6 +3388,7 @@ #define pmpaddr_csr_write pmpaddr_csr_write_riscv64 #define pmpcfg_csr_read pmpcfg_csr_read_riscv64 #define pmpcfg_csr_write pmpcfg_csr_write_riscv64 +#define riscv_cpu_claim_interrupts riscv_cpu_claim_interrupts_riscv64 #define riscv_cpu_do_interrupt riscv_cpu_do_interrupt_riscv64 #define riscv_cpu_do_unaligned_access riscv_cpu_do_unaligned_access_riscv64 #define riscv_cpu_exec_interrupt riscv_cpu_exec_interrupt_riscv64 diff --git a/qemu/target/riscv/cpu.h b/qemu/target/riscv/cpu.h index ddc2d54f..45a3721f 100644 --- a/qemu/target/riscv/cpu.h +++ b/qemu/target/riscv/cpu.h @@ -142,6 +142,7 @@ struct CPURISCVState { * mip is 32-bits to allow atomic_read on 32-bit hosts. */ uint32_t mip; + uint32_t miclaim; target_ulong mie; target_ulong mideleg; @@ -271,6 +272,7 @@ void riscv_cpu_list(FILE *f, fprintf_function cpu_fprintf); #define cpu_mmu_index riscv_cpu_mmu_index #ifndef CONFIG_USER_ONLY +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value); #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ #endif diff --git a/qemu/target/riscv/cpu_helper.c b/qemu/target/riscv/cpu_helper.c index d86de54a..d4fb93fc 100644 --- a/qemu/target/riscv/cpu_helper.c +++ b/qemu/target/riscv/cpu_helper.c @@ -72,6 +72,17 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request) #if !defined(CONFIG_USER_ONLY) +int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts) +{ + CPURISCVState *env = &cpu->env; + if (env->miclaim & interrupts) { + return -1; + } else { + env->miclaim |= interrupts; + return 0; + } +} + /* iothread_mutex must be held */ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) { diff --git a/qemu/target/riscv/csr.c b/qemu/target/riscv/csr.c index dd5c0124..d7048631 100644 --- a/qemu/target/riscv/csr.c +++ b/qemu/target/riscv/csr.c @@ -557,16 +557,10 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value, target_ulong new_value, target_ulong write_mask) { RISCVCPU *cpu = riscv_env_get_cpu(env); - target_ulong mask = write_mask & delegable_ints; + /* Allow software control of delegable interrupts not claimed by hardware */ + target_ulong mask = write_mask & delegable_ints & ~env->miclaim; uint32_t old_mip; - /* We can't allow the supervisor to control SEIP as this would allow the - * supervisor to clear a pending external interrupt which will result in - * lost a interrupt in the case a PLIC is attached. The SEIP bit must be - * hardware controlled when a PLIC is attached. This should be an option - * for CPUs with software-delegated Supervisor External Interrupts. */ - mask &= ~MIP_SEIP; - if (mask) { // Unicorn: commented out //qemu_mutex_lock_iothread();