| 1 | /* |
| 2 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | * |
| 4 | * QEMU Virtual M68K Machine |
| 5 | * |
| 6 | * (c) 2020 Laurent Vivier <laurent@vivier.eu> |
| 7 | * |
| 8 | */ |
| 9 | |
| 10 | #include "qemu/osdep.h" |
| 11 | #include "qemu/units.h" |
| 12 | #include "qemu/guest-random.h" |
| 13 | #include "exec/target_page.h" |
| 14 | #include "system/system.h" |
| 15 | #include "target/m68k/cpu.h" |
| 16 | #include "hw/core/boards.h" |
| 17 | #include "hw/core/qdev-properties.h" |
| 18 | #include "elf.h" |
| 19 | #include "hw/core/loader.h" |
| 20 | #include "ui/console.h" |
| 21 | #include "hw/core/sysbus.h" |
| 22 | #include "standard-headers/asm-m68k/bootinfo.h" |
| 23 | #include "standard-headers/asm-m68k/bootinfo-virt.h" |
| 24 | #include "bootinfo.h" |
| 25 | #include "net/net.h" |
| 26 | #include "qapi/error.h" |
| 27 | #include "qemu/error-report.h" |
| 28 | #include "system/qtest.h" |
| 29 | #include "system/runstate.h" |
| 30 | #include "system/reset.h" |
| 31 | |
| 32 | #include "hw/intc/m68k_irqc.h" |
| 33 | #include "hw/misc/virt_ctrl.h" |
| 34 | #include "hw/char/goldfish_tty.h" |
| 35 | #include "hw/rtc/goldfish_rtc.h" |
| 36 | #include "hw/intc/goldfish_pic.h" |
| 37 | #include "hw/virtio/virtio-mmio.h" |
| 38 | #include "hw/virtio/virtio-blk.h" |
| 39 | |
| 40 | /* |
| 41 | * 6 goldfish-pic for CPU IRQ #1 to IRQ #6 |
| 42 | * CPU IRQ #1 -> PIC #1 |
| 43 | * IRQ #1 to IRQ #31 -> unused |
| 44 | * IRQ #32 -> goldfish-tty |
| 45 | * CPU IRQ #2 -> PIC #2 |
| 46 | * IRQ #1 to IRQ #32 -> virtio-mmio from 1 to 32 |
| 47 | * CPU IRQ #3 -> PIC #3 |
| 48 | * IRQ #1 to IRQ #32 -> virtio-mmio from 33 to 64 |
| 49 | * CPU IRQ #4 -> PIC #4 |
| 50 | * IRQ #1 to IRQ #32 -> virtio-mmio from 65 to 96 |
| 51 | * CPU IRQ #5 -> PIC #5 |
| 52 | * IRQ #1 to IRQ #32 -> virtio-mmio from 97 to 128 |
| 53 | * CPU IRQ #6 -> PIC #6 |
| 54 | * IRQ #1 -> goldfish-rtc |
| 55 | * IRQ #2 to IRQ #32 -> unused |
| 56 | * CPU IRQ #7 -> NMI |
| 57 | */ |
| 58 | |
| 59 | #define PIC_IRQ_BASE(num) (8 + (num - 1) * 32) |
| 60 | #define PIC_IRQ(num, irq) (PIC_IRQ_BASE(num) + irq - 1) |
| 61 | #define PIC_GPIO(pic_irq) (qdev_get_gpio_in(pic_dev[(pic_irq - 8) / 32], \ |
| 62 | (pic_irq - 8) % 32)) |
| 63 | |
| 64 | #define VIRT_GF_PIC_MMIO_BASE 0xff000000 /* MMIO: 0xff000000 - 0xff005fff */ |
| 65 | #define VIRT_GF_PIC_IRQ_BASE 1 /* IRQ: #1 -> #6 */ |
| 66 | #define VIRT_GF_PIC_NB 6 |
| 67 | |
| 68 | /* 2 goldfish-rtc (and timer) */ |
| 69 | #define VIRT_GF_RTC_MMIO_BASE 0xff006000 /* MMIO: 0xff006000 - 0xff007fff */ |
| 70 | #define VIRT_GF_RTC_IRQ_BASE PIC_IRQ(6, 1) /* PIC: #6, IRQ: #1 */ |
| 71 | #define VIRT_GF_RTC_NB 2 |
| 72 | |
| 73 | /* 1 goldfish-tty */ |
| 74 | #define VIRT_GF_TTY_MMIO_BASE 0xff008000 /* MMIO: 0xff008000 - 0xff008fff */ |
| 75 | #define VIRT_GF_TTY_IRQ_BASE PIC_IRQ(1, 32) /* PIC: #1, IRQ: #32 */ |
| 76 | |
| 77 | /* 1 virt-ctrl */ |
| 78 | #define VIRT_CTRL_MMIO_BASE 0xff009000 /* MMIO: 0xff009000 - 0xff009fff */ |
| 79 | #define VIRT_CTRL_IRQ_BASE PIC_IRQ(1, 1) /* PIC: #1, IRQ: #1 */ |
| 80 | |
| 81 | /* |
| 82 | * virtio-mmio size is 0x200 bytes |
| 83 | * we use 4 goldfish-pic to attach them, |
| 84 | * we can attach 32 virtio devices / goldfish-pic |
| 85 | * -> we can manage 32 * 4 = 128 virtio devices |
| 86 | */ |
| 87 | #define VIRT_VIRTIO_MMIO_BASE 0xff010000 /* MMIO: 0xff010000 - 0xff01ffff */ |
| 88 | #define VIRT_VIRTIO_IRQ_BASE PIC_IRQ(2, 1) /* PIC: 2, 3, 4, 5, IRQ: ALL */ |
| 89 | |
| 90 | typedef struct { |
| 91 | M68kCPU *cpu; |
| 92 | hwaddr initial_pc; |
| 93 | hwaddr initial_stack; |
| 94 | } ResetInfo; |
| 95 | |
| 96 | static void main_cpu_reset(void *opaque) |
| 97 | { |
| 98 | ResetInfo *reset_info = opaque; |
| 99 | M68kCPU *cpu = reset_info->cpu; |
| 100 | CPUState *cs = CPU(cpu); |
| 101 | |
| 102 | cpu_reset(cs); |
| 103 | cpu->env.aregs[7] = reset_info->initial_stack; |
| 104 | cpu->env.pc = reset_info->initial_pc; |
| 105 | } |
| 106 | |
| 107 | static void rerandomize_rng_seed(void *opaque) |
| 108 | { |
| 109 | struct bi_record *rng_seed = opaque; |
| 110 | qemu_guest_getrandom_nofail((void *)rng_seed->data + 2, |
| 111 | be16_to_cpu(*(uint16_t *)rng_seed->data)); |
| 112 | } |
| 113 | |
| 114 | static void virt_init(MachineState *machine) |
| 115 | { |
| 116 | M68kCPU *cpu = NULL; |
| 117 | int32_t kernel_size; |
| 118 | uint64_t elf_entry; |
| 119 | ram_addr_t initrd_base; |
| 120 | int32_t initrd_size; |
| 121 | ram_addr_t ram_size = machine->ram_size; |
| 122 | const char *kernel_filename = machine->kernel_filename; |
| 123 | const char *initrd_filename = machine->initrd_filename; |
| 124 | const char *kernel_cmdline = machine->kernel_cmdline; |
| 125 | hwaddr parameters_base; |
| 126 | DeviceState *dev; |
| 127 | DeviceState *irqc_dev; |
| 128 | DeviceState *pic_dev[VIRT_GF_PIC_NB]; |
| 129 | SysBusDevice *sysbus; |
| 130 | hwaddr io_base; |
| 131 | int i; |
| 132 | ResetInfo *reset_info; |
| 133 | uint8_t rng_seed[32]; |
| 134 | |
| 135 | if (ram_size > 3399672 * KiB) { |
| 136 | /* |
| 137 | * The physical memory can be up to 4 GiB - 16 MiB, but linux |
| 138 | * kernel crashes after this limit (~ 3.2 GiB) |
| 139 | */ |
| 140 | error_report("Too much memory for this machine: %" PRId64 " KiB, " |
| 141 | "maximum 3399672 KiB", ram_size / KiB); |
| 142 | exit(1); |
| 143 | } |
| 144 | |
| 145 | reset_info = g_new0(ResetInfo, 1); |
| 146 | |
| 147 | /* init CPUs */ |
| 148 | cpu = M68K_CPU(cpu_create(machine->cpu_type)); |
| 149 | |
| 150 | reset_info->cpu = cpu; |
| 151 | qemu_register_reset(main_cpu_reset, reset_info); |
| 152 | |
| 153 | /* RAM */ |
| 154 | memory_region_add_subregion(get_system_memory(), 0, machine->ram); |
| 155 | |
| 156 | /* IRQ Controller */ |
| 157 | |
| 158 | irqc_dev = qdev_new(TYPE_M68K_IRQC); |
| 159 | object_property_set_link(OBJECT(irqc_dev), "m68k-cpu", |
| 160 | OBJECT(cpu), &error_abort); |
| 161 | sysbus_realize_and_unref(SYS_BUS_DEVICE(irqc_dev), &error_fatal); |
| 162 | |
| 163 | /* |
| 164 | * 6 goldfish-pic |
| 165 | * |
| 166 | * map: 0xff000000 - 0xff006fff = 28 KiB |
| 167 | * IRQ: #1 (lower priority) -> #6 (higher priority) |
| 168 | * |
| 169 | */ |
| 170 | io_base = VIRT_GF_PIC_MMIO_BASE; |
| 171 | for (i = 0; i < VIRT_GF_PIC_NB; i++) { |
| 172 | pic_dev[i] = qdev_new(TYPE_GOLDFISH_PIC); |
| 173 | sysbus = SYS_BUS_DEVICE(pic_dev[i]); |
| 174 | qdev_prop_set_uint8(pic_dev[i], "index", i); |
| 175 | sysbus_realize_and_unref(sysbus, &error_fatal); |
| 176 | |
| 177 | sysbus_mmio_map(sysbus, 0, io_base); |
| 178 | sysbus_connect_irq(sysbus, 0, qdev_get_gpio_in(irqc_dev, i)); |
| 179 | |
| 180 | io_base += 0x1000; |
| 181 | } |
| 182 | |
| 183 | /* goldfish-rtc */ |
| 184 | io_base = VIRT_GF_RTC_MMIO_BASE; |
| 185 | for (i = 0; i < VIRT_GF_RTC_NB; i++) { |
| 186 | dev = qdev_new(TYPE_GOLDFISH_RTC); |
| 187 | qdev_prop_set_bit(dev, "big-endian", true); |
| 188 | sysbus = SYS_BUS_DEVICE(dev); |
| 189 | sysbus_realize_and_unref(sysbus, &error_fatal); |
| 190 | sysbus_mmio_map(sysbus, 0, io_base); |
| 191 | sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_RTC_IRQ_BASE + i)); |
| 192 | |
| 193 | io_base += 0x1000; |
| 194 | } |
| 195 | |
| 196 | /* goldfish-tty */ |
| 197 | dev = qdev_new(TYPE_GOLDFISH_TTY); |
| 198 | sysbus = SYS_BUS_DEVICE(dev); |
| 199 | qdev_prop_set_chr(dev, "chardev", serial_hd(0)); |
| 200 | sysbus_realize_and_unref(sysbus, &error_fatal); |
| 201 | sysbus_mmio_map(sysbus, 0, VIRT_GF_TTY_MMIO_BASE); |
| 202 | sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_GF_TTY_IRQ_BASE)); |
| 203 | |
| 204 | /* virt controller */ |
| 205 | dev = sysbus_create_simple(TYPE_VIRT_CTRL, VIRT_CTRL_MMIO_BASE, |
| 206 | PIC_GPIO(VIRT_CTRL_IRQ_BASE)); |
| 207 | |
| 208 | /* virtio-mmio */ |
| 209 | io_base = VIRT_VIRTIO_MMIO_BASE; |
| 210 | for (i = 0; i < 128; i++) { |
| 211 | dev = qdev_new(TYPE_VIRTIO_MMIO); |
| 212 | qdev_prop_set_bit(dev, "force-legacy", false); |
| 213 | sysbus = SYS_BUS_DEVICE(dev); |
| 214 | sysbus_realize_and_unref(sysbus, &error_fatal); |
| 215 | sysbus_connect_irq(sysbus, 0, PIC_GPIO(VIRT_VIRTIO_IRQ_BASE + i)); |
| 216 | sysbus_mmio_map(sysbus, 0, io_base); |
| 217 | io_base += 0x200; |
| 218 | } |
| 219 | |
| 220 | if (kernel_filename) { |
| 221 | CPUState *cs = CPU(cpu); |
| 222 | uint64_t high; |
| 223 | void *param_blob, *param_ptr, *param_rng_seed; |
| 224 | |
| 225 | if (kernel_cmdline) { |
| 226 | param_blob = g_malloc(strlen(kernel_cmdline) + 1024); |
| 227 | } else { |
| 228 | param_blob = g_malloc(1024); |
| 229 | } |
| 230 | |
| 231 | kernel_size = load_elf(kernel_filename, NULL, NULL, NULL, |
| 232 | &elf_entry, NULL, &high, NULL, ELFDATA2MSB, |
| 233 | EM_68K, 0, 0); |
| 234 | if (kernel_size < 0) { |
| 235 | error_report("could not load kernel '%s'", kernel_filename); |
| 236 | exit(1); |
| 237 | } |
| 238 | reset_info->initial_pc = elf_entry; |
| 239 | parameters_base = (high + 1) & ~1; |
| 240 | param_ptr = param_blob; |
| 241 | |
| 242 | BOOTINFO1(param_ptr, BI_MACHTYPE, MACH_VIRT); |
| 243 | if (m68k_feature(&cpu->env, M68K_FEATURE_M68020)) { |
| 244 | BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68020); |
| 245 | } else if (m68k_feature(&cpu->env, M68K_FEATURE_M68030)) { |
| 246 | BOOTINFO1(param_ptr, BI_MMUTYPE, MMU_68030); |
| 247 | BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68030); |
| 248 | } else if (m68k_feature(&cpu->env, M68K_FEATURE_M68040)) { |
| 249 | BOOTINFO1(param_ptr, BI_FPUTYPE, FPU_68040); |
| 250 | BOOTINFO1(param_ptr, BI_MMUTYPE, MMU_68040); |
| 251 | BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68040); |
| 252 | } else if (m68k_feature(&cpu->env, M68K_FEATURE_M68060)) { |
| 253 | BOOTINFO1(param_ptr, BI_FPUTYPE, FPU_68060); |
| 254 | BOOTINFO1(param_ptr, BI_MMUTYPE, MMU_68060); |
| 255 | BOOTINFO1(param_ptr, BI_CPUTYPE, CPU_68060); |
| 256 | } |
| 257 | BOOTINFO2(param_ptr, BI_MEMCHUNK, 0, ram_size); |
| 258 | |
| 259 | BOOTINFO1(param_ptr, BI_VIRT_QEMU_VERSION, |
| 260 | ((QEMU_VERSION_MAJOR << 24) | (QEMU_VERSION_MINOR << 16) | |
| 261 | (QEMU_VERSION_MICRO << 8))); |
| 262 | BOOTINFO2(param_ptr, BI_VIRT_GF_PIC_BASE, |
| 263 | VIRT_GF_PIC_MMIO_BASE, VIRT_GF_PIC_IRQ_BASE); |
| 264 | BOOTINFO2(param_ptr, BI_VIRT_GF_RTC_BASE, |
| 265 | VIRT_GF_RTC_MMIO_BASE, VIRT_GF_RTC_IRQ_BASE); |
| 266 | BOOTINFO2(param_ptr, BI_VIRT_GF_TTY_BASE, |
| 267 | VIRT_GF_TTY_MMIO_BASE, VIRT_GF_TTY_IRQ_BASE); |
| 268 | BOOTINFO2(param_ptr, BI_VIRT_CTRL_BASE, |
| 269 | VIRT_CTRL_MMIO_BASE, VIRT_CTRL_IRQ_BASE); |
| 270 | BOOTINFO2(param_ptr, BI_VIRT_VIRTIO_BASE, |
| 271 | VIRT_VIRTIO_MMIO_BASE, VIRT_VIRTIO_IRQ_BASE); |
| 272 | |
| 273 | if (kernel_cmdline) { |
| 274 | BOOTINFOSTR(param_ptr, BI_COMMAND_LINE, |
| 275 | kernel_cmdline); |
| 276 | } |
| 277 | |
| 278 | /* Pass seed to RNG. */ |
| 279 | param_rng_seed = param_ptr; |
| 280 | qemu_guest_getrandom_nofail(rng_seed, sizeof(rng_seed)); |
| 281 | BOOTINFODATA(param_ptr, BI_RNG_SEED, |
| 282 | rng_seed, sizeof(rng_seed)); |
| 283 | |
| 284 | /* load initrd */ |
| 285 | if (initrd_filename) { |
| 286 | initrd_size = get_image_size(initrd_filename, NULL); |
| 287 | if (initrd_size < 0) { |
| 288 | error_report("could not load initial ram disk '%s'", |
| 289 | initrd_filename); |
| 290 | exit(1); |
| 291 | } |
| 292 | |
| 293 | initrd_base = (ram_size - initrd_size) & TARGET_PAGE_MASK; |
| 294 | load_image_targphys(initrd_filename, initrd_base, |
| 295 | ram_size - initrd_base, &error_fatal); |
| 296 | BOOTINFO2(param_ptr, BI_RAMDISK, initrd_base, |
| 297 | initrd_size); |
| 298 | } else { |
| 299 | initrd_base = 0; |
| 300 | initrd_size = 0; |
| 301 | } |
| 302 | BOOTINFO0(param_ptr, BI_LAST); |
| 303 | rom_add_blob_fixed_as("bootinfo", param_blob, param_ptr - param_blob, |
| 304 | parameters_base, cs->as); |
| 305 | qemu_register_reset_nosnapshotload(rerandomize_rng_seed, |
| 306 | rom_ptr_for_as(cs->as, parameters_base, |
| 307 | param_ptr - param_blob) + |
| 308 | (param_rng_seed - param_blob)); |
| 309 | g_free(param_blob); |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | static void virt_machine_class_init(ObjectClass *oc, const void *data) |
| 314 | { |
| 315 | MachineClass *mc = MACHINE_CLASS(oc); |
| 316 | mc->desc = "QEMU M68K Virtual Machine"; |
| 317 | mc->init = virt_init; |
| 318 | mc->default_cpu_type = M68K_CPU_TYPE_NAME("m68040"); |
| 319 | mc->max_cpus = 1; |
| 320 | mc->no_floppy = 1; |
| 321 | mc->no_parallel = 1; |
| 322 | mc->default_ram_id = "m68k_virt.ram"; |
| 323 | } |
| 324 | |
| 325 | static const TypeInfo virt_machine_info = { |
| 326 | .name = MACHINE_TYPE_NAME("virt"), |
| 327 | .parent = TYPE_MACHINE, |
| 328 | .abstract = true, |
| 329 | .class_init = virt_machine_class_init, |
| 330 | }; |
| 331 | |
| 332 | static void virt_machine_register_types(void) |
| 333 | { |
| 334 | type_register_static(&virt_machine_info); |
| 335 | } |
| 336 | |
| 337 | type_init(virt_machine_register_types) |
| 338 | |
| 339 | #define DEFINE_VIRT_MACHINE_IMPL(latest, ...) \ |
| 340 | static void MACHINE_VER_SYM(class_init, virt, __VA_ARGS__)( \ |
| 341 | ObjectClass *oc, \ |
| 342 | const void *data) \ |
| 343 | { \ |
| 344 | MachineClass *mc = MACHINE_CLASS(oc); \ |
| 345 | MACHINE_VER_SYM(options, virt, __VA_ARGS__)(mc); \ |
| 346 | mc->desc = "QEMU " MACHINE_VER_STR(__VA_ARGS__) " M68K Virtual Machine"; \ |
| 347 | MACHINE_VER_DEPRECATION(__VA_ARGS__); \ |
| 348 | if (latest) { \ |
| 349 | mc->alias = "virt"; \ |
| 350 | } \ |
| 351 | } \ |
| 352 | static const TypeInfo MACHINE_VER_SYM(info, virt, __VA_ARGS__) = \ |
| 353 | { \ |
| 354 | .name = MACHINE_VER_TYPE_NAME("virt", __VA_ARGS__), \ |
| 355 | .parent = MACHINE_TYPE_NAME("virt"), \ |
| 356 | .class_init = MACHINE_VER_SYM(class_init, virt, __VA_ARGS__), \ |
| 357 | }; \ |
| 358 | static void MACHINE_VER_SYM(register, virt, __VA_ARGS__)(void) \ |
| 359 | { \ |
| 360 | MACHINE_VER_DELETION(__VA_ARGS__); \ |
| 361 | type_register_static(&MACHINE_VER_SYM(info, virt, __VA_ARGS__)); \ |
| 362 | } \ |
| 363 | type_init(MACHINE_VER_SYM(register, virt, __VA_ARGS__)); |
| 364 | |
| 365 | #define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \ |
| 366 | DEFINE_VIRT_MACHINE_IMPL(true, major, minor) |
| 367 | #define DEFINE_VIRT_MACHINE(major, minor) \ |
| 368 | DEFINE_VIRT_MACHINE_IMPL(false, major, minor) |
| 369 | |
| 370 | static void virt_machine_11_2_options(MachineClass *mc) |
| 371 | { |
| 372 | } |
| 373 | DEFINE_VIRT_MACHINE_AS_LATEST(11, 2) |
| 374 | |
| 375 | static void virt_machine_11_1_options(MachineClass *mc) |
| 376 | { |
| 377 | virt_machine_11_2_options(mc); |
| 378 | compat_props_add(mc->compat_props, hw_compat_11_1, hw_compat_11_1_len); |
| 379 | } |
| 380 | DEFINE_VIRT_MACHINE(11, 1) |
| 381 | |
| 382 | static void virt_machine_11_0_options(MachineClass *mc) |
| 383 | { |
| 384 | virt_machine_11_1_options(mc); |
| 385 | compat_props_add(mc->compat_props, hw_compat_11_0, hw_compat_11_0_len); |
| 386 | } |
| 387 | DEFINE_VIRT_MACHINE(11, 0) |
| 388 | |
| 389 | static void virt_machine_10_2_options(MachineClass *mc) |
| 390 | { |
| 391 | virt_machine_11_0_options(mc); |
| 392 | compat_props_add(mc->compat_props, hw_compat_10_2, hw_compat_10_2_len); |
| 393 | } |
| 394 | DEFINE_VIRT_MACHINE(10, 2) |
| 395 | |
| 396 | static void virt_machine_10_1_options(MachineClass *mc) |
| 397 | { |
| 398 | virt_machine_10_2_options(mc); |
| 399 | compat_props_add(mc->compat_props, hw_compat_10_1, hw_compat_10_1_len); |
| 400 | } |
| 401 | DEFINE_VIRT_MACHINE(10, 1) |
| 402 | |
| 403 | static void virt_machine_10_0_options(MachineClass *mc) |
| 404 | { |
| 405 | virt_machine_10_1_options(mc); |
| 406 | compat_props_add(mc->compat_props, hw_compat_10_0, hw_compat_10_0_len); |
| 407 | } |
| 408 | DEFINE_VIRT_MACHINE(10, 0) |
| 409 | |
| 410 | static void virt_machine_9_2_options(MachineClass *mc) |
| 411 | { |
| 412 | virt_machine_10_0_options(mc); |
| 413 | compat_props_add(mc->compat_props, hw_compat_9_2, hw_compat_9_2_len); |
| 414 | } |
| 415 | DEFINE_VIRT_MACHINE(9, 2) |
| 416 | |
| 417 | static void virt_machine_9_1_options(MachineClass *mc) |
| 418 | { |
| 419 | virt_machine_9_2_options(mc); |
| 420 | compat_props_add(mc->compat_props, hw_compat_9_1, hw_compat_9_1_len); |
| 421 | } |
| 422 | DEFINE_VIRT_MACHINE(9, 1) |
| 423 | |
| 424 | static void virt_machine_9_0_options(MachineClass *mc) |
| 425 | { |
| 426 | virt_machine_9_1_options(mc); |
| 427 | compat_props_add(mc->compat_props, hw_compat_9_0, hw_compat_9_0_len); |
| 428 | } |
| 429 | DEFINE_VIRT_MACHINE(9, 0) |
| 430 | |
| 431 | static void virt_machine_8_2_options(MachineClass *mc) |
| 432 | { |
| 433 | virt_machine_9_0_options(mc); |
| 434 | compat_props_add(mc->compat_props, hw_compat_8_2, hw_compat_8_2_len); |
| 435 | } |
| 436 | DEFINE_VIRT_MACHINE(8, 2) |
| 437 | |
| 438 | static void virt_machine_8_1_options(MachineClass *mc) |
| 439 | { |
| 440 | virt_machine_8_2_options(mc); |
| 441 | compat_props_add(mc->compat_props, hw_compat_8_1, hw_compat_8_1_len); |
| 442 | } |
| 443 | DEFINE_VIRT_MACHINE(8, 1) |
| 444 | |
| 445 | static void virt_machine_8_0_options(MachineClass *mc) |
| 446 | { |
| 447 | virt_machine_8_1_options(mc); |
| 448 | compat_props_add(mc->compat_props, hw_compat_8_0, hw_compat_8_0_len); |
| 449 | } |
| 450 | DEFINE_VIRT_MACHINE(8, 0) |
| 451 | |
| 452 | static void virt_machine_7_2_options(MachineClass *mc) |
| 453 | { |
| 454 | virt_machine_8_0_options(mc); |
| 455 | compat_props_add(mc->compat_props, hw_compat_7_2, hw_compat_7_2_len); |
| 456 | } |
| 457 | DEFINE_VIRT_MACHINE(7, 2) |
| 458 | |
| 459 | static void virt_machine_7_1_options(MachineClass *mc) |
| 460 | { |
| 461 | virt_machine_7_2_options(mc); |
| 462 | compat_props_add(mc->compat_props, hw_compat_7_1, hw_compat_7_1_len); |
| 463 | } |
| 464 | DEFINE_VIRT_MACHINE(7, 1) |
| 465 | |
| 466 | static void virt_machine_7_0_options(MachineClass *mc) |
| 467 | { |
| 468 | virt_machine_7_1_options(mc); |
| 469 | compat_props_add(mc->compat_props, hw_compat_7_0, hw_compat_7_0_len); |
| 470 | } |
| 471 | DEFINE_VIRT_MACHINE(7, 0) |
| 472 | |
| 473 | static void virt_machine_6_2_options(MachineClass *mc) |
| 474 | { |
| 475 | virt_machine_7_0_options(mc); |
| 476 | compat_props_add(mc->compat_props, hw_compat_6_2, hw_compat_6_2_len); |
| 477 | } |
| 478 | DEFINE_VIRT_MACHINE(6, 2) |
| 479 | |
| 480 | static void virt_machine_6_1_options(MachineClass *mc) |
| 481 | { |
| 482 | virt_machine_6_2_options(mc); |
| 483 | compat_props_add(mc->compat_props, hw_compat_6_1, hw_compat_6_1_len); |
| 484 | } |
| 485 | DEFINE_VIRT_MACHINE(6, 1) |
| 486 | |
| 487 | static void virt_machine_6_0_options(MachineClass *mc) |
| 488 | { |
| 489 | virt_machine_6_1_options(mc); |
| 490 | compat_props_add(mc->compat_props, hw_compat_6_0, hw_compat_6_0_len); |
| 491 | } |
| 492 | DEFINE_VIRT_MACHINE(6, 0) |