From 63b695f2aa505d11542ecd8a272d42019a37a676 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 11 Dec 2018 22:37:17 +0000 Subject: [PATCH 01/14] hw/riscv/virt: Increase the number of interrupts Increase the number of interrupts to match the HiFive Unleashed board. Signed-off-by: Alistair Francis Tested-by: Guenter Roeck Tested-by: Andrea Bolognani Signed-off-by: Palmer Dabbelt --- include/hw/riscv/virt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index 91163d6cbf..2b2e6dd4ea 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -45,7 +45,7 @@ enum { UART0_IRQ = 10, VIRTIO_IRQ = 1, /* 1 to 8 */ VIRTIO_COUNT = 8, - VIRTIO_NDEV = 10 + VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */ }; enum { From bb1973aadb78bfb653287421d9df8ade1accc4af Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 11 Dec 2018 22:37:26 +0000 Subject: [PATCH 02/14] hw/riscv/virt: Adjust memory layout spacing Signed-off-by: Alistair Francis Reviewed-by: Logan Gunthorpe Tested-by: Guenter Roeck Tested-by: Andrea Bolognani Signed-off-by: Palmer Dabbelt --- hw/riscv/virt.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 2b38f89070..6b6fa39aaa 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -47,14 +47,14 @@ static const struct MemmapEntry { hwaddr base; hwaddr size; } virt_memmap[] = { - [VIRT_DEBUG] = { 0x0, 0x100 }, - [VIRT_MROM] = { 0x1000, 0x11000 }, - [VIRT_TEST] = { 0x100000, 0x1000 }, - [VIRT_CLINT] = { 0x2000000, 0x10000 }, - [VIRT_PLIC] = { 0xc000000, 0x4000000 }, - [VIRT_UART0] = { 0x10000000, 0x100 }, - [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, - [VIRT_DRAM] = { 0x80000000, 0x0 }, + [VIRT_DEBUG] = { 0x0, 0x100 }, + [VIRT_MROM] = { 0x1000, 0x11000 }, + [VIRT_TEST] = { 0x100000, 0x1000 }, + [VIRT_CLINT] = { 0x2000000, 0x10000 }, + [VIRT_PLIC] = { 0xc000000, 0x4000000 }, + [VIRT_UART0] = { 0x10000000, 0x100 }, + [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, + [VIRT_DRAM] = { 0x80000000, 0x0 }, }; static uint64_t load_kernel(const char *kernel_filename) From 6d56e39649808696b2321cbd200dd7ccaa7ef7fe Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 11 Dec 2018 22:37:36 +0000 Subject: [PATCH 03/14] hw/riscv/virt: Connect the gpex PCIe Connect the gpex PCIe device based on the device tree included in the HiFive Unleashed ROM. Signed-off-by: Alistair Francis Signed-off-by: Logan Gunthorpe Reviewed-by: Logan Gunthorpe Tested-by: Guenter Roeck Tested-by: Andrea Bolognani Signed-off-by: Palmer Dabbelt --- default-configs/riscv32-softmmu.mak | 5 +- default-configs/riscv64-softmmu.mak | 5 +- hw/riscv/virt.c | 131 +++++++++++++++++++++++++++- include/hw/riscv/virt.h | 13 ++- 4 files changed, 150 insertions(+), 4 deletions(-) diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak index 7937c69e22..c5ea36cba5 100644 --- a/default-configs/riscv32-softmmu.mak +++ b/default-configs/riscv32-softmmu.mak @@ -1,7 +1,10 @@ # Default configuration for riscv-softmmu +include pci.mak + CONFIG_SERIAL=y CONFIG_VIRTIO_MMIO=y -include virtio.mak CONFIG_CADENCE=y + +CONFIG_PCI_GENERIC=y diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak index 7937c69e22..c5ea36cba5 100644 --- a/default-configs/riscv64-softmmu.mak +++ b/default-configs/riscv64-softmmu.mak @@ -1,7 +1,10 @@ # Default configuration for riscv-softmmu +include pci.mak + CONFIG_SERIAL=y CONFIG_VIRTIO_MMIO=y -include virtio.mak CONFIG_CADENCE=y + +CONFIG_PCI_GENERIC=y diff --git a/hw/riscv/virt.c b/hw/riscv/virt.c index 6b6fa39aaa..e7f0716fb6 100644 --- a/hw/riscv/virt.c +++ b/hw/riscv/virt.c @@ -39,6 +39,8 @@ #include "sysemu/arch_init.h" #include "sysemu/device_tree.h" #include "exec/address-spaces.h" +#include "hw/pci/pci.h" +#include "hw/pci-host/gpex.h" #include "elf.h" #include @@ -55,6 +57,9 @@ static const struct MemmapEntry { [VIRT_UART0] = { 0x10000000, 0x100 }, [VIRT_VIRTIO] = { 0x10001000, 0x1000 }, [VIRT_DRAM] = { 0x80000000, 0x0 }, + [VIRT_PCIE_MMIO] = { 0x40000000, 0x40000000 }, + [VIRT_PCIE_PIO] = { 0x03000000, 0x00010000 }, + [VIRT_PCIE_ECAM] = { 0x30000000, 0x10000000 }, }; static uint64_t load_kernel(const char *kernel_filename) @@ -98,6 +103,51 @@ static hwaddr load_initrd(const char *filename, uint64_t mem_size, return *start + size; } +static void create_pcie_irq_map(void *fdt, char *nodename, + uint32_t plic_phandle) +{ + int pin, dev; + uint32_t + full_irq_map[GPEX_NUM_IRQS * GPEX_NUM_IRQS * FDT_INT_MAP_WIDTH] = {}; + uint32_t *irq_map = full_irq_map; + + /* This code creates a standard swizzle of interrupts such that + * each device's first interrupt is based on it's PCI_SLOT number. + * (See pci_swizzle_map_irq_fn()) + * + * We only need one entry per interrupt in the table (not one per + * possible slot) seeing the interrupt-map-mask will allow the table + * to wrap to any number of devices. + */ + for (dev = 0; dev < GPEX_NUM_IRQS; dev++) { + int devfn = dev * 0x8; + + for (pin = 0; pin < GPEX_NUM_IRQS; pin++) { + int irq_nr = PCIE_IRQ + ((pin + PCI_SLOT(devfn)) % GPEX_NUM_IRQS); + int i = 0; + + irq_map[i] = cpu_to_be32(devfn << 8); + + i += FDT_PCI_ADDR_CELLS; + irq_map[i] = cpu_to_be32(pin + 1); + + i += FDT_PCI_INT_CELLS; + irq_map[i++] = cpu_to_be32(plic_phandle); + + i += FDT_PLIC_ADDR_CELLS; + irq_map[i] = cpu_to_be32(irq_nr); + + irq_map += FDT_INT_MAP_WIDTH; + } + } + + qemu_fdt_setprop(fdt, nodename, "interrupt-map", + full_irq_map, sizeof(full_irq_map)); + + qemu_fdt_setprop_cells(fdt, nodename, "interrupt-map-mask", + 0x1800, 0, 0, 0x7); +} + static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, uint64_t mem_size, const char *cmdline) { @@ -203,7 +253,10 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, nodename = g_strdup_printf("/soc/interrupt-controller@%lx", (long)memmap[VIRT_PLIC].base); qemu_fdt_add_subnode(fdt, nodename); - qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", 1); + qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", + FDT_PLIC_ADDR_CELLS); + qemu_fdt_setprop_cell(fdt, nodename, "#interrupt-cells", + FDT_PLIC_INT_CELLS); qemu_fdt_setprop_string(fdt, nodename, "compatible", "riscv,plic0"); qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0); qemu_fdt_setprop(fdt, nodename, "interrupts-extended", @@ -233,6 +286,33 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, g_free(nodename); } + nodename = g_strdup_printf("/soc/pci@%lx", + (long) memmap[VIRT_PCIE_ECAM].base); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", + FDT_PCI_ADDR_CELLS); + qemu_fdt_setprop_cells(fdt, nodename, "#interrupt-cells", + FDT_PCI_INT_CELLS); + qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0x2); + qemu_fdt_setprop_string(fdt, nodename, "compatible", + "pci-host-ecam-generic"); + qemu_fdt_setprop_string(fdt, nodename, "device_type", "pci"); + qemu_fdt_setprop_cell(fdt, nodename, "linux,pci-domain", 0); + qemu_fdt_setprop_cells(fdt, nodename, "bus-range", 0, + memmap[VIRT_PCIE_ECAM].base / + PCIE_MMCFG_SIZE_MIN - 1); + qemu_fdt_setprop(fdt, nodename, "dma-coherent", NULL, 0); + qemu_fdt_setprop_cells(fdt, nodename, "reg", 0, memmap[VIRT_PCIE_ECAM].base, + 0, memmap[VIRT_PCIE_ECAM].size); + qemu_fdt_setprop_sized_cells(fdt, nodename, "ranges", + 1, FDT_PCI_RANGE_IOPORT, 2, 0, + 2, memmap[VIRT_PCIE_PIO].base, 2, memmap[VIRT_PCIE_PIO].size, + 1, FDT_PCI_RANGE_MMIO, + 2, memmap[VIRT_PCIE_MMIO].base, + 2, memmap[VIRT_PCIE_MMIO].base, 2, memmap[VIRT_PCIE_MMIO].size); + create_pcie_irq_map(fdt, nodename, plic_phandle); + g_free(nodename); + nodename = g_strdup_printf("/test@%lx", (long)memmap[VIRT_TEST].base); qemu_fdt_add_subnode(fdt, nodename); @@ -263,6 +343,47 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap, return fdt; } + +static inline DeviceState *gpex_pcie_init(MemoryRegion *sys_mem, + hwaddr ecam_base, hwaddr ecam_size, + hwaddr mmio_base, hwaddr mmio_size, + hwaddr pio_base, + DeviceState *plic, bool link_up) +{ + DeviceState *dev; + MemoryRegion *ecam_alias, *ecam_reg; + MemoryRegion *mmio_alias, *mmio_reg; + qemu_irq irq; + int i; + + dev = qdev_create(NULL, TYPE_GPEX_HOST); + + qdev_init_nofail(dev); + + ecam_alias = g_new0(MemoryRegion, 1); + ecam_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0); + memory_region_init_alias(ecam_alias, OBJECT(dev), "pcie-ecam", + ecam_reg, 0, ecam_size); + memory_region_add_subregion(get_system_memory(), ecam_base, ecam_alias); + + mmio_alias = g_new0(MemoryRegion, 1); + mmio_reg = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 1); + memory_region_init_alias(mmio_alias, OBJECT(dev), "pcie-mmio", + mmio_reg, mmio_base, mmio_size); + memory_region_add_subregion(get_system_memory(), mmio_base, mmio_alias); + + sysbus_mmio_map(SYS_BUS_DEVICE(dev), 2, pio_base); + + for (i = 0; i < GPEX_NUM_IRQS; i++) { + irq = qdev_get_gpio_in(plic, PCIE_IRQ + i); + + sysbus_connect_irq(SYS_BUS_DEVICE(dev), i, irq); + gpex_set_irq_num(GPEX_HOST(dev), i, PCIE_IRQ + i); + } + + return dev; +} + static void riscv_virt_board_init(MachineState *machine) { const struct MemmapEntry *memmap = virt_memmap; @@ -385,6 +506,14 @@ static void riscv_virt_board_init(MachineState *machine) qdev_get_gpio_in(DEVICE(s->plic), VIRTIO_IRQ + i)); } + gpex_pcie_init(system_memory, + memmap[VIRT_PCIE_ECAM].base, + memmap[VIRT_PCIE_ECAM].size, + memmap[VIRT_PCIE_MMIO].base, + memmap[VIRT_PCIE_MMIO].size, + memmap[VIRT_PCIE_PIO].base, + DEVICE(s->plic), true); + serial_mm_init(system_memory, memmap[VIRT_UART0].base, 0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193, serial_hd(0), DEVICE_LITTLE_ENDIAN); diff --git a/include/hw/riscv/virt.h b/include/hw/riscv/virt.h index 2b2e6dd4ea..f12deaebd6 100644 --- a/include/hw/riscv/virt.h +++ b/include/hw/riscv/virt.h @@ -38,13 +38,17 @@ enum { VIRT_PLIC, VIRT_UART0, VIRT_VIRTIO, - VIRT_DRAM + VIRT_DRAM, + VIRT_PCIE_MMIO, + VIRT_PCIE_PIO, + VIRT_PCIE_ECAM }; enum { UART0_IRQ = 10, VIRTIO_IRQ = 1, /* 1 to 8 */ VIRTIO_COUNT = 8, + PCIE_IRQ = 0x20, /* 32 to 35 */ VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */ }; @@ -62,6 +66,13 @@ enum { #define VIRT_PLIC_CONTEXT_BASE 0x200000 #define VIRT_PLIC_CONTEXT_STRIDE 0x1000 +#define FDT_PCI_ADDR_CELLS 3 +#define FDT_PCI_INT_CELLS 1 +#define FDT_PLIC_ADDR_CELLS 0 +#define FDT_PLIC_INT_CELLS 1 +#define FDT_INT_MAP_WIDTH (FDT_PCI_ADDR_CELLS + FDT_PCI_INT_CELLS + 1 + \ + FDT_PLIC_ADDR_CELLS + FDT_PLIC_INT_CELLS) + #if defined(TARGET_RISCV32) #define VIRT_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0 #elif defined(TARGET_RISCV64) From a9a0c2d1235a25049ceddb666dec66ba3f59a791 Mon Sep 17 00:00:00 2001 From: Alistair Francis Date: Tue, 11 Dec 2018 22:37:46 +0000 Subject: [PATCH 04/14] riscv: Enable VGA and PCIE_VGA Enable compile support for VGA devices. This allows the user to conenct a display by adding '-device bochs-display -display sdl' to their command line argument. Signed-off-by: Alistair Francis Reviewed-by: Logan Gunthorpe Tested-by: Andrea Bolognani Signed-off-by: Palmer Dabbelt --- default-configs/riscv32-softmmu.mak | 3 +++ default-configs/riscv64-softmmu.mak | 3 +++ 2 files changed, 6 insertions(+) diff --git a/default-configs/riscv32-softmmu.mak b/default-configs/riscv32-softmmu.mak index c5ea36cba5..dbc9398284 100644 --- a/default-configs/riscv32-softmmu.mak +++ b/default-configs/riscv32-softmmu.mak @@ -8,3 +8,6 @@ CONFIG_VIRTIO_MMIO=y CONFIG_CADENCE=y CONFIG_PCI_GENERIC=y + +CONFIG_VGA=y +CONFIG_VGA_PCI=y diff --git a/default-configs/riscv64-softmmu.mak b/default-configs/riscv64-softmmu.mak index c5ea36cba5..dbc9398284 100644 --- a/default-configs/riscv64-softmmu.mak +++ b/default-configs/riscv64-softmmu.mak @@ -8,3 +8,6 @@ CONFIG_VIRTIO_MMIO=y CONFIG_CADENCE=y CONFIG_PCI_GENERIC=y + +CONFIG_VGA=y +CONFIG_VGA_PCI=y From fe93582cf52ee67f6ab5a59051d354344010cfdc Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Thu, 13 Dec 2018 18:34:52 +0000 Subject: [PATCH 05/14] sifive_u: Add clock DT node for GEM ethernet The GEM ethernet on SiFive unleashed has fixed input clock of 125MHz as-per SiFive FU540 manual. This patch updates FDT generation for QEMU sifive_u machine to provide fixed-rate clock for GEM ethernet. Signed-off-by: Anup Patel Signed-off-by: Anup Patel Signed-off-by: Alistair Francis Reviewed-by: Palmer Dabbelt Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_u.c | 18 +++++++++++++++++- include/hw/riscv/sifive_u.h | 3 ++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index ef07df2442..5c41ee5017 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -85,7 +85,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, int cpu; uint32_t *cells; char *nodename; - uint32_t plic_phandle; + char ethclk_names[] = "pclk\0hclk\0tx_clk"; + uint32_t plic_phandle, ethclk_phandle; fdt = s->fdt = create_device_tree(&s->fdt_size); if (!fdt) { @@ -197,6 +198,17 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, g_free(cells); g_free(nodename); + nodename = g_strdup_printf("/soc/ethclk"); + qemu_fdt_add_subnode(fdt, nodename); + qemu_fdt_setprop_string(fdt, nodename, "compatible", "fixed-clock"); + qemu_fdt_setprop_cell(fdt, nodename, "#clock-cells", 0x0); + qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", + SIFIVE_U_GEM_CLOCK_FREQ); + qemu_fdt_setprop_cell(fdt, nodename, "phandle", 3); + qemu_fdt_setprop_cell(fdt, nodename, "linux,phandle", 3); + ethclk_phandle = qemu_fdt_get_phandle(fdt, nodename); + g_free(nodename); + nodename = g_strdup_printf("/soc/ethernet@%lx", (long)memmap[SIFIVE_U_GEM].base); qemu_fdt_add_subnode(fdt, nodename); @@ -208,6 +220,10 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_string(fdt, nodename, "phy-mode", "gmii"); qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle); qemu_fdt_setprop_cells(fdt, nodename, "interrupts", SIFIVE_U_GEM_IRQ); + qemu_fdt_setprop_cells(fdt, nodename, "clocks", + ethclk_phandle, ethclk_phandle, ethclk_phandle); + qemu_fdt_setprop(fdt, nodename, "clocks-names", ethclk_names, + sizeof(ethclk_names)); qemu_fdt_setprop_cells(fdt, nodename, "#address-cells", 1); qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0); g_free(nodename); diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index e8b4d9ffa3..be13cc1304 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -63,7 +63,8 @@ enum { }; enum { - SIFIVE_U_CLOCK_FREQ = 1000000000 + SIFIVE_U_CLOCK_FREQ = 1000000000, + SIFIVE_U_GEM_CLOCK_FREQ = 125000000 }; #define SIFIVE_U_PLIC_HART_CONFIG "MS" From 6c60757eb667c5c5b4a1f6ce3eff874b83bcd734 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Thu, 13 Dec 2018 18:36:17 +0000 Subject: [PATCH 06/14] sifive_u: Set 'clock-frequency' DT property for SiFive UART The 'clock-frequency' DT property is required by U-Boot to compute the divider value. This patch sets the 'clock-frequency' DT property of the SiFive UART device tree node (similar to virt machine). Signed-off-by: Anup Patel Signed-off-by: Anup Patel Signed-off-by: Alistair Francis Reviewed-by: Palmer Dabbelt Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_u.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 5c41ee5017..849fa2e631 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -241,6 +241,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap, qemu_fdt_setprop_cells(fdt, nodename, "reg", 0x0, memmap[SIFIVE_U_UART0].base, 0x0, memmap[SIFIVE_U_UART0].size); + qemu_fdt_setprop_cell(fdt, nodename, "clock-frequency", + SIFIVE_U_CLOCK_FREQ / 2); qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle); qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 1); From 9543fdaf223aac0313638752abfb3d6c2cf2169c Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Fri, 14 Dec 2018 00:18:30 +0000 Subject: [PATCH 07/14] RISC-V: Add hartid and \n to interrupt logging Add carriage return that was erroneously removed when converting to qemu_log. Change hard coded core number to the actual hartid. Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Palmer Dabbelt Cc: Alistair Francis Signed-off-by: Michael Clark Reviewed-by: Alistair Francis Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- target/riscv/cpu_helper.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/target/riscv/cpu_helper.c b/target/riscv/cpu_helper.c index 86f9f4730c..0234c2d528 100644 --- a/target/riscv/cpu_helper.c +++ b/target/riscv/cpu_helper.c @@ -445,11 +445,13 @@ void riscv_cpu_do_interrupt(CPUState *cs) if (RISCV_DEBUG_INTERRUPT) { int log_cause = cs->exception_index & RISCV_EXCP_INT_MASK; if (cs->exception_index & RISCV_EXCP_INT_FLAG) { - qemu_log_mask(LOG_TRACE, "core 0: trap %s, epc 0x" TARGET_FMT_lx, - riscv_intr_names[log_cause], env->pc); + qemu_log_mask(LOG_TRACE, "core " + TARGET_FMT_ld ": trap %s, epc 0x" TARGET_FMT_lx "\n", + env->mhartid, riscv_intr_names[log_cause], env->pc); } else { - qemu_log_mask(LOG_TRACE, "core 0: intr %s, epc 0x" TARGET_FMT_lx, - riscv_excp_names[log_cause], env->pc); + qemu_log_mask(LOG_TRACE, "core " + TARGET_FMT_ld ": intr %s, epc 0x" TARGET_FMT_lx "\n", + env->mhartid, riscv_excp_names[log_cause], env->pc); } } @@ -511,8 +513,8 @@ void riscv_cpu_do_interrupt(CPUState *cs) if (hasbadaddr) { if (RISCV_DEBUG_INTERRUPT) { - qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld - ": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr); + qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x" + TARGET_FMT_lx "\n", env->mhartid, env->badaddr); } env->sbadaddr = env->badaddr; } else { @@ -536,8 +538,8 @@ void riscv_cpu_do_interrupt(CPUState *cs) if (hasbadaddr) { if (RISCV_DEBUG_INTERRUPT) { - qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld - ": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr); + qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x" + TARGET_FMT_lx "\n", env->mhartid, env->badaddr); } env->mbadaddr = env->badaddr; } else { From ef9e41df680a494dec92fe8d166cb2bc531b29a4 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Fri, 14 Dec 2018 00:18:39 +0000 Subject: [PATCH 08/14] RISC-V: Fix CLINT timecmp low 32-bit writes A missing shift made updates to the low order bits of timecmp erroneously copy the old low order bits into the high order bits of the 64-bit timecmp register. Add the missing shift and rename timecmp local variables to timecmp_hi and timecmp_lo. This bug didn't show up as the low order bits are usually written first followed by the high order bits meaning the high order bits contained an invalid value between the timecmp_lo and timecmp_hi update. Cc: Palmer Dabbelt Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Alistair Francis Co-Authored-by: Johannes Haring Signed-off-by: Michael Clark Reviewed-by: Alistair Francis Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_clint.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hw/riscv/sifive_clint.c b/hw/riscv/sifive_clint.c index 0d2fd52487..d4c159e937 100644 --- a/hw/riscv/sifive_clint.c +++ b/hw/riscv/sifive_clint.c @@ -146,15 +146,15 @@ static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value, error_report("clint: invalid timecmp hartid: %zu", hartid); } else if ((addr & 0x7) == 0) { /* timecmp_lo */ - uint64_t timecmp = env->timecmp; + uint64_t timecmp_hi = env->timecmp >> 32; sifive_clint_write_timecmp(RISCV_CPU(cpu), - timecmp << 32 | (value & 0xFFFFFFFF)); + timecmp_hi << 32 | (value & 0xFFFFFFFF)); return; } else if ((addr & 0x7) == 4) { /* timecmp_hi */ - uint64_t timecmp = env->timecmp; + uint64_t timecmp_lo = env->timecmp; sifive_clint_write_timecmp(RISCV_CPU(cpu), - value << 32 | (timecmp & 0xFFFFFFFF)); + value << 32 | (timecmp_lo & 0xFFFFFFFF)); } else { error_report("clint: invalid timecmp write: %08x", (uint32_t)addr); } From e41848e5c9245947c09fb0cf3e160ec9350907f4 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Fri, 14 Dec 2018 00:18:54 +0000 Subject: [PATCH 09/14] RISC-V: Fix PLIC pending bitfield reads The address calculation for the pending bitfield had a copy paste bug. This bug went unnoticed because the Linux PLIC driver does not read the pending bitfield, rather it reads pending interrupt numbers from the claim register and writes acknowledgements back to the claim register. Cc: Palmer Dabbelt Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Alistair Francis Reported-by: Vincent Siles Signed-off-by: Michael Clark Reviewed-by: Alistair Francis Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_plic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/riscv/sifive_plic.c b/hw/riscv/sifive_plic.c index 9cf9a1f986..d12ec3fc9a 100644 --- a/hw/riscv/sifive_plic.c +++ b/hw/riscv/sifive_plic.c @@ -214,7 +214,7 @@ static uint64_t sifive_plic_read(void *opaque, hwaddr addr, unsigned size) } 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]); From 194eef09d06358ea50b52340df853e9beeccce15 Mon Sep 17 00:00:00 2001 From: Michael Clark Date: Fri, 14 Dec 2018 00:19:03 +0000 Subject: [PATCH 10/14] RISC-V: Enable second UART on sifive_e and sifive_u Previously the second UARTs on the sifive_e and sifive_u machines where disabled due to check-qtest-riscv32 and check-qtest-riscv64 failures. Recent changes in the QEMU core serial code have resolved these failures so the second UARTs can be instantiated. Cc: Palmer Dabbelt Cc: Sagar Karandikar Cc: Bastian Koppelmann Cc: Alistair Francis Signed-off-by: Michael Clark Reviewed-by: Alistair Francis Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_e.c | 5 ++--- hw/riscv/sifive_u.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/hw/riscv/sifive_e.c b/hw/riscv/sifive_e.c index cb513cc3bb..5d9d65ff29 100644 --- a/hw/riscv/sifive_e.c +++ b/hw/riscv/sifive_e.c @@ -192,9 +192,8 @@ static void riscv_sifive_e_soc_realize(DeviceState *dev, Error **errp) memmap[SIFIVE_E_QSPI0].base, memmap[SIFIVE_E_QSPI0].size); sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm0", memmap[SIFIVE_E_PWM0].base, memmap[SIFIVE_E_PWM0].size); - /* sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base, - serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), - SIFIVE_E_UART1_IRQ)); */ + sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base, + serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART1_IRQ)); sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi1", memmap[SIFIVE_E_QSPI1].base, memmap[SIFIVE_E_QSPI1].size); sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm1", diff --git a/hw/riscv/sifive_u.c b/hw/riscv/sifive_u.c index 849fa2e631..3bd3b67507 100644 --- a/hw/riscv/sifive_u.c +++ b/hw/riscv/sifive_u.c @@ -368,9 +368,8 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp) memmap[SIFIVE_U_PLIC].size); sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base, serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ)); - /* sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base, - serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), - SIFIVE_U_UART1_IRQ)); */ + sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base, + serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ)); sifive_clint_create(memmap[SIFIVE_U_CLINT].base, memmap[SIFIVE_U_CLINT].size, smp_cpus, SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE); From 40061ac0bc5bdfcfa1234dbf8e2a880fd9fc4c2e Mon Sep 17 00:00:00 2001 From: Nathaniel Graff Date: Fri, 14 Dec 2018 00:19:12 +0000 Subject: [PATCH 11/14] sifive_uart: Implement interrupt pending register The watermark bits are set in the interrupt pending register according to the configuration of txcnt and rxcnt in the txctrl and rxctrl registers. Since the UART TX does not implement a FIFO, the txwm bit is set as long as the TX watermark level is greater than zero. Signed-off-by: Nathaniel Graff Reviewed-by: Michael Clark Reviewed-by: Alistair Francis Signed-off-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- hw/riscv/sifive_uart.c | 24 +++++++++++++++++++----- include/hw/riscv/sifive_uart.h | 3 +++ 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/hw/riscv/sifive_uart.c b/hw/riscv/sifive_uart.c index b0c3798cf2..456a3d3697 100644 --- a/hw/riscv/sifive_uart.c +++ b/hw/riscv/sifive_uart.c @@ -28,12 +28,26 @@ * Not yet implemented: * * Transmit FIFO using "qemu/fifo8.h" - * SIFIVE_UART_IE_TXWM interrupts - * SIFIVE_UART_IE_RXWM interrupts must honor fifo watermark - * Rx FIFO watermark interrupt trigger threshold - * Tx FIFO watermark interrupt trigger threshold. */ +/* Returns the state of the IP (interrupt pending) register */ +static uint64_t uart_ip(SiFiveUARTState *s) +{ + uint64_t ret = 0; + + uint64_t txcnt = SIFIVE_UART_GET_TXCNT(s->txctrl); + uint64_t rxcnt = SIFIVE_UART_GET_RXCNT(s->rxctrl); + + if (txcnt != 0) { + ret |= SIFIVE_UART_IP_TXWM; + } + if (s->rx_fifo_len > rxcnt) { + ret |= SIFIVE_UART_IP_RXWM; + } + + return ret; +} + static void update_irq(SiFiveUARTState *s) { int cond = 0; @@ -69,7 +83,7 @@ uart_read(void *opaque, hwaddr addr, unsigned int size) case SIFIVE_UART_IE: return s->ie; case SIFIVE_UART_IP: - return s->rx_fifo_len ? SIFIVE_UART_IP_RXWM : 0; + return uart_ip(s); case SIFIVE_UART_TXCTRL: return s->txctrl; case SIFIVE_UART_RXCTRL: diff --git a/include/hw/riscv/sifive_uart.h b/include/hw/riscv/sifive_uart.h index 504f18a60f..c8dc1c57fd 100644 --- a/include/hw/riscv/sifive_uart.h +++ b/include/hw/riscv/sifive_uart.h @@ -43,6 +43,9 @@ enum { SIFIVE_UART_IP_RXWM = 2 /* Receive watermark interrupt pending */ }; +#define SIFIVE_UART_GET_TXCNT(txctrl) ((txctrl >> 16) & 0x7) +#define SIFIVE_UART_GET_RXCNT(rxctrl) ((rxctrl >> 16) & 0x7) + #define TYPE_SIFIVE_UART "riscv.sifive.uart" #define SIFIVE_UART(obj) \ From 71a150bc914ef154d1321cc3602a4e80a433fc52 Mon Sep 17 00:00:00 2001 From: Anup Patel Date: Fri, 14 Dec 2018 19:12:32 +0000 Subject: [PATCH 12/14] target/riscv/pmp.c: Fix pmp_decode_napot() Currently, start and end address of a PMP region are not decoded correctly by pmp_decode_napot(). Let's say we have a 128KB PMP region with base address as 0x80000000. Now, the PMPADDRx CSR value for this region will be 0x20003fff. The current pmp_decode_napot() implementation will decode PMPADDRx CSR as t1=14, base=0x100000000, and range=0x1ffff whereas it should have decoded PMPADDRx CSR as t1=14, base=0x80000000, and range=0x1fff. This patch fixes the base value decoding in pmp_decode_napot() when PMPADDRx CSR is not -1 (i.e. 0xffffffffffffffff). Signed-off-by: Anup Patel Signed-off-by: Anup Patel Signed-off-by: Alistair Francis Reviewed-by: Palmer Dabbelt Signed-off-by: Palmer Dabbelt --- target/riscv/pmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/riscv/pmp.c b/target/riscv/pmp.c index 03abd8fe5e..15a5366616 100644 --- a/target/riscv/pmp.c +++ b/target/riscv/pmp.c @@ -138,7 +138,7 @@ static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea) return; } else { target_ulong t1 = ctz64(~a); - target_ulong base = (a & ~(((target_ulong)1 << t1) - 1)) << 3; + target_ulong base = (a & ~(((target_ulong)1 << t1) - 1)) << 2; target_ulong range = ((target_ulong)1 << (t1 + 3)) - 1; *sa = base; *ea = base + range; From 41fbbba7753457331d971887a74d9a96066f65ba Mon Sep 17 00:00:00 2001 From: Mao Zhongyi Date: Mon, 26 Nov 2018 11:20:38 +0800 Subject: [PATCH 13/14] riscv/cpu: use device_class_set_parent_realize Signed-off-by: Mao Zhongyi Reviewed-by: Bastian Koppelmann Reviewed-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- target/riscv/cpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/target/riscv/cpu.c b/target/riscv/cpu.c index a025a0a3ba..5e8a2cb2ba 100644 --- a/target/riscv/cpu.c +++ b/target/riscv/cpu.c @@ -330,8 +330,8 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data) CPUClass *cc = CPU_CLASS(c); DeviceClass *dc = DEVICE_CLASS(c); - mcc->parent_realize = dc->realize; - dc->realize = riscv_cpu_realize; + device_class_set_parent_realize(dc, riscv_cpu_realize, + &mcc->parent_realize); mcc->parent_reset = cc->reset; cc->reset = riscv_cpu_reset; From 7b91ae7d7944056c5e8045342e4039e978e43c82 Mon Sep 17 00:00:00 2001 From: Palmer Dabbelt Date: Wed, 21 Nov 2018 12:57:36 -0800 Subject: [PATCH 14/14] MAINTAINERS: Mark RISC-V as Supported There's at least two of us that are paid to work on this. Reviewed-by: Alistair Francis Signed-off-by: Palmer Dabbelt --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index d676c73f88..317eff6cec 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -262,7 +262,7 @@ M: Alistair Francis M: Sagar Karandikar M: Bastian Koppelmann L: qemu-riscv@nongnu.org -S: Maintained +S: Supported F: target/riscv/ F: hw/riscv/ F: include/hw/riscv/