Skip to content

Commit 1697837

Browse files
rajnesh-kanwalalistair23
authored andcommitted
target/riscv: Add M-mode virtual interrupt and IRQ filtering support.
This change adds support for inserting virtual interrupts from M-mode into S-mode using mvien and mvip csrs. IRQ filtering is a use case of this change, i-e M-mode can stop delegating an interrupt to S-mode and instead enable it in MIE and receive those interrupts in M-mode and then selectively inject the interrupt using mvien and mvip. Also, the spec doesn't mandate the interrupt to be actually supported in hardware. Which allows M-mode to assert virtual interrupts to S-mode that have no connection to any real interrupt events. This is defined as part of the AIA specification [0], "5.3 Interrupt filtering and virtual interrupts for supervisor level". [0]: https://github.com/riscv/riscv-aia/releases/download/1.0/riscv-interrupts-1.0.pdf Signed-off-by: Rajnesh Kanwal <[email protected]> Reviewed-by: Daniel Henrique Barboza <[email protected]> Message-ID: <[email protected]> Signed-off-by: Alistair Francis <[email protected]>
1 parent 1ebad50 commit 1697837

File tree

6 files changed

+291
-38
lines changed

6 files changed

+291
-38
lines changed

target/riscv/cpu.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -813,7 +813,8 @@ static bool riscv_cpu_has_work(CPUState *cs)
813813
* Definition of the WFI instruction requires it to ignore the privilege
814814
* mode and delegation registers, but respect individual enables
815815
*/
816-
return riscv_cpu_all_pending(env) != 0;
816+
return riscv_cpu_all_pending(env) != 0 ||
817+
riscv_cpu_sirq_pending(env) != RISCV_EXCP_NONE;
817818
#else
818819
return true;
819820
#endif

target/riscv/cpu.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,12 @@ struct CPUArchState {
202202
uint64_t mie;
203203
uint64_t mideleg;
204204

205+
/*
206+
* When mideleg[i]=0 and mvien[i]=1, sie[i] is no more
207+
* alias of mie[i] and needs to be maintained separatly.
208+
*/
209+
uint64_t sie;
210+
205211
target_ulong satp; /* since: priv-1.10.0 */
206212
target_ulong stval;
207213
target_ulong medeleg;
@@ -222,6 +228,8 @@ struct CPUArchState {
222228
/* AIA CSRs */
223229
target_ulong miselect;
224230
target_ulong siselect;
231+
uint64_t mvien;
232+
uint64_t mvip;
225233

226234
/* Hypervisor CSRs */
227235
target_ulong hstatus;

target/riscv/cpu_bits.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,12 @@ typedef enum RISCVException {
735735
#define MIE_SSIE (1 << IRQ_S_SOFT)
736736
#define MIE_USIE (1 << IRQ_U_SOFT)
737737

738+
/* Machine constants */
739+
#define M_MODE_INTERRUPTS ((uint64_t)(MIP_MSIP | MIP_MTIP | MIP_MEIP))
740+
#define S_MODE_INTERRUPTS ((uint64_t)(MIP_SSIP | MIP_STIP | MIP_SEIP))
741+
#define VS_MODE_INTERRUPTS ((uint64_t)(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP))
742+
#define HS_MODE_INTERRUPTS ((uint64_t)(MIP_SGEIP | VS_MODE_INTERRUPTS))
743+
738744
/* General PointerMasking CSR bits */
739745
#define PM_ENABLE 0x00000001ULL
740746
#define PM_CURRENT 0x00000002ULL

target/riscv/cpu_helper.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,10 @@ static int riscv_cpu_pending_to_irq(CPURISCVState *env,
376376
return best_irq;
377377
}
378378

379+
/*
380+
* Doesn't report interrupts inserted using mvip from M-mode firmware. Those
381+
* are returned in riscv_cpu_sirq_pending().
382+
*/
379383
uint64_t riscv_cpu_all_pending(CPURISCVState *env)
380384
{
381385
uint32_t gein = get_field(env->hstatus, HSTATUS_VGEIN);
@@ -398,9 +402,10 @@ int riscv_cpu_sirq_pending(CPURISCVState *env)
398402
{
399403
uint64_t irqs = riscv_cpu_all_pending(env) & env->mideleg &
400404
~(MIP_VSSIP | MIP_VSTIP | MIP_VSEIP);
405+
uint64_t irqs_f = env->mvip & env->mvien & ~env->mideleg & env->sie;
401406

402407
return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
403-
irqs, env->siprio);
408+
irqs | irqs_f, env->siprio);
404409
}
405410

406411
int riscv_cpu_vsirq_pending(CPURISCVState *env)
@@ -414,8 +419,8 @@ int riscv_cpu_vsirq_pending(CPURISCVState *env)
414419

415420
static int riscv_cpu_local_irq_pending(CPURISCVState *env)
416421
{
422+
uint64_t irqs, pending, mie, hsie, vsie, irqs_f;
417423
int virq;
418-
uint64_t irqs, pending, mie, hsie, vsie;
419424

420425
/* Determine interrupt enable state of all privilege modes */
421426
if (env->virt_enabled) {
@@ -441,8 +446,11 @@ static int riscv_cpu_local_irq_pending(CPURISCVState *env)
441446
irqs, env->miprio);
442447
}
443448

449+
/* Check for virtual S-mode interrupts. */
450+
irqs_f = env->mvip & (env->mvien & ~env->mideleg) & env->sie;
451+
444452
/* Check HS-mode interrupts */
445-
irqs = pending & env->mideleg & ~env->hideleg & -hsie;
453+
irqs = ((pending & env->mideleg & ~env->hideleg) | irqs_f) & -hsie;
446454
if (irqs) {
447455
return riscv_cpu_pending_to_irq(env, IRQ_S_EXT, IPRIO_DEFAULT_S,
448456
irqs, env->siprio);
@@ -622,19 +630,21 @@ int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint64_t interrupts)
622630

623631
void riscv_cpu_interrupt(CPURISCVState *env)
624632
{
625-
uint64_t gein, vsgein = 0, vstip = 0;
633+
uint64_t gein, vsgein = 0, vstip = 0, irqf = 0;
626634
CPUState *cs = env_cpu(env);
627635

628636
QEMU_IOTHREAD_LOCK_GUARD();
629637

630638
if (env->virt_enabled) {
631639
gein = get_field(env->hstatus, HSTATUS_VGEIN);
632640
vsgein = (env->hgeip & (1ULL << gein)) ? MIP_VSEIP : 0;
641+
} else {
642+
irqf = env->mvien & env->mvip & env->sie;
633643
}
634644

635645
vstip = env->vstime_irq ? MIP_VSTIP : 0;
636646

637-
if (env->mip | vsgein | vstip) {
647+
if (env->mip | vsgein | vstip | irqf) {
638648
cpu_interrupt(cs, CPU_INTERRUPT_HARD);
639649
} else {
640650
cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
@@ -1611,6 +1621,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
16111621
bool async = !!(cs->exception_index & RISCV_EXCP_INT_FLAG);
16121622
target_ulong cause = cs->exception_index & RISCV_EXCP_INT_MASK;
16131623
uint64_t deleg = async ? env->mideleg : env->medeleg;
1624+
bool s_injected = env->mvip & (1 << cause) & env->mvien &&
1625+
!(env->mip & (1 << cause));
16141626
target_ulong tval = 0;
16151627
target_ulong tinst = 0;
16161628
target_ulong htval = 0;
@@ -1699,8 +1711,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
16991711
__func__, env->mhartid, async, cause, env->pc, tval,
17001712
riscv_cpu_get_trap_name(cause, async));
17011713

1702-
if (env->priv <= PRV_S &&
1703-
cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
1714+
if (env->priv <= PRV_S && cause < 64 &&
1715+
(((deleg >> cause) & 1) || s_injected)) {
17041716
/* handle the trap in S-mode */
17051717
if (riscv_has_ext(env, RVH)) {
17061718
uint64_t hdeleg = async ? env->hideleg : env->hedeleg;

0 commit comments

Comments
 (0)