RISC-V Changes for 3.2, Part 1
This pull request contains the first set of RISC-V patches I'd like to target for the 3.2 development cycle. It's really just a collection of bug fixes with one major new feature: PCIe can now be attached to RISC-V guests. This has passed my usual test of booting the latest Linux RC into a Fedora disk image on the virt machine. -----BEGIN PGP SIGNATURE----- iQJHBAABCAAxFiEEAM520YNJYN/OiG3470yhUCzLq0EFAlwdDlkTHHBhbG1lckBk YWJiZWx0LmNvbQAKCRDvTKFQLMurQWJgEACdUZuZIYGu1b1QjOLmSzPSVa+EvP5V +AAXekfsk3T3dNuVDtQyb2IfcPsI/QZkr6WcO0gWsY4TWPXwm6fMKyvZFBFxq2hM RWYtgeHDSSJ1ZY0AGz8Lz//zC76rJfbQDl5TsPQEX0ARCdV8VI0Uh0paaWDRypHz 5tXruzuHAp0dKk9czyBGC//LrWdNBMGhcti9QxN0ivyvR6FXJndEGvY9UL5WcF8t rPbX+r1n/lezaJTdKAybyy5SaEQoyGChhxyESA9MCj1foE3MKd5oXArOGEmU6dwP PdJznOn1T/4IozAMHYUpzSIlJ5ssoa/KdZbULE4MIWBmfh0+AeVYDnmrGEffdmWw d2MNJrn1yFSEaey+i19DCZIl2+4xbpjzq3GZVDllGGDznXNiG3ORiaiCOATLDubJ WYHxLETln/Ix1fBq3u6QbV7GeJ6EIZ+MobNwJEq1kvmyoU3tqrcFBOYMw7usvTda TcYDVNbhtWtdv0EhwxFpV+8otamcWfoE7OTl5Msy+9ZpV9JWABssvU/aXu68eNi/ nHlCggrXUh4i4c+XoPeyckTj4GQ8QpoSt8PNx8SIbz+ElKC5BoChInXo8o1XKjhA wYLYyL7XH6NjdQAlerIvWIKA6tWKG8SqL8kvr9P05tZLmzc4UoQ1h5QlXf5BiAKO e4qNigdEd+VtYw== =BAOm -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/palmer/tags/riscv-for-master-3.2-part1' into staging RISC-V Changes for 3.2, Part 1 This pull request contains the first set of RISC-V patches I'd like to target for the 3.2 development cycle. It's really just a collection of bug fixes with one major new feature: PCIe can now be attached to RISC-V guests. This has passed my usual test of booting the latest Linux RC into a Fedora disk image on the virt machine. # gpg: Signature made Fri 21 Dec 2018 16:01:29 GMT # gpg: using RSA key EF4CA1502CCBAB41 # gpg: Good signature from "Palmer Dabbelt <palmer@dabbelt.com>" # gpg: aka "Palmer Dabbelt <palmer@sifive.com>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 00CE 76D1 8349 60DF CE88 6DF8 EF4C A150 2CCB AB41 * remotes/palmer/tags/riscv-for-master-3.2-part1: MAINTAINERS: Mark RISC-V as Supported riscv/cpu: use device_class_set_parent_realize target/riscv/pmp.c: Fix pmp_decode_napot() sifive_uart: Implement interrupt pending register RISC-V: Enable second UART on sifive_e and sifive_u RISC-V: Fix PLIC pending bitfield reads RISC-V: Fix CLINT timecmp low 32-bit writes RISC-V: Add hartid and \n to interrupt logging sifive_u: Set 'clock-frequency' DT property for SiFive UART sifive_u: Add clock DT node for GEM ethernet riscv: Enable VGA and PCIE_VGA hw/riscv/virt: Connect the gpex PCIe hw/riscv/virt: Adjust memory layout spacing hw/riscv/virt: Increase the number of interrupts Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
20d6c7312f
@ -262,7 +262,7 @@ M: Alistair Francis <Alistair.Francis@wdc.com>
|
|||||||
M: Sagar Karandikar <sagark@eecs.berkeley.edu>
|
M: Sagar Karandikar <sagark@eecs.berkeley.edu>
|
||||||
M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
|
M: Bastian Koppelmann <kbastian@mail.uni-paderborn.de>
|
||||||
L: qemu-riscv@nongnu.org
|
L: qemu-riscv@nongnu.org
|
||||||
S: Maintained
|
S: Supported
|
||||||
F: target/riscv/
|
F: target/riscv/
|
||||||
F: hw/riscv/
|
F: hw/riscv/
|
||||||
F: include/hw/riscv/
|
F: include/hw/riscv/
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
# Default configuration for riscv-softmmu
|
# Default configuration for riscv-softmmu
|
||||||
|
|
||||||
|
include pci.mak
|
||||||
|
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
CONFIG_VIRTIO_MMIO=y
|
CONFIG_VIRTIO_MMIO=y
|
||||||
include virtio.mak
|
|
||||||
|
|
||||||
CONFIG_CADENCE=y
|
CONFIG_CADENCE=y
|
||||||
|
|
||||||
|
CONFIG_PCI_GENERIC=y
|
||||||
|
|
||||||
|
CONFIG_VGA=y
|
||||||
|
CONFIG_VGA_PCI=y
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
# Default configuration for riscv-softmmu
|
# Default configuration for riscv-softmmu
|
||||||
|
|
||||||
|
include pci.mak
|
||||||
|
|
||||||
CONFIG_SERIAL=y
|
CONFIG_SERIAL=y
|
||||||
CONFIG_VIRTIO_MMIO=y
|
CONFIG_VIRTIO_MMIO=y
|
||||||
include virtio.mak
|
|
||||||
|
|
||||||
CONFIG_CADENCE=y
|
CONFIG_CADENCE=y
|
||||||
|
|
||||||
|
CONFIG_PCI_GENERIC=y
|
||||||
|
|
||||||
|
CONFIG_VGA=y
|
||||||
|
CONFIG_VGA_PCI=y
|
||||||
|
@ -146,15 +146,15 @@ static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
|
|||||||
error_report("clint: invalid timecmp hartid: %zu", hartid);
|
error_report("clint: invalid timecmp hartid: %zu", hartid);
|
||||||
} else if ((addr & 0x7) == 0) {
|
} else if ((addr & 0x7) == 0) {
|
||||||
/* timecmp_lo */
|
/* timecmp_lo */
|
||||||
uint64_t timecmp = env->timecmp;
|
uint64_t timecmp_hi = env->timecmp >> 32;
|
||||||
sifive_clint_write_timecmp(RISCV_CPU(cpu),
|
sifive_clint_write_timecmp(RISCV_CPU(cpu),
|
||||||
timecmp << 32 | (value & 0xFFFFFFFF));
|
timecmp_hi << 32 | (value & 0xFFFFFFFF));
|
||||||
return;
|
return;
|
||||||
} else if ((addr & 0x7) == 4) {
|
} else if ((addr & 0x7) == 4) {
|
||||||
/* timecmp_hi */
|
/* timecmp_hi */
|
||||||
uint64_t timecmp = env->timecmp;
|
uint64_t timecmp_lo = env->timecmp;
|
||||||
sifive_clint_write_timecmp(RISCV_CPU(cpu),
|
sifive_clint_write_timecmp(RISCV_CPU(cpu),
|
||||||
value << 32 | (timecmp & 0xFFFFFFFF));
|
value << 32 | (timecmp_lo & 0xFFFFFFFF));
|
||||||
} else {
|
} else {
|
||||||
error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
|
error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
memmap[SIFIVE_E_QSPI0].base, memmap[SIFIVE_E_QSPI0].size);
|
||||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm0",
|
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm0",
|
||||||
memmap[SIFIVE_E_PWM0].base, memmap[SIFIVE_E_PWM0].size);
|
memmap[SIFIVE_E_PWM0].base, memmap[SIFIVE_E_PWM0].size);
|
||||||
/* sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base,
|
sifive_uart_create(sys_mem, memmap[SIFIVE_E_UART1].base,
|
||||||
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic),
|
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_E_UART1_IRQ));
|
||||||
SIFIVE_E_UART1_IRQ)); */
|
|
||||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi1",
|
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.qspi1",
|
||||||
memmap[SIFIVE_E_QSPI1].base, memmap[SIFIVE_E_QSPI1].size);
|
memmap[SIFIVE_E_QSPI1].base, memmap[SIFIVE_E_QSPI1].size);
|
||||||
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm1",
|
sifive_mmio_emulate(sys_mem, "riscv.sifive.e.pwm1",
|
||||||
|
@ -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 */
|
} else if (addr >= plic->pending_base && /* 1 bit per source */
|
||||||
addr < plic->pending_base + (plic->num_sources >> 3))
|
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) {
|
if (RISCV_DEBUG_PLIC) {
|
||||||
qemu_log("plic: read pending: word=%d value=%d\n",
|
qemu_log("plic: read pending: word=%d value=%d\n",
|
||||||
word, plic->pending[word]);
|
word, plic->pending[word]);
|
||||||
|
@ -85,7 +85,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
|||||||
int cpu;
|
int cpu;
|
||||||
uint32_t *cells;
|
uint32_t *cells;
|
||||||
char *nodename;
|
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);
|
fdt = s->fdt = create_device_tree(&s->fdt_size);
|
||||||
if (!fdt) {
|
if (!fdt) {
|
||||||
@ -197,6 +198,17 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
|||||||
g_free(cells);
|
g_free(cells);
|
||||||
g_free(nodename);
|
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",
|
nodename = g_strdup_printf("/soc/ethernet@%lx",
|
||||||
(long)memmap[SIFIVE_U_GEM].base);
|
(long)memmap[SIFIVE_U_GEM].base);
|
||||||
qemu_fdt_add_subnode(fdt, nodename);
|
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_string(fdt, nodename, "phy-mode", "gmii");
|
||||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupt-parent", plic_phandle);
|
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, "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, "#address-cells", 1);
|
||||||
qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0);
|
qemu_fdt_setprop_cells(fdt, nodename, "#size-cells", 0);
|
||||||
g_free(nodename);
|
g_free(nodename);
|
||||||
@ -225,6 +241,8 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
|
|||||||
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
qemu_fdt_setprop_cells(fdt, nodename, "reg",
|
||||||
0x0, memmap[SIFIVE_U_UART0].base,
|
0x0, memmap[SIFIVE_U_UART0].base,
|
||||||
0x0, memmap[SIFIVE_U_UART0].size);
|
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, "interrupt-parent", plic_phandle);
|
||||||
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 1);
|
qemu_fdt_setprop_cells(fdt, nodename, "interrupts", 1);
|
||||||
|
|
||||||
@ -350,9 +368,8 @@ static void riscv_sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
|||||||
memmap[SIFIVE_U_PLIC].size);
|
memmap[SIFIVE_U_PLIC].size);
|
||||||
sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base,
|
sifive_uart_create(system_memory, memmap[SIFIVE_U_UART0].base,
|
||||||
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
|
serial_hd(0), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART0_IRQ));
|
||||||
/* sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
|
sifive_uart_create(system_memory, memmap[SIFIVE_U_UART1].base,
|
||||||
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic),
|
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
|
||||||
SIFIVE_U_UART1_IRQ)); */
|
|
||||||
sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
|
sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
|
||||||
memmap[SIFIVE_U_CLINT].size, smp_cpus,
|
memmap[SIFIVE_U_CLINT].size, smp_cpus,
|
||||||
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
|
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE);
|
||||||
|
@ -28,12 +28,26 @@
|
|||||||
* Not yet implemented:
|
* Not yet implemented:
|
||||||
*
|
*
|
||||||
* Transmit FIFO using "qemu/fifo8.h"
|
* 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)
|
static void update_irq(SiFiveUARTState *s)
|
||||||
{
|
{
|
||||||
int cond = 0;
|
int cond = 0;
|
||||||
@ -69,7 +83,7 @@ uart_read(void *opaque, hwaddr addr, unsigned int size)
|
|||||||
case SIFIVE_UART_IE:
|
case SIFIVE_UART_IE:
|
||||||
return s->ie;
|
return s->ie;
|
||||||
case SIFIVE_UART_IP:
|
case SIFIVE_UART_IP:
|
||||||
return s->rx_fifo_len ? SIFIVE_UART_IP_RXWM : 0;
|
return uart_ip(s);
|
||||||
case SIFIVE_UART_TXCTRL:
|
case SIFIVE_UART_TXCTRL:
|
||||||
return s->txctrl;
|
return s->txctrl;
|
||||||
case SIFIVE_UART_RXCTRL:
|
case SIFIVE_UART_RXCTRL:
|
||||||
|
131
hw/riscv/virt.c
131
hw/riscv/virt.c
@ -39,6 +39,8 @@
|
|||||||
#include "sysemu/arch_init.h"
|
#include "sysemu/arch_init.h"
|
||||||
#include "sysemu/device_tree.h"
|
#include "sysemu/device_tree.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
|
#include "hw/pci/pci.h"
|
||||||
|
#include "hw/pci-host/gpex.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
|
|
||||||
#include <libfdt.h>
|
#include <libfdt.h>
|
||||||
@ -55,6 +57,9 @@ static const struct MemmapEntry {
|
|||||||
[VIRT_UART0] = { 0x10000000, 0x100 },
|
[VIRT_UART0] = { 0x10000000, 0x100 },
|
||||||
[VIRT_VIRTIO] = { 0x10001000, 0x1000 },
|
[VIRT_VIRTIO] = { 0x10001000, 0x1000 },
|
||||||
[VIRT_DRAM] = { 0x80000000, 0x0 },
|
[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)
|
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;
|
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,
|
static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
||||||
uint64_t mem_size, const char *cmdline)
|
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",
|
nodename = g_strdup_printf("/soc/interrupt-controller@%lx",
|
||||||
(long)memmap[VIRT_PLIC].base);
|
(long)memmap[VIRT_PLIC].base);
|
||||||
qemu_fdt_add_subnode(fdt, nodename);
|
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_string(fdt, nodename, "compatible", "riscv,plic0");
|
||||||
qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
|
qemu_fdt_setprop(fdt, nodename, "interrupt-controller", NULL, 0);
|
||||||
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
|
qemu_fdt_setprop(fdt, nodename, "interrupts-extended",
|
||||||
@ -233,6 +286,33 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
|||||||
g_free(nodename);
|
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",
|
nodename = g_strdup_printf("/test@%lx",
|
||||||
(long)memmap[VIRT_TEST].base);
|
(long)memmap[VIRT_TEST].base);
|
||||||
qemu_fdt_add_subnode(fdt, nodename);
|
qemu_fdt_add_subnode(fdt, nodename);
|
||||||
@ -263,6 +343,47 @@ static void *create_fdt(RISCVVirtState *s, const struct MemmapEntry *memmap,
|
|||||||
return fdt;
|
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)
|
static void riscv_virt_board_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
const struct MemmapEntry *memmap = virt_memmap;
|
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));
|
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,
|
serial_mm_init(system_memory, memmap[VIRT_UART0].base,
|
||||||
0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193,
|
0, qdev_get_gpio_in(DEVICE(s->plic), UART0_IRQ), 399193,
|
||||||
serial_hd(0), DEVICE_LITTLE_ENDIAN);
|
serial_hd(0), DEVICE_LITTLE_ENDIAN);
|
||||||
|
@ -63,7 +63,8 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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"
|
#define SIFIVE_U_PLIC_HART_CONFIG "MS"
|
||||||
|
@ -43,6 +43,9 @@ enum {
|
|||||||
SIFIVE_UART_IP_RXWM = 2 /* Receive watermark interrupt pending */
|
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 TYPE_SIFIVE_UART "riscv.sifive.uart"
|
||||||
|
|
||||||
#define SIFIVE_UART(obj) \
|
#define SIFIVE_UART(obj) \
|
||||||
|
@ -38,14 +38,18 @@ enum {
|
|||||||
VIRT_PLIC,
|
VIRT_PLIC,
|
||||||
VIRT_UART0,
|
VIRT_UART0,
|
||||||
VIRT_VIRTIO,
|
VIRT_VIRTIO,
|
||||||
VIRT_DRAM
|
VIRT_DRAM,
|
||||||
|
VIRT_PCIE_MMIO,
|
||||||
|
VIRT_PCIE_PIO,
|
||||||
|
VIRT_PCIE_ECAM
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
UART0_IRQ = 10,
|
UART0_IRQ = 10,
|
||||||
VIRTIO_IRQ = 1, /* 1 to 8 */
|
VIRTIO_IRQ = 1, /* 1 to 8 */
|
||||||
VIRTIO_COUNT = 8,
|
VIRTIO_COUNT = 8,
|
||||||
VIRTIO_NDEV = 10
|
PCIE_IRQ = 0x20, /* 32 to 35 */
|
||||||
|
VIRTIO_NDEV = 0x35 /* Arbitrary maximum number of interrupts */
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -62,6 +66,13 @@ enum {
|
|||||||
#define VIRT_PLIC_CONTEXT_BASE 0x200000
|
#define VIRT_PLIC_CONTEXT_BASE 0x200000
|
||||||
#define VIRT_PLIC_CONTEXT_STRIDE 0x1000
|
#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)
|
#if defined(TARGET_RISCV32)
|
||||||
#define VIRT_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0
|
#define VIRT_CPU TYPE_RISCV_CPU_RV32GCSU_V1_10_0
|
||||||
#elif defined(TARGET_RISCV64)
|
#elif defined(TARGET_RISCV64)
|
||||||
|
@ -330,8 +330,8 @@ static void riscv_cpu_class_init(ObjectClass *c, void *data)
|
|||||||
CPUClass *cc = CPU_CLASS(c);
|
CPUClass *cc = CPU_CLASS(c);
|
||||||
DeviceClass *dc = DEVICE_CLASS(c);
|
DeviceClass *dc = DEVICE_CLASS(c);
|
||||||
|
|
||||||
mcc->parent_realize = dc->realize;
|
device_class_set_parent_realize(dc, riscv_cpu_realize,
|
||||||
dc->realize = riscv_cpu_realize;
|
&mcc->parent_realize);
|
||||||
|
|
||||||
mcc->parent_reset = cc->reset;
|
mcc->parent_reset = cc->reset;
|
||||||
cc->reset = riscv_cpu_reset;
|
cc->reset = riscv_cpu_reset;
|
||||||
|
@ -445,11 +445,13 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||||||
if (RISCV_DEBUG_INTERRUPT) {
|
if (RISCV_DEBUG_INTERRUPT) {
|
||||||
int log_cause = cs->exception_index & RISCV_EXCP_INT_MASK;
|
int log_cause = cs->exception_index & RISCV_EXCP_INT_MASK;
|
||||||
if (cs->exception_index & RISCV_EXCP_INT_FLAG) {
|
if (cs->exception_index & RISCV_EXCP_INT_FLAG) {
|
||||||
qemu_log_mask(LOG_TRACE, "core 0: trap %s, epc 0x" TARGET_FMT_lx,
|
qemu_log_mask(LOG_TRACE, "core "
|
||||||
riscv_intr_names[log_cause], env->pc);
|
TARGET_FMT_ld ": trap %s, epc 0x" TARGET_FMT_lx "\n",
|
||||||
|
env->mhartid, riscv_intr_names[log_cause], env->pc);
|
||||||
} else {
|
} else {
|
||||||
qemu_log_mask(LOG_TRACE, "core 0: intr %s, epc 0x" TARGET_FMT_lx,
|
qemu_log_mask(LOG_TRACE, "core "
|
||||||
riscv_excp_names[log_cause], env->pc);
|
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 (hasbadaddr) {
|
||||||
if (RISCV_DEBUG_INTERRUPT) {
|
if (RISCV_DEBUG_INTERRUPT) {
|
||||||
qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld
|
qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x"
|
||||||
": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr);
|
TARGET_FMT_lx "\n", env->mhartid, env->badaddr);
|
||||||
}
|
}
|
||||||
env->sbadaddr = env->badaddr;
|
env->sbadaddr = env->badaddr;
|
||||||
} else {
|
} else {
|
||||||
@ -536,8 +538,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
|
|||||||
|
|
||||||
if (hasbadaddr) {
|
if (hasbadaddr) {
|
||||||
if (RISCV_DEBUG_INTERRUPT) {
|
if (RISCV_DEBUG_INTERRUPT) {
|
||||||
qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld
|
qemu_log_mask(LOG_TRACE, "core " TARGET_FMT_ld ": badaddr 0x"
|
||||||
": badaddr 0x" TARGET_FMT_lx, env->mhartid, env->badaddr);
|
TARGET_FMT_lx "\n", env->mhartid, env->badaddr);
|
||||||
}
|
}
|
||||||
env->mbadaddr = env->badaddr;
|
env->mbadaddr = env->badaddr;
|
||||||
} else {
|
} else {
|
||||||
|
@ -138,7 +138,7 @@ static void pmp_decode_napot(target_ulong a, target_ulong *sa, target_ulong *ea)
|
|||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
target_ulong t1 = ctz64(~a);
|
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;
|
target_ulong range = ((target_ulong)1 << (t1 + 3)) - 1;
|
||||||
*sa = base;
|
*sa = base;
|
||||||
*ea = base + range;
|
*ea = base + range;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user