1e1cecdcaSLaurent Vivier /*
265b4c8c7SPhilippe Mathieu-Daudé * SPDX-License-Identifier: GPL-2.0-or-later
3e1cecdcaSLaurent Vivier *
48b81968cSMichael Tokarev * QEMU Virtual M68K Machine
5e1cecdcaSLaurent Vivier *
6e1cecdcaSLaurent Vivier * (c) 2020 Laurent Vivier <laurent@vivier.eu>
7e1cecdcaSLaurent Vivier *
8e1cecdcaSLaurent Vivier */
9e1cecdcaSLaurent Vivier
10e1cecdcaSLaurent Vivier #include "qemu/osdep.h"
11e1cecdcaSLaurent Vivier #include "qemu/units.h"
12a988465dSJason A. Donenfeld #include "qemu/guest-random.h"
13e1cecdcaSLaurent Vivier #include "sysemu/sysemu.h"
14e1cecdcaSLaurent Vivier #include "cpu.h"
15e1cecdcaSLaurent Vivier #include "hw/boards.h"
16e1cecdcaSLaurent Vivier #include "hw/qdev-properties.h"
17e1cecdcaSLaurent Vivier #include "elf.h"
18e1cecdcaSLaurent Vivier #include "hw/loader.h"
19e1cecdcaSLaurent Vivier #include "ui/console.h"
20e1cecdcaSLaurent Vivier #include "hw/sysbus.h"
21e1cecdcaSLaurent Vivier #include "standard-headers/asm-m68k/bootinfo.h"
22e1cecdcaSLaurent Vivier #include "standard-headers/asm-m68k/bootinfo-virt.h"
23e1cecdcaSLaurent Vivier #include "bootinfo.h"
24e1cecdcaSLaurent Vivier #include "net/net.h"
25e1cecdcaSLaurent Vivier #include "qapi/error.h"
26cc37d98bSRichard Henderson #include "qemu/error-report.h"
27e1cecdcaSLaurent Vivier #include "sysemu/qtest.h"
28e1cecdcaSLaurent Vivier #include "sysemu/runstate.h"
29e1cecdcaSLaurent Vivier #include "sysemu/reset.h"
30e1cecdcaSLaurent Vivier
31e1cecdcaSLaurent Vivier #include "hw/intc/m68k_irqc.h"
32e1cecdcaSLaurent Vivier #include "hw/misc/virt_ctrl.h"
33e1cecdcaSLaurent Vivier #include "hw/char/goldfish_tty.h"
34e1cecdcaSLaurent Vivier #include "hw/rtc/goldfish_rtc.h"
35e1cecdcaSLaurent Vivier #include "hw/intc/goldfish_pic.h"
36e1cecdcaSLaurent Vivier #include "hw/virtio/virtio-mmio.h"
37e1cecdcaSLaurent Vivier #include "hw/virtio/virtio-blk.h"
38e1cecdcaSLaurent Vivier
39e1cecdcaSLaurent Vivier /*
40e1cecdcaSLaurent Vivier * 6 goldfish-pic for CPU IRQ #1 to IRQ #6
41e1cecdcaSLaurent Vivier * CPU IRQ #1 -> PIC #1
42e1cecdcaSLaurent Vivier * IRQ #1 to IRQ #31 -> unused
43e1cecdcaSLaurent Vivier * IRQ #32 -> goldfish-tty
44e1cecdcaSLaurent Vivier * CPU IRQ #2 -> PIC #2
45e1cecdcaSLaurent Vivier * IRQ #1 to IRQ #32 -> virtio-mmio from 1 to 32
46e1cecdcaSLaurent Vivier * CPU IRQ #3 -> PIC #3
47e1cecdcaSLaurent Vivier * IRQ #1 to IRQ #32 -> virtio-mmio from 33 to 64
48e1cecdcaSLaurent Vivier * CPU IRQ #4 -> PIC #4
49e1cecdcaSLaurent Vivier * IRQ #1 to IRQ #32 -> virtio-mmio from 65 to 96
50e1cecdcaSLaurent Vivier * CPU IRQ #5 -> PIC #5
51e1cecdcaSLaurent Vivier * IRQ #1 to IRQ #32 -> virtio-mmio from 97 to 128
52e1cecdcaSLaurent Vivier * CPU IRQ #6 -> PIC #6
53e1cecdcaSLaurent Vivier * IRQ #1 -> goldfish-rtc
54e1cecdcaSLaurent Vivier * IRQ #2 to IRQ #32 -> unused
55e1cecdcaSLaurent Vivier * CPU IRQ #7 -> NMI
56e1cecdcaSLaurent Vivier */
57e1cecdcaSLaurent Vivier
58e1cecdcaSLaurent Vivier #define PIC_IRQ_BASE(num) (8 + (num - 1) * 32)
59e1cecdcaSLaurent Vivier #define PIC_IRQ(num, irq) (PIC_IRQ_BASE(num) + irq - 1)
60e1cecdcaSLaurent Vivier #define PIC_GPIO(pic_irq) (qdev_get_gpio_in(pic_dev[(pic_irq - 8) / 32], \
61e1cecdcaSLaurent Vivier (pic_irq - 8) % 32))
62e1cecdcaSLaurent Vivier
63e1cecdcaSLaurent Vivier #define VIRT_GF_PIC_MMIO_BASE 0xff000000 /* MMIO: 0xff000000 - 0xff005fff */
64e1cecdcaSLaurent Vivier #define VIRT_GF_PIC_IRQ_BASE 1 /* IRQ: #1 -> #6 */
65e1cecdcaSLaurent Vivier #define VIRT_GF_PIC_NB 6
66e1cecdcaSLaurent Vivier
67e1cecdcaSLaurent Vivier /* 2 goldfish-rtc (and timer) */
68e1cecdcaSLaurent Vivier #define VIRT_GF_RTC_MMIO_BASE 0xff006000 /* MMIO: 0xff006000 - 0xff007fff */
69e1cecdcaSLaurent Vivier #define VIRT_GF_RTC_IRQ_BASE PIC_IRQ(6, 1) /* PIC: #6, IRQ: #1 */
70e1cecdcaSLaurent Vivier #define VIRT_GF_RTC_NB 2
71e1cecdcaSLaurent Vivier
72e1cecdcaSLaurent Vivier /* 1 goldfish-tty */
73e1cecdcaSLaurent Vivier #define VIRT_GF_TTY_MMIO_BASE 0xff008000 /* MMIO: 0xff008000 - 0xff008fff */
74e1cecdcaSLaurent Vivier #define VIRT_GF_TTY_IRQ_BASE PIC_IRQ(1, 32) /* PIC: #1, IRQ: #32 */
75e1cecdcaSLaurent Vivier
76e1cecdcaSLaurent Vivier /* 1 virt-ctrl */
77e1cecdcaSLaurent Vivier #define VIRT_CTRL_MMIO_BASE 0xff009000 /* MMIO: 0xff009000 - 0xff009fff */
78e1cecdcaSLaurent Vivier #define VIRT_CTRL_IRQ_BASE PIC_IRQ(1, 1) /* PIC: #1, IRQ: #1 */
79e1cecdcaSLaurent Vivier
80e1cecdcaSLaurent Vivier /*
81e1cecdcaSLaurent Vivier * virtio-mmio size is 0x200 bytes
82e1cecdcaSLaurent Vivier * we use 4 goldfish-pic to attach them,
83e1cecdcaSLaurent Vivier * we can attach 32 virtio devices / goldfish-pic
84e1cecdcaSLaurent Vivier * -> we can manage 32 * 4 = 128 virtio devices
85e1cecdcaSLaurent Vivier */
86e1cecdcaSLaurent Vivier #define VIRT_VIRTIO_MMIO_BASE 0xff010000 /* MMIO: 0xff010000 - 0xff01ffff */
87e1cecdcaSLaurent Vivier #define VIRT_VIRTIO_IRQ_BASE PIC_IRQ(2, 1) /* PIC: 2, 3, 4, 5, IRQ: ALL */
88e1cecdcaSLaurent Vivier
89e48b140eSLaurent Vivier typedef struct {
90e48b140eSLaurent Vivier M68kCPU *cpu;
91e48b140eSLaurent Vivier hwaddr initial_pc;
92e48b140eSLaurent Vivier hwaddr initial_stack;
93e48b140eSLaurent Vivier } ResetInfo;
94e48b140eSLaurent Vivier
main_cpu_reset(void * opaque)95e1cecdcaSLaurent Vivier static void main_cpu_reset(void *opaque)
96e1cecdcaSLaurent Vivier {
97e48b140eSLaurent Vivier ResetInfo *reset_info = opaque;
98e48b140eSLaurent Vivier M68kCPU *cpu = reset_info->cpu;
99e1cecdcaSLaurent Vivier CPUState *cs = CPU(cpu);
100e1cecdcaSLaurent Vivier
101e1cecdcaSLaurent Vivier cpu_reset(cs);
102e48b140eSLaurent Vivier cpu->env.aregs[7] = reset_info->initial_stack;
103e48b140eSLaurent Vivier cpu->env.pc = reset_info->initial_pc;
104e1cecdcaSLaurent Vivier }
105e1cecdcaSLaurent Vivier
rerandomize_rng_seed(void * opaque)1061ffd007cSJason A. Donenfeld static void rerandomize_rng_seed(void *opaque)
1071ffd007cSJason A. Donenfeld {
1081ffd007cSJason A. Donenfeld struct bi_record *rng_seed = opaque;
1091ffd007cSJason A. Donenfeld qemu_guest_getrandom_nofail((void *)rng_seed->data + 2,
1101ffd007cSJason A. Donenfeld be16_to_cpu(*(uint16_t *)rng_seed->data));
1111ffd007cSJason A. Donenfeld }
1121ffd007cSJason A. Donenfeld
virt_init(MachineState * machine)113e1cecdcaSLaurent Vivier static void virt_init(MachineState *machine)
114e1cecdcaSLaurent Vivier {
115e1cecdcaSLaurent Vivier M68kCPU *cpu = NULL;
116e1cecdcaSLaurent Vivier int32_t kernel_size;
117e1cecdcaSLaurent Vivier uint64_t elf_entry;
118e1cecdcaSLaurent Vivier ram_addr_t initrd_base;
119e1cecdcaSLaurent Vivier int32_t initrd_size;
120e1cecdcaSLaurent Vivier ram_addr_t ram_size = machine->ram_size;
121e1cecdcaSLaurent Vivier const char *kernel_filename = machine->kernel_filename;
122e1cecdcaSLaurent Vivier const char *initrd_filename = machine->initrd_filename;
123e1cecdcaSLaurent Vivier const char *kernel_cmdline = machine->kernel_cmdline;
124e1cecdcaSLaurent Vivier hwaddr parameters_base;
125e1cecdcaSLaurent Vivier DeviceState *dev;
126e1cecdcaSLaurent Vivier DeviceState *irqc_dev;
127e1cecdcaSLaurent Vivier DeviceState *pic_dev[VIRT_GF_PIC_NB];
128e1cecdcaSLaurent Vivier SysBusDevice *sysbus;
129e1cecdcaSLaurent Vivier hwaddr io_base;
130e1cecdcaSLaurent Vivier int i;
131e48b140eSLaurent Vivier ResetInfo *reset_info;
132a988465dSJason A. Donenfeld uint8_t rng_seed[32];
133e1cecdcaSLaurent Vivier
134e1cecdcaSLaurent Vivier if (ram_size > 3399672 * KiB) {
135e1cecdcaSLaurent Vivier /*
136e1cecdcaSLaurent Vivier * The physical memory can be up to 4 GiB - 16 MiB, but linux
137e1cecdcaSLaurent Vivier * kernel crashes after this limit (~ 3.2 GiB)
138e1cecdcaSLaurent Vivier */
139e1cecdcaSLaurent Vivier error_report("Too much memory for this machine: %" PRId64 " KiB, "
140e1cecdcaSLaurent Vivier "maximum 3399672 KiB", ram_size / KiB);
141e1cecdcaSLaurent Vivier exit(1);
142e1cecdcaSLaurent Vivier }
143e1cecdcaSLaurent Vivier
144b21e2380SMarkus Armbruster reset_info = g_new0(ResetInfo, 1);
145e48b140eSLaurent Vivier
146e1cecdcaSLaurent Vivier /* init CPUs */
147e1cecdcaSLaurent Vivier cpu = M68K_CPU(cpu_create(machine->cpu_type));
148e48b140eSLaurent Vivier
149e48b140eSLaurent Vivier reset_info->cpu = cpu;
150e48b140eSLaurent Vivier qemu_register_reset(main_cpu_reset, reset_info);
151e1cecdcaSLaurent Vivier
152e1cecdcaSLaurent Vivier /* RAM */
153e1cecdcaSLaurent Vivier memory_region_add_subregion(get_system_memory(), 0, machine->ram);
154e1cecdcaSLaurent Vivier
155e1cecdcaSLaurent Vivier /* IRQ Controller */
156e1cecdcaSLaurent Vivier
157e1cecdcaSLaurent Vivier irqc_dev = qdev_new(TYPE_M68K_IRQC);
158b8fc6195SPhilippe Mathieu-Daudé object_property_set_link(OBJECT(irqc_dev), "m68k-cpu",
159b8fc6195SPhilippe Mathieu-Daudé OBJECT(cpu), &error_abort);
160e1cecdcaSLaurent Vivier sysbus_realize_and_unref(SYS_BUS_DEVICE(irqc_dev), &error_fatal);
161e1cecdcaSLaurent Vivier
162e1cecdcaSLaurent Vivier /*
163e1cecdcaSLaurent Vivier * 6 goldfish-pic
164e1cecdcaSLaurent Vivier *
165e1cecdcaSLaurent Vivier * map: 0xff000000 - 0xff006fff = 28 KiB
166e1cecdcaSLaurent Vivier * IRQ: #1 (lower priority) -> #6 (higher priority)
167e1cecdcaSLaurent Vivier *
168e1cecdcaSLaurent Vivier */
169e1cecdcaSLaurent Vivier io_base = VIRT_GF_PIC_MMIO_BASE;
170e1cecdcaSLaurent Vivier for (i = 0; i < VIRT_GF_PIC_NB; i++) {
171e1cecdcaSLaurent Vivier pic_dev[i] = qdev_new(TYPE_GOLDFISH_PIC);
172e1cecdcaSLaurent Vivier sysbus = SYS_BUS_DEVICE(pic_dev[i]);
173e1cecdcaSLaurent Vivier qdev_prop_set_uint8(pic_dev[i], "index", i);
174e1cecdcaSLaurent Vivier sysbus_realize_and_unref(sysbus, &error_fatal);
175e1cecdcaSLaurent Vivier
176e1cecdcaSLaurent Vivier sysbus_mmio_map(sysbus, 0, io_base);
177e1cecdcaSLaurent Vivier sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(irqc_dev, i));
178e1cecdcaSLaurent Vivier
179e1cecdcaSLaurent Vivier io_base += 0x1000;
180e1cecdcaSLaurent Vivier }
181e1cecdcaSLaurent Vivier
182e1cecdcaSLaurent Vivier /* goldfish-rtc */
183e1cecdcaSLaurent Vivier io_base = VIRT_GF_RTC_MMIO_BASE;
184e1cecdcaSLaurent Vivier for (i = 0; i < VIRT_GF_RTC_NB; i++) {
185e1cecdcaSLaurent Vivier dev = qdev_new(TYPE_GOLDFISH_RTC);
18665f5144eSStafford Horne qdev_prop_set_bit(dev, "big-endian", true);
187e1cecdcaSLaurent Vivier sysbus = SYS_BUS_DEVICE(dev);
188e1cecdcaSLaurent Vivier sysbus_realize_and_unref(sysbus, &error_fatal);
189e1cecdcaSLaurent Vivier sysbus_mmio_map(sysbus, 0, io_base);
190e1cecdcaSLaurent Vivier sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_RTC_IRQ_BASE + i));
191e1cecdcaSLaurent Vivier
192e1cecdcaSLaurent Vivier io_base += 0x1000;
193e1cecdcaSLaurent Vivier }
194e1cecdcaSLaurent Vivier
195e1cecdcaSLaurent Vivier /* goldfish-tty */
196e1cecdcaSLaurent Vivier dev = qdev_new(TYPE_GOLDFISH_TTY);
197e1cecdcaSLaurent Vivier sysbus = SYS_BUS_DEVICE(dev);
198e1cecdcaSLaurent Vivier qdev_prop_set_chr(dev, "chardev", serial_hd(0));
199e1cecdcaSLaurent Vivier sysbus_realize_and_unref(sysbus, &error_fatal);
200e1cecdcaSLaurent Vivier sysbus_mmio_map(sysbus, 0, VIRT_GF_TTY_MMIO_BASE);
201e1cecdcaSLaurent Vivier sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_TTY_IRQ_BASE));
202e1cecdcaSLaurent Vivier
203e1cecdcaSLaurent Vivier /* virt controller */
2047f090ed7SPhilippe Mathieu-Daudé dev = sysbus_create_simple(TYPE_VIRT_CTRL, VIRT_CTRL_MMIO_BASE,
2057f090ed7SPhilippe Mathieu-Daudé PIC_GPIO(VIRT_CTRL_IRQ_BASE));
206e1cecdcaSLaurent Vivier
207e1cecdcaSLaurent Vivier /* virtio-mmio */
208e1cecdcaSLaurent Vivier io_base = VIRT_VIRTIO_MMIO_BASE;
209e1cecdcaSLaurent Vivier for (i = 0; i < 128; i++) {
210e1cecdcaSLaurent Vivier dev = qdev_new(TYPE_VIRTIO_MMIO);
211e1cecdcaSLaurent Vivier qdev_prop_set_bit(dev, "force-legacy", false);
212e1cecdcaSLaurent Vivier sysbus = SYS_BUS_DEVICE(dev);
213e1cecdcaSLaurent Vivier sysbus_realize_and_unref(sysbus, &error_fatal);
214e1cecdcaSLaurent Vivier sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_VIRTIO_IRQ_BASE + i));
215e1cecdcaSLaurent Vivier sysbus_mmio_map(sysbus, 0, io_base);
216e1cecdcaSLaurent Vivier io_base += 0x200;
217e1cecdcaSLaurent Vivier }
218e1cecdcaSLaurent Vivier
219e1cecdcaSLaurent Vivier if (kernel_filename) {
220e1cecdcaSLaurent Vivier CPUState *cs = CPU(cpu);
221e1cecdcaSLaurent Vivier uint64_t high;
222281ac13eSJason A. Donenfeld void *param_blob, *param_ptr, *param_rng_seed;
223281ac13eSJason A. Donenfeld
224281ac13eSJason A. Donenfeld if (kernel_cmdline) {
225281ac13eSJason A. Donenfeld param_blob = g_malloc(strlen(kernel_cmdline) + 1024);
226281ac13eSJason A. Donenfeld } else {
227281ac13eSJason A. Donenfeld param_blob = g_malloc(1024);
228281ac13eSJason A. Donenfeld }
229e1cecdcaSLaurent Vivier
230e1cecdcaSLaurent Vivier kernel_size = load_elf(kernel_filename, NULL, NULL, NULL,
231e1cecdcaSLaurent Vivier &elf_entry, NULL, &high, NULL, 1,
232e1cecdcaSLaurent Vivier EM_68K, 0, 0);
233e1cecdcaSLaurent Vivier if (kernel_size < 0) {
234e1cecdcaSLaurent Vivier error_report("could not load kernel '%s'", kernel_filename);
235e1cecdcaSLaurent Vivier exit(1);
236e1cecdcaSLaurent Vivier }
237e48b140eSLaurent Vivier reset_info->initial_pc = elf_entry;
238e1cecdcaSLaurent Vivier parameters_base = (high + 1) & ~1;
239281ac13eSJason A. Donenfeld param_ptr = param_blob;
240e1cecdcaSLaurent Vivier
241281ac13eSJason A. Donenfeld BOOTINFO1(param_ptr, BI_MACHTYPE, MACH_VIRT);
242e39a0809SLaurent Vivier if (m68k_feature(&cpu->env, M68K_FEATURE_M68020)) {
243e39a0809SLaurent Vivier BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68020);
244e39a0809SLaurent Vivier } else if (m68k_feature(&cpu->env, M68K_FEATURE_M68030)) {
245e39a0809SLaurent Vivier BOOTINFO1(param_ptr, BI_MMUTYPE, MMU_68030);
246e39a0809SLaurent Vivier BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68030);
247e39a0809SLaurent Vivier } else if (m68k_feature(&cpu->env, M68K_FEATURE_M68040)) {
248281ac13eSJason A. Donenfeld BOOTINFO1(param_ptr, BI_FPUTYPE, FPU_68040);
249281ac13eSJason A. Donenfeld BOOTINFO1(param_ptr, BI_MMUTYPE, MMU_68040);
250281ac13eSJason A. Donenfeld BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68040);
251e39a0809SLaurent Vivier } else if (m68k_feature(&cpu->env, M68K_FEATURE_M68060)) {
252e39a0809SLaurent Vivier BOOTINFO1(param_ptr, BI_FPUTYPE, FPU_68060);
253e39a0809SLaurent Vivier BOOTINFO1(param_ptr, BI_MMUTYPE, MMU_68060);
254e39a0809SLaurent Vivier BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68060);
255e39a0809SLaurent Vivier }
256281ac13eSJason A. Donenfeld BOOTINFO2(param_ptr, BI_MEMCHUNK, 0, ram_size);
257e1cecdcaSLaurent Vivier
258281ac13eSJason A. Donenfeld BOOTINFO1(param_ptr, BI_VIRT_QEMU_VERSION,
259e1cecdcaSLaurent Vivier ((QEMU_VERSION_MAJOR << 24) | (QEMU_VERSION_MINOR << 16) |
260e1cecdcaSLaurent Vivier (QEMU_VERSION_MICRO << 8)));
261281ac13eSJason A. Donenfeld BOOTINFO2(param_ptr, BI_VIRT_GF_PIC_BASE,
262e1cecdcaSLaurent Vivier VIRT_GF_PIC_MMIO_BASE, VIRT_GF_PIC_IRQ_BASE);
263281ac13eSJason A. Donenfeld BOOTINFO2(param_ptr, BI_VIRT_GF_RTC_BASE,
264e1cecdcaSLaurent Vivier VIRT_GF_RTC_MMIO_BASE, VIRT_GF_RTC_IRQ_BASE);
265281ac13eSJason A. Donenfeld BOOTINFO2(param_ptr, BI_VIRT_GF_TTY_BASE,
266e1cecdcaSLaurent Vivier VIRT_GF_TTY_MMIO_BASE, VIRT_GF_TTY_IRQ_BASE);
267281ac13eSJason A. Donenfeld BOOTINFO2(param_ptr, BI_VIRT_CTRL_BASE,
268e1cecdcaSLaurent Vivier VIRT_CTRL_MMIO_BASE, VIRT_CTRL_IRQ_BASE);
269281ac13eSJason A. Donenfeld BOOTINFO2(param_ptr, BI_VIRT_VIRTIO_BASE,
270e1cecdcaSLaurent Vivier VIRT_VIRTIO_MMIO_BASE, VIRT_VIRTIO_IRQ_BASE);
271e1cecdcaSLaurent Vivier
272e1cecdcaSLaurent Vivier if (kernel_cmdline) {
273281ac13eSJason A. Donenfeld BOOTINFOSTR(param_ptr, BI_COMMAND_LINE,
274e1cecdcaSLaurent Vivier kernel_cmdline);
275e1cecdcaSLaurent Vivier }
276e1cecdcaSLaurent Vivier
277a988465dSJason A. Donenfeld /* Pass seed to RNG. */
278281ac13eSJason A. Donenfeld param_rng_seed = param_ptr;
279a988465dSJason A. Donenfeld qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed));
280281ac13eSJason A. Donenfeld BOOTINFODATA(param_ptr, BI_RNG_SEED,
281a988465dSJason A. Donenfeld rng_seed, sizeof(rng_seed));
282a988465dSJason A. Donenfeld
283e1cecdcaSLaurent Vivier /* load initrd */
284e1cecdcaSLaurent Vivier if (initrd_filename) {
285e1cecdcaSLaurent Vivier initrd_size = get_image_size(initrd_filename);
286e1cecdcaSLaurent Vivier if (initrd_size < 0) {
287e1cecdcaSLaurent Vivier error_report("could not load initial ram disk '%s'",
288e1cecdcaSLaurent Vivier initrd_filename);
289e1cecdcaSLaurent Vivier exit(1);
290e1cecdcaSLaurent Vivier }
291e1cecdcaSLaurent Vivier
292e1cecdcaSLaurent Vivier initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK;
293e1cecdcaSLaurent Vivier load_image_targphys(initrd_filename, initrd_base,
294e1cecdcaSLaurent Vivier ram_size - initrd_base);
295281ac13eSJason A. Donenfeld BOOTINFO2(param_ptr, BI_RAMDISK, initrd_base,
296e1cecdcaSLaurent Vivier initrd_size);
297e1cecdcaSLaurent Vivier } else {
298e1cecdcaSLaurent Vivier initrd_base = 0;
299e1cecdcaSLaurent Vivier initrd_size = 0;
300e1cecdcaSLaurent Vivier }
301281ac13eSJason A. Donenfeld BOOTINFO0(param_ptr, BI_LAST);
302281ac13eSJason A. Donenfeld rom_add_blob_fixed_as("bootinfo", param_blob, param_ptr - param_blob,
303281ac13eSJason A. Donenfeld parameters_base, cs->as);
3041ffd007cSJason A. Donenfeld qemu_register_reset_nosnapshotload(rerandomize_rng_seed,
3051ffd007cSJason A. Donenfeld rom_ptr_for_as(cs->as, parameters_base,
306281ac13eSJason A. Donenfeld param_ptr - param_blob) +
3071ffd007cSJason A. Donenfeld (param_rng_seed - param_blob));
308281ac13eSJason A. Donenfeld g_free(param_blob);
309e1cecdcaSLaurent Vivier }
310e1cecdcaSLaurent Vivier }
311e1cecdcaSLaurent Vivier
virt_machine_class_init(ObjectClass * oc,void * data)312e1cecdcaSLaurent Vivier static void virt_machine_class_init(ObjectClass *oc, void *data)
313e1cecdcaSLaurent Vivier {
314e1cecdcaSLaurent Vivier MachineClass *mc = MACHINE_CLASS(oc);
315e1cecdcaSLaurent Vivier mc->desc = "QEMU M68K Virtual Machine";
316e1cecdcaSLaurent Vivier mc->init = virt_init;
317e1cecdcaSLaurent Vivier mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040");
318e1cecdcaSLaurent Vivier mc->max_cpus = 1;
319e1cecdcaSLaurent Vivier mc->no_floppy = 1;
320e1cecdcaSLaurent Vivier mc->no_parallel = 1;
321e1cecdcaSLaurent Vivier mc->default_ram_id = "m68k_virt.ram";
322e1cecdcaSLaurent Vivier }
323e1cecdcaSLaurent Vivier
324e1cecdcaSLaurent Vivier static const TypeInfo virt_machine_info = {
325e1cecdcaSLaurent Vivier .name = MACHINE_TYPE_NAME("virt"),
326e1cecdcaSLaurent Vivier .parent = TYPE_MACHINE,
327e1cecdcaSLaurent Vivier .abstract = true,
328e1cecdcaSLaurent Vivier .class_init = virt_machine_class_init,
329e1cecdcaSLaurent Vivier };
330e1cecdcaSLaurent Vivier
virt_machine_register_types(void)331e1cecdcaSLaurent Vivier static void virt_machine_register_types(void)
332e1cecdcaSLaurent Vivier {
333e1cecdcaSLaurent Vivier type_register_static(&virt_machine_info);
334e1cecdcaSLaurent Vivier }
335e1cecdcaSLaurent Vivier
type_init(virt_machine_register_types)336e1cecdcaSLaurent Vivier type_init(virt_machine_register_types)
337e1cecdcaSLaurent Vivier
3381d32d1d1SDaniel P. Berrangé #define DEFINE_VIRT_MACHINE_IMPL(latest, ...) \
3391d32d1d1SDaniel P. Berrangé static void MACHINE_VER_SYM(class_init, virt, __VA_ARGS__)( \
3401d32d1d1SDaniel P. Berrangé ObjectClass *oc, \
341e1cecdcaSLaurent Vivier void *data) \
342e1cecdcaSLaurent Vivier { \
343e1cecdcaSLaurent Vivier MachineClass *mc = MACHINE_CLASS(oc); \
3441d32d1d1SDaniel P. Berrangé MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \
3451d32d1d1SDaniel P. Berrangé mc->desc = "QEMU " MACHINE_VER_STR(__VA_ARGS__) " M68K Virtual Machine"; \
3468d3122a8SDaniel P. Berrangé MACHINE_VER_DEPRECATION(__VA_ARGS__); \
347e1cecdcaSLaurent Vivier if (latest) { \
348e1cecdcaSLaurent Vivier mc->alias = "virt"; \
349e1cecdcaSLaurent Vivier } \
350e1cecdcaSLaurent Vivier } \
3511d32d1d1SDaniel P. Berrangé static const TypeInfo MACHINE_VER_SYM(info, virt, __VA_ARGS__) = \
352e1cecdcaSLaurent Vivier { \
3531d32d1d1SDaniel P. Berrangé .name = MACHINE_VER_TYPE_NAME("virt", __VA_ARGS__), \
3541d32d1d1SDaniel P. Berrangé .parent = MACHINE_TYPE_NAME("virt"), \
3551d32d1d1SDaniel P. Berrangé .class_init = MACHINE_VER_SYM(class_init, virt, __VA_ARGS__), \
3561d32d1d1SDaniel P. Berrangé }; \
3571d32d1d1SDaniel P. Berrangé static void MACHINE_VER_SYM(register, virt, __VA_ARGS__)(void) \
3581d32d1d1SDaniel P. Berrangé { \
359a391eeb1SDaniel P. Berrangé MACHINE_VER_DELETION(__VA_ARGS__); \
3601d32d1d1SDaniel P. Berrangé type_register_static(&MACHINE_VER_SYM(info, virt, __VA_ARGS__)); \
361e1cecdcaSLaurent Vivier } \
3621d32d1d1SDaniel P. Berrangé type_init(MACHINE_VER_SYM(register, virt, __VA_ARGS__));
3631d32d1d1SDaniel P. Berrangé
3641d32d1d1SDaniel P. Berrangé #define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \
3651d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE_IMPL(true, major, minor)
3661d32d1d1SDaniel P. Berrangé #define DEFINE_VIRT_MACHINE(major, minor) \
3671d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE_IMPL(false, major, minor)
368e1cecdcaSLaurent Vivier
369*fb6051e7SCornelia Huck static void virt_machine_9_2_options(MachineClass *mc)
370e1cecdcaSLaurent Vivier {
371e1cecdcaSLaurent Vivier }
372*fb6051e7SCornelia Huck DEFINE_VIRT_MACHINE_AS_LATEST(9, 2)
373*fb6051e7SCornelia Huck
virt_machine_9_1_options(MachineClass * mc)374*fb6051e7SCornelia Huck static void virt_machine_9_1_options(MachineClass *mc)
375*fb6051e7SCornelia Huck {
376*fb6051e7SCornelia Huck virt_machine_9_2_options(mc);
377*fb6051e7SCornelia Huck compat_props_add(mc->compat_props, hw_compat_9_1, hw_compat_9_1_len);
378*fb6051e7SCornelia Huck }
379*fb6051e7SCornelia Huck DEFINE_VIRT_MACHINE(9, 1)
38085fa9acdSPaolo Bonzini
virt_machine_9_0_options(MachineClass * mc)38185fa9acdSPaolo Bonzini static void virt_machine_9_0_options(MachineClass *mc)
38285fa9acdSPaolo Bonzini {
38385fa9acdSPaolo Bonzini virt_machine_9_1_options(mc);
38485fa9acdSPaolo Bonzini compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len);
38585fa9acdSPaolo Bonzini }
3861d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE(9, 0)
3872b10a676SCornelia Huck
virt_machine_8_2_options(MachineClass * mc)3882b10a676SCornelia Huck static void virt_machine_8_2_options(MachineClass *mc)
3892b10a676SCornelia Huck {
3902b10a676SCornelia Huck virt_machine_9_0_options(mc);
3912b10a676SCornelia Huck compat_props_add(mc->compat_props, hw_compat_8_2, hw_compat_8_2_len);
3922b10a676SCornelia Huck }
3931d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE(8, 2)
39495f5c89eSCornelia Huck
virt_machine_8_1_options(MachineClass * mc)39595f5c89eSCornelia Huck static void virt_machine_8_1_options(MachineClass *mc)
39695f5c89eSCornelia Huck {
39795f5c89eSCornelia Huck virt_machine_8_2_options(mc);
39895f5c89eSCornelia Huck compat_props_add(mc->compat_props, hw_compat_8_1, hw_compat_8_1_len);
39995f5c89eSCornelia Huck }
4001d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE(8, 1)
401f9be4771SCornelia Huck
virt_machine_8_0_options(MachineClass * mc)402f9be4771SCornelia Huck static void virt_machine_8_0_options(MachineClass *mc)
403f9be4771SCornelia Huck {
404f9be4771SCornelia Huck virt_machine_8_1_options(mc);
405f9be4771SCornelia Huck compat_props_add(mc->compat_props, hw_compat_8_0, hw_compat_8_0_len);
406f9be4771SCornelia Huck }
4071d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE(8, 0)
408db723c80SCornelia Huck
virt_machine_7_2_options(MachineClass * mc)409db723c80SCornelia Huck static void virt_machine_7_2_options(MachineClass *mc)
410db723c80SCornelia Huck {
411db723c80SCornelia Huck virt_machine_8_0_options(mc);
412db723c80SCornelia Huck compat_props_add(mc->compat_props, hw_compat_7_2, hw_compat_7_2_len);
413db723c80SCornelia Huck }
4141d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE(7, 2)
415f514e147SCornelia Huck
virt_machine_7_1_options(MachineClass * mc)416f514e147SCornelia Huck static void virt_machine_7_1_options(MachineClass *mc)
417f514e147SCornelia Huck {
418f514e147SCornelia Huck virt_machine_7_2_options(mc);
419f514e147SCornelia Huck compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len);
420f514e147SCornelia Huck }
4211d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE(7, 1)
4220ca70366SCornelia Huck
virt_machine_7_0_options(MachineClass * mc)4230ca70366SCornelia Huck static void virt_machine_7_0_options(MachineClass *mc)
4240ca70366SCornelia Huck {
4250ca70366SCornelia Huck virt_machine_7_1_options(mc);
4260ca70366SCornelia Huck compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len);
4270ca70366SCornelia Huck }
4281d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE(7, 0)
429214bdf8eSLaurent Vivier
virt_machine_6_2_options(MachineClass * mc)430214bdf8eSLaurent Vivier static void virt_machine_6_2_options(MachineClass *mc)
431214bdf8eSLaurent Vivier {
432214bdf8eSLaurent Vivier virt_machine_7_0_options(mc);
433214bdf8eSLaurent Vivier compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len);
434214bdf8eSLaurent Vivier }
4351d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE(6, 2)
4366ed25621SLaurent Vivier
virt_machine_6_1_options(MachineClass * mc)4376ed25621SLaurent Vivier static void virt_machine_6_1_options(MachineClass *mc)
4386ed25621SLaurent Vivier {
4396ed25621SLaurent Vivier virt_machine_6_2_options(mc);
4406ed25621SLaurent Vivier compat_props_add(mc->compat_props, hw_compat_6_1, hw_compat_6_1_len);
4416ed25621SLaurent Vivier }
4421d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE(6, 1)
4436837f299SLaurent Vivier
virt_machine_6_0_options(MachineClass * mc)4446837f299SLaurent Vivier static void virt_machine_6_0_options(MachineClass *mc)
4456837f299SLaurent Vivier {
4466837f299SLaurent Vivier virt_machine_6_1_options(mc);
4476837f299SLaurent Vivier compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len);
4486837f299SLaurent Vivier }
4491d32d1d1SDaniel P. Berrangé DEFINE_VIRT_MACHINE(6, 0)
450