qemu-riscv
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]