hw/riscv: virt: Add optional AIA APLIC support to virt machine

We extend virt machine to emulate AIA APLIC devices only when
"aia=aplic" parameter is passed along with machine name in QEMU
command-line. When "aia=none" or not specified then we fallback
to original PLIC device emulation.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Signed-off-by: Anup Patel <anup@brainfault.org>
Reviewed-by: Alistair Francis <alistair.francis@wdc.com>
Message-Id: <20220220085526.808674-2-anup@brainfault.org>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Anup Patel 2022-02-20 14:25:22 +05:30 committed by Alistair Francis
parent 90f9e35b78
commit e6faee6585
3 changed files with 259 additions and 59 deletions

View File

@ -42,6 +42,7 @@ config RISCV_VIRT
select PFLASH_CFI01 select PFLASH_CFI01
select SERIAL select SERIAL
select RISCV_ACLINT select RISCV_ACLINT
select RISCV_APLIC
select SIFIVE_PLIC select SIFIVE_PLIC
select SIFIVE_TEST select SIFIVE_TEST
select VIRTIO_MMIO select VIRTIO_MMIO

View File

@ -33,6 +33,7 @@
#include "hw/riscv/boot.h" #include "hw/riscv/boot.h"
#include "hw/riscv/numa.h" #include "hw/riscv/numa.h"
#include "hw/intc/riscv_aclint.h" #include "hw/intc/riscv_aclint.h"
#include "hw/intc/riscv_aplic.h"
#include "hw/intc/sifive_plic.h" #include "hw/intc/sifive_plic.h"
#include "hw/misc/sifive_test.h" #include "hw/misc/sifive_test.h"
#include "chardev/char.h" #include "chardev/char.h"
@ -52,6 +53,8 @@ static const MemMapEntry virt_memmap[] = {
[VIRT_ACLINT_SSWI] = { 0x2F00000, 0x4000 }, [VIRT_ACLINT_SSWI] = { 0x2F00000, 0x4000 },
[VIRT_PCIE_PIO] = { 0x3000000, 0x10000 }, [VIRT_PCIE_PIO] = { 0x3000000, 0x10000 },
[VIRT_PLIC] = { 0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) }, [VIRT_PLIC] = { 0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) },
[VIRT_APLIC_M] = { 0xc000000, APLIC_SIZE(VIRT_CPUS_MAX) },
[VIRT_APLIC_S] = { 0xd000000, APLIC_SIZE(VIRT_CPUS_MAX) },
[VIRT_UART0] = { 0x10000000, 0x100 }, [VIRT_UART0] = { 0x10000000, 0x100 },
[VIRT_VIRTIO] = { 0x10001000, 0x1000 }, [VIRT_VIRTIO] = { 0x10001000, 0x1000 },
[VIRT_FW_CFG] = { 0x10100000, 0x18 }, [VIRT_FW_CFG] = { 0x10100000, 0x18 },
@ -133,12 +136,13 @@ static void virt_flash_map(RISCVVirtState *s,
sysmem); sysmem);
} }
static void create_pcie_irq_map(void *fdt, char *nodename, static void create_pcie_irq_map(RISCVVirtState *s, void *fdt, char *nodename,
uint32_t plic_phandle) uint32_t irqchip_phandle)
{ {
int pin, dev; int pin, dev;
uint32_t uint32_t irq_map_stride = 0;
full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * FDT_INT_MAP_WIDTH] = {}; uint32_t full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS *
FDT_MAX_INT_MAP_WIDTH] = {};
uint32_t *irq_map = full_irq_map; uint32_t *irq_map = full_irq_map;
/* This code creates a standard swizzle of interrupts such that /* This code creates a standard swizzle of interrupts such that
@ -156,23 +160,31 @@ static void create_pcie_irq_map(void *fdt, char *nodename,
int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS);
int i = 0; int i = 0;
/* Fill PCI address cells */
irq_map[i] = cpu_to_be32(devfn << 8); irq_map[i] = cpu_to_be32(devfn << 8);
i += FDT_PCI_ADDR_CELLS; i += FDT_PCI_ADDR_CELLS;
/* Fill PCI Interrupt cells */
irq_map[i] = cpu_to_be32(pin + 1); irq_map[i] = cpu_to_be32(pin + 1);
i += FDT_PCI_INT_CELLS; i += FDT_PCI_INT_CELLS;
irq_map[i++] = cpu_to_be32(plic_phandle);
i += FDT_PLIC_ADDR_CELLS; /* Fill interrupt controller phandle and cells */
irq_map[i] = cpu_to_be32(irq_nr); irq_map[i++] = cpu_to_be32(irqchip_phandle);
irq_map[i++] = cpu_to_be32(irq_nr);
if (s->aia_type != VIRT_AIA_TYPE_NONE) {
irq_map[i++] = cpu_to_be32(0x4);
}
irq_map += FDT_INT_MAP_WIDTH; if (!irq_map_stride) {
irq_map_stride = i;
}
irq_map += irq_map_stride;
} }
} }
qemu_fdt_setprop(fdt, nodename, "interrupt-map", qemu_fdt_setprop(fdt, nodename, "interrupt-map", full_irq_map,
full_irq_map, sizeof(full_irq_map)); GPEX_NUM_IRQS * GPEX_NUM_IRQS *
irq_map_stride * sizeof(uint32_t));
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask",
0x1800, 0, 0, 0x7); 0x1800, 0, 0, 0x7);
@ -404,8 +416,6 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket); plic_addr = memmap[VIRT_PLIC].base + (memmap[VIRT_PLIC].size * socket);
plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr); plic_name = g_strdup_printf("/soc/plic@%lx", plic_addr);
qemu_fdt_add_subnode(mc->fdt, plic_name); qemu_fdt_add_subnode(mc->fdt, plic_name);
qemu_fdt_setprop_cell(mc->fdt, plic_name,
"#address-cells", FDT_PLIC_ADDR_CELLS);
qemu_fdt_setprop_cell(mc->fdt, plic_name, qemu_fdt_setprop_cell(mc->fdt, plic_name,
"#interrupt-cells", FDT_PLIC_INT_CELLS); "#interrupt-cells", FDT_PLIC_INT_CELLS);
qemu_fdt_setprop_string_array(mc->fdt, plic_name, "compatible", qemu_fdt_setprop_string_array(mc->fdt, plic_name, "compatible",
@ -425,6 +435,76 @@ static void create_fdt_socket_plic(RISCVVirtState *s,
g_free(plic_cells); g_free(plic_cells);
} }
static void create_fdt_socket_aia(RISCVVirtState *s,
const MemMapEntry *memmap, int socket,
uint32_t *phandle, uint32_t *intc_phandles,
uint32_t *aplic_phandles)
{
int cpu;
char *aplic_name;
uint32_t *aplic_cells;
unsigned long aplic_addr;
MachineState *mc = MACHINE(s);
uint32_t aplic_m_phandle, aplic_s_phandle;
aplic_m_phandle = (*phandle)++;
aplic_s_phandle = (*phandle)++;
aplic_cells = g_new0(uint32_t, s->soc[socket].num_harts * 2);
/* M-level APLIC node */
for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
aplic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_M_EXT);
}
aplic_addr = memmap[VIRT_APLIC_M].base +
(memmap[VIRT_APLIC_M].size * socket);
aplic_name = g_strdup_printf("/soc/aplic@%lx", aplic_addr);
qemu_fdt_add_subnode(mc->fdt, aplic_name);
qemu_fdt_setprop_string(mc->fdt, aplic_name, "compatible", "riscv,aplic");
qemu_fdt_setprop_cell(mc->fdt, aplic_name,
"#interrupt-cells", FDT_APLIC_INT_CELLS);
qemu_fdt_setprop(mc->fdt, aplic_name, "interrupt-controller", NULL, 0);
qemu_fdt_setprop(mc->fdt, aplic_name, "interrupts-extended",
aplic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 2);
qemu_fdt_setprop_cells(mc->fdt, aplic_name, "reg",
0x0, aplic_addr, 0x0, memmap[VIRT_APLIC_M].size);
qemu_fdt_setprop_cell(mc->fdt, aplic_name, "riscv,num-sources",
VIRT_IRQCHIP_NUM_SOURCES);
qemu_fdt_setprop_cell(mc->fdt, aplic_name, "riscv,children",
aplic_s_phandle);
qemu_fdt_setprop_cells(mc->fdt, aplic_name, "riscv,delegate",
aplic_s_phandle, 0x1, VIRT_IRQCHIP_NUM_SOURCES);
riscv_socket_fdt_write_id(mc, mc->fdt, aplic_name, socket);
qemu_fdt_setprop_cell(mc->fdt, aplic_name, "phandle", aplic_m_phandle);
g_free(aplic_name);
/* S-level APLIC node */
for (cpu = 0; cpu < s->soc[socket].num_harts; cpu++) {
aplic_cells[cpu * 2 + 0] = cpu_to_be32(intc_phandles[cpu]);
aplic_cells[cpu * 2 + 1] = cpu_to_be32(IRQ_S_EXT);
}
aplic_addr = memmap[VIRT_APLIC_S].base +
(memmap[VIRT_APLIC_S].size * socket);
aplic_name = g_strdup_printf("/soc/aplic@%lx", aplic_addr);
qemu_fdt_add_subnode(mc->fdt, aplic_name);
qemu_fdt_setprop_string(mc->fdt, aplic_name, "compatible", "riscv,aplic");
qemu_fdt_setprop_cell(mc->fdt, aplic_name,
"#interrupt-cells", FDT_APLIC_INT_CELLS);
qemu_fdt_setprop(mc->fdt, aplic_name, "interrupt-controller", NULL, 0);
qemu_fdt_setprop(mc->fdt, aplic_name, "interrupts-extended",
aplic_cells, s->soc[socket].num_harts * sizeof(uint32_t) * 2);
qemu_fdt_setprop_cells(mc->fdt, aplic_name, "reg",
0x0, aplic_addr, 0x0, memmap[VIRT_APLIC_S].size);
qemu_fdt_setprop_cell(mc->fdt, aplic_name, "riscv,num-sources",
VIRT_IRQCHIP_NUM_SOURCES);
riscv_socket_fdt_write_id(mc, mc->fdt, aplic_name, socket);
qemu_fdt_setprop_cell(mc->fdt, aplic_name, "phandle", aplic_s_phandle);
g_free(aplic_name);
g_free(aplic_cells);
aplic_phandles[socket] = aplic_s_phandle;
}
static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
bool is_32_bit, uint32_t *phandle, bool is_32_bit, uint32_t *phandle,
uint32_t *irq_mmio_phandle, uint32_t *irq_mmio_phandle,
@ -463,8 +543,13 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap,
} }
} }
if (s->aia_type == VIRT_AIA_TYPE_NONE) {
create_fdt_socket_plic(s, memmap, socket, phandle, create_fdt_socket_plic(s, memmap, socket, phandle,
intc_phandles, xplic_phandles); intc_phandles, xplic_phandles);
} else {
create_fdt_socket_aia(s, memmap, socket, phandle,
intc_phandles, xplic_phandles);
}
g_free(intc_phandles); g_free(intc_phandles);
g_free(clust_name); g_free(clust_name);
@ -505,7 +590,13 @@ static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap,
0x0, memmap[VIRT_VIRTIO].size); 0x0, memmap[VIRT_VIRTIO].size);
qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
irq_virtio_phandle); irq_virtio_phandle);
qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", VIRTIO_IRQ + i); if (s->aia_type == VIRT_AIA_TYPE_NONE) {
qemu_fdt_setprop_cell(mc->fdt, name, "interrupts",
VIRTIO_IRQ + i);
} else {
qemu_fdt_setprop_cells(mc->fdt, name, "interrupts",
VIRTIO_IRQ + i, 0x4);
}
g_free(name); g_free(name);
} }
} }
@ -543,7 +634,7 @@ static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap,
2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.base,
2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size); 2, virt_high_pcie_memmap.base, 2, virt_high_pcie_memmap.size);
create_pcie_irq_map(mc->fdt, name, irq_pcie_phandle); create_pcie_irq_map(s, mc->fdt, name, irq_pcie_phandle);
g_free(name); g_free(name);
} }
@ -602,7 +693,11 @@ static void create_fdt_uart(RISCVVirtState *s, const MemMapEntry *memmap,
0x0, memmap[VIRT_UART0].size); 0x0, memmap[VIRT_UART0].size);
qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400); qemu_fdt_setprop_cell(mc->fdt, name, "clock-frequency", 3686400);
qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle); qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", irq_mmio_phandle);
if (s->aia_type == VIRT_AIA_TYPE_NONE) {
qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ); qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", UART0_IRQ);
} else {
qemu_fdt_setprop_cells(mc->fdt, name, "interrupts", UART0_IRQ, 0x4);
}
qemu_fdt_add_subnode(mc->fdt, "/chosen"); qemu_fdt_add_subnode(mc->fdt, "/chosen");
qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name); qemu_fdt_setprop_string(mc->fdt, "/chosen", "stdout-path", name);
@ -623,7 +718,11 @@ static void create_fdt_rtc(RISCVVirtState *s, const MemMapEntry *memmap,
0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size); 0x0, memmap[VIRT_RTC].base, 0x0, memmap[VIRT_RTC].size);
qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent", qemu_fdt_setprop_cell(mc->fdt, name, "interrupt-parent",
irq_mmio_phandle); irq_mmio_phandle);
if (s->aia_type == VIRT_AIA_TYPE_NONE) {
qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", RTC_IRQ); qemu_fdt_setprop_cell(mc->fdt, name, "interrupts", RTC_IRQ);
} else {
qemu_fdt_setprop_cells(mc->fdt, name, "interrupts", RTC_IRQ, 0x4);
}
g_free(name); g_free(name);
} }
@ -704,7 +803,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
hwaddr high_mmio_base, hwaddr high_mmio_base,
hwaddr high_mmio_size, hwaddr high_mmio_size,
hwaddr pio_base, hwaddr pio_base,
DeviceState *plic) DeviceState *irqchip)
{ {
DeviceState *dev; DeviceState *dev;
MemoryRegion *ecam_alias, *ecam_reg; MemoryRegion *ecam_alias, *ecam_reg;
@ -738,7 +837,7 @@ static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem,
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base);
for (i = 0; i < GPEX_NUM_IRQS; i++) { for (i = 0; i < GPEX_NUM_IRQS; i++) {
irq = qdev_get_gpio_in(plic, PCIE_IRQ + i); irq = qdev_get_gpio_in(irqchip, PCIE_IRQ + i);
sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq);
gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i); gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i);
@ -769,18 +868,75 @@ static FWCfgState *create_fw_cfg(const MachineState *mc)
return fw_cfg; return fw_cfg;
} }
static DeviceState *virt_create_plic(const MemMapEntry *memmap, int socket,
int base_hartid, int hart_count)
{
DeviceState *ret;
char *plic_hart_config;
/* Per-socket PLIC hart topology configuration string */
plic_hart_config = riscv_plic_hart_config_string(hart_count);
/* Per-socket PLIC */
ret = sifive_plic_create(
memmap[VIRT_PLIC].base + socket * memmap[VIRT_PLIC].size,
plic_hart_config, hart_count, base_hartid,
VIRT_IRQCHIP_NUM_SOURCES,
((1U << VIRT_IRQCHIP_NUM_PRIO_BITS) - 1),
VIRT_PLIC_PRIORITY_BASE,
VIRT_PLIC_PENDING_BASE,
VIRT_PLIC_ENABLE_BASE,
VIRT_PLIC_ENABLE_STRIDE,
VIRT_PLIC_CONTEXT_BASE,
VIRT_PLIC_CONTEXT_STRIDE,
memmap[VIRT_PLIC].size);
g_free(plic_hart_config);
return ret;
}
static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type,
const MemMapEntry *memmap, int socket,
int base_hartid, int hart_count)
{
DeviceState *aplic_m;
/* Per-socket M-level APLIC */
aplic_m = riscv_aplic_create(
memmap[VIRT_APLIC_M].base + socket * memmap[VIRT_APLIC_M].size,
memmap[VIRT_APLIC_M].size,
base_hartid, hart_count,
VIRT_IRQCHIP_NUM_SOURCES,
VIRT_IRQCHIP_NUM_PRIO_BITS,
false, true, NULL);
if (aplic_m) {
/* Per-socket S-level APLIC */
riscv_aplic_create(
memmap[VIRT_APLIC_S].base + socket * memmap[VIRT_APLIC_S].size,
memmap[VIRT_APLIC_S].size,
base_hartid, hart_count,
VIRT_IRQCHIP_NUM_SOURCES,
VIRT_IRQCHIP_NUM_PRIO_BITS,
false, false, aplic_m);
}
return aplic_m;
}
static void virt_machine_init(MachineState *machine) static void virt_machine_init(MachineState *machine)
{ {
const MemMapEntry *memmap = virt_memmap; const MemMapEntry *memmap = virt_memmap;
RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); RISCVVirtState *s = RISCV_VIRT_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory(); MemoryRegion *system_memory = get_system_memory();
MemoryRegion *mask_rom = g_new(MemoryRegion, 1); MemoryRegion *mask_rom = g_new(MemoryRegion, 1);
char *plic_hart_config, *soc_name; char *soc_name;
target_ulong start_addr = memmap[VIRT_DRAM].base; target_ulong start_addr = memmap[VIRT_DRAM].base;
target_ulong firmware_end_addr, kernel_start_addr; target_ulong firmware_end_addr, kernel_start_addr;
uint32_t fdt_load_addr; uint32_t fdt_load_addr;
uint64_t kernel_entry; uint64_t kernel_entry;
DeviceState *mmio_plic, *virtio_plic, *pcie_plic; DeviceState *mmio_irqchip, *virtio_irqchip, *pcie_irqchip;
int i, base_hartid, hart_count; int i, base_hartid, hart_count;
/* Check socket count limit */ /* Check socket count limit */
@ -791,7 +947,7 @@ static void virt_machine_init(MachineState *machine)
} }
/* Initialize sockets */ /* Initialize sockets */
mmio_plic = virtio_plic = pcie_plic = NULL; mmio_irqchip = virtio_irqchip = pcie_irqchip = NULL;
for (i = 0; i < riscv_socket_count(machine); i++) { for (i = 0; i < riscv_socket_count(machine); i++) {
if (!riscv_socket_check_hartids(machine, i)) { if (!riscv_socket_check_hartids(machine, i)) {
error_report("discontinuous hartids in socket%d", i); error_report("discontinuous hartids in socket%d", i);
@ -843,36 +999,27 @@ static void virt_machine_init(MachineState *machine)
} }
} }
/* Per-socket PLIC hart topology configuration string */ /* Per-socket interrupt controller */
plic_hart_config = riscv_plic_hart_config_string(hart_count); if (s->aia_type == VIRT_AIA_TYPE_NONE) {
s->irqchip[i] = virt_create_plic(memmap, i,
base_hartid, hart_count);
} else {
s->irqchip[i] = virt_create_aia(s->aia_type, memmap, i,
base_hartid, hart_count);
}
/* Per-socket PLIC */ /* Try to use different IRQCHIP instance based device type */
s->plic[i] = sifive_plic_create(
memmap[VIRT_PLIC].base + i * memmap[VIRT_PLIC].size,
plic_hart_config, hart_count, base_hartid,
VIRT_PLIC_NUM_SOURCES,
VIRT_PLIC_NUM_PRIORITIES,
VIRT_PLIC_PRIORITY_BASE,
VIRT_PLIC_PENDING_BASE,
VIRT_PLIC_ENABLE_BASE,
VIRT_PLIC_ENABLE_STRIDE,
VIRT_PLIC_CONTEXT_BASE,
VIRT_PLIC_CONTEXT_STRIDE,
memmap[VIRT_PLIC].size);
g_free(plic_hart_config);
/* Try to use different PLIC instance based device type */
if (i == 0) { if (i == 0) {
mmio_plic = s->plic[i]; mmio_irqchip = s->irqchip[i];
virtio_plic = s->plic[i]; virtio_irqchip = s->irqchip[i];
pcie_plic = s->plic[i]; pcie_irqchip = s->irqchip[i];
} }
if (i == 1) { if (i == 1) {
virtio_plic = s->plic[i]; virtio_irqchip = s->irqchip[i];
pcie_plic = s->plic[i]; pcie_irqchip = s->irqchip[i];
} }
if (i == 2) { if (i == 2) {
pcie_plic = s->plic[i]; pcie_irqchip = s->irqchip[i];
} }
} }
@ -990,7 +1137,7 @@ static void virt_machine_init(MachineState *machine)
for (i = 0; i < VIRTIO_COUNT; i++) { for (i = 0; i < VIRTIO_COUNT; i++) {
sysbus_create_simple("virtio-mmio", sysbus_create_simple("virtio-mmio",
memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size, memmap[VIRT_VIRTIO].base + i * memmap[VIRT_VIRTIO].size,
qdev_get_gpio_in(DEVICE(virtio_plic), VIRTIO_IRQ + i)); qdev_get_gpio_in(DEVICE(virtio_irqchip), VIRTIO_IRQ + i));
} }
gpex_pcie_init(system_memory, gpex_pcie_init(system_memory,
@ -1001,14 +1148,14 @@ static void virt_machine_init(MachineState *machine)
virt_high_pcie_memmap.base, virt_high_pcie_memmap.base,
virt_high_pcie_memmap.size, virt_high_pcie_memmap.size,
memmap[VIRT_PCIE_PIO].base, memmap[VIRT_PCIE_PIO].base,
DEVICE(pcie_plic)); DEVICE(pcie_irqchip));
serial_mm_init(system_memory, memmap[VIRT_UART0].base, serial_mm_init(system_memory, memmap[VIRT_UART0].base,
0, qdev_get_gpio_in(DEVICE(mmio_plic), UART0_IRQ), 399193, 0, qdev_get_gpio_in(DEVICE(mmio_irqchip), UART0_IRQ), 399193,
serial_hd(0), DEVICE_LITTLE_ENDIAN); serial_hd(0), DEVICE_LITTLE_ENDIAN);
sysbus_create_simple("goldfish_rtc", memmap[VIRT_RTC].base, sysbus_create_simple("goldfish_rtc", memmap[VIRT_RTC].base,
qdev_get_gpio_in(DEVICE(mmio_plic), RTC_IRQ)); qdev_get_gpio_in(DEVICE(mmio_irqchip), RTC_IRQ));
virt_flash_create(s); virt_flash_create(s);
@ -1024,6 +1171,37 @@ static void virt_machine_instance_init(Object *obj)
{ {
} }
static char *virt_get_aia(Object *obj, Error **errp)
{
RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
const char *val;
switch (s->aia_type) {
case VIRT_AIA_TYPE_APLIC:
val = "aplic";
break;
default:
val = "none";
break;
};
return g_strdup(val);
}
static void virt_set_aia(Object *obj, const char *val, Error **errp)
{
RISCVVirtState *s = RISCV_VIRT_MACHINE(obj);
if (!strcmp(val, "none")) {
s->aia_type = VIRT_AIA_TYPE_NONE;
} else if (!strcmp(val, "aplic")) {
s->aia_type = VIRT_AIA_TYPE_APLIC;
} else {
error_setg(errp, "Invalid AIA interrupt controller type");
error_append_hint(errp, "Valid values are none, and aplic.\n");
}
}
static bool virt_get_aclint(Object *obj, Error **errp) static bool virt_get_aclint(Object *obj, Error **errp)
{ {
MachineState *ms = MACHINE(obj); MachineState *ms = MACHINE(obj);
@ -1062,6 +1240,13 @@ static void virt_machine_class_init(ObjectClass *oc, void *data)
object_class_property_set_description(oc, "aclint", object_class_property_set_description(oc, "aclint",
"Set on/off to enable/disable " "Set on/off to enable/disable "
"emulating ACLINT devices"); "emulating ACLINT devices");
object_class_property_add_str(oc, "aia", virt_get_aia,
virt_set_aia);
object_class_property_set_description(oc, "aia",
"Set type of AIA interrupt "
"conttoller. Valid values are "
"none, and aplic.");
} }
static const TypeInfo virt_machine_typeinfo = { static const TypeInfo virt_machine_typeinfo = {

View File

@ -32,18 +32,24 @@ typedef struct RISCVVirtState RISCVVirtState;
DECLARE_INSTANCE_CHECKER(RISCVVirtState, RISCV_VIRT_MACHINE, DECLARE_INSTANCE_CHECKER(RISCVVirtState, RISCV_VIRT_MACHINE,
TYPE_RISCV_VIRT_MACHINE) TYPE_RISCV_VIRT_MACHINE)
typedef enum RISCVVirtAIAType {
VIRT_AIA_TYPE_NONE = 0,
VIRT_AIA_TYPE_APLIC,
} RISCVVirtAIAType;
struct RISCVVirtState { struct RISCVVirtState {
/*< private >*/ /*< private >*/
MachineState parent; MachineState parent;
/*< public >*/ /*< public >*/
RISCVHartArrayState soc[VIRT_SOCKETS_MAX]; RISCVHartArrayState soc[VIRT_SOCKETS_MAX];
DeviceState *plic[VIRT_SOCKETS_MAX]; DeviceState *irqchip[VIRT_SOCKETS_MAX];
PFlashCFI01 *flash[2]; PFlashCFI01 *flash[2];
FWCfgState *fw_cfg; FWCfgState *fw_cfg;
int fdt_size; int fdt_size;
bool have_aclint; bool have_aclint;
RISCVVirtAIAType aia_type;
}; };
enum { enum {
@ -54,6 +60,8 @@ enum {
VIRT_CLINT, VIRT_CLINT,
VIRT_ACLINT_SSWI, VIRT_ACLINT_SSWI,
VIRT_PLIC, VIRT_PLIC,
VIRT_APLIC_M,
VIRT_APLIC_S,
VIRT_UART0, VIRT_UART0,
VIRT_VIRTIO, VIRT_VIRTIO,
VIRT_FW_CFG, VIRT_FW_CFG,
@ -73,8 +81,9 @@ enum {
VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */ VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */
}; };
#define VIRT_PLIC_NUM_SOURCES 127 #define VIRT_IRQCHIP_NUM_SOURCES 127
#define VIRT_PLIC_NUM_PRIORITIES 7 #define VIRT_IRQCHIP_NUM_PRIO_BITS 3
#define VIRT_PLIC_PRIORITY_BASE 0x04 #define VIRT_PLIC_PRIORITY_BASE 0x04
#define VIRT_PLIC_PENDING_BASE 0x1000 #define VIRT_PLIC_PENDING_BASE 0x1000
#define VIRT_PLIC_ENABLE_BASE 0x2000 #define VIRT_PLIC_ENABLE_BASE 0x2000
@ -86,9 +95,14 @@ enum {
#define FDT_PCI_ADDR_CELLS 3 #define FDT_PCI_ADDR_CELLS 3
#define FDT_PCI_INT_CELLS 1 #define FDT_PCI_INT_CELLS 1
#define FDT_PLIC_ADDR_CELLS 0
#define FDT_PLIC_INT_CELLS 1 #define FDT_PLIC_INT_CELLS 1
#define FDT_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + 1 + \ #define FDT_APLIC_INT_CELLS 2
FDT_PLIC_ADDR_CELLS + FDT_PLIC_INT_CELLS) #define FDT_MAX_INT_CELLS 2
#define FDT_MAX_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
1 + FDT_MAX_INT_CELLS)
#define FDT_PLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
1 + FDT_PLIC_INT_CELLS)
#define FDT_APLIC_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + \
1 + FDT_APLIC_INT_CELLS)
#endif #endif