From 2c12de146071beca8021d71cf2ac49bde36b2c8e Mon Sep 17 00:00:00 2001 From: Sunil V L Date: Wed, 6 Nov 2024 10:34:04 -0300 Subject: hw/riscv/virt: Add IOMMU as platform device if the option is set Add a new machine option called 'iommu-sys' that enables a riscv-iommu-sys platform device for the 'virt' machine. The option is default 'off'. The device will use IRQs 36 to 39. We will not support both riscv-iommu-sys and riscv-iommu-pci devices in the same board in this first implementation. If a riscv-iommu-pci device is added in the command line we will disable the riscv-iommu-sys device. Signed-off-by: Sunil V L Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20241106133407.604587-5-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 102 insertions(+), 2 deletions(-) (limited to 'hw/riscv/virt.c') diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 2feb851f15..c5ada635f1 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -33,6 +33,7 @@ #include "target/riscv/pmu.h" #include "hw/riscv/riscv_hart.h" #include "hw/riscv/iommu.h" +#include "hw/riscv/riscv-iommu-bits.h" #include "hw/riscv/virt.h" #include "hw/riscv/boot.h" #include "hw/riscv/numa.h" @@ -76,6 +77,7 @@ static const MemMapEntry virt_memmap[] = { [VIRT_CLINT] = { 0x2000000, 0x10000 }, [VIRT_ACLINT_SSWI] = { 0x2F00000, 0x4000 }, [VIRT_PCIE_PIO] = { 0x3000000, 0x10000 }, + [VIRT_IOMMU_SYS] = { 0x3010000, 0x1000 }, [VIRT_PLATFORM_BUS] = { 0x4000000, 0x2000000 }, [VIRT_PLIC] = { 0xc000000, VIRT_PLIC_SIZE(VIRT_CPUS_MAX * 2) }, [VIRT_APLIC_M] = { 0xc000000, APLIC_SIZE(VIRT_CPUS_MAX) }, @@ -853,7 +855,8 @@ static void create_fdt_virtio(RISCVVirtState *s, const MemMapEntry *memmap, static void create_fdt_pcie(RISCVVirtState *s, const MemMapEntry *memmap, uint32_t irq_pcie_phandle, - uint32_t msi_pcie_phandle) + uint32_t msi_pcie_phandle, + uint32_t iommu_sys_phandle) { g_autofree char *name = NULL; MachineState *ms = MACHINE(s); @@ -887,6 +890,12 @@ 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.size); + if (virt_is_iommu_sys_enabled(s)) { + qemu_fdt_setprop_cells(ms->fdt, name, "iommu-map", + 0, iommu_sys_phandle, 0, 0, 0, + iommu_sys_phandle, 0, 0xffff); + } + create_pcie_irq_map(s, ms->fdt, name, irq_pcie_phandle); } @@ -1033,6 +1042,44 @@ static void create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf) bdf + 1, iommu_phandle, bdf + 1, 0xffff - bdf); } +static void create_fdt_iommu_sys(RISCVVirtState *s, uint32_t irq_chip, + uint32_t *iommu_sys_phandle) +{ + const char comp[] = "riscv,iommu"; + void *fdt = MACHINE(s)->fdt; + uint32_t iommu_phandle; + g_autofree char *iommu_node = NULL; + hwaddr addr = s->memmap[VIRT_IOMMU_SYS].base; + hwaddr size = s->memmap[VIRT_IOMMU_SYS].size; + uint32_t iommu_irq_map[RISCV_IOMMU_INTR_COUNT] = { + IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_CQ, + IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_FQ, + IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_PM, + IOMMU_SYS_IRQ + RISCV_IOMMU_INTR_PQ, + }; + + iommu_node = g_strdup_printf("/soc/iommu@%x", + (unsigned int) s->memmap[VIRT_IOMMU_SYS].base); + iommu_phandle = qemu_fdt_alloc_phandle(fdt); + qemu_fdt_add_subnode(fdt, iommu_node); + + qemu_fdt_setprop(fdt, iommu_node, "compatible", comp, sizeof(comp)); + qemu_fdt_setprop_cell(fdt, iommu_node, "#iommu-cells", 1); + qemu_fdt_setprop_cell(fdt, iommu_node, "phandle", iommu_phandle); + + qemu_fdt_setprop_cells(fdt, iommu_node, "reg", + addr >> 32, addr, size >> 32, size); + qemu_fdt_setprop_cell(fdt, iommu_node, "interrupt-parent", irq_chip); + + qemu_fdt_setprop_cells(fdt, iommu_node, "interrupts", + iommu_irq_map[0], FDT_IRQ_TYPE_EDGE_LOW, + iommu_irq_map[1], FDT_IRQ_TYPE_EDGE_LOW, + iommu_irq_map[2], FDT_IRQ_TYPE_EDGE_LOW, + iommu_irq_map[3], FDT_IRQ_TYPE_EDGE_LOW); + + *iommu_sys_phandle = iommu_phandle; +} + static void create_fdt_iommu(RISCVVirtState *s, uint16_t bdf) { const char comp[] = "riscv,pci-iommu"; @@ -1061,6 +1108,7 @@ static void finalize_fdt(RISCVVirtState *s) { uint32_t phandle = 1, irq_mmio_phandle = 1, msi_pcie_phandle = 1; uint32_t irq_pcie_phandle = 1, irq_virtio_phandle = 1; + uint32_t iommu_sys_phandle = 1; create_fdt_sockets(s, virt_memmap, &phandle, &irq_mmio_phandle, &irq_pcie_phandle, &irq_virtio_phandle, @@ -1068,7 +1116,11 @@ static void finalize_fdt(RISCVVirtState *s) create_fdt_virtio(s, virt_memmap, irq_virtio_phandle); - create_fdt_pcie(s, virt_memmap, irq_pcie_phandle, msi_pcie_phandle); + if (virt_is_iommu_sys_enabled(s)) { + create_fdt_iommu_sys(s, irq_mmio_phandle, &iommu_sys_phandle); + } + create_fdt_pcie(s, virt_memmap, irq_pcie_phandle, msi_pcie_phandle, + iommu_sys_phandle); create_fdt_reset(s, virt_memmap, &phandle); @@ -1648,6 +1700,22 @@ static void virt_machine_init(MachineState *machine) create_fdt(s, memmap); } + if (virt_is_iommu_sys_enabled(s)) { + DeviceState *iommu_sys = qdev_new(TYPE_RISCV_IOMMU_SYS); + + object_property_set_uint(OBJECT(iommu_sys), "addr", + s->memmap[VIRT_IOMMU_SYS].base, + &error_fatal); + object_property_set_uint(OBJECT(iommu_sys), "base-irq", + IOMMU_SYS_IRQ, + &error_fatal); + object_property_set_link(OBJECT(iommu_sys), "irqchip", + OBJECT(mmio_irqchip), + &error_fatal); + + sysbus_realize_and_unref(SYS_BUS_DEVICE(iommu_sys), &error_fatal); + } + s->machine_done.notify = virt_machine_done; qemu_add_machine_init_done_notifier(&s->machine_done); } @@ -1661,6 +1729,7 @@ static void virt_machine_instance_init(Object *obj) s->oem_id = g_strndup(ACPI_BUILD_APPNAME6, 6); s->oem_table_id = g_strndup(ACPI_BUILD_APPNAME8, 8); s->acpi = ON_OFF_AUTO_AUTO; + s->iommu_sys = ON_OFF_AUTO_AUTO; } static char *virt_get_aia_guests(Object *obj, Error **errp) @@ -1733,6 +1802,28 @@ static void virt_set_aclint(Object *obj, bool value, Error **errp) s->have_aclint = value; } +bool virt_is_iommu_sys_enabled(RISCVVirtState *s) +{ + return s->iommu_sys == ON_OFF_AUTO_ON; +} + +static void virt_get_iommu_sys(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); + OnOffAuto iommu_sys = s->iommu_sys; + + visit_type_OnOffAuto(v, name, &iommu_sys, errp); +} + +static void virt_set_iommu_sys(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + RISCVVirtState *s = RISCV_VIRT_MACHINE(obj); + + visit_type_OnOffAuto(v, name, &s->iommu_sys, errp); +} + bool virt_is_acpi_enabled(RISCVVirtState *s) { return s->acpi != ON_OFF_AUTO_OFF; @@ -1759,10 +1850,12 @@ static HotplugHandler *virt_machine_get_hotplug_handler(MachineState *machine, DeviceState *dev) { MachineClass *mc = MACHINE_GET_CLASS(machine); + RISCVVirtState *s = RISCV_VIRT_MACHINE(machine); if (device_is_dynamic_sysbus(mc, dev) || object_dynamic_cast(OBJECT(dev), TYPE_VIRTIO_IOMMU_PCI) || object_dynamic_cast(OBJECT(dev), TYPE_RISCV_IOMMU_PCI)) { + s->iommu_sys = ON_OFF_AUTO_OFF; return HOTPLUG_HANDLER(machine); } @@ -1789,6 +1882,7 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, if (object_dynamic_cast(OBJECT(dev), TYPE_RISCV_IOMMU_PCI)) { create_fdt_iommu(s, pci_get_bdf(PCI_DEVICE(dev))); + s->iommu_sys = ON_OFF_AUTO_OFF; } } @@ -1851,6 +1945,12 @@ static void virt_machine_class_init(ObjectClass *oc, void *data) NULL, NULL); object_class_property_set_description(oc, "acpi", "Enable ACPI"); + + object_class_property_add(oc, "iommu-sys", "OnOffAuto", + virt_get_iommu_sys, virt_set_iommu_sys, + NULL, NULL); + object_class_property_set_description(oc, "iommu-sys", + "Enable IOMMU platform device"); } static const TypeInfo virt_machine_typeinfo = { -- cgit 1.4.1 From 01c1caa9d1b4a1938e0baba1a64c26636a3aff9f Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Wed, 6 Nov 2024 10:34:05 -0300 Subject: hw/riscv/virt.c, riscv-iommu-sys.c: add MSIx support MSIx support is added in the RISC-V IOMMU platform device by including the required MSIx facilities to alow software to properly setup the MSIx subsystem. We took inspiration of what is being done in the riscv-iommu-pci device, mainly msix_init() and msix_notify(), while keeping in mind that riscv-iommu-sys isn't a true PCI device and we don't need to copy/paste all the contents of these MSIx functions. Two extra MSI MemoryRegions were added: 'msix-table' and 'msix-pba'. They are used to manage r/w of the MSI table and Pending Bit Array (PBA) respectively. Both are subregions of the main IOMMU memory region, iommu->regs_mr, initialized during riscv_iommu_realize(), and each one has their own handlers for MSIx reads and writes. This is the expected memory map when using this device in the 'virt' machine: 0000000003010000-0000000003010fff (prio 0, i/o): riscv-iommu-regs 0000000003010300-000000000301034f (prio 0, i/o): msix-table 0000000003010400-0000000003010407 (prio 0, i/o): msix-pba We're now able to set IGS to RISCV_IOMMU_CAP_IGS_BOTH, and userspace is free to decide which interrupt model to use. Enabling MSIx support for this device in the 'virt' machine requires adding 'msi-parent' in the iommu-sys DT. Signed-off-by: Daniel Henrique Barboza Acked-by: Alistair Francis Message-ID: <20241106133407.604587-6-dbarboza@ventanamicro.com> [ Changes by AF: - Used PRIx64 in trace ] Signed-off-by: Alistair Francis --- hw/riscv/riscv-iommu-sys.c | 116 +++++++++++++++++++++++++++++++++++++++++++-- hw/riscv/trace-events | 2 + hw/riscv/virt.c | 6 ++- 3 files changed, 119 insertions(+), 5 deletions(-) (limited to 'hw/riscv/virt.c') diff --git a/hw/riscv/riscv-iommu-sys.c b/hw/riscv/riscv-iommu-sys.c index 4b82046ce9..a0ef67a20b 100644 --- a/hw/riscv/riscv-iommu-sys.c +++ b/hw/riscv/riscv-iommu-sys.c @@ -26,11 +26,15 @@ #include "qemu/host-utils.h" #include "qemu/module.h" #include "qom/object.h" +#include "exec/exec-all.h" +#include "trace.h" #include "riscv-iommu.h" #define RISCV_IOMMU_SYSDEV_ICVEC_VECTORS 0x3333 +#define RISCV_IOMMU_PCI_MSIX_VECTORS 5 + /* RISC-V IOMMU System Platform Device Emulation */ struct RISCVIOMMUStateSys { @@ -39,21 +43,123 @@ struct RISCVIOMMUStateSys { uint32_t base_irq; DeviceState *irqchip; RISCVIOMMUState iommu; + + /* Wired int support */ qemu_irq irqs[RISCV_IOMMU_INTR_COUNT]; + + /* Memory Regions for MSIX table and pending bit entries. */ + MemoryRegion msix_table_mmio; + MemoryRegion msix_pba_mmio; + uint8_t *msix_table; + uint8_t *msix_pba; +}; + +static uint64_t msix_table_mmio_read(void *opaque, hwaddr addr, + unsigned size) +{ + RISCVIOMMUStateSys *s = opaque; + + g_assert(addr + size <= RISCV_IOMMU_PCI_MSIX_VECTORS * PCI_MSIX_ENTRY_SIZE); + return pci_get_long(s->msix_table + addr); +} + +static void msix_table_mmio_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ + RISCVIOMMUStateSys *s = opaque; + + g_assert(addr + size <= RISCV_IOMMU_PCI_MSIX_VECTORS * PCI_MSIX_ENTRY_SIZE); + pci_set_long(s->msix_table + addr, val); +} + +static const MemoryRegionOps msix_table_mmio_ops = { + .read = msix_table_mmio_read, + .write = msix_table_mmio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .max_access_size = 4, + }, +}; + +static uint64_t msix_pba_mmio_read(void *opaque, hwaddr addr, + unsigned size) +{ + RISCVIOMMUStateSys *s = opaque; + + return pci_get_long(s->msix_pba + addr); +} + +static void msix_pba_mmio_write(void *opaque, hwaddr addr, + uint64_t val, unsigned size) +{ +} + +static const MemoryRegionOps msix_pba_mmio_ops = { + .read = msix_pba_mmio_read, + .write = msix_pba_mmio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 8, + }, + .impl = { + .max_access_size = 4, + }, }; +static void riscv_iommu_sysdev_init_msi(RISCVIOMMUStateSys *s, + uint32_t n_vectors) +{ + RISCVIOMMUState *iommu = &s->iommu; + uint32_t table_size = table_size = n_vectors * PCI_MSIX_ENTRY_SIZE; + uint32_t table_offset = RISCV_IOMMU_REG_MSI_CONFIG; + uint32_t pba_size = QEMU_ALIGN_UP(n_vectors, 64) / 8; + uint32_t pba_offset = RISCV_IOMMU_REG_MSI_CONFIG + 256; + + s->msix_table = g_malloc0(table_size); + s->msix_pba = g_malloc0(pba_size); + + memory_region_init_io(&s->msix_table_mmio, OBJECT(s), &msix_table_mmio_ops, + s, "msix-table", table_size); + memory_region_add_subregion(&iommu->regs_mr, table_offset, + &s->msix_table_mmio); + + memory_region_init_io(&s->msix_pba_mmio, OBJECT(s), &msix_pba_mmio_ops, s, + "msix-pba", pba_size); + memory_region_add_subregion(&iommu->regs_mr, pba_offset, + &s->msix_pba_mmio); +} + +static void riscv_iommu_sysdev_send_MSI(RISCVIOMMUStateSys *s, + uint32_t vector) +{ + uint8_t *table_entry = s->msix_table + vector * PCI_MSIX_ENTRY_SIZE; + uint64_t msi_addr = pci_get_quad(table_entry + PCI_MSIX_ENTRY_LOWER_ADDR); + uint32_t msi_data = pci_get_long(table_entry + PCI_MSIX_ENTRY_DATA); + MemTxResult result; + + address_space_stl_le(&address_space_memory, msi_addr, + msi_data, MEMTXATTRS_UNSPECIFIED, &result); + trace_riscv_iommu_sys_msi_sent(vector, msi_addr, msi_data, result); +} + static void riscv_iommu_sysdev_notify(RISCVIOMMUState *iommu, unsigned vector) { RISCVIOMMUStateSys *s = container_of(iommu, RISCVIOMMUStateSys, iommu); uint32_t fctl = riscv_iommu_reg_get32(iommu, RISCV_IOMMU_REG_FCTL); - /* We do not support MSIs yet */ - if (!(fctl & RISCV_IOMMU_FCTL_WSI)) { + if (fctl & RISCV_IOMMU_FCTL_WSI) { + qemu_irq_pulse(s->irqs[vector]); + trace_riscv_iommu_sys_irq_sent(vector); return; } - qemu_irq_pulse(s->irqs[vector]); + riscv_iommu_sysdev_send_MSI(s, vector); } static void riscv_iommu_sys_realize(DeviceState *dev, Error **errp) @@ -82,6 +188,8 @@ static void riscv_iommu_sys_realize(DeviceState *dev, Error **errp) irq = qdev_get_gpio_in(s->irqchip, s->base_irq + i); sysbus_connect_irq(sysdev, i, irq); } + + riscv_iommu_sysdev_init_msi(s, RISCV_IOMMU_PCI_MSIX_VECTORS); } static void riscv_iommu_sys_init(Object *obj) @@ -93,7 +201,7 @@ static void riscv_iommu_sys_init(Object *obj) qdev_alias_all_properties(DEVICE(iommu), obj); iommu->icvec_avail_vectors = RISCV_IOMMU_SYSDEV_ICVEC_VECTORS; - riscv_iommu_set_cap_igs(iommu, RISCV_IOMMU_CAP_IGS_WSI); + riscv_iommu_set_cap_igs(iommu, RISCV_IOMMU_CAP_IGS_BOTH); } static Property riscv_iommu_sys_properties[] = { diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events index 0527c56c91..525fd5b730 100644 --- a/hw/riscv/trace-events +++ b/hw/riscv/trace-events @@ -15,3 +15,5 @@ riscv_iommu_icvec_write(uint32_t orig, uint32_t actual) "ICVEC write: incoming 0 riscv_iommu_ats(const char *id, unsigned b, unsigned d, unsigned f, uint64_t iova) "%s: translate request %04x:%02x.%u iova: 0x%"PRIx64 riscv_iommu_ats_inval(const char *id) "%s: dev-iotlb invalidate" riscv_iommu_ats_prgr(const char *id) "%s: dev-iotlb page request group response" +riscv_iommu_sys_irq_sent(uint32_t vector) "IRQ sent to vector %u" +riscv_iommu_sys_msi_sent(uint32_t vector, uint64_t msi_addr, uint32_t msi_data, uint32_t result) "MSI sent to vector %u msi_addr 0x%"PRIx64" msi_data 0x%x result %u" diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index c5ada635f1..5d058511be 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1043,6 +1043,7 @@ static void create_fdt_virtio_iommu(RISCVVirtState *s, uint16_t bdf) } static void create_fdt_iommu_sys(RISCVVirtState *s, uint32_t irq_chip, + uint32_t msi_phandle, uint32_t *iommu_sys_phandle) { const char comp[] = "riscv,iommu"; @@ -1077,6 +1078,8 @@ static void create_fdt_iommu_sys(RISCVVirtState *s, uint32_t irq_chip, iommu_irq_map[2], FDT_IRQ_TYPE_EDGE_LOW, iommu_irq_map[3], FDT_IRQ_TYPE_EDGE_LOW); + qemu_fdt_setprop_cell(fdt, iommu_node, "msi-parent", msi_phandle); + *iommu_sys_phandle = iommu_phandle; } @@ -1117,7 +1120,8 @@ static void finalize_fdt(RISCVVirtState *s) create_fdt_virtio(s, virt_memmap, irq_virtio_phandle); if (virt_is_iommu_sys_enabled(s)) { - create_fdt_iommu_sys(s, irq_mmio_phandle, &iommu_sys_phandle); + create_fdt_iommu_sys(s, irq_mmio_phandle, msi_pcie_phandle, + &iommu_sys_phandle); } create_fdt_pcie(s, virt_memmap, irq_pcie_phandle, msi_pcie_phandle, iommu_sys_phandle); -- cgit 1.4.1 From 01948b1dea1ce9cafa8df7f0dc3d2aac6056ddbc Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 19 Nov 2024 16:17:00 -0300 Subject: hw/riscv/virt.c: reduce virt_use_kvm_aia() usage In create_fdt_sockets() we have the following pattern: if (kvm_enabled() && virt_use_kvm_aia(s)) { (... do stuff ...) } else { (... do other stuff ...) } if (kvm_enabled() && virt_use_kvm_aia(s)) { (... do more stuff ...) } else { (... do more other stuff) } Do everything in a single if/else clause to reduce the usage of virt_use_kvm_aia() helper and to make the code a bit less repetitive. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20241119191706.718860-3-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'hw/riscv/virt.c') diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 5d058511be..e54e1257c0 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -783,6 +783,10 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, msi_m_phandle, msi_s_phandle, phandle, &intc_phandles[0], xplic_phandles, ms->smp.cpus); + + *irq_mmio_phandle = xplic_phandles[0]; + *irq_virtio_phandle = xplic_phandles[0]; + *irq_pcie_phandle = xplic_phandles[0]; } else { phandle_pos = ms->smp.cpus; for (socket = (socket_count - 1); socket >= 0; socket--) { @@ -800,13 +804,7 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, s->soc[socket].num_harts); } } - } - if (kvm_enabled() && virt_use_kvm_aia(s)) { - *irq_mmio_phandle = xplic_phandles[0]; - *irq_virtio_phandle = xplic_phandles[0]; - *irq_pcie_phandle = xplic_phandles[0]; - } else { for (socket = 0; socket < socket_count; socket++) { if (socket == 0) { *irq_mmio_phandle = xplic_phandles[socket]; -- cgit 1.4.1 From 2711e1e324a84e5ce3d7408d723c25d86fc892a8 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 19 Nov 2024 16:17:01 -0300 Subject: hw/riscv/virt.c: rename helper to virt_use_kvm_aia_aplic_imsic() Similar to the riscv_is_kvm_aia_aplic_imsic() helper from riscv_aplic.c, the existing virt_use_kvm_aia() is testing for KVM aia=aplic-imsic with in-kernel irqchip enabled. It is not checking for a generic AIA support. Rename the helper to virt_use_kvm_aia_aplic_imsic() to reflect what the helper is doing, and use the existing riscv_is_kvm_aia_aplic_imsic() to obscure details such as the presence of the in-kernel irqchip. Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20241119191706.718860-4-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/riscv/virt.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'hw/riscv/virt.c') diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index e54e1257c0..a67ab80b16 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -59,9 +59,11 @@ #include "hw/virtio/virtio-iommu.h" /* KVM AIA only supports APLIC MSI. APLIC Wired is always emulated by QEMU. */ -static bool virt_use_kvm_aia(RISCVVirtState *s) +static bool virt_use_kvm_aia_aplic_imsic(RISCVVirtAIAType aia_type) { - return kvm_irqchip_in_kernel() && s->aia_type == VIRT_AIA_TYPE_APLIC_IMSIC; + bool msimode = aia_type == VIRT_AIA_TYPE_APLIC_IMSIC; + + return riscv_is_kvm_aia_aplic_imsic(msimode); } static bool virt_aclint_allowed(void) @@ -777,8 +779,8 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, *msi_pcie_phandle = msi_s_phandle; } - /* KVM AIA only has one APLIC instance */ - if (kvm_enabled() && virt_use_kvm_aia(s)) { + /* KVM AIA aplic-imsic only has one APLIC instance */ + if (kvm_enabled() && virt_use_kvm_aia_aplic_imsic(s->aia_type)) { create_fdt_socket_aplic(s, memmap, 0, msi_m_phandle, msi_s_phandle, phandle, &intc_phandles[0], xplic_phandles, @@ -1619,7 +1621,7 @@ static void virt_machine_init(MachineState *machine) } } - if (kvm_enabled() && virt_use_kvm_aia(s)) { + if (kvm_enabled() && virt_use_kvm_aia_aplic_imsic(s->aia_type)) { kvm_riscv_aia_create(machine, IMSIC_MMIO_GROUP_MIN_SHIFT, VIRT_IRQCHIP_NUM_SOURCES, VIRT_IRQCHIP_NUM_MSIS, memmap[VIRT_APLIC_S].base, -- cgit 1.4.1 From b319ef15b899c31cad985e50640393483479a3db Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 19 Nov 2024 16:17:03 -0300 Subject: hw/riscv/virt.c, riscv_aplic.c: add 'emulated_aplic' helpers The current logic to determine if we don't need an emulated APLIC controller, i.e. KVM will provide for us, is to determine if we're running KVM, with in-kernel irqchip support, and running aia=aplic-imsic. This is modelled by riscv_is_kvm_aia_aplic_imsic() and virt_use_kvm_aia_aplic_imsic(). This won't suffice to support irqchip_split() mode: it will match exactly the same conditions as the one above, but setting the irqchip to 'split' mode will now require us to emulate an APLIC s-mode controller, like we're doing with 'aia=aplic'. Create a new riscv_use_emulated_aplic() helper that will encapsulate this logic. Replace the uses of "riscv_is_kvm_aia_aplic_imsic()" with this helper every time we're taking a decision on emulate an APLIC controller or not. Do the same in virt.c with virt_use_emulated_aplic(). Signed-off-by: Daniel Henrique Barboza Reviewed-by: Alistair Francis Message-ID: <20241119191706.718860-6-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/intc/riscv_aplic.c | 24 +++++++++++++++++++++--- hw/riscv/virt.c | 14 ++++++++++++-- include/hw/intc/riscv_aplic.h | 1 + 3 files changed, 34 insertions(+), 5 deletions(-) (limited to 'hw/riscv/virt.c') diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index 9f9814a40b..ba4e802888 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -32,6 +32,7 @@ #include "target/riscv/cpu.h" #include "sysemu/sysemu.h" #include "sysemu/kvm.h" +#include "sysemu/tcg.h" #include "kvm/kvm_riscv.h" #include "migration/vmstate.h" @@ -159,6 +160,23 @@ bool riscv_is_kvm_aia_aplic_imsic(bool msimode) return kvm_irqchip_in_kernel() && msimode; } +bool riscv_use_emulated_aplic(bool msimode) +{ +#ifdef CONFIG_KVM + if (tcg_enabled()) { + return true; + } + + if (!riscv_is_kvm_aia_aplic_imsic(msimode)) { + return true; + } + + return kvm_kernel_irqchip_split(); +#else + return true; +#endif +} + static bool riscv_aplic_irq_rectified_val(RISCVAPLICState *aplic, uint32_t irq) { @@ -857,7 +875,7 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp) uint32_t i; RISCVAPLICState *aplic = RISCV_APLIC(dev); - if (!riscv_is_kvm_aia_aplic_imsic(aplic->msimode)) { + if (riscv_use_emulated_aplic(aplic->msimode)) { aplic->bitfield_words = (aplic->num_irqs + 31) >> 5; aplic->sourcecfg = g_new0(uint32_t, aplic->num_irqs); aplic->state = g_new0(uint32_t, aplic->num_irqs); @@ -881,7 +899,7 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp) * have IRQ lines delegated by their parent APLIC. */ if (!aplic->parent) { - if (kvm_enabled() && riscv_is_kvm_aia_aplic_imsic(aplic->msimode)) { + if (kvm_enabled() && !riscv_use_emulated_aplic(aplic->msimode)) { qdev_init_gpio_in(dev, riscv_kvm_aplic_request, aplic->num_irqs); } else { qdev_init_gpio_in(dev, riscv_aplic_request, aplic->num_irqs); @@ -1025,7 +1043,7 @@ DeviceState *riscv_aplic_create(hwaddr addr, hwaddr size, sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); - if (!riscv_is_kvm_aia_aplic_imsic(msimode)) { + if (riscv_use_emulated_aplic(msimode)) { sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); } diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index a67ab80b16..937dfd1ef2 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -66,6 +66,13 @@ static bool virt_use_kvm_aia_aplic_imsic(RISCVVirtAIAType aia_type) return riscv_is_kvm_aia_aplic_imsic(msimode); } +static bool virt_use_emulated_aplic(RISCVVirtAIAType aia_type) +{ + bool msimode = aia_type == VIRT_AIA_TYPE_APLIC_IMSIC; + + return riscv_use_emulated_aplic(msimode); +} + static bool virt_aclint_allowed(void) { return tcg_enabled() || qtest_enabled(); @@ -779,8 +786,11 @@ static void create_fdt_sockets(RISCVVirtState *s, const MemMapEntry *memmap, *msi_pcie_phandle = msi_s_phandle; } - /* KVM AIA aplic-imsic only has one APLIC instance */ - if (kvm_enabled() && virt_use_kvm_aia_aplic_imsic(s->aia_type)) { + /* + * With KVM AIA aplic-imsic, using an irqchip without split + * mode, we'll use only one APLIC instance. + */ + if (!virt_use_emulated_aplic(s->aia_type)) { create_fdt_socket_aplic(s, memmap, 0, msi_m_phandle, msi_s_phandle, phandle, &intc_phandles[0], xplic_phandles, diff --git a/include/hw/intc/riscv_aplic.h b/include/hw/intc/riscv_aplic.h index fd0e6427d9..74ae5d87b5 100644 --- a/include/hw/intc/riscv_aplic.h +++ b/include/hw/intc/riscv_aplic.h @@ -72,6 +72,7 @@ struct RISCVAPLICState { void riscv_aplic_add_child(DeviceState *parent, DeviceState *child); bool riscv_is_kvm_aia_aplic_imsic(bool msimode); +bool riscv_use_emulated_aplic(bool msimode); DeviceState *riscv_aplic_create(hwaddr addr, hwaddr size, uint32_t hartid_base, uint32_t num_harts, uint32_t num_sources, -- cgit 1.4.1 From e0c87e30678394cbca7585ef103b773a396be4d8 Mon Sep 17 00:00:00 2001 From: Daniel Henrique Barboza Date: Tue, 19 Nov 2024 16:17:04 -0300 Subject: hw/intc/riscv_aplic: add kvm_msicfgaddr for split mode aplic-imsic The last step to enable KVM AIA aplic-imsic with irqchip in split mode is to deal with how MSIs are going to be sent. In our current design we don't allow an APLIC controller to send MSIs unless it's on m-mode. And we also do not allow Supervisor MSI address configuration via the 'smsiaddrcfg' and 'smsiaddrcfgh' registers unless it's also a m-mode APLIC controller. Add a new RISCVACPLICState attribute called 'kvm_msicfgaddr'. This attribute represents the base configuration address for MSIs, in our case the base addr of the IMSIC controller. This attribute is being set only when running irqchip_split() mode with aia=aplic-imsic. During riscv_aplic_msi_send() we'll check if the attribute was set to skip the check for a m-mode APLIC controller and to change the resulting MSI addr by adding kvm_msicfgaddr right before address_space_stl_le(). Signed-off-by: Daniel Henrique Barboza Acked-by: Alistair Francis Message-ID: <20241119191706.718860-7-dbarboza@ventanamicro.com> Signed-off-by: Alistair Francis --- hw/intc/riscv_aplic.c | 42 +++++++++++++++++++++++++++++++++--------- hw/riscv/virt.c | 6 +++++- include/hw/intc/riscv_aplic.h | 6 ++++++ 3 files changed, 44 insertions(+), 10 deletions(-) (limited to 'hw/riscv/virt.c') diff --git a/hw/intc/riscv_aplic.c b/hw/intc/riscv_aplic.c index ba4e802888..1e4cdb500c 100644 --- a/hw/intc/riscv_aplic.c +++ b/hw/intc/riscv_aplic.c @@ -177,6 +177,16 @@ bool riscv_use_emulated_aplic(bool msimode) #endif } +void riscv_aplic_set_kvm_msicfgaddr(RISCVAPLICState *aplic, hwaddr addr) +{ +#ifdef CONFIG_KVM + if (riscv_use_emulated_aplic(aplic->msimode)) { + aplic->kvm_msicfgaddr = extract64(addr, 0, 32); + aplic->kvm_msicfgaddrH = extract64(addr, 32, 32); + } +#endif +} + static bool riscv_aplic_irq_rectified_val(RISCVAPLICState *aplic, uint32_t irq) { @@ -381,13 +391,16 @@ static void riscv_aplic_msi_send(RISCVAPLICState *aplic, uint32_t lhxs, lhxw, hhxs, hhxw, group_idx, msicfgaddr, msicfgaddrH; aplic_m = aplic; - while (aplic_m && !aplic_m->mmode) { - aplic_m = aplic_m->parent; - } - if (!aplic_m) { - qemu_log_mask(LOG_GUEST_ERROR, "%s: m-level APLIC not found\n", - __func__); - return; + + if (!aplic->kvm_splitmode) { + while (aplic_m && !aplic_m->mmode) { + aplic_m = aplic_m->parent; + } + if (!aplic_m) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: m-level APLIC not found\n", + __func__); + return; + } } if (aplic->mmode) { @@ -419,6 +432,11 @@ static void riscv_aplic_msi_send(RISCVAPLICState *aplic, addr |= (uint64_t)(guest_idx & APLIC_xMSICFGADDR_PPN_HART(lhxs)); addr <<= APLIC_xMSICFGADDR_PPN_SHIFT; + if (aplic->kvm_splitmode) { + addr |= aplic->kvm_msicfgaddr; + addr |= ((uint64_t)aplic->kvm_msicfgaddrH << 32); + } + address_space_stl_le(&address_space_memory, addr, eiid, MEMTXATTRS_UNSPECIFIED, &result); if (result != MEMTX_OK) { @@ -892,6 +910,10 @@ static void riscv_aplic_realize(DeviceState *dev, Error **errp) memory_region_init_io(&aplic->mmio, OBJECT(dev), &riscv_aplic_ops, aplic, TYPE_RISCV_APLIC, aplic->aperture_size); sysbus_init_mmio(SYS_BUS_DEVICE(dev), &aplic->mmio); + + if (kvm_enabled()) { + aplic->kvm_splitmode = true; + } } /* @@ -939,8 +961,8 @@ static const Property riscv_aplic_properties[] = { static const VMStateDescription vmstate_riscv_aplic = { .name = "riscv_aplic", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = (const VMStateField[]) { VMSTATE_UINT32(domaincfg, RISCVAPLICState), VMSTATE_UINT32(mmsicfgaddr, RISCVAPLICState), @@ -948,6 +970,8 @@ static const VMStateDescription vmstate_riscv_aplic = { VMSTATE_UINT32(smsicfgaddr, RISCVAPLICState), VMSTATE_UINT32(smsicfgaddrH, RISCVAPLICState), VMSTATE_UINT32(genmsi, RISCVAPLICState), + VMSTATE_UINT32(kvm_msicfgaddr, RISCVAPLICState), + VMSTATE_UINT32(kvm_msicfgaddrH, RISCVAPLICState), VMSTATE_VARRAY_UINT32(sourcecfg, RISCVAPLICState, num_irqs, 0, vmstate_info_uint32, uint32_t), diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 937dfd1ef2..43a1c86c33 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1300,7 +1300,7 @@ static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests, int base_hartid, int hart_count) { int i; - hwaddr addr; + hwaddr addr = 0; uint32_t guest_bits; DeviceState *aplic_s = NULL; DeviceState *aplic_m = NULL; @@ -1350,6 +1350,10 @@ static DeviceState *virt_create_aia(RISCVVirtAIAType aia_type, int aia_guests, VIRT_IRQCHIP_NUM_PRIO_BITS, msimode, false, aplic_m); + if (kvm_enabled() && msimode) { + riscv_aplic_set_kvm_msicfgaddr(RISCV_APLIC(aplic_s), addr); + } + return kvm_enabled() ? aplic_s : aplic_m; } diff --git a/include/hw/intc/riscv_aplic.h b/include/hw/intc/riscv_aplic.h index 74ae5d87b5..489b9133c2 100644 --- a/include/hw/intc/riscv_aplic.h +++ b/include/hw/intc/riscv_aplic.h @@ -68,11 +68,17 @@ struct RISCVAPLICState { uint32_t num_irqs; bool msimode; bool mmode; + + /* To support KVM aia=aplic-imsic with irqchip split mode */ + bool kvm_splitmode; + uint32_t kvm_msicfgaddr; + uint32_t kvm_msicfgaddrH; }; void riscv_aplic_add_child(DeviceState *parent, DeviceState *child); bool riscv_is_kvm_aia_aplic_imsic(bool msimode); bool riscv_use_emulated_aplic(bool msimode); +void riscv_aplic_set_kvm_msicfgaddr(RISCVAPLICState *aplic, hwaddr addr); DeviceState *riscv_aplic_create(hwaddr addr, hwaddr size, uint32_t hartid_base, uint32_t num_harts, uint32_t num_sources, -- cgit 1.4.1 From b4132a9e62978e247bce66e70499c4e2cad8d870 Mon Sep 17 00:00:00 2001 From: Jim Shu Date: Wed, 20 Nov 2024 23:39:33 +0800 Subject: hw/riscv: Support to load DTB after 3GB memory on 64-bit system. Larger initrd image will overlap the DTB at 3GB address. Since 64-bit system doesn't have 32-bit addressable issue, we just load DTB to the end of dram in 64-bit system. Signed-off-by: Jim Shu Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Message-ID: <20241120153935.24706-2-jim.shu@sifive.com> [ Changes by AF - Store fdt_load_addr_hi32 in the reset vector ] Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 14 +++++++++----- hw/riscv/microchip_pfsoc.c | 4 ++-- hw/riscv/sifive_u.c | 8 +++++--- hw/riscv/spike.c | 4 ++-- hw/riscv/virt.c | 2 +- include/hw/riscv/boot.h | 2 +- 6 files changed, 20 insertions(+), 14 deletions(-) (limited to 'hw/riscv/virt.c') diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index 2e319168db..d36d3a7104 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -293,7 +293,7 @@ out: * The FDT is fdt_packed() during the calculation. */ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size, - MachineState *ms) + MachineState *ms, RISCVHartArrayState *harts) { int ret = fdt_pack(ms->fdt); hwaddr dram_end, temp; @@ -317,11 +317,15 @@ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size, /* * We should put fdt as far as possible to avoid kernel/initrd overwriting - * its content. But it should be addressable by 32 bit system as well. - * Thus, put it at an 2MB aligned address that less than fdt size from the - * end of dram or 3GB whichever is lesser. + * its content. But it should be addressable by 32 bit system as well in RV32. + * Thus, put it near to the end of dram in RV64, and put it near to the end + * of dram or 3GB whichever is lesser in RV32. */ - temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end; + if (!riscv_is_32bit(harts)) { + temp = dram_end; + } else { + temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end; + } return QEMU_ALIGN_DOWN(temp - fdtsize, 2 * MiB); } diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index f9a3b43d2e..ba8b0a2c26 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -519,7 +519,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) bool kernel_as_payload = false; target_ulong firmware_end_addr, kernel_start_addr; uint64_t kernel_entry; - uint32_t fdt_load_addr; + uint64_t fdt_load_addr; DriveInfo *dinfo = drive_get(IF_SD, 0, 0); /* Sanity check on RAM size */ @@ -625,7 +625,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) /* Compute the fdt load address in dram */ fdt_load_addr = riscv_compute_fdt_addr(memmap[MICROCHIP_PFSOC_DRAM_LO].base, memmap[MICROCHIP_PFSOC_DRAM_LO].size, - machine); + machine, &s->soc.u_cpus); riscv_load_fdt(fdt_load_addr, machine->fdt); /* Load the reset vector */ diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 124ffd4842..fd59124500 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -518,8 +518,9 @@ static void sifive_u_machine_init(MachineState *machine) target_ulong firmware_end_addr, kernel_start_addr; const char *firmware_name; uint32_t start_addr_hi32 = 0x00000000; + uint32_t fdt_load_addr_hi32 = 0x00000000; int i; - uint32_t fdt_load_addr; + uint64_t fdt_load_addr; uint64_t kernel_entry; DriveInfo *dinfo; BlockBackend *blk; @@ -606,11 +607,12 @@ static void sifive_u_machine_init(MachineState *machine) fdt_load_addr = riscv_compute_fdt_addr(memmap[SIFIVE_U_DEV_DRAM].base, memmap[SIFIVE_U_DEV_DRAM].size, - machine); + machine, &s->soc.u_cpus); riscv_load_fdt(fdt_load_addr, machine->fdt); if (!riscv_is_32bit(&s->soc.u_cpus)) { start_addr_hi32 = (uint64_t)start_addr >> 32; + fdt_load_addr_hi32 = fdt_load_addr >> 32; } /* reset vector */ @@ -625,7 +627,7 @@ static void sifive_u_machine_init(MachineState *machine) start_addr, /* start: .dword */ start_addr_hi32, fdt_load_addr, /* fdt_laddr: .dword */ - 0x00000000, + fdt_load_addr_hi32, 0x00000000, /* fw_dyn: */ }; diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index fceb91d946..acd7ab1ae1 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -201,7 +201,7 @@ static void spike_board_init(MachineState *machine) hwaddr firmware_load_addr = memmap[SPIKE_DRAM].base; target_ulong kernel_start_addr; char *firmware_name; - uint32_t fdt_load_addr; + uint64_t fdt_load_addr; uint64_t kernel_entry; char *soc_name; int i, base_hartid, hart_count; @@ -317,7 +317,7 @@ static void spike_board_init(MachineState *machine) fdt_load_addr = riscv_compute_fdt_addr(memmap[SPIKE_DRAM].base, memmap[SPIKE_DRAM].size, - machine); + machine, &s->soc[0]); riscv_load_fdt(fdt_load_addr, machine->fdt); /* load the reset vector */ diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 43a1c86c33..98da79a5be 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1492,7 +1492,7 @@ static void virt_machine_done(Notifier *notifier, void *data) fdt_load_addr = riscv_compute_fdt_addr(memmap[VIRT_DRAM].base, memmap[VIRT_DRAM].size, - machine); + machine, &s->soc[0]); riscv_load_fdt(fdt_load_addr, machine->fdt); /* load the reset vector */ diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index f778b560de..34a80c5ff4 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -49,7 +49,7 @@ target_ulong riscv_load_kernel(MachineState *machine, bool load_initrd, symbol_fn_t sym_cb); uint64_t riscv_compute_fdt_addr(hwaddr dram_start, uint64_t dram_size, - MachineState *ms); + MachineState *ms, RISCVHartArrayState *harts); void riscv_load_fdt(hwaddr fdt_addr, void *fdt); void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts, hwaddr saddr, -- cgit 1.4.1 From d3592955af2a015be1d7138643b4a010eee0ff0c Mon Sep 17 00:00:00 2001 From: Jim Shu Date: Wed, 20 Nov 2024 23:39:34 +0800 Subject: hw/riscv: Add a new struct RISCVBootInfo Add a new struct RISCVBootInfo to sync boot information between multiple boot functions. Signed-off-by: Jim Shu Reviewed-by: Alistair Francis Reviewed-by: Daniel Henrique Barboza Message-ID: <20241120153935.24706-3-jim.shu@sifive.com> Signed-off-by: Alistair Francis --- hw/riscv/boot.c | 65 +++++++++++++++++++++++++++------------------- hw/riscv/microchip_pfsoc.c | 11 +++++--- hw/riscv/opentitan.c | 4 ++- hw/riscv/sifive_e.c | 4 ++- hw/riscv/sifive_u.c | 12 +++++---- hw/riscv/spike.c | 12 +++++---- hw/riscv/virt.c | 13 ++++++---- include/hw/riscv/boot.h | 25 ++++++++++++------ 8 files changed, 90 insertions(+), 56 deletions(-) (limited to 'hw/riscv/virt.c') diff --git a/hw/riscv/boot.c b/hw/riscv/boot.c index d36d3a7104..81d27f935e 100644 --- a/hw/riscv/boot.c +++ b/hw/riscv/boot.c @@ -67,9 +67,15 @@ char *riscv_plic_hart_config_string(int hart_count) return g_strjoinv(",", (char **)vals); } -target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts, +void riscv_boot_info_init(RISCVBootInfo *info, RISCVHartArrayState *harts) +{ + info->kernel_size = 0; + info->is_32bit = riscv_is_32bit(harts); +} + +target_ulong riscv_calc_kernel_start_addr(RISCVBootInfo *info, target_ulong firmware_end_addr) { - if (riscv_is_32bit(harts)) { + if (info->is_32bit) { return QEMU_ALIGN_UP(firmware_end_addr, 4 * MiB); } else { return QEMU_ALIGN_UP(firmware_end_addr, 2 * MiB); @@ -175,7 +181,7 @@ target_ulong riscv_load_firmware(const char *firmware_filename, exit(1); } -static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) +static void riscv_load_initrd(MachineState *machine, RISCVBootInfo *info) { const char *filename = machine->initrd_filename; uint64_t mem_size = machine->ram_size; @@ -196,7 +202,7 @@ static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) * halfway into RAM, and for boards with 1GB of RAM or more we put * the initrd at 512MB. */ - start = kernel_entry + MIN(mem_size / 2, 512 * MiB); + start = info->image_low_addr + MIN(mem_size / 2, 512 * MiB); size = load_ramdisk(filename, start, mem_size - start); if (size == -1) { @@ -215,14 +221,14 @@ static void riscv_load_initrd(MachineState *machine, uint64_t kernel_entry) } } -target_ulong riscv_load_kernel(MachineState *machine, - RISCVHartArrayState *harts, - target_ulong kernel_start_addr, - bool load_initrd, - symbol_fn_t sym_cb) +void riscv_load_kernel(MachineState *machine, + RISCVBootInfo *info, + target_ulong kernel_start_addr, + bool load_initrd, + symbol_fn_t sym_cb) { const char *kernel_filename = machine->kernel_filename; - uint64_t kernel_load_base, kernel_entry; + ssize_t kernel_size; void *fdt = machine->fdt; g_assert(kernel_filename != NULL); @@ -234,21 +240,28 @@ target_ulong riscv_load_kernel(MachineState *machine, * the (expected) load address load address. This allows kernels to have * separate SBI and ELF entry points (used by FreeBSD, for example). */ - if (load_elf_ram_sym(kernel_filename, NULL, NULL, NULL, - NULL, &kernel_load_base, NULL, NULL, 0, - EM_RISCV, 1, 0, NULL, true, sym_cb) > 0) { - kernel_entry = kernel_load_base; + kernel_size = load_elf_ram_sym(kernel_filename, NULL, NULL, NULL, NULL, + &info->image_low_addr, &info->image_high_addr, + NULL, 0, EM_RISCV, 1, 0, NULL, true, sym_cb); + if (kernel_size > 0) { + info->kernel_size = kernel_size; goto out; } - if (load_uimage_as(kernel_filename, &kernel_entry, NULL, NULL, - NULL, NULL, NULL) > 0) { + kernel_size = load_uimage_as(kernel_filename, &info->image_low_addr, + NULL, NULL, NULL, NULL, NULL); + if (kernel_size > 0) { + info->kernel_size = kernel_size; + info->image_high_addr = info->image_low_addr + kernel_size; goto out; } - if (load_image_targphys_as(kernel_filename, kernel_start_addr, - current_machine->ram_size, NULL) > 0) { - kernel_entry = kernel_start_addr; + kernel_size = load_image_targphys_as(kernel_filename, kernel_start_addr, + current_machine->ram_size, NULL); + if (kernel_size > 0) { + info->kernel_size = kernel_size; + info->image_low_addr = kernel_start_addr; + info->image_high_addr = info->image_low_addr + kernel_size; goto out; } @@ -257,23 +270,21 @@ target_ulong riscv_load_kernel(MachineState *machine, out: /* - * For 32 bit CPUs 'kernel_entry' can be sign-extended by + * For 32 bit CPUs 'image_low_addr' can be sign-extended by * load_elf_ram_sym(). */ - if (riscv_is_32bit(harts)) { - kernel_entry = extract64(kernel_entry, 0, 32); + if (info->is_32bit) { + info->image_low_addr = extract64(info->image_low_addr, 0, 32); } if (load_initrd && machine->initrd_filename) { - riscv_load_initrd(machine, kernel_entry); + riscv_load_initrd(machine, info); } if (fdt && machine->kernel_cmdline && *machine->kernel_cmdline) { qemu_fdt_setprop_string(fdt, "/chosen", "bootargs", machine->kernel_cmdline); } - - return kernel_entry; } /* @@ -293,7 +304,7 @@ out: * The FDT is fdt_packed() during the calculation. */ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size, - MachineState *ms, RISCVHartArrayState *harts) + MachineState *ms, RISCVBootInfo *info) { int ret = fdt_pack(ms->fdt); hwaddr dram_end, temp; @@ -321,7 +332,7 @@ uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size, * Thus, put it near to the end of dram in RV64, and put it near to the end * of dram or 3GB whichever is lesser in RV32. */ - if (!riscv_is_32bit(harts)) { + if (!info->is_32bit) { temp = dram_end; } else { temp = (dram_base < 3072 * MiB) ? MIN(dram_end, 3072 * MiB) : dram_end; diff --git a/hw/riscv/microchip_pfsoc.c b/hw/riscv/microchip_pfsoc.c index ba8b0a2c26..a302965b6d 100644 --- a/hw/riscv/microchip_pfsoc.c +++ b/hw/riscv/microchip_pfsoc.c @@ -521,6 +521,7 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) uint64_t kernel_entry; uint64_t fdt_load_addr; DriveInfo *dinfo = drive_get(IF_SD, 0, 0); + RISCVBootInfo boot_info; /* Sanity check on RAM size */ if (machine->ram_size < mc->default_ram_size) { @@ -615,17 +616,19 @@ static void microchip_icicle_kit_machine_init(MachineState *machine) firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, &firmware_load_addr, NULL); + riscv_boot_info_init(&boot_info, &s->soc.u_cpus); if (kernel_as_payload) { - kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus, + kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info, firmware_end_addr); - kernel_entry = riscv_load_kernel(machine, &s->soc.u_cpus, - kernel_start_addr, true, NULL); + riscv_load_kernel(machine, &boot_info, kernel_start_addr, + true, NULL); + kernel_entry = boot_info.image_low_addr; /* Compute the fdt load address in dram */ fdt_load_addr = riscv_compute_fdt_addr(memmap[MICROCHIP_PFSOC_DRAM_LO].base, memmap[MICROCHIP_PFSOC_DRAM_LO].size, - machine, &s->soc.u_cpus); + machine, &boot_info); riscv_load_fdt(fdt_load_addr, machine->fdt); /* Load the reset vector */ diff --git a/hw/riscv/opentitan.c b/hw/riscv/opentitan.c index 8ce85ea9f7..87ad9c8f34 100644 --- a/hw/riscv/opentitan.c +++ b/hw/riscv/opentitan.c @@ -81,6 +81,7 @@ static void opentitan_machine_init(MachineState *machine) OpenTitanState *s = OPENTITAN_MACHINE(machine); const MemMapEntry *memmap = ibex_memmap; MemoryRegion *sys_mem = get_system_memory(); + RISCVBootInfo boot_info; if (machine->ram_size != mc->default_ram_size) { char *sz = size_to_str(mc->default_ram_size); @@ -102,8 +103,9 @@ static void opentitan_machine_init(MachineState *machine) riscv_load_firmware(machine->firmware, &firmware_load_addr, NULL); } + riscv_boot_info_init(&boot_info, &s->soc.cpus); if (machine->kernel_filename) { - riscv_load_kernel(machine, &s->soc.cpus, + riscv_load_kernel(machine, &boot_info, memmap[IBEX_DEV_RAM].base, false, NULL); } diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index 5a1959f2a9..ebcd33ab95 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -78,6 +78,7 @@ static void sifive_e_machine_init(MachineState *machine) SiFiveEState *s = RISCV_E_MACHINE(machine); MemoryRegion *sys_mem = get_system_memory(); int i; + RISCVBootInfo boot_info; if (machine->ram_size != mc->default_ram_size) { char *sz = size_to_str(mc->default_ram_size); @@ -113,8 +114,9 @@ static void sifive_e_machine_init(MachineState *machine) rom_add_blob_fixed_as("mrom.reset", reset_vec, sizeof(reset_vec), memmap[SIFIVE_E_DEV_MROM].base, &address_space_memory); + riscv_boot_info_init(&boot_info, &s->soc.cpus); if (machine->kernel_filename) { - riscv_load_kernel(machine, &s->soc.cpus, + riscv_load_kernel(machine, &boot_info, memmap[SIFIVE_E_DEV_DTIM].base, false, NULL); } diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index fd59124500..6270e1ccec 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -526,6 +526,7 @@ static void sifive_u_machine_init(MachineState *machine) BlockBackend *blk; DeviceState *flash_dev, *sd_dev, *card_dev; qemu_irq flash_cs, sd_cs; + RISCVBootInfo boot_info; /* Initialize SoC */ object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_RISCV_U_SOC); @@ -591,12 +592,13 @@ static void sifive_u_machine_init(MachineState *machine) firmware_end_addr = riscv_find_and_load_firmware(machine, firmware_name, &start_addr, NULL); + riscv_boot_info_init(&boot_info, &s->soc.u_cpus); if (machine->kernel_filename) { - kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc.u_cpus, + kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info, firmware_end_addr); - - kernel_entry = riscv_load_kernel(machine, &s->soc.u_cpus, - kernel_start_addr, true, NULL); + riscv_load_kernel(machine, &boot_info, kernel_start_addr, + true, NULL); + kernel_entry = boot_info.image_low_addr; } else { /* * If dynamic firmware is used, it doesn't know where is the next mode @@ -607,7 +609,7 @@ static void sifive_u_machine_init(MachineState *machine) fdt_load_addr = riscv_compute_fdt_addr(memmap[SIFIVE_U_DEV_DRAM].base, memmap[SIFIVE_U_DEV_DRAM].size, - machine, &s->soc.u_cpus); + machine, &boot_info); riscv_load_fdt(fdt_load_addr, machine->fdt); if (!riscv_is_32bit(&s->soc.u_cpus)) { diff --git a/hw/riscv/spike.c b/hw/riscv/spike.c index acd7ab1ae1..c3ad16d316 100644 --- a/hw/riscv/spike.c +++ b/hw/riscv/spike.c @@ -206,6 +206,7 @@ static void spike_board_init(MachineState *machine) char *soc_name; int i, base_hartid, hart_count; bool htif_custom_base = false; + RISCVBootInfo boot_info; /* Check socket count limit */ if (SPIKE_SOCKETS_MAX < riscv_socket_count(machine)) { @@ -300,13 +301,14 @@ static void spike_board_init(MachineState *machine) create_fdt(s, memmap, riscv_is_32bit(&s->soc[0]), htif_custom_base); /* Load kernel */ + riscv_boot_info_init(&boot_info, &s->soc[0]); if (machine->kernel_filename) { - kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0], + kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info, firmware_end_addr); - kernel_entry = riscv_load_kernel(machine, &s->soc[0], - kernel_start_addr, - true, htif_symbol_callback); + riscv_load_kernel(machine, &boot_info, kernel_start_addr, + true, htif_symbol_callback); + kernel_entry = boot_info.image_low_addr; } else { /* * If dynamic firmware is used, it doesn't know where is the next mode @@ -317,7 +319,7 @@ static void spike_board_init(MachineState *machine) fdt_load_addr = riscv_compute_fdt_addr(memmap[SPIKE_DRAM].base, memmap[SPIKE_DRAM].size, - machine, &s->soc[0]); + machine, &boot_info); riscv_load_fdt(fdt_load_addr, machine->fdt); /* load the reset vector */ diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 98da79a5be..d2bfdec56a 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -1434,6 +1434,7 @@ static void virt_machine_done(Notifier *notifier, void *data) uint64_t fdt_load_addr; uint64_t kernel_entry = 0; BlockBackend *pflash_blk0; + RISCVBootInfo boot_info; /* * An user provided dtb must include everything, including @@ -1482,17 +1483,19 @@ static void virt_machine_done(Notifier *notifier, void *data) } } + riscv_boot_info_init(&boot_info, &s->soc[0]); + if (machine->kernel_filename && !kernel_entry) { - kernel_start_addr = riscv_calc_kernel_start_addr(&s->soc[0], + kernel_start_addr = riscv_calc_kernel_start_addr(&boot_info, firmware_end_addr); - - kernel_entry = riscv_load_kernel(machine, &s->soc[0], - kernel_start_addr, true, NULL); + riscv_load_kernel(machine, &boot_info, kernel_start_addr, + true, NULL); + kernel_entry = boot_info.image_low_addr; } fdt_load_addr = riscv_compute_fdt_addr(memmap[VIRT_DRAM].base, memmap[VIRT_DRAM].size, - machine, &s->soc[0]); + machine, &boot_info); riscv_load_fdt(fdt_load_addr, machine->fdt); /* load the reset vector */ diff --git a/include/hw/riscv/boot.h b/include/hw/riscv/boot.h index 34a80c5ff4..06b51ed086 100644 --- a/include/hw/riscv/boot.h +++ b/include/hw/riscv/boot.h @@ -27,11 +27,20 @@ #define RISCV32_BIOS_BIN "opensbi-riscv32-generic-fw_dynamic.bin" #define RISCV64_BIOS_BIN "opensbi-riscv64-generic-fw_dynamic.bin" +typedef struct RISCVBootInfo { + ssize_t kernel_size; + hwaddr image_low_addr; + hwaddr image_high_addr; + + bool is_32bit; +} RISCVBootInfo; + bool riscv_is_32bit(RISCVHartArrayState *harts); char *riscv_plic_hart_config_string(int hart_count); -target_ulong riscv_calc_kernel_start_addr(RISCVHartArrayState *harts, +void riscv_boot_info_init(RISCVBootInfo *info, RISCVHartArrayState *harts); +target_ulong riscv_calc_kernel_start_addr(RISCVBootInfo *info, target_ulong firmware_end_addr); target_ulong riscv_find_and_load_firmware(MachineState *machine, const char *default_machine_firmware, @@ -43,13 +52,13 @@ char *riscv_find_firmware(const char *firmware_filename, target_ulong riscv_load_firmware(const char *firmware_filename, hwaddr *firmware_load_addr, symbol_fn_t sym_cb); -target_ulong riscv_load_kernel(MachineState *machine, - RISCVHartArrayState *harts, - target_ulong firmware_end_addr, - bool load_initrd, - symbol_fn_t sym_cb); -uint64_t riscv_compute_fdt_addr(hwaddr dram_start, uint64_t dram_size, - MachineState *ms, RISCVHartArrayState *harts); +void riscv_load_kernel(MachineState *machine, + RISCVBootInfo *info, + target_ulong kernel_start_addr, + bool load_initrd, + symbol_fn_t sym_cb); +uint64_t riscv_compute_fdt_addr(hwaddr dram_base, hwaddr dram_size, + MachineState *ms, RISCVBootInfo *info); void riscv_load_fdt(hwaddr fdt_addr, void *fdt); void riscv_setup_rom_reset_vec(MachineState *machine, RISCVHartArrayState *harts, hwaddr saddr, -- cgit 1.4.1