From: Richard Henderson <richard.henderson@linaro.org>
To: qemu-devel@nongnu.org
Cc: Helge Deller <deller@gmx.de>
Subject: [Qemu-devel] [PATCH v3 41/45] hw/hppa: Implement DINO system board
Date: Wed, 24 Jan 2018 15:26:21 -0800 [thread overview]
Message-ID: <20180124232625.30105-42-richard.henderson@linaro.org> (raw)
In-Reply-To: <20180124232625.30105-1-richard.henderson@linaro.org>
From: Helge Deller <deller@gmx.de>
Now that we have the prerequisites in target/hppa/,
implement the hardware for a PA7100LC.
This also enables build for hppa-softmmu.
Signed-off-by: Helge Deller <deller@gmx.de>
[rth: Since it is all new code, squashed all branch development
withing hw/hppa/ to a single patch.]
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
Makefile.objs | 1 +
hw/hppa/hppa_hardware.h | 40 +++
hw/hppa/hppa_sys.h | 24 ++
hw/hppa/dino.c | 518 +++++++++++++++++++++++++++++++++++++++
hw/hppa/machine.c | 246 ++++++++++++++++++-
hw/hppa/pci.c | 90 +++++++
default-configs/hppa-softmmu.mak | 14 ++
hw/hppa/Makefile.objs | 2 +-
hw/hppa/trace-events | 4 +
9 files changed, 937 insertions(+), 2 deletions(-)
create mode 100644 hw/hppa/hppa_hardware.h
create mode 100644 hw/hppa/hppa_sys.h
create mode 100644 hw/hppa/dino.c
create mode 100644 hw/hppa/pci.c
create mode 100644 default-configs/hppa-softmmu.mak
create mode 100644 hw/hppa/trace-events
diff --git a/Makefile.objs b/Makefile.objs
index 669d8d684d..c52925133a 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -155,6 +155,7 @@ trace-events-subdirs += hw/vfio
trace-events-subdirs += hw/acpi
trace-events-subdirs += hw/arm
trace-events-subdirs += hw/alpha
+trace-events-subdirs += hw/hppa
trace-events-subdirs += hw/xen
trace-events-subdirs += hw/ide
trace-events-subdirs += ui
diff --git a/hw/hppa/hppa_hardware.h b/hw/hppa/hppa_hardware.h
new file mode 100644
index 0000000000..2c61b1f77c
--- /dev/null
+++ b/hw/hppa/hppa_hardware.h
@@ -0,0 +1,40 @@
+/* HPPA cores and system support chips. */
+
+#define FIRMWARE_START 0xf0000000
+#define FIRMWARE_END 0xf0800000
+
+#define DEVICE_HPA_LEN 0x00100000
+
+#define GSC_HPA 0xffc00000
+#define DINO_HPA 0xfff80000
+#define DINO_UART_HPA 0xfff83000
+#define DINO_UART_BASE 0xfff83800
+#define DINO_SCSI_HPA 0xfff8c000
+#define LASI_HPA 0xffd00000
+#define LASI_UART_HPA 0xffd05000
+#define LASI_SCSI_HPA 0xffd06000
+#define LASI_LAN_HPA 0xffd07000
+#define LASI_LPT_HPA 0xffd02000
+#define LASI_AUDIO_HPA 0xffd04000
+#define LASI_PS2KBD_HPA 0xffd08000
+#define LASI_PS2MOU_HPA 0xffd08100
+#define LASI_GFX_HPA 0xf8000000
+#define CPU_HPA 0xfff10000
+#define MEMORY_HPA 0xfffbf000
+
+#define PCI_HPA DINO_HPA /* PCI bus */
+#define IDE_HPA 0xf9000000 /* Boot disc controller */
+
+/* offsets to DINO HPA: */
+#define DINO_PCI_ADDR 0x064
+#define DINO_CONFIG_DATA 0x068
+#define DINO_IO_DATA 0x06c
+
+#define PORT_PCI_CMD (PCI_HPA + DINO_PCI_ADDR)
+#define PORT_PCI_DATA (PCI_HPA + DINO_CONFIG_DATA)
+
+#define PORT_SERIAL1 (DINO_UART_HPA + 0x800)
+#define PORT_SERIAL2 (LASI_UART_HPA + 0x800)
+
+#define HPPA_MAX_CPUS 32 /* max. number of SMP CPUs */
+#define CPU_CLOCK_MHZ 250 /* emulate a 250 MHz CPU */
diff --git a/hw/hppa/hppa_sys.h b/hw/hppa/hppa_sys.h
new file mode 100644
index 0000000000..a182d1f34e
--- /dev/null
+++ b/hw/hppa/hppa_sys.h
@@ -0,0 +1,24 @@
+/* HPPA cores and system support chips. */
+
+#ifndef HW_HPPA_SYS_H
+#define HW_HPPA_SYS_H
+
+#include "target/hppa/cpu-qom.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_host.h"
+#include "hw/ide.h"
+#include "hw/i386/pc.h"
+#include "hw/irq.h"
+
+#include "hw/hppa/hppa_hardware.h"
+
+PCIBus *dino_init(MemoryRegion *, qemu_irq *, qemu_irq *);
+
+#define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost"
+
+/* hppa_pci.c. */
+extern const MemoryRegionOps hppa_pci_ignore_ops;
+extern const MemoryRegionOps hppa_pci_conf1_ops;
+extern const MemoryRegionOps hppa_pci_iack_ops;
+
+#endif
diff --git a/hw/hppa/dino.c b/hw/hppa/dino.c
new file mode 100644
index 0000000000..15aefde09c
--- /dev/null
+++ b/hw/hppa/dino.c
@@ -0,0 +1,518 @@
+/*
+ * HP-PARISC Dino PCI chipset emulation.
+ *
+ * (C) 2017 by Helge Deller <deller@gmx.de>
+ *
+ * This work is licensed under the GNU GPL license version 2 or later.
+ *
+ * Documentation available at:
+ * https://parisc.wiki.kernel.org/images-parisc/9/91/Dino_ers.pdf
+ * https://parisc.wiki.kernel.org/images-parisc/7/70/Dino_3_1_Errata.pdf
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "cpu.h"
+#include "hw/hw.h"
+#include "hw/devices.h"
+#include "sysemu/sysemu.h"
+#include "hw/pci/pci.h"
+#include "hw/pci/pci_bus.h"
+#include "hppa_sys.h"
+#include "exec/address-spaces.h"
+
+
+#define TYPE_DINO_PCI_HOST_BRIDGE "dino-pcihost"
+
+#define DINO_IAR0 0x004
+#define DINO_IODC 0x008
+#define DINO_IRR0 0x00C /* RO */
+#define DINO_IAR1 0x010
+#define DINO_IRR1 0x014 /* RO */
+#define DINO_IMR 0x018
+#define DINO_IPR 0x01C
+#define DINO_TOC_ADDR 0x020
+#define DINO_ICR 0x024
+#define DINO_ILR 0x028 /* RO */
+#define DINO_IO_COMMAND 0x030 /* WO */
+#define DINO_IO_STATUS 0x034 /* RO */
+#define DINO_IO_CONTROL 0x038
+#define DINO_IO_GSC_ERR_RESP 0x040 /* RO */
+#define DINO_IO_ERR_INFO 0x044 /* RO */
+#define DINO_IO_PCI_ERR_RESP 0x048 /* RO */
+#define DINO_IO_FBB_EN 0x05c
+#define DINO_IO_ADDR_EN 0x060
+#define DINO_PCI_CONFIG_ADDR 0x064
+#define DINO_PCI_CONFIG_DATA 0x068
+#define DINO_PCI_IO_DATA 0x06c
+#define DINO_PCI_MEM_DATA 0x070 /* Dino 3.x only */
+#define DINO_GSC2X_CONFIG 0x7b4 /* RO */
+#define DINO_GMASK 0x800
+#define DINO_PAMR 0x804
+#define DINO_PAPR 0x808
+#define DINO_DAMODE 0x80c
+#define DINO_PCICMD 0x810
+#define DINO_PCISTS 0x814 /* R/WC */
+#define DINO_MLTIM 0x81c
+#define DINO_BRDG_FEAT 0x820
+#define DINO_PCIROR 0x824
+#define DINO_PCIWOR 0x828
+#define DINO_TLTIM 0x830
+
+#define DINO_IRQS 11 /* bits 0-10 are architected */
+#define DINO_IRR_MASK 0x5ff /* only 10 bits are implemented */
+#define DINO_LOCAL_IRQS (DINO_IRQS + 1)
+#define DINO_MASK_IRQ(x) (1 << (x))
+
+#define PCIINTA 0x001
+#define PCIINTB 0x002
+#define PCIINTC 0x004
+#define PCIINTD 0x008
+#define PCIINTE 0x010
+#define PCIINTF 0x020
+#define GSCEXTINT 0x040
+/* #define xxx 0x080 - bit 7 is "default" */
+/* #define xxx 0x100 - bit 8 not used */
+/* #define xxx 0x200 - bit 9 not used */
+#define RS232INT 0x400
+
+#define DINO_MEM_CHUNK_SIZE (8 * 1024 * 1024) /* 8MB */
+
+#define DINO_PCI_HOST_BRIDGE(obj) \
+ OBJECT_CHECK(DinoState, (obj), TYPE_DINO_PCI_HOST_BRIDGE)
+
+typedef struct DinoState {
+ PCIHostState parent_obj;
+
+ /* PCI_CONFIG_ADDR is parent_obj.config_reg, via pci_host_conf_be_ops,
+ so that we can map PCI_CONFIG_DATA to pci_host_data_be_ops. */
+
+ uint32_t iar0;
+ uint32_t iar1;
+ uint32_t imr;
+ uint32_t ipr;
+ uint32_t icr;
+ uint32_t ilr;
+ uint32_t io_addr_en;
+ uint32_t io_control;
+
+ MemoryRegion this_mem;
+ MemoryRegion pci_mem;
+ MemoryRegion pci_mem_alias[32];
+
+ AddressSpace bm_as;
+ MemoryRegion bm;
+ MemoryRegion bm_ram_alias;
+ MemoryRegion bm_pci_alias;
+
+ MemoryRegion cpu0_eir_mem;
+} DinoState;
+
+/*
+ * Dino can forward memory accesses from the CPU in the range between
+ * 0xf0800000 and 0xff000000 to the PCI bus.
+ */
+static void gsc_to_pci_forwarding(DinoState *s)
+{
+ uint32_t io_addr_en, tmp;
+ int enabled, i;
+
+ tmp = extract32(s->io_control, 7, 2);
+ enabled = (tmp == 0x01);
+ io_addr_en = s->io_addr_en;
+
+ memory_region_transaction_begin();
+ for (i = 1; i < 31; i++) {
+ MemoryRegion *mem = &s->pci_mem_alias[i];
+ if (enabled && (io_addr_en & (1U << i))) {
+ if (!memory_region_is_mapped(mem)) {
+ uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE;
+ memory_region_add_subregion(get_system_memory(), addr, mem);
+ }
+ } else if (memory_region_is_mapped(mem)) {
+ memory_region_del_subregion(get_system_memory(), mem);
+ }
+ }
+ memory_region_transaction_commit();
+}
+
+static bool dino_chip_mem_valid(void *opaque, hwaddr addr,
+ unsigned size, bool is_write)
+{
+ switch (addr) {
+ case DINO_IAR0:
+ case DINO_IAR1:
+ case DINO_IRR0:
+ case DINO_IRR1:
+ case DINO_IMR:
+ case DINO_IPR:
+ case DINO_ICR:
+ case DINO_ILR:
+ case DINO_IO_CONTROL:
+ case DINO_IO_ADDR_EN:
+ case DINO_PCI_IO_DATA:
+ return true;
+ case DINO_PCI_IO_DATA + 2:
+ return size <= 2;
+ case DINO_PCI_IO_DATA + 1:
+ case DINO_PCI_IO_DATA + 3:
+ return size == 1;
+ }
+ return false;
+}
+
+static MemTxResult dino_chip_read_with_attrs(void *opaque, hwaddr addr,
+ uint64_t *data, unsigned size,
+ MemTxAttrs attrs)
+{
+ DinoState *s = opaque;
+ MemTxResult ret = MEMTX_OK;
+ AddressSpace *io;
+ uint16_t ioaddr;
+ uint32_t val;
+
+ switch (addr) {
+ case DINO_PCI_IO_DATA ... DINO_PCI_IO_DATA + 3:
+ /* Read from PCI IO space. */
+ io = &address_space_io;
+ ioaddr = s->parent_obj.config_reg;
+ switch (size) {
+ case 1:
+ val = address_space_ldub(io, ioaddr, attrs, &ret);
+ break;
+ case 2:
+ val = address_space_lduw_be(io, ioaddr, attrs, &ret);
+ break;
+ case 4:
+ val = address_space_ldl_be(io, ioaddr, attrs, &ret);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ break;
+
+ case DINO_IO_ADDR_EN:
+ val = s->io_addr_en;
+ break;
+ case DINO_IO_CONTROL:
+ val = s->io_control;
+ break;
+
+ case DINO_IAR0:
+ val = s->iar0;
+ break;
+ case DINO_IAR1:
+ val = s->iar1;
+ break;
+ case DINO_IMR:
+ val = s->imr;
+ break;
+ case DINO_ICR:
+ val = s->icr;
+ break;
+ case DINO_IPR:
+ val = s->ipr;
+ /* Any read to IPR clears the register. */
+ s->ipr = 0;
+ break;
+ case DINO_ILR:
+ val = s->ilr;
+ break;
+ case DINO_IRR0:
+ val = s->ilr & s->imr & ~s->icr;
+ break;
+ case DINO_IRR1:
+ val = s->ilr & s->imr & s->icr;
+ break;
+
+ default:
+ /* Controlled by dino_chip_mem_valid above. */
+ g_assert_not_reached();
+ }
+
+ *data = val;
+ return ret;
+}
+
+static MemTxResult dino_chip_write_with_attrs(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size,
+ MemTxAttrs attrs)
+{
+ DinoState *s = opaque;
+ AddressSpace *io;
+ MemTxResult ret;
+ uint16_t ioaddr;
+
+ switch (addr) {
+ case DINO_IO_DATA ... DINO_PCI_IO_DATA + 3:
+ /* Write into PCI IO space. */
+ io = &address_space_io;
+ ioaddr = s->parent_obj.config_reg;
+ switch (size) {
+ case 1:
+ address_space_stb(io, ioaddr, val, attrs, &ret);
+ break;
+ case 2:
+ address_space_stw_be(io, ioaddr, val, attrs, &ret);
+ break;
+ case 4:
+ address_space_stl_be(io, ioaddr, val, attrs, &ret);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return ret;
+
+ case DINO_IO_ADDR_EN:
+ /* Never allow first (=firmware) and last (=Dino) areas. */
+ s->io_addr_en = val & 0x7ffffffe;
+ gsc_to_pci_forwarding(s);
+ break;
+ case DINO_IO_CONTROL:
+ s->io_control = val;
+ gsc_to_pci_forwarding(s);
+ break;
+
+ case DINO_IAR0:
+ s->iar0 = val;
+ break;
+ case DINO_IAR1:
+ s->iar1 = val;
+ break;
+ case DINO_IMR:
+ s->imr = val;
+ break;
+ case DINO_ICR:
+ s->icr = val;
+ break;
+ case DINO_IPR:
+ /* Any write to IPR clears the register. */
+ s->ipr = 0;
+ break;
+
+ case DINO_ILR:
+ case DINO_IRR0:
+ case DINO_IRR1:
+ /* These registers are read-only. */
+ break;
+
+ default:
+ /* Controlled by dino_chip_mem_valid above. */
+ g_assert_not_reached();
+ }
+ return MEMTX_OK;
+}
+
+static const MemoryRegionOps dino_chip_ops = {
+ .read_with_attrs = dino_chip_read_with_attrs,
+ .write_with_attrs = dino_chip_write_with_attrs,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ .accepts = dino_chip_mem_valid,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static const VMStateDescription vmstate_dino = {
+ .name = "Dino",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(iar0, DinoState),
+ VMSTATE_UINT32(iar1, DinoState),
+ VMSTATE_UINT32(imr, DinoState),
+ VMSTATE_UINT32(ipr, DinoState),
+ VMSTATE_UINT32(icr, DinoState),
+ VMSTATE_UINT32(ilr, DinoState),
+ VMSTATE_UINT32(io_addr_en, DinoState),
+ VMSTATE_UINT32(io_control, DinoState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+
+/* Unlike pci_config_data_le_ops, no check of high bit set in config_reg. */
+
+static uint64_t dino_config_data_read(void *opaque, hwaddr addr, unsigned len)
+{
+ PCIHostState *s = opaque;
+ return pci_data_read(s->bus, s->config_reg | (addr & 3), len);
+}
+
+static void dino_config_data_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned len)
+{
+ PCIHostState *s = opaque;
+ pci_data_write(s->bus, s->config_reg | (addr & 3), val, len);
+}
+
+static const MemoryRegionOps dino_config_data_ops = {
+ .read = dino_config_data_read,
+ .write = dino_config_data_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
+static AddressSpace *dino_pcihost_set_iommu(PCIBus *bus, void *opaque,
+ int devfn)
+{
+ DinoState *s = opaque;
+
+ return &s->bm_as;
+}
+
+/*
+ * Dino interrupts are connected as shown on Page 78, Table 23
+ * (Little-endian bit numbers)
+ * 0 PCI INTA
+ * 1 PCI INTB
+ * 2 PCI INTC
+ * 3 PCI INTD
+ * 4 PCI INTE
+ * 5 PCI INTF
+ * 6 GSC External Interrupt
+ * 7 Bus Error for "less than fatal" mode
+ * 8 PS2
+ * 9 Unused
+ * 10 RS232
+ */
+
+static void dino_set_irq(void *opaque, int irq, int level)
+{
+ DinoState *s = opaque;
+ uint32_t bit = 1u << irq;
+ uint32_t old_ilr = s->ilr;
+
+ if (level) {
+ uint32_t ena = bit & ~old_ilr;
+ s->ipr |= ena;
+ s->ilr = old_ilr | bit;
+ if (ena & s->imr) {
+ uint32_t iar = (ena & s->icr ? s->iar1 : s->iar0);
+ stl_be_phys(&address_space_memory, iar & -32, iar & 31);
+ }
+ } else {
+ s->ilr = old_ilr & ~bit;
+ }
+}
+
+static int dino_pci_map_irq(PCIDevice *d, int irq_num)
+{
+ int slot = d->devfn >> 3;
+ int local_irq;
+
+ assert(irq_num >= 0 && irq_num <= 3);
+
+ local_irq = slot & 0x03;
+
+ return local_irq;
+}
+
+static void dino_set_timer_irq(void *opaque, int irq, int level)
+{
+ /* ??? Not connected. */
+}
+
+static void dino_set_serial_irq(void *opaque, int irq, int level)
+{
+ dino_set_irq(opaque, 10, level);
+}
+
+PCIBus *dino_init(MemoryRegion *addr_space,
+ qemu_irq *p_rtc_irq, qemu_irq *p_ser_irq)
+{
+ DeviceState *dev;
+ DinoState *s;
+ PCIBus *b;
+ int i;
+
+ dev = qdev_create(NULL, TYPE_DINO_PCI_HOST_BRIDGE);
+ s = DINO_PCI_HOST_BRIDGE(dev);
+
+ /* Dino PCI access from main memory. */
+ memory_region_init_io(&s->this_mem, OBJECT(s), &dino_chip_ops,
+ s, "dino", 4096);
+ memory_region_add_subregion(addr_space, DINO_HPA, &s->this_mem);
+
+ /* Dino PCI config. */
+ memory_region_init_io(&s->parent_obj.conf_mem, OBJECT(&s->parent_obj),
+ &pci_host_conf_be_ops, dev, "pci-conf-idx", 4);
+ memory_region_init_io(&s->parent_obj.data_mem, OBJECT(&s->parent_obj),
+ &dino_config_data_ops, dev, "pci-conf-data", 4);
+ memory_region_add_subregion(&s->this_mem, DINO_PCI_CONFIG_ADDR,
+ &s->parent_obj.conf_mem);
+ memory_region_add_subregion(&s->this_mem, DINO_CONFIG_DATA,
+ &s->parent_obj.data_mem);
+
+ /* Dino PCI bus memory. */
+ memory_region_init(&s->pci_mem, OBJECT(s), "pci-memory", 1ull << 32);
+
+ b = pci_register_root_bus(dev, "pci", dino_set_irq, dino_pci_map_irq, s,
+ &s->pci_mem, get_system_io(),
+ PCI_DEVFN(0, 0), 32, TYPE_PCI_BUS);
+ s->parent_obj.bus = b;
+ qdev_init_nofail(dev);
+
+ /* Set up windows into PCI bus memory. */
+ for (i = 1; i < 31; i++) {
+ uint32_t addr = 0xf0000000 + i * DINO_MEM_CHUNK_SIZE;
+ char *name = g_strdup_printf("PCI Outbound Window %d", i);
+ memory_region_init_alias(&s->pci_mem_alias[i], OBJECT(s),
+ name, &s->pci_mem, addr,
+ DINO_MEM_CHUNK_SIZE);
+ }
+
+ /* Set up PCI view of memory: Bus master address space. */
+ memory_region_init(&s->bm, OBJECT(s), "bm-dino", 1ull << 32);
+ memory_region_init_alias(&s->bm_ram_alias, OBJECT(s),
+ "bm-system", addr_space, 0,
+ 0xf0000000 + DINO_MEM_CHUNK_SIZE);
+ memory_region_init_alias(&s->bm_pci_alias, OBJECT(s),
+ "bm-pci", &s->pci_mem,
+ 0xf0000000 + DINO_MEM_CHUNK_SIZE,
+ 31 * DINO_MEM_CHUNK_SIZE);
+ memory_region_add_subregion(&s->bm, 0,
+ &s->bm_ram_alias);
+ memory_region_add_subregion(&s->bm,
+ 0xf0000000 + DINO_MEM_CHUNK_SIZE,
+ &s->bm_pci_alias);
+ address_space_init(&s->bm_as, &s->bm, "pci-bm");
+ pci_setup_iommu(b, dino_pcihost_set_iommu, s);
+
+ *p_rtc_irq = qemu_allocate_irq(dino_set_timer_irq, s, 0);
+ *p_ser_irq = qemu_allocate_irq(dino_set_serial_irq, s, 0);
+
+ return b;
+}
+
+static int dino_pcihost_init(SysBusDevice *dev)
+{
+ return 0;
+}
+
+static void dino_pcihost_class_init(ObjectClass *klass, void *data)
+{
+ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ k->init = dino_pcihost_init;
+ dc->vmsd = &vmstate_dino;
+}
+
+static const TypeInfo dino_pcihost_info = {
+ .name = TYPE_DINO_PCI_HOST_BRIDGE,
+ .parent = TYPE_PCI_HOST_BRIDGE,
+ .instance_size = sizeof(DinoState),
+ .class_init = dino_pcihost_class_init,
+};
+
+static void dino_register_types(void)
+{
+ type_register_static(&dino_pcihost_info);
+}
+
+type_init(dino_register_types)
diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index 79958da18f..2b66298af5 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -16,20 +16,264 @@
#include "hw/ide.h"
#include "hw/timer/i8254.h"
#include "hw/char/serial.h"
+#include "hw/hppa/hppa_sys.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
+#define MAX_IDE_BUS 2
+
+static ISABus *hppa_isa_bus(void)
+{
+ ISABus *isa_bus;
+ qemu_irq *isa_irqs;
+ MemoryRegion *isa_region;
+
+ isa_region = g_new(MemoryRegion, 1);
+ memory_region_init_io(isa_region, NULL, &hppa_pci_ignore_ops,
+ NULL, "isa-io", 0x800);
+ memory_region_add_subregion(get_system_memory(), IDE_HPA,
+ isa_region);
+
+ isa_bus = isa_bus_new(NULL, get_system_memory(), isa_region,
+ &error_abort);
+ isa_irqs = i8259_init(isa_bus,
+ /* qemu_allocate_irq(dino_set_isa_irq, s, 0)); */
+ NULL);
+ isa_bus_irqs(isa_bus, isa_irqs);
+
+ return isa_bus;
+}
+
+static uint64_t cpu_hppa_to_phys(void *opaque, uint64_t addr)
+{
+ addr &= (0x10000000 - 1);
+ return addr;
+}
+
+static HPPACPU *cpu[HPPA_MAX_CPUS];
+static uint64_t firmware_entry;
static void machine_hppa_init(MachineState *machine)
{
+ const char *kernel_filename = machine->kernel_filename;
+ const char *kernel_cmdline = machine->kernel_cmdline;
+ const char *initrd_filename = machine->initrd_filename;
+ PCIBus *pci_bus;
+ ISABus *isa_bus;
+ qemu_irq rtc_irq, serial_irq;
+ char *firmware_filename;
+ uint64_t firmware_low, firmware_high;
+ long size;
+ uint64_t kernel_entry = 0, kernel_low, kernel_high;
+ MemoryRegion *addr_space = get_system_memory();
+ MemoryRegion *rom_region;
+ MemoryRegion *ram_region;
+ MemoryRegion *cpu_region;
+ long i;
+
+ ram_size = machine->ram_size;
+
+ /* Create CPUs. */
+ for (i = 0; i < smp_cpus; i++) {
+ cpu[i] = HPPA_CPU(cpu_create(machine->cpu_type));
+
+ cpu_region = g_new(MemoryRegion, 1);
+ memory_region_init_io(cpu_region, OBJECT(cpu[i]), &hppa_io_eir_ops,
+ cpu[i], g_strdup_printf("cpu%ld-io-eir", i), 4);
+ memory_region_add_subregion(addr_space, CPU_HPA + i * 0x1000,
+ cpu_region);
+ }
+
+ /* Limit main memory. */
+ if (ram_size > FIRMWARE_START) {
+ machine->ram_size = ram_size = FIRMWARE_START;
+ }
+
+ /* Main memory region. */
+ ram_region = g_new(MemoryRegion, 1);
+ memory_region_allocate_system_memory(ram_region, OBJECT(machine),
+ "ram", ram_size);
+ memory_region_add_subregion(addr_space, 0, ram_region);
+
+ /* Init Dino (PCI host bus chip). */
+ pci_bus = dino_init(addr_space, &rtc_irq, &serial_irq);
+ assert(pci_bus);
+
+ /* Create ISA bus. */
+ isa_bus = hppa_isa_bus();
+ assert(isa_bus);
+
+ /* Realtime clock, used by firmware for PDC_TOD call. */
+ mc146818_rtc_init(isa_bus, 2000, rtc_irq);
+
+ /* Serial code setup. */
+ if (serial_hds[0]) {
+ uint32_t addr = DINO_UART_HPA + 0x800;
+ serial_mm_init(addr_space, addr, 0, serial_irq,
+ 115200, serial_hds[0], DEVICE_BIG_ENDIAN);
+ fprintf(stderr, "Serial port created at 0x%x\n", addr);
+ }
+
+ /* SCSI disk setup. */
+ lsi53c895a_create(pci_bus);
+
+ /* Network setup. e1000 is good enough, failing Tulip support. */
+ for (i = 0; i < nb_nics; i++) {
+ pci_nic_init_nofail(&nd_table[i], pci_bus, "e1000", NULL);
+ }
+
+ /* Load firmware. Given that this is not "real" firmware,
+ but one explicitly written for the emulation, we might as
+ well load it directly from an ELF image. */
+ firmware_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS,
+ bios_name ? bios_name :
+ "hppa-firmware.img");
+ if (firmware_filename == NULL) {
+ error_report("no firmware provided");
+ exit(1);
+ }
+
+ size = load_elf(firmware_filename, NULL,
+ NULL, &firmware_entry, &firmware_low, &firmware_high,
+ true, EM_PARISC, 0, 0);
+
+ /* Unfortunately, load_elf sign-extends reading elf32. */
+ firmware_entry = (target_ureg)firmware_entry;
+ firmware_low = (target_ureg)firmware_low;
+ firmware_high = (target_ureg)firmware_high;
+
+ if (size < 0) {
+ error_report("could not load firmware '%s'", firmware_filename);
+ exit(1);
+ }
+ fprintf(stderr, "Firmware loaded at 0x%08lx-0x%08lx, entry at 0x%08lx.\n",
+ firmware_low, firmware_high, firmware_entry);
+ if (firmware_low < ram_size || firmware_high >= FIRMWARE_END) {
+ error_report("Firmware overlaps with memory or IO space");
+ exit(1);
+ }
+ g_free(firmware_filename);
+
+ rom_region = g_new(MemoryRegion, 1);
+ memory_region_allocate_system_memory(rom_region, OBJECT(machine),
+ "firmware",
+ (FIRMWARE_END - FIRMWARE_START));
+ memory_region_add_subregion(addr_space, FIRMWARE_START, rom_region);
+
+ /* Load kernel */
+ if (kernel_filename) {
+ fprintf(stderr, "LOADING kernel '%s'\n", kernel_filename);
+ size = load_elf(kernel_filename, &cpu_hppa_to_phys,
+ NULL, &kernel_entry, &kernel_low, &kernel_high,
+ true, EM_PARISC, 0, 0);
+
+ /* Unfortunately, load_elf sign-extends reading elf32. */
+ kernel_entry = (target_ureg) cpu_hppa_to_phys(NULL, kernel_entry);
+ kernel_low = (target_ureg)kernel_low;
+ kernel_high = (target_ureg)kernel_high;
+
+ if (size < 0) {
+ error_report("could not load kernel '%s'", kernel_filename);
+ exit(1);
+ }
+
+ fprintf(stderr, "Kernel loaded at 0x%08lx-0x%08lx, entry at 0x%08lx, "
+ "size %ld kB.\n",
+ kernel_low, kernel_high, kernel_entry, size / 1024);
+
+ if (kernel_cmdline) {
+ cpu[0]->env.gr[24] = 0x4000;
+ pstrcpy_targphys("cmdline", cpu[0]->env.gr[24],
+ TARGET_PAGE_SIZE, kernel_cmdline);
+ }
+
+ if (initrd_filename) {
+ ram_addr_t initrd_base;
+ long initrd_size;
+
+ initrd_size = get_image_size(initrd_filename);
+ if (initrd_size < 0) {
+ error_report("could not load initial ram disk '%s'",
+ initrd_filename);
+ exit(1);
+ }
+
+ /* Load the initrd image high in memory.
+ Mirror the algorithm used by palo:
+ (1) Due to sign-extension problems and PDC,
+ put the initrd no higher than 1G.
+ (2) Reserve 64k for stack. */
+ initrd_base = MIN(ram_size, 1024 * 1024 * 1024);
+ initrd_base = initrd_base - 64 * 1024;
+ initrd_base = (initrd_base - initrd_size) & TARGET_PAGE_MASK;
+
+ if (initrd_base < kernel_high) {
+ error_report("kernel and initial ram disk too large!");
+ exit(1);
+ }
+
+ load_image_targphys(initrd_filename, initrd_base, initrd_size);
+ cpu[0]->env.gr[23] = initrd_base;
+ cpu[0]->env.gr[22] = initrd_base + initrd_size;
+ }
+ }
+
+ if (!kernel_entry) {
+ /* When booting via firmware, tell firmware if we want interactive
+ * mode (kernel_entry=1), and to boot from CD (gr[24]='d')
+ * or hard disc * (gr[24]='c').
+ */
+ kernel_entry = boot_menu ? 1 : 0;
+ cpu[0]->env.gr[24] = machine->boot_order[0];
+ }
+
+ /* We jump to the firmware entry routine and pass the
+ * various parameters in registers. After firmware initialization,
+ * firmware will start the Linux kernel with ramdisk and cmdline.
+ */
+ cpu[0]->env.gr[26] = ram_size;
+ cpu[0]->env.gr[25] = kernel_entry;
+
+ /* tell firmware how many SMP CPUs to present in inventory table */
+ cpu[0]->env.gr[21] = smp_cpus;
}
+static void hppa_machine_reset(void)
+{
+ int i;
+
+ qemu_devices_reset();
+
+ /* Start all CPUs at the firmware entry point.
+ * Monarch CPU will initialize firmware, secondary CPUs
+ * will enter a small idle look and wait for rendevouz. */
+ for (i = 0; i < smp_cpus; i++) {
+ cpu_set_pc(CPU(cpu[i]), firmware_entry);
+ cpu[i]->env.gr[5] = CPU_HPA + i * 0x1000;
+ }
+
+ /* already initialized by machine_hppa_init()? */
+ if (cpu[0]->env.gr[26] == ram_size) {
+ return;
+ }
+
+ cpu[0]->env.gr[26] = ram_size;
+ cpu[0]->env.gr[25] = 0; /* no firmware boot menu */
+ cpu[0]->env.gr[24] = 'c';
+ /* gr22/gr23 unused, no initrd while reboot. */
+ cpu[0]->env.gr[21] = smp_cpus;
+}
+
+
static void machine_hppa_machine_init(MachineClass *mc)
{
mc->desc = "HPPA generic machine";
+ mc->default_cpu_type = TYPE_HPPA_CPU;
mc->init = machine_hppa_init;
+ mc->reset = hppa_machine_reset;
mc->block_default_type = IF_SCSI;
- mc->max_cpus = 1;
+ mc->max_cpus = HPPA_MAX_CPUS;
+ mc->default_cpus = 1;
mc->is_default = 1;
mc->default_ram_size = 512 * M_BYTE;
mc->default_boot_order = "cd";
diff --git a/hw/hppa/pci.c b/hw/hppa/pci.c
new file mode 100644
index 0000000000..766420254e
--- /dev/null
+++ b/hw/hppa/pci.c
@@ -0,0 +1,90 @@
+/*
+ * QEMU HP-PARISC PCI support functions.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "hppa_sys.h"
+#include "qemu/log.h"
+#include "sysemu/sysemu.h"
+#include "trace.h"
+
+
+/* Fallback for unassigned PCI I/O operations. Avoids MCHK. */
+
+static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return 0;
+}
+
+static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size)
+{
+}
+
+const MemoryRegionOps hppa_pci_ignore_ops = {
+ .read = ignore_read,
+ .write = ignore_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+};
+
+
+/* PCI config space reads/writes, to byte-word addressable memory. */
+static uint64_t bw_conf1_read(void *opaque, hwaddr addr,
+ unsigned size)
+{
+ PCIBus *b = opaque;
+ return pci_data_read(b, addr, size);
+}
+
+static void bw_conf1_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ PCIBus *b = opaque;
+ pci_data_write(b, addr, val, size);
+}
+
+const MemoryRegionOps hppa_pci_conf1_ops = {
+ .read = bw_conf1_read,
+ .write = bw_conf1_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+/* PCI/EISA Interrupt Acknowledge Cycle. */
+
+static uint64_t iack_read(void *opaque, hwaddr addr, unsigned size)
+{
+ return pic_read_irq(isa_pic);
+}
+
+static void special_write(void *opaque, hwaddr addr,
+ uint64_t val, unsigned size)
+{
+ trace_hppa_pci_iack_write();
+}
+
+const MemoryRegionOps hppa_pci_iack_ops = {
+ .read = iack_read,
+ .write = special_write,
+ .endianness = DEVICE_BIG_ENDIAN,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
diff --git a/default-configs/hppa-softmmu.mak b/default-configs/hppa-softmmu.mak
new file mode 100644
index 0000000000..013e5f046f
--- /dev/null
+++ b/default-configs/hppa-softmmu.mak
@@ -0,0 +1,14 @@
+include pci.mak
+include usb.mak
+CONFIG_SERIAL=y
+CONFIG_SERIAL_ISA=y
+CONFIG_ISA_BUS=y
+CONFIG_I8259=y
+CONFIG_VIRTIO_PCI=$(CONFIG_PCI)
+CONFIG_VIRTIO=y
+CONFIG_E1000_PCI=y
+CONFIG_IDE_ISA=y
+CONFIG_IDE_CMD646=y
+# CONFIG_IDE_MMIO=y
+CONFIG_VIRTIO_VGA=y
+CONFIG_MC146818RTC=y
diff --git a/hw/hppa/Makefile.objs b/hw/hppa/Makefile.objs
index 46b2ae18de..bef241ed25 100644
--- a/hw/hppa/Makefile.objs
+++ b/hw/hppa/Makefile.objs
@@ -1 +1 @@
-obj-y += machine.o
+obj-y += machine.o pci.o dino.o
diff --git a/hw/hppa/trace-events b/hw/hppa/trace-events
new file mode 100644
index 0000000000..14c67937e1
--- /dev/null
+++ b/hw/hppa/trace-events
@@ -0,0 +1,4 @@
+# See docs/devel/tracing.txt for syntax documentation.
+
+# hw/hppa/pci.c
+hppa_pci_iack_write(void) ""
--
2.14.3
next prev parent reply other threads:[~2018-01-24 23:27 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-01-24 23:25 [Qemu-devel] [PATCH v3 00/45] hppa-softmmu Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 01/45] target/hppa: Skeleton support for hppa-softmmu Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 02/45] target/hppa: Define the rest of the PSW Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 03/45] target/hppa: Disable gateway page emulation for system mode Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 04/45] target/hppa: Define hardware exception types Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 05/45] target/hppa: Split address size from register size Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 06/45] target/hppa: Implement mmu_idx from IA privilege level Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 07/45] target/hppa: Implement the system mask instructions Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 08/45] target/hppa: Add space registers Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 09/45] target/hppa: Add control registers Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 10/45] target/hppa: Adjust insn mask for mfctl, w Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 11/45] target/hppa: Implement rfi Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 12/45] target/hppa: Fill in hppa_cpu_do_interrupt/hppa_cpu_exec_interrupt Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 13/45] target/hppa: Implement unaligned access trap Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 14/45] target/hppa: Use space registers in data operations Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 15/45] target/hppa: Avoid privilege level decrease during branches Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 16/45] target/hppa: Implement IASQ Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 17/45] target/hppa: Implement tlb_fill Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 18/45] target/hppa: Implement external interrupts Richard Henderson
2018-01-24 23:25 ` [Qemu-devel] [PATCH v3 19/45] target/hppa: Implement the interval timer Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 20/45] target/hppa: Log unimplemented instructions Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 21/45] target/hppa: Implement I*TLBA and I*TLBP insns Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 22/45] target/hppa: Implement P*TLB and P*TLBE insns Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 23/45] target/hppa: Implement LDWA Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 24/45] target/hppa: Implement LPA Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 25/45] target/hppa: Implement LCI Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 26/45] target/hppa: Implement SYNCDMA insn Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 27/45] target/hppa: Implement halt and reset instructions Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 28/45] target/hppa: Optimize for flat addressing space Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 29/45] target/hppa: Add system registers to gdbstub Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 30/45] target/hppa: Add migration for the cpu Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 31/45] target/hppa: Implement B,GATE insn Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 32/45] target/hppa: Only use EXCP_DTLB_MISS Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 33/45] qom: Add MMU_DEBUG_LOAD Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 34/45] target/hppa: Use MMU_DEBUG_LOAD when reloading for CR[IIR] Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 35/45] target/hppa: Increase number of temp regs Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 36/45] target/hppa: Fix comment Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 37/45] target/hppa: Implement LDSID for system mode Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 38/45] target/hppa: Implement a pause instruction Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 39/45] target/hppa: Implement STWA Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 40/45] target/hppa: Enable MTTCG Richard Henderson
2018-01-24 23:26 ` Richard Henderson [this message]
2018-01-25 11:22 ` [Qemu-devel] [PATCH v3 41/45] hw/hppa: Implement DINO system board Philippe Mathieu-Daudé
2018-01-27 13:22 ` Helge Deller
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 42/45] pc-bios: Add hppa-firmware.img and git submodule Richard Henderson
2018-02-04 22:40 ` Philippe Mathieu-Daudé
2018-02-06 7:35 ` Helge Deller
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 43/45] hw/hppa: Add MAINTAINERS entry Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 44/45] target/hppa: Fix 32-bit operand masks for 0E FCVT Richard Henderson
2018-01-24 23:26 ` [Qemu-devel] [PATCH v3 45/45] target/hppa: Implement PROBE for system mode Richard Henderson
2018-01-25 0:11 ` [Qemu-devel] [PATCH v3 00/45] hppa-softmmu no-reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180124232625.30105-42-richard.henderson@linaro.org \
--to=richard.henderson@linaro.org \
--cc=deller@gmx.de \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.