diff options
Diffstat (limited to 'hw/riscv/sifive_plic.c')
| -rw-r--r-- | hw/riscv/sifive_plic.c | 38 |
1 files changed, 31 insertions, 7 deletions
diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index d12ec3fc9a..07a032d93d 100644 --- a/hw/riscv/sifive_plic.c +++ b/hw/riscv/sifive_plic.c @@ -22,7 +22,9 @@ #include "qemu/log.h" #include "qemu/error-report.h" #include "hw/sysbus.h" +#include "hw/pci/msi.h" #include "target/riscv/cpu.h" +#include "sysemu/sysemu.h" #include "hw/riscv/sifive_plic.h" #define RISCV_DEBUG_PLIC 0 @@ -205,7 +207,7 @@ static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size) if (addr >= plic->priority_base && /* 4 bytes per source */ addr < plic->priority_base + (plic->num_sources << 2)) { - uint32_t irq = (addr - plic->priority_base) >> 2; + uint32_t irq = ((addr - plic->priority_base) >> 2) + 1; if (RISCV_DEBUG_PLIC) { qemu_log("plic: read priority: irq=%d priority=%d\n", irq, plic->source_priority[irq]); @@ -261,7 +263,9 @@ static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size) } err: - error_report("plic: invalid register read: %08x", (uint32_t)addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid register read 0x%" HWADDR_PRIx "\n", + __func__, addr); return 0; } @@ -278,7 +282,7 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value, if (addr >= plic->priority_base && /* 4 bytes per source */ addr < plic->priority_base + (plic->num_sources << 2)) { - uint32_t irq = (addr - plic->priority_base) >> 2; + uint32_t irq = ((addr - plic->priority_base) >> 2) + 1; plic->source_priority[irq] = value & 7; if (RISCV_DEBUG_PLIC) { qemu_log("plic: write priority: irq=%d priority=%d\n", @@ -288,7 +292,9 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value, } else if (addr >= plic->pending_base && /* 1 bit per source */ addr < plic->pending_base + (plic->num_sources >> 3)) { - error_report("plic: invalid pending write: %08x", (uint32_t)addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid pending write: 0x%" HWADDR_PRIx "", + __func__, addr); return; } else if (addr >= plic->enable_base && /* 1 bit per source */ addr < plic->enable_base + plic->num_addrs * plic->enable_stride) @@ -338,7 +344,9 @@ static void sifive_plic_write(void *opaque, hwaddr addr, uint64_t value, } err: - error_report("plic: invalid register write: %08x", (uint32_t)addr); + qemu_log_mask(LOG_GUEST_ERROR, + "%s: Invalid register write 0x%" HWADDR_PRIx "\n", + __func__, addr); } static const MemoryRegionOps sifive_plic_ops = { @@ -383,7 +391,7 @@ static void parse_hart_config(SiFivePLICState *plic) p = plic->hart_config; while ((c = *p++)) { if (c == ',') { - addrid += __builtin_popcount(modes); + addrid += ctpop8(modes); modes = 0; hartid++; } else { @@ -397,7 +405,7 @@ static void parse_hart_config(SiFivePLICState *plic) } } if (modes) { - addrid += __builtin_popcount(modes); + addrid += ctpop8(modes); } hartid++; @@ -431,6 +439,7 @@ static void sifive_plic_irq_request(void *opaque, int irq, int level) static void sifive_plic_realize(DeviceState *dev, Error **errp) { SiFivePLICState *plic = SIFIVE_PLIC(dev); + int i; memory_region_init_io(&plic->mmio, OBJECT(dev), &sifive_plic_ops, plic, TYPE_SIFIVE_PLIC, plic->aperture_size); @@ -443,6 +452,21 @@ static void sifive_plic_realize(DeviceState *dev, Error **errp) 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); + + /* 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. + */ + for (i = 0; i < smp_cpus; i++) { + RISCVCPU *cpu = RISCV_CPU(qemu_get_cpu(i)); + if (riscv_cpu_claim_interrupts(cpu, MIP_SEIP) < 0) { + error_report("SEIP already claimed"); + exit(1); + } + } + + msi_nonbroken = true; } static void sifive_plic_class_init(ObjectClass *klass, void *data) |