#include "qemu/osdep.h"
#include "qemu/log.h"
+#include "qemu/module.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
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]);
} else if (addr >= plic->pending_base && /* 1 bit per source */
addr < plic->pending_base + (plic->num_sources >> 3))
{
- uint32_t word = (addr - plic->priority_base) >> 2;
+ uint32_t word = (addr - plic->pending_base) >> 2;
if (RISCV_DEBUG_PLIC) {
qemu_log("plic: read pending: word=%d value=%d\n",
word, plic->pending[word]);
}
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;
}
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",
} 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)
}
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 = {
p = plic->hart_config;
while ((c = *p++)) {
if (c == ',') {
- addrid += __builtin_popcount(modes);
+ addrid += ctpop8(modes);
modes = 0;
hartid++;
} else {
}
}
if (modes) {
- addrid += __builtin_popcount(modes);
+ addrid += ctpop8(modes);
}
hartid++;
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);
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)