]> git.proxmox.com Git - mirror_qemu.git/blame - hw/hppa/machine.c
Merge tag 'pull-maintainer-may24-160524-2' of https://gitlab.com/stsquad/qemu into...
[mirror_qemu.git] / hw / hppa / machine.c
CommitLineData
813dff13
HD
1/*
2 * QEMU HPPA hardware system emulator.
a536f564
HD
3 * (C) Copyright 2018-2023 Helge Deller <deller@gmx.de>
4 *
5 * This work is licensed under the GNU GPL license version 2 or later.
813dff13
HD
6 */
7
8#include "qemu/osdep.h"
2c65db5e 9#include "qemu/datadir.h"
813dff13 10#include "cpu.h"
813dff13
HD
11#include "elf.h"
12#include "hw/loader.h"
813dff13 13#include "qemu/error-report.h"
71e8a915 14#include "sysemu/reset.h"
813dff13 15#include "sysemu/sysemu.h"
a9314795 16#include "sysemu/qtest.h"
b28c4a64 17#include "sysemu/runstate.h"
bcdb9064 18#include "hw/rtc/mc146818rtc.h"
813dff13
HD
19#include "hw/timer/i8254.h"
20#include "hw/char/serial.h"
9701e569 21#include "hw/char/parallel.h"
134ba73f 22#include "hw/intc/i8259.h"
d26c575c 23#include "hw/input/lasips2.h"
376b8519 24#include "hw/net/lasi_82596.h"
4a4554c6 25#include "hw/nmi.h"
2ed4faa0 26#include "hw/usb.h"
134ba73f 27#include "hw/pci/pci.h"
7df6f751 28#include "hw/pci/pci_device.h"
2ed4faa0 29#include "hw/pci-host/astro.h"
0db9350e 30#include "hw/pci-host/dino.h"
45f569a1 31#include "hw/misc/lasi.h"
148da670 32#include "hppa_hardware.h"
c108cc59 33#include "qemu/units.h"
813dff13 34#include "qapi/error.h"
852c27e2 35#include "net/net.h"
691cbbad 36#include "qemu/log.h"
813dff13 37
f88131d9 38#define MIN_SEABIOS_HPPA_VERSION 12 /* require at least this fw version */
28b71a2e 39
ed35afcb
HD
40#define HPA_POWER_BUTTON (FIRMWARE_END - 0x10)
41static hwaddr soft_power_reg;
b28c4a64 42
932befaa
MCA
43#define enable_lasi_lan() 0
44
7df6f751 45static DeviceState *lasi_dev;
932befaa 46
b28c4a64
HD
47static void hppa_powerdown_req(Notifier *n, void *opaque)
48{
b28c4a64
HD
49 uint32_t val;
50
51 val = ldl_be_phys(&address_space_memory, soft_power_reg);
52 if ((val >> 8) == 0) {
53 /* immediately shut down when under hardware control */
54 qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN);
55 return;
56 }
57
58 /* clear bit 31 to indicate that the power switch was pressed. */
59 val &= ~1;
60 stl_be_phys(&address_space_memory, soft_power_reg, val);
61}
62
63static Notifier hppa_system_powerdown_notifier = {
64 .notify = hppa_powerdown_req
65};
66
28f5332a
MCA
67/* Fallback for unassigned PCI I/O operations. Avoids MCHK. */
68static uint64_t ignore_read(void *opaque, hwaddr addr, unsigned size)
69{
70 return 0;
71}
72
73static void ignore_write(void *opaque, hwaddr addr, uint64_t v, unsigned size)
74{
75}
76
77static const MemoryRegionOps hppa_pci_ignore_ops = {
78 .read = ignore_read,
79 .write = ignore_write,
80 .endianness = DEVICE_BIG_ENDIAN,
81 .valid = {
82 .min_access_size = 1,
83 .max_access_size = 8,
84 },
85 .impl = {
86 .min_access_size = 1,
87 .max_access_size = 8,
88 },
89};
b28c4a64 90
f386a16e 91static ISABus *hppa_isa_bus(hwaddr addr)
a72bd606
HD
92{
93 ISABus *isa_bus;
94 qemu_irq *isa_irqs;
95 MemoryRegion *isa_region;
96
97 isa_region = g_new(MemoryRegion, 1);
98 memory_region_init_io(isa_region, NULL, &hppa_pci_ignore_ops,
99 NULL, "isa-io", 0x800);
f386a16e 100 memory_region_add_subregion(get_system_memory(), addr, isa_region);
a72bd606
HD
101
102 isa_bus = isa_bus_new(NULL, get_system_memory(), isa_region,
103 &error_abort);
a536f564 104 isa_irqs = i8259_init(isa_bus, NULL);
7067887e 105 isa_bus_register_input_irqs(isa_bus, isa_irqs);
a72bd606
HD
106
107 return isa_bus;
108}
109
e2c41ee5
HD
110/*
111 * Helper functions to emulate RTC clock and DebugOutputPort
112 */
113static time_t rtc_ref;
114
115static uint64_t io_cpu_read(void *opaque, hwaddr addr, unsigned size)
116{
117 uint64_t val = 0;
118
119 switch (addr) {
120 case 0: /* RTC clock */
121 val = time(NULL);
122 val += rtc_ref;
123 break;
124 case 8: /* DebugOutputPort */
125 return 0xe9; /* readback */
126 }
127 return val;
128}
129
130static void io_cpu_write(void *opaque, hwaddr addr,
131 uint64_t val, unsigned size)
132{
133 unsigned char ch;
134 Chardev *debugout;
135
136 switch (addr) {
137 case 0: /* RTC clock */
138 rtc_ref = val - time(NULL);
139 break;
140 case 8: /* DebugOutputPort */
141 ch = val;
142 debugout = serial_hd(0);
143 if (debugout) {
144 qemu_chr_fe_write_all(debugout->be, &ch, 1);
145 } else {
146 fprintf(stderr, "%c", ch);
147 }
148 break;
149 }
150}
151
152static const MemoryRegionOps hppa_io_helper_ops = {
153 .read = io_cpu_read,
154 .write = io_cpu_write,
155 .endianness = DEVICE_BIG_ENDIAN,
156 .valid = {
157 .min_access_size = 1,
158 .max_access_size = 8,
159 },
160 .impl = {
161 .min_access_size = 1,
162 .max_access_size = 8,
163 },
164};
165
f386a16e 166typedef uint64_t TranslateFn(void *opaque, uint64_t addr);
e2c41ee5 167
f386a16e 168static uint64_t linux_kernel_virt_to_phys(void *opaque, uint64_t addr)
a72bd606
HD
169{
170 addr &= (0x10000000 - 1);
171 return addr;
172}
173
f386a16e
RH
174static uint64_t translate_pa10(void *dummy, uint64_t addr)
175{
176 return (uint32_t)addr;
177}
178
179static uint64_t translate_pa20(void *dummy, uint64_t addr)
180{
181 return hppa_abs_to_phys_pa2_w0(addr);
182}
183
a72bd606
HD
184static HPPACPU *cpu[HPPA_MAX_CPUS];
185static uint64_t firmware_entry;
813dff13 186
32ff8bf2
HD
187static void fw_cfg_boot_set(void *opaque, const char *boot_device,
188 Error **errp)
189{
190 fw_cfg_modify_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
191}
192
f386a16e
RH
193static FWCfgState *create_fw_cfg(MachineState *ms, PCIBus *pci_bus,
194 hwaddr addr)
28b71a2e
HD
195{
196 FWCfgState *fw_cfg;
197 uint64_t val;
069d2966 198 const char qemu_version[] = QEMU_VERSION;
bcd4dd4c 199 MachineClass *mc = MACHINE_GET_CLASS(ms);
9cf2112b 200 int btlb_entries = HPPA_BTLB_ENTRIES(&cpu[0]->env);
bcd4dd4c 201 int len;
28b71a2e 202
f386a16e 203 fw_cfg = fw_cfg_init_mem(addr, addr + 4);
28b71a2e
HD
204 fw_cfg_add_i16(fw_cfg, FW_CFG_NB_CPUS, ms->smp.cpus);
205 fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, HPPA_MAX_CPUS);
bfdf22bc 206 fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, ms->ram_size);
28b71a2e
HD
207
208 val = cpu_to_le64(MIN_SEABIOS_HPPA_VERSION);
209 fw_cfg_add_file(fw_cfg, "/etc/firmware-min-version",
0572f011 210 g_memdup2(&val, sizeof(val)), sizeof(val));
28b71a2e 211
9cf2112b 212 val = cpu_to_le64(HPPA_TLB_ENTRIES - btlb_entries);
df5c6a50 213 fw_cfg_add_file(fw_cfg, "/etc/cpu/tlb_entries",
0572f011 214 g_memdup2(&val, sizeof(val)), sizeof(val));
df5c6a50 215
9cf2112b 216 val = cpu_to_le64(btlb_entries);
bcd4dd4c 217 fw_cfg_add_file(fw_cfg, "/etc/cpu/btlb_entries",
0572f011 218 g_memdup2(&val, sizeof(val)), sizeof(val));
bcd4dd4c
HD
219
220 len = strlen(mc->name) + 1;
221 fw_cfg_add_file(fw_cfg, "/etc/hppa/machine",
0572f011 222 g_memdup2(mc->name, len), len);
bcd4dd4c 223
ed35afcb 224 val = cpu_to_le64(soft_power_reg);
bcd4dd4c 225 fw_cfg_add_file(fw_cfg, "/etc/hppa/power-button-addr",
0572f011 226 g_memdup2(&val, sizeof(val)), sizeof(val));
bcd4dd4c 227
e2c41ee5
HD
228 val = cpu_to_le64(CPU_HPA + 16);
229 fw_cfg_add_file(fw_cfg, "/etc/hppa/rtc-addr",
0572f011 230 g_memdup2(&val, sizeof(val)), sizeof(val));
e2c41ee5 231
bcd4dd4c
HD
232 val = cpu_to_le64(CPU_HPA + 24);
233 fw_cfg_add_file(fw_cfg, "/etc/hppa/DebugOutputPort",
0572f011 234 g_memdup2(&val, sizeof(val)), sizeof(val));
b28c4a64 235
97ec4d21 236 fw_cfg_add_i16(fw_cfg, FW_CFG_BOOT_DEVICE, ms->boot_config.order[0]);
32ff8bf2
HD
237 qemu_register_boot_set(fw_cfg_boot_set, fw_cfg);
238
069d2966 239 fw_cfg_add_file(fw_cfg, "/etc/qemu-version",
0572f011 240 g_memdup2(qemu_version, sizeof(qemu_version)),
069d2966
HD
241 sizeof(qemu_version));
242
bcd4dd4c
HD
243 fw_cfg_add_extra_pci_roots(pci_bus, fw_cfg);
244
28b71a2e
HD
245 return fw_cfg;
246}
247
e881e3c8
MCA
248static LasiState *lasi_init(void)
249{
250 DeviceState *dev;
251
252 dev = qdev_new(TYPE_LASI_CHIP);
253 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
254
255 return LASI_CHIP(dev);
256}
257
0d068996
MCA
258static DinoState *dino_init(MemoryRegion *addr_space)
259{
260 DeviceState *dev;
261
262 dev = qdev_new(TYPE_DINO_PCI_HOST_BRIDGE);
263 object_property_set_link(OBJECT(dev), "memory-as", OBJECT(addr_space),
264 &error_fatal);
265 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
266
267 return DINO_PCI_HOST_BRIDGE(dev);
268}
269
7df6f751
HD
270/*
271 * Step 1: Create CPUs and Memory
272 */
f386a16e 273static TranslateFn *machine_HP_common_init_cpus(MachineState *machine)
813dff13 274{
a72bd606 275 MemoryRegion *addr_space = get_system_memory();
33decbd2 276 unsigned int smp_cpus = machine->smp.cpus;
f386a16e
RH
277 TranslateFn *translate;
278 MemoryRegion *cpu_region;
92039f61 279 uint64_t ram_max;
a72bd606 280
a72bd606 281 /* Create CPUs. */
f386a16e 282 for (unsigned int i = 0; i < smp_cpus; i++) {
a72bd606 283 cpu[i] = HPPA_CPU(cpu_create(machine->cpu_type));
f386a16e
RH
284 }
285
286 /*
287 * For now, treat address layout as if PSW_W is clear.
288 * TODO: create a proper hppa64 board model and load elf64 firmware.
289 */
290 if (hppa_is_pa20(&cpu[0]->env)) {
291 translate = translate_pa20;
92039f61 292 ram_max = 0xf0000000; /* 3.75 GB (limited by 32-bit firmware) */
f386a16e
RH
293 } else {
294 translate = translate_pa10;
92039f61 295 ram_max = 0xf0000000; /* 3.75 GB (32-bit CPU) */
f386a16e
RH
296 }
297
ed35afcb
HD
298 soft_power_reg = translate(NULL, HPA_POWER_BUTTON);
299
f386a16e
RH
300 for (unsigned int i = 0; i < smp_cpus; i++) {
301 g_autofree char *name = g_strdup_printf("cpu%u-io-eir", i);
a72bd606
HD
302
303 cpu_region = g_new(MemoryRegion, 1);
304 memory_region_init_io(cpu_region, OBJECT(cpu[i]), &hppa_io_eir_ops,
266a880e 305 cpu[i], name, 4);
f386a16e
RH
306 memory_region_add_subregion(addr_space,
307 translate(NULL, CPU_HPA + i * 0x1000),
a72bd606
HD
308 cpu_region);
309 }
310
e2c41ee5
HD
311 /* RTC and DebugOutputPort on CPU #0 */
312 cpu_region = g_new(MemoryRegion, 1);
313 memory_region_init_io(cpu_region, OBJECT(cpu[0]), &hppa_io_helper_ops,
314 cpu[0], "cpu0-io-rtc", 2 * sizeof(uint64_t));
f386a16e
RH
315 memory_region_add_subregion(addr_space, translate(NULL, CPU_HPA + 16),
316 cpu_region);
e2c41ee5 317
a72bd606 318 /* Main memory region. */
92039f61
HD
319 if (machine->ram_size > ram_max) {
320 info_report("Max RAM size limited to %" PRIu64 " MB", ram_max / MiB);
321 machine->ram_size = ram_max;
b7746b11 322 }
7c59c1e0 323 memory_region_add_subregion_overlap(addr_space, 0, machine->ram, -1);
f386a16e
RH
324
325 return translate;
7df6f751 326}
7c59c1e0 327
7df6f751
HD
328/*
329 * Last creation step: Add SCSI discs, NICs, graphics & load firmware
330 */
f386a16e
RH
331static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
332 TranslateFn *translate)
7df6f751
HD
333{
334 const char *kernel_filename = machine->kernel_filename;
335 const char *kernel_cmdline = machine->kernel_cmdline;
336 const char *initrd_filename = machine->initrd_filename;
a9314795 337 const char *firmware = machine->firmware;
7df6f751
HD
338 MachineClass *mc = MACHINE_GET_CLASS(machine);
339 DeviceState *dev;
2ed4faa0 340 PCIDevice *pci_dev;
7df6f751
HD
341 char *firmware_filename;
342 uint64_t firmware_low, firmware_high;
343 long size;
344 uint64_t kernel_entry = 0, kernel_low, kernel_high;
345 MemoryRegion *addr_space = get_system_memory();
346 MemoryRegion *rom_region;
7df6f751
HD
347 unsigned int smp_cpus = machine->smp.cpus;
348 SysBusDevice *s;
28b71a2e 349
a72bd606 350 /* SCSI disk setup. */
d8a32200
HD
351 if (drive_get_max_bus(IF_SCSI) >= 0) {
352 dev = DEVICE(pci_create_simple(pci_bus, -1, "lsi53c895a"));
353 lsi53c8xx_handle_legacy_cmdline(dev);
354 }
a72bd606 355
4765384c
SS
356 /* Graphics setup. */
357 if (machine->enable_graphics && vga_interface_type != VGA_NONE) {
f9bcb2d6 358 vga_interface_created = true;
3e80f690 359 dev = qdev_new("artist");
4765384c 360 s = SYS_BUS_DEVICE(dev);
3c6ef471 361 sysbus_realize_and_unref(s, &error_fatal);
f386a16e
RH
362 sysbus_mmio_map(s, 0, translate(NULL, LASI_GFX_HPA));
363 sysbus_mmio_map(s, 1, translate(NULL, ARTIST_FB_ADDR));
4765384c
SS
364 }
365
0e6de551 366 /* Network setup. */
2a98878f 367 if (lasi_dev) {
f386a16e 368 lasi_82596_init(addr_space, translate(NULL, LASI_LAN_HPA),
2a98878f
DW
369 qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA),
370 enable_lasi_lan());
c3c3fe47
MCA
371 }
372
2a98878f 373 pci_init_nic_devices(pci_bus, mc->default_nic);
a72bd606 374
2ed4faa0
HD
375 /* BMC board: HP Powerbar SP2 Diva (with console only) */
376 pci_dev = pci_new(-1, "pci-serial");
377 if (!lasi_dev) {
378 /* bind default keyboard/serial to Diva card */
379 qdev_prop_set_chr(DEVICE(pci_dev), "chardev", serial_hd(0));
380 }
381 qdev_prop_set_uint8(DEVICE(pci_dev), "prog_if", 0);
382 pci_realize_and_unref(pci_dev, pci_bus, &error_fatal);
383 pci_config_set_vendor_id(pci_dev->config, PCI_VENDOR_ID_HP);
384 pci_config_set_device_id(pci_dev->config, 0x1048);
385 pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_VENDOR_ID], PCI_VENDOR_ID_HP);
386 pci_set_word(&pci_dev->config[PCI_SUBSYSTEM_ID], 0x1227); /* Powerbar */
387
388 /* create a second serial PCI card when running Astro */
d8a32200 389 if (serial_hd(1) && !lasi_dev) {
2ed4faa0
HD
390 pci_dev = pci_new(-1, "pci-serial-4x");
391 qdev_prop_set_chr(DEVICE(pci_dev), "chardev1", serial_hd(1));
392 qdev_prop_set_chr(DEVICE(pci_dev), "chardev2", serial_hd(2));
393 qdev_prop_set_chr(DEVICE(pci_dev), "chardev3", serial_hd(3));
394 qdev_prop_set_chr(DEVICE(pci_dev), "chardev4", serial_hd(4));
395 pci_realize_and_unref(pci_dev, pci_bus, &error_fatal);
396 }
397
398 /* create USB OHCI controller for USB keyboard & mouse on Astro machines */
82523f4a
PB
399 if (!lasi_dev && machine->enable_graphics && defaults_enabled()) {
400 USBBus *usb_bus;
401
2ed4faa0 402 pci_create_simple(pci_bus, -1, "pci-ohci");
82523f4a
PB
403 usb_bus = USB_BUS(object_resolve_type_unambiguous(TYPE_USB_BUS,
404 &error_abort));
405 usb_create_simple(usb_bus, "usb-kbd");
406 usb_create_simple(usb_bus, "usb-mouse");
2ed4faa0
HD
407 }
408
b28c4a64
HD
409 /* register power switch emulation */
410 qemu_register_powerdown_notifier(&hppa_system_powerdown_notifier);
411
7df6f751 412 /* fw_cfg configuration interface */
f386a16e 413 create_fw_cfg(machine, pci_bus, translate(NULL, FW_CFG_IO_BASE));
7df6f751 414
a72bd606
HD
415 /* Load firmware. Given that this is not "real" firmware,
416 but one explicitly written for the emulation, we might as
a9314795
HD
417 well load it directly from an ELF image. Load the 64-bit
418 firmware on 64-bit machines by default if not specified
419 on command line. */
420 if (!qtest_enabled()) {
421 if (!firmware) {
422 firmware = lasi_dev ? "hppa-firmware.img" : "hppa-firmware64.img";
423 }
424 firmware_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, firmware);
425 if (firmware_filename == NULL) {
426 error_report("no firmware provided");
427 exit(1);
428 }
a72bd606 429
a9314795
HD
430 size = load_elf(firmware_filename, NULL, translate, NULL,
431 &firmware_entry, &firmware_low, &firmware_high, NULL,
432 true, EM_PARISC, 0, 0);
a72bd606 433
a9314795
HD
434 if (size < 0) {
435 error_report("could not load firmware '%s'", firmware_filename);
436 exit(1);
437 }
438 qemu_log_mask(CPU_LOG_PAGE, "Firmware loaded at 0x%08" PRIx64
439 "-0x%08" PRIx64 ", entry at 0x%08" PRIx64 ".\n",
440 firmware_low, firmware_high, firmware_entry);
441 if (firmware_low < translate(NULL, FIRMWARE_START) ||
442 firmware_high >= translate(NULL, FIRMWARE_END)) {
443 error_report("Firmware overlaps with memory or IO space");
444 exit(1);
445 }
446 g_free(firmware_filename);
a72bd606 447 }
a72bd606
HD
448
449 rom_region = g_new(MemoryRegion, 1);
6a3a2e82
IM
450 memory_region_init_ram(rom_region, NULL, "firmware",
451 (FIRMWARE_END - FIRMWARE_START), &error_fatal);
f386a16e
RH
452 memory_region_add_subregion(addr_space,
453 translate(NULL, FIRMWARE_START), rom_region);
a72bd606
HD
454
455 /* Load kernel */
456 if (kernel_filename) {
f386a16e 457 size = load_elf(kernel_filename, NULL, linux_kernel_virt_to_phys,
6cdda0ff 458 NULL, &kernel_entry, &kernel_low, &kernel_high, NULL,
a72bd606
HD
459 true, EM_PARISC, 0, 0);
460
f386a16e 461 kernel_entry = linux_kernel_virt_to_phys(NULL, kernel_entry);
a72bd606
HD
462
463 if (size < 0) {
464 error_report("could not load kernel '%s'", kernel_filename);
465 exit(1);
466 }
691cbbad
RH
467 qemu_log_mask(CPU_LOG_PAGE, "Kernel loaded at 0x%08" PRIx64
468 "-0x%08" PRIx64 ", entry at 0x%08" PRIx64
c108cc59
PMD
469 ", size %" PRIu64 " kB\n",
470 kernel_low, kernel_high, kernel_entry, size / KiB);
a72bd606
HD
471
472 if (kernel_cmdline) {
473 cpu[0]->env.gr[24] = 0x4000;
474 pstrcpy_targphys("cmdline", cpu[0]->env.gr[24],
475 TARGET_PAGE_SIZE, kernel_cmdline);
476 }
477
478 if (initrd_filename) {
479 ram_addr_t initrd_base;
f3839fda 480 int64_t initrd_size;
a72bd606
HD
481
482 initrd_size = get_image_size(initrd_filename);
483 if (initrd_size < 0) {
484 error_report("could not load initial ram disk '%s'",
485 initrd_filename);
486 exit(1);
487 }
488
489 /* Load the initrd image high in memory.
490 Mirror the algorithm used by palo:
491 (1) Due to sign-extension problems and PDC,
492 put the initrd no higher than 1G.
493 (2) Reserve 64k for stack. */
bfdf22bc 494 initrd_base = MIN(machine->ram_size, 1 * GiB);
c108cc59 495 initrd_base = initrd_base - 64 * KiB;
a72bd606
HD
496 initrd_base = (initrd_base - initrd_size) & TARGET_PAGE_MASK;
497
498 if (initrd_base < kernel_high) {
499 error_report("kernel and initial ram disk too large!");
500 exit(1);
501 }
502
503 load_image_targphys(initrd_filename, initrd_base, initrd_size);
504 cpu[0]->env.gr[23] = initrd_base;
505 cpu[0]->env.gr[22] = initrd_base + initrd_size;
506 }
507 }
508
509 if (!kernel_entry) {
510 /* When booting via firmware, tell firmware if we want interactive
511 * mode (kernel_entry=1), and to boot from CD (gr[24]='d')
512 * or hard disc * (gr[24]='c').
513 */
97ec4d21
PB
514 kernel_entry = machine->boot_config.has_menu ? machine->boot_config.menu : 0;
515 cpu[0]->env.gr[24] = machine->boot_config.order[0];
a72bd606
HD
516 }
517
518 /* We jump to the firmware entry routine and pass the
519 * various parameters in registers. After firmware initialization,
520 * firmware will start the Linux kernel with ramdisk and cmdline.
521 */
bfdf22bc 522 cpu[0]->env.gr[26] = machine->ram_size;
a72bd606
HD
523 cpu[0]->env.gr[25] = kernel_entry;
524
525 /* tell firmware how many SMP CPUs to present in inventory table */
526 cpu[0]->env.gr[21] = smp_cpus;
24576007
HD
527
528 /* tell firmware fw_cfg port */
529 cpu[0]->env.gr[19] = FW_CFG_IO_BASE;
813dff13
HD
530}
531
7df6f751
HD
532/*
533 * Create HP B160L workstation
534 */
535static void machine_HP_B160L_init(MachineState *machine)
536{
537 DeviceState *dev, *dino_dev;
538 MemoryRegion *addr_space = get_system_memory();
f386a16e 539 TranslateFn *translate;
7df6f751
HD
540 ISABus *isa_bus;
541 PCIBus *pci_bus;
542
543 /* Create CPUs and RAM. */
f386a16e 544 translate = machine_HP_common_init_cpus(machine);
7df6f751 545
3d1611bf
HD
546 if (hppa_is_pa20(&cpu[0]->env)) {
547 error_report("The HP B160L workstation requires a 32-bit "
548 "CPU. Use '-machine C3700' instead.");
549 exit(1);
550 }
551
7df6f751
HD
552 /* Init Lasi chip */
553 lasi_dev = DEVICE(lasi_init());
f386a16e 554 memory_region_add_subregion(addr_space, translate(NULL, LASI_HPA),
7df6f751
HD
555 sysbus_mmio_get_region(
556 SYS_BUS_DEVICE(lasi_dev), 0));
557
558 /* Init Dino (PCI host bus chip). */
559 dino_dev = DEVICE(dino_init(addr_space));
f386a16e 560 memory_region_add_subregion(addr_space, translate(NULL, DINO_HPA),
7df6f751
HD
561 sysbus_mmio_get_region(
562 SYS_BUS_DEVICE(dino_dev), 0));
563 pci_bus = PCI_BUS(qdev_get_child_bus(dino_dev, "pci"));
564 assert(pci_bus);
565
566 /* Create ISA bus, needed for PS/2 kbd/mouse port emulation */
f386a16e 567 isa_bus = hppa_isa_bus(translate(NULL, IDE_HPA));
7df6f751
HD
568 assert(isa_bus);
569
570 /* Serial ports: Lasi and Dino use a 7.272727 MHz clock. */
f386a16e 571 serial_mm_init(addr_space, translate(NULL, LASI_UART_HPA + 0x800), 0,
7df6f751
HD
572 qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 7272727 / 16,
573 serial_hd(0), DEVICE_BIG_ENDIAN);
574
f386a16e 575 serial_mm_init(addr_space, translate(NULL, DINO_UART_HPA + 0x800), 0,
7df6f751
HD
576 qdev_get_gpio_in(dino_dev, DINO_IRQ_RS232INT), 7272727 / 16,
577 serial_hd(1), DEVICE_BIG_ENDIAN);
578
579 /* Parallel port */
f386a16e 580 parallel_mm_init(addr_space, translate(NULL, LASI_LPT_HPA + 0x800), 0,
7df6f751
HD
581 qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA),
582 parallel_hds[0]);
583
584 /* PS/2 Keyboard/Mouse */
585 dev = qdev_new(TYPE_LASIPS2);
586 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
587 sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
588 qdev_get_gpio_in(lasi_dev, LASI_IRQ_PS2KBD_HPA));
f386a16e
RH
589 memory_region_add_subregion(addr_space,
590 translate(NULL, LASI_PS2KBD_HPA),
7df6f751
HD
591 sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
592 0));
f386a16e
RH
593 memory_region_add_subregion(addr_space,
594 translate(NULL, LASI_PS2KBD_HPA + 0x100),
7df6f751
HD
595 sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
596 1));
597
598 /* Add SCSI discs, NICs, graphics & load firmware */
f386a16e 599 machine_HP_common_init_tail(machine, pci_bus, translate);
7df6f751
HD
600}
601
2ed4faa0
HD
602static AstroState *astro_init(void)
603{
604 DeviceState *dev;
605
606 dev = qdev_new(TYPE_ASTRO_CHIP);
607 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
608
609 return ASTRO_CHIP(dev);
610}
611
612/*
613 * Create HP C3700 workstation
614 */
615static void machine_HP_C3700_init(MachineState *machine)
616{
617 PCIBus *pci_bus;
618 AstroState *astro;
619 DeviceState *astro_dev;
620 MemoryRegion *addr_space = get_system_memory();
f386a16e 621 TranslateFn *translate;
2ed4faa0
HD
622
623 /* Create CPUs and RAM. */
f386a16e 624 translate = machine_HP_common_init_cpus(machine);
2ed4faa0 625
3d1611bf
HD
626 if (!hppa_is_pa20(&cpu[0]->env)) {
627 error_report("The HP C3000 workstation requires a 64-bit CPU. "
628 "Use '-machine B160L' instead.");
629 exit(1);
630 }
631
2ed4faa0
HD
632 /* Init Astro and the Elroys (PCI host bus chips). */
633 astro = astro_init();
634 astro_dev = DEVICE(astro);
f386a16e 635 memory_region_add_subregion(addr_space, translate(NULL, ASTRO_HPA),
2ed4faa0
HD
636 sysbus_mmio_get_region(
637 SYS_BUS_DEVICE(astro_dev), 0));
638 pci_bus = PCI_BUS(qdev_get_child_bus(DEVICE(astro->elroy[0]), "pci"));
639 assert(pci_bus);
640
641 /* Add SCSI discs, NICs, graphics & load firmware */
f386a16e 642 machine_HP_common_init_tail(machine, pci_bus, translate);
2ed4faa0
HD
643}
644
7966d70f 645static void hppa_machine_reset(MachineState *ms, ShutdownCause reason)
a72bd606 646{
33decbd2 647 unsigned int smp_cpus = ms->smp.cpus;
a72bd606
HD
648 int i;
649
7966d70f 650 qemu_devices_reset(reason);
a72bd606
HD
651
652 /* Start all CPUs at the firmware entry point.
653 * Monarch CPU will initialize firmware, secondary CPUs
50ba97e9 654 * will enter a small idle loop and wait for rendevouz. */
a72bd606 655 for (i = 0; i < smp_cpus; i++) {
50ba97e9
HD
656 CPUState *cs = CPU(cpu[i]);
657
658 cpu_set_pc(cs, firmware_entry);
659 cpu[i]->env.psw = PSW_Q;
a72bd606 660 cpu[i]->env.gr[5] = CPU_HPA + i * 0x1000;
50ba97e9
HD
661
662 cs->exception_index = -1;
663 cs->halted = 0;
a72bd606
HD
664 }
665
666 /* already initialized by machine_hppa_init()? */
bfdf22bc 667 if (cpu[0]->env.gr[26] == ms->ram_size) {
a72bd606
HD
668 return;
669 }
670
bfdf22bc 671 cpu[0]->env.gr[26] = ms->ram_size;
a72bd606
HD
672 cpu[0]->env.gr[25] = 0; /* no firmware boot menu */
673 cpu[0]->env.gr[24] = 'c';
674 /* gr22/gr23 unused, no initrd while reboot. */
675 cpu[0]->env.gr[21] = smp_cpus;
24576007
HD
676 /* tell firmware fw_cfg port */
677 cpu[0]->env.gr[19] = FW_CFG_IO_BASE;
a72bd606
HD
678}
679
4a4554c6
HD
680static void hppa_nmi(NMIState *n, int cpu_index, Error **errp)
681{
682 CPUState *cs;
683
684 CPU_FOREACH(cs) {
685 cpu_interrupt(cs, CPU_INTERRUPT_NMI);
686 }
687}
a72bd606 688
7df6f751 689static void HP_B160L_machine_init_class_init(ObjectClass *oc, void *data)
813dff13 690{
790a4428
GS
691 static const char * const valid_cpu_types[] = {
692 TYPE_HPPA_CPU,
693 NULL
694 };
42cc2bf6
MCA
695 MachineClass *mc = MACHINE_CLASS(oc);
696 NMIClass *nc = NMI_CLASS(oc);
697
7df6f751 698 mc->desc = "HP B160L workstation";
a72bd606 699 mc->default_cpu_type = TYPE_HPPA_CPU;
790a4428 700 mc->valid_cpu_types = valid_cpu_types;
7df6f751 701 mc->init = machine_HP_B160L_init;
a72bd606 702 mc->reset = hppa_machine_reset;
813dff13 703 mc->block_default_type = IF_SCSI;
a72bd606
HD
704 mc->max_cpus = HPPA_MAX_CPUS;
705 mc->default_cpus = 1;
ea0ac7f6 706 mc->is_default = true;
d23b6caa 707 mc->default_ram_size = 512 * MiB;
813dff13 708 mc->default_boot_order = "cd";
7c59c1e0 709 mc->default_ram_id = "ram";
9f8981a9 710 mc->default_nic = "tulip";
813dff13 711
4a4554c6
HD
712 nc->nmi_monitor_handler = hppa_nmi;
713}
714
7df6f751
HD
715static const TypeInfo HP_B160L_machine_init_typeinfo = {
716 .name = MACHINE_TYPE_NAME("B160L"),
c165905c 717 .parent = TYPE_MACHINE,
7df6f751 718 .class_init = HP_B160L_machine_init_class_init,
4a4554c6
HD
719 .interfaces = (InterfaceInfo[]) {
720 { TYPE_NMI },
721 { }
722 },
723};
724
2ed4faa0
HD
725static void HP_C3700_machine_init_class_init(ObjectClass *oc, void *data)
726{
790a4428
GS
727 static const char * const valid_cpu_types[] = {
728 TYPE_HPPA64_CPU,
729 NULL
730 };
2ed4faa0
HD
731 MachineClass *mc = MACHINE_CLASS(oc);
732 NMIClass *nc = NMI_CLASS(oc);
733
734 mc->desc = "HP C3700 workstation";
fd9b04bf 735 mc->default_cpu_type = TYPE_HPPA64_CPU;
790a4428 736 mc->valid_cpu_types = valid_cpu_types;
2ed4faa0
HD
737 mc->init = machine_HP_C3700_init;
738 mc->reset = hppa_machine_reset;
739 mc->block_default_type = IF_SCSI;
740 mc->max_cpus = HPPA_MAX_CPUS;
741 mc->default_cpus = 1;
742 mc->is_default = false;
743 mc->default_ram_size = 1024 * MiB;
744 mc->default_boot_order = "cd";
745 mc->default_ram_id = "ram";
746 mc->default_nic = "tulip";
747
748 nc->nmi_monitor_handler = hppa_nmi;
749}
750
751static const TypeInfo HP_C3700_machine_init_typeinfo = {
752 .name = MACHINE_TYPE_NAME("C3700"),
753 .parent = TYPE_MACHINE,
754 .class_init = HP_C3700_machine_init_class_init,
755 .interfaces = (InterfaceInfo[]) {
756 { TYPE_NMI },
757 { }
758 },
759};
760
297d4103 761static void hppa_machine_init_register_types(void)
4a4554c6 762{
7df6f751 763 type_register_static(&HP_B160L_machine_init_typeinfo);
2ed4faa0 764 type_register_static(&HP_C3700_machine_init_typeinfo);
4a4554c6
HD
765}
766
297d4103 767type_init(hppa_machine_init_register_types)