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
This commit is contained in:
Michael Clark 2019-03-19 23:47:35 -04:00 committed by Lioncash
parent a4f2dcde28
commit 2e0c040062
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
6 changed files with 18 additions and 8 deletions

View file

@ -5467,6 +5467,7 @@ riscv_symbols = (
'pmpaddr_csr_write', 'pmpaddr_csr_write',
'pmpcfg_csr_read', 'pmpcfg_csr_read',
'pmpcfg_csr_write', 'pmpcfg_csr_write',
'riscv_cpu_claim_interrupts',
'riscv_cpu_do_interrupt', 'riscv_cpu_do_interrupt',
'riscv_cpu_do_unaligned_access', 'riscv_cpu_do_unaligned_access',
'riscv_cpu_exec_interrupt', 'riscv_cpu_exec_interrupt',

View file

@ -3388,6 +3388,7 @@
#define pmpaddr_csr_write pmpaddr_csr_write_riscv32 #define pmpaddr_csr_write pmpaddr_csr_write_riscv32
#define pmpcfg_csr_read pmpcfg_csr_read_riscv32 #define pmpcfg_csr_read pmpcfg_csr_read_riscv32
#define pmpcfg_csr_write pmpcfg_csr_write_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_interrupt riscv_cpu_do_interrupt_riscv32
#define riscv_cpu_do_unaligned_access riscv_cpu_do_unaligned_access_riscv32 #define riscv_cpu_do_unaligned_access riscv_cpu_do_unaligned_access_riscv32
#define riscv_cpu_exec_interrupt riscv_cpu_exec_interrupt_riscv32 #define riscv_cpu_exec_interrupt riscv_cpu_exec_interrupt_riscv32

View file

@ -3388,6 +3388,7 @@
#define pmpaddr_csr_write pmpaddr_csr_write_riscv64 #define pmpaddr_csr_write pmpaddr_csr_write_riscv64
#define pmpcfg_csr_read pmpcfg_csr_read_riscv64 #define pmpcfg_csr_read pmpcfg_csr_read_riscv64
#define pmpcfg_csr_write pmpcfg_csr_write_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_interrupt riscv_cpu_do_interrupt_riscv64
#define riscv_cpu_do_unaligned_access riscv_cpu_do_unaligned_access_riscv64 #define riscv_cpu_do_unaligned_access riscv_cpu_do_unaligned_access_riscv64
#define riscv_cpu_exec_interrupt riscv_cpu_exec_interrupt_riscv64 #define riscv_cpu_exec_interrupt riscv_cpu_exec_interrupt_riscv64

View file

@ -142,6 +142,7 @@ struct CPURISCVState {
* mip is 32-bits to allow atomic_read on 32-bit hosts. * mip is 32-bits to allow atomic_read on 32-bit hosts.
*/ */
uint32_t mip; uint32_t mip;
uint32_t miclaim;
target_ulong mie; target_ulong mie;
target_ulong mideleg; 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 #define cpu_mmu_index riscv_cpu_mmu_index
#ifndef CONFIG_USER_ONLY #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); 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 */ #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
#endif #endif

View file

@ -72,6 +72,17 @@ bool riscv_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
#if !defined(CONFIG_USER_ONLY) #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 */ /* iothread_mutex must be held */
uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value) uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
{ {

View file

@ -557,16 +557,10 @@ static int rmw_mip(CPURISCVState *env, int csrno, target_ulong *ret_value,
target_ulong new_value, target_ulong write_mask) target_ulong new_value, target_ulong write_mask)
{ {
RISCVCPU *cpu = riscv_env_get_cpu(env); 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; 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) { if (mask) {
// Unicorn: commented out // Unicorn: commented out
//qemu_mutex_lock_iothread(); //qemu_mutex_lock_iothread();