From: Keith Monahan <[email protected]>

The local broadcast I/O space is used by older operating systems like HP-UX 9.05
to send an interrupt to all CPUs, or to issue a system reset.
Wire it up on the emulated 715 machine to allow HP-UX 9.05 to run.

Signed-off-by: Keith Monahan <[email protected]>
Signed-off-by: Helge Deller <[email protected]>
---
 hw/hppa/machine.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/hw/hppa/machine.c b/hw/hppa/machine.c
index 96d57b9b0f..8d378385b2 100644
--- a/hw/hppa/machine.c
+++ b/hw/hppa/machine.c
@@ -573,6 +573,47 @@ static void machine_HP_common_init_tail(MachineState 
*machine, PCIBus *pci_bus,
     cpu[0]->env.kernel_entry = kernel_entry;
 }
 
+/*
+ * Local broadcast I/O space: a write to IO_EIR (offset 0) posts an external
+ * interrupt on all processors, CMD_RESET (5) written to IO_COMMAND (0x30)
+ * resets the system.  HP-UX 9 reboots through the latter.
+ */
+#define HPPA_BROADCAST_HPA      0xfffc0000
+#define HPPA_IO_COMMAND         0x30
+#define HPPA_CMD_RESET          5
+
+static uint64_t hppa_broadcast_read(void *opaque, hwaddr addr, unsigned size)
+{
+    return 0;
+}
+
+static void hppa_broadcast_write(void *opaque, hwaddr addr, uint64_t val,
+                                 unsigned size)
+{
+    unsigned int i;
+
+    switch (addr) {
+    case 0:
+        for (i = 0; i < current_machine->smp.cpus; i++) {
+            hppa_io_eir_ops.write(cpu[i], 0, val, 4);
+        }
+        break;
+    case HPPA_IO_COMMAND:
+        if (val == HPPA_CMD_RESET) {
+            qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
+        }
+        break;
+    }
+}
+
+static const MemoryRegionOps hppa_broadcast_ops = {
+    .read = hppa_broadcast_read,
+    .write = hppa_broadcast_write,
+    .endianness = DEVICE_BIG_ENDIAN,
+    .valid.min_access_size = 4,
+    .valid.max_access_size = 4,
+};
+
 /*
  * Create HP 715/64 workstation
  */
@@ -597,6 +638,14 @@ static void machine_HP_715_init(MachineState *machine)
     isa_bus = hppa_isa_bus(translate(NULL, IDE_HPA));
     assert(isa_bus);
 
+    /* Local broadcast I/O space */
+    MemoryRegion *dev_mr_bcast = g_new(MemoryRegion, 1);
+    memory_region_init_io(dev_mr_bcast, NULL, &hppa_broadcast_ops, NULL,
+                          "local-broadcast", 0x1000);
+    memory_region_add_subregion(addr_space,
+                                translate(NULL, HPPA_BROADCAST_HPA),
+                                dev_mr_bcast);
+
     /* Init Lasi chip */
     lasi_dev = DEVICE(lasi_init());
     hpm->lasi_dev = lasi_dev;
-- 
2.54.0


Reply via email to