[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 1/2] hw/riscv: plic: Fix highest IRQ source slot
From: |
Emmanuel Blot |
Subject: |
[PATCH 1/2] hw/riscv: plic: Fix highest IRQ source slot |
Date: |
Tue, 3 Nov 2020 16:29:18 +0100 |
PLIC IRQ 0 is defined as non-existent (special case to signal no interrupt).
As PLIC IRQ arrays and bitfields are defined for N = num_sources channels but
indexed from 1..N and not 0..N-1, N+1 slots should be allocated.
Fix the fix source_priority buffer overflows and the last IRQ slot handling
that was discarded.
Signed-off-by: Emmanuel Blot <emmanuel.blot@sifive.com>
---
hw/intc/sifive_plic.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/hw/intc/sifive_plic.c b/hw/intc/sifive_plic.c
index f42fd695d8..e2e3d0b4c8 100644
--- a/hw/intc/sifive_plic.c
+++ b/hw/intc/sifive_plic.c
@@ -178,6 +178,9 @@ static uint32_t sifive_plic_claim(SiFivePLICState *plic,
uint32_t addrid)
}
for (j = 0; j < 32; j++) {
int irq = (i << 5) + j;
+ if (irq > plic->num_sources) {
+ break;
+ }
uint32_t prio = plic->source_priority[irq];
int enabled = pending_enabled_not_claimed & (1 << j);
if (enabled && prio > max_prio) {
@@ -213,7 +216,7 @@ static uint64_t sifive_plic_read(void *opaque, hwaddr addr,
unsigned size)
}
return plic->source_priority[irq];
} else if (addr >= plic->pending_base && /* 1 bit per source */
- addr < plic->pending_base + (plic->num_sources >> 3))
+ addr < plic->pending_base + ((plic->num_sources + 1) >> 3))
{
uint32_t word = (addr - plic->pending_base) >> 2;
if (RISCV_DEBUG_PLIC) {
@@ -290,7 +293,7 @@ static void sifive_plic_write(void *opaque, hwaddr addr,
uint64_t value,
sifive_plic_update(plic);
return;
} else if (addr >= plic->pending_base && /* 1 bit per source */
- addr < plic->pending_base + (plic->num_sources >> 3))
+ addr < plic->pending_base + ((plic->num_sources + 1) >> 3))
{
qemu_log_mask(LOG_GUEST_ERROR,
"%s: invalid pending write: 0x%" HWADDR_PRIx "",
@@ -335,7 +338,7 @@ static void sifive_plic_write(void *opaque, hwaddr addr,
uint64_t value,
mode_to_char(plic->addr_config[addrid].mode),
(uint32_t)value);
}
- if (value < plic->num_sources) {
+ if (value && value < (plic->num_sources + 1)) {
sifive_plic_set_claimed(plic, value, false);
sifive_plic_update(plic);
}
@@ -447,14 +450,14 @@ static void sifive_plic_realize(DeviceState *dev, Error
**errp)
memory_region_init_io(&plic->mmio, OBJECT(dev), &sifive_plic_ops, plic,
TYPE_SIFIVE_PLIC, plic->aperture_size);
parse_hart_config(plic);
- plic->bitfield_words = (plic->num_sources + 31) >> 5;
- plic->source_priority = g_new0(uint32_t, plic->num_sources);
+ plic->bitfield_words = (plic->num_sources + 1 + 31) >> 5;
+ plic->source_priority = g_new0(uint32_t, plic->num_sources + 1);
plic->target_priority = g_new(uint32_t, plic->num_addrs);
plic->pending = g_new0(uint32_t, plic->bitfield_words);
plic->claimed = g_new0(uint32_t, plic->bitfield_words);
plic->enable = g_new0(uint32_t, plic->bitfield_words * plic->num_addrs);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &plic->mmio);
- qdev_init_gpio_in(dev, sifive_plic_irq_request, plic->num_sources);
+ qdev_init_gpio_in(dev, sifive_plic_irq_request, plic->num_sources + 1);
/* 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
--
2.28.0