1 /* 2 * QEMU Machine 3 * 4 * Copyright (C) 2014 Red Hat Inc 5 * 6 * Authors: 7 * Marcel Apfelbaum <marcel.a@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 */ 12 13 #include "qemu/osdep.h" 14 #include "hw/boards.h" 15 #include "qapi/error.h" 16 #include "qapi-visit.h" 17 #include "qapi/visitor.h" 18 #include "hw/sysbus.h" 19 #include "sysemu/sysemu.h" 20 #include "sysemu/numa.h" 21 #include "qemu/error-report.h" 22 #include "qemu/cutils.h" 23 24 static char *machine_get_accel(Object *obj, Error **errp) 25 { 26 MachineState *ms = MACHINE(obj); 27 28 return g_strdup(ms->accel); 29 } 30 31 static void machine_set_accel(Object *obj, const char *value, Error **errp) 32 { 33 MachineState *ms = MACHINE(obj); 34 35 g_free(ms->accel); 36 ms->accel = g_strdup(value); 37 } 38 39 static void machine_set_kernel_irqchip(Object *obj, Visitor *v, 40 const char *name, void *opaque, 41 Error **errp) 42 { 43 Error *err = NULL; 44 MachineState *ms = MACHINE(obj); 45 OnOffSplit mode; 46 47 visit_type_OnOffSplit(v, name, &mode, &err); 48 if (err) { 49 error_propagate(errp, err); 50 return; 51 } else { 52 switch (mode) { 53 case ON_OFF_SPLIT_ON: 54 ms->kernel_irqchip_allowed = true; 55 ms->kernel_irqchip_required = true; 56 ms->kernel_irqchip_split = false; 57 break; 58 case ON_OFF_SPLIT_OFF: 59 ms->kernel_irqchip_allowed = false; 60 ms->kernel_irqchip_required = false; 61 ms->kernel_irqchip_split = false; 62 break; 63 case ON_OFF_SPLIT_SPLIT: 64 ms->kernel_irqchip_allowed = true; 65 ms->kernel_irqchip_required = true; 66 ms->kernel_irqchip_split = true; 67 break; 68 default: 69 /* The value was checked in visit_type_OnOffSplit() above. If 70 * we get here, then something is wrong in QEMU. 71 */ 72 abort(); 73 } 74 } 75 } 76 77 static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v, 78 const char *name, void *opaque, 79 Error **errp) 80 { 81 MachineState *ms = MACHINE(obj); 82 int64_t value = ms->kvm_shadow_mem; 83 84 visit_type_int(v, name, &value, errp); 85 } 86 87 static void machine_set_kvm_shadow_mem(Object *obj, Visitor *v, 88 const char *name, void *opaque, 89 Error **errp) 90 { 91 MachineState *ms = MACHINE(obj); 92 Error *error = NULL; 93 int64_t value; 94 95 visit_type_int(v, name, &value, &error); 96 if (error) { 97 error_propagate(errp, error); 98 return; 99 } 100 101 ms->kvm_shadow_mem = value; 102 } 103 104 static char *machine_get_kernel(Object *obj, Error **errp) 105 { 106 MachineState *ms = MACHINE(obj); 107 108 return g_strdup(ms->kernel_filename); 109 } 110 111 static void machine_set_kernel(Object *obj, const char *value, Error **errp) 112 { 113 MachineState *ms = MACHINE(obj); 114 115 g_free(ms->kernel_filename); 116 ms->kernel_filename = g_strdup(value); 117 } 118 119 static char *machine_get_initrd(Object *obj, Error **errp) 120 { 121 MachineState *ms = MACHINE(obj); 122 123 return g_strdup(ms->initrd_filename); 124 } 125 126 static void machine_set_initrd(Object *obj, const char *value, Error **errp) 127 { 128 MachineState *ms = MACHINE(obj); 129 130 g_free(ms->initrd_filename); 131 ms->initrd_filename = g_strdup(value); 132 } 133 134 static char *machine_get_append(Object *obj, Error **errp) 135 { 136 MachineState *ms = MACHINE(obj); 137 138 return g_strdup(ms->kernel_cmdline); 139 } 140 141 static void machine_set_append(Object *obj, const char *value, Error **errp) 142 { 143 MachineState *ms = MACHINE(obj); 144 145 g_free(ms->kernel_cmdline); 146 ms->kernel_cmdline = g_strdup(value); 147 } 148 149 static char *machine_get_dtb(Object *obj, Error **errp) 150 { 151 MachineState *ms = MACHINE(obj); 152 153 return g_strdup(ms->dtb); 154 } 155 156 static void machine_set_dtb(Object *obj, const char *value, Error **errp) 157 { 158 MachineState *ms = MACHINE(obj); 159 160 g_free(ms->dtb); 161 ms->dtb = g_strdup(value); 162 } 163 164 static char *machine_get_dumpdtb(Object *obj, Error **errp) 165 { 166 MachineState *ms = MACHINE(obj); 167 168 return g_strdup(ms->dumpdtb); 169 } 170 171 static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp) 172 { 173 MachineState *ms = MACHINE(obj); 174 175 g_free(ms->dumpdtb); 176 ms->dumpdtb = g_strdup(value); 177 } 178 179 static void machine_get_phandle_start(Object *obj, Visitor *v, 180 const char *name, void *opaque, 181 Error **errp) 182 { 183 MachineState *ms = MACHINE(obj); 184 int64_t value = ms->phandle_start; 185 186 visit_type_int(v, name, &value, errp); 187 } 188 189 static void machine_set_phandle_start(Object *obj, Visitor *v, 190 const char *name, void *opaque, 191 Error **errp) 192 { 193 MachineState *ms = MACHINE(obj); 194 Error *error = NULL; 195 int64_t value; 196 197 visit_type_int(v, name, &value, &error); 198 if (error) { 199 error_propagate(errp, error); 200 return; 201 } 202 203 ms->phandle_start = value; 204 } 205 206 static char *machine_get_dt_compatible(Object *obj, Error **errp) 207 { 208 MachineState *ms = MACHINE(obj); 209 210 return g_strdup(ms->dt_compatible); 211 } 212 213 static void machine_set_dt_compatible(Object *obj, const char *value, Error **errp) 214 { 215 MachineState *ms = MACHINE(obj); 216 217 g_free(ms->dt_compatible); 218 ms->dt_compatible = g_strdup(value); 219 } 220 221 static bool machine_get_dump_guest_core(Object *obj, Error **errp) 222 { 223 MachineState *ms = MACHINE(obj); 224 225 return ms->dump_guest_core; 226 } 227 228 static void machine_set_dump_guest_core(Object *obj, bool value, Error **errp) 229 { 230 MachineState *ms = MACHINE(obj); 231 232 ms->dump_guest_core = value; 233 } 234 235 static bool machine_get_mem_merge(Object *obj, Error **errp) 236 { 237 MachineState *ms = MACHINE(obj); 238 239 return ms->mem_merge; 240 } 241 242 static void machine_set_mem_merge(Object *obj, bool value, Error **errp) 243 { 244 MachineState *ms = MACHINE(obj); 245 246 ms->mem_merge = value; 247 } 248 249 static bool machine_get_usb(Object *obj, Error **errp) 250 { 251 MachineState *ms = MACHINE(obj); 252 253 return ms->usb; 254 } 255 256 static void machine_set_usb(Object *obj, bool value, Error **errp) 257 { 258 MachineState *ms = MACHINE(obj); 259 260 ms->usb = value; 261 ms->usb_disabled = !value; 262 } 263 264 static bool machine_get_graphics(Object *obj, Error **errp) 265 { 266 MachineState *ms = MACHINE(obj); 267 268 return ms->enable_graphics; 269 } 270 271 static void machine_set_graphics(Object *obj, bool value, Error **errp) 272 { 273 MachineState *ms = MACHINE(obj); 274 275 ms->enable_graphics = value; 276 } 277 278 static bool machine_get_igd_gfx_passthru(Object *obj, Error **errp) 279 { 280 MachineState *ms = MACHINE(obj); 281 282 return ms->igd_gfx_passthru; 283 } 284 285 static void machine_set_igd_gfx_passthru(Object *obj, bool value, Error **errp) 286 { 287 MachineState *ms = MACHINE(obj); 288 289 ms->igd_gfx_passthru = value; 290 } 291 292 static char *machine_get_firmware(Object *obj, Error **errp) 293 { 294 MachineState *ms = MACHINE(obj); 295 296 return g_strdup(ms->firmware); 297 } 298 299 static void machine_set_firmware(Object *obj, const char *value, Error **errp) 300 { 301 MachineState *ms = MACHINE(obj); 302 303 g_free(ms->firmware); 304 ms->firmware = g_strdup(value); 305 } 306 307 static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) 308 { 309 MachineState *ms = MACHINE(obj); 310 311 ms->suppress_vmdesc = value; 312 } 313 314 static bool machine_get_suppress_vmdesc(Object *obj, Error **errp) 315 { 316 MachineState *ms = MACHINE(obj); 317 318 return ms->suppress_vmdesc; 319 } 320 321 static void machine_set_enforce_config_section(Object *obj, bool value, 322 Error **errp) 323 { 324 MachineState *ms = MACHINE(obj); 325 326 ms->enforce_config_section = value; 327 } 328 329 static bool machine_get_enforce_config_section(Object *obj, Error **errp) 330 { 331 MachineState *ms = MACHINE(obj); 332 333 return ms->enforce_config_section; 334 } 335 336 static void error_on_sysbus_device(SysBusDevice *sbdev, void *opaque) 337 { 338 error_report("Option '-device %s' cannot be handled by this machine", 339 object_class_get_name(object_get_class(OBJECT(sbdev)))); 340 exit(1); 341 } 342 343 static void machine_init_notify(Notifier *notifier, void *data) 344 { 345 Object *machine = qdev_get_machine(); 346 ObjectClass *oc = object_get_class(machine); 347 MachineClass *mc = MACHINE_CLASS(oc); 348 349 if (mc->has_dynamic_sysbus) { 350 /* Our machine can handle dynamic sysbus devices, we're all good */ 351 return; 352 } 353 354 /* 355 * Loop through all dynamically created devices and check whether there 356 * are sysbus devices among them. If there are, error out. 357 */ 358 foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL); 359 } 360 361 HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine) 362 { 363 int i; 364 Object *cpu; 365 HotpluggableCPUList *head = NULL; 366 const char *cpu_type; 367 368 cpu = machine->possible_cpus->cpus[0].cpu; 369 assert(cpu); /* Boot cpu is always present */ 370 cpu_type = object_get_typename(cpu); 371 for (i = 0; i < machine->possible_cpus->len; i++) { 372 HotpluggableCPUList *list_item = g_new0(typeof(*list_item), 1); 373 HotpluggableCPU *cpu_item = g_new0(typeof(*cpu_item), 1); 374 375 cpu_item->type = g_strdup(cpu_type); 376 cpu_item->vcpus_count = machine->possible_cpus->cpus[i].vcpus_count; 377 cpu_item->props = g_memdup(&machine->possible_cpus->cpus[i].props, 378 sizeof(*cpu_item->props)); 379 380 cpu = machine->possible_cpus->cpus[i].cpu; 381 if (cpu) { 382 cpu_item->has_qom_path = true; 383 cpu_item->qom_path = object_get_canonical_path(cpu); 384 } 385 list_item->value = cpu_item; 386 list_item->next = head; 387 head = list_item; 388 } 389 return head; 390 } 391 392 /** 393 * machine_set_cpu_numa_node: 394 * @machine: machine object to modify 395 * @props: specifies which cpu objects to assign to 396 * numa node specified by @props.node_id 397 * @errp: if an error occurs, a pointer to an area to store the error 398 * 399 * Associate NUMA node specified by @props.node_id with cpu slots that 400 * match socket/core/thread-ids specified by @props. It's recommended to use 401 * query-hotpluggable-cpus.props values to specify affected cpu slots, 402 * which would lead to exact 1:1 mapping of cpu slots to NUMA node. 403 * 404 * However for CLI convenience it's possible to pass in subset of properties, 405 * which would affect all cpu slots that match it. 406 * Ex for pc machine: 407 * -smp 4,cores=2,sockets=2 -numa node,nodeid=0 -numa node,nodeid=1 \ 408 * -numa cpu,node-id=0,socket_id=0 \ 409 * -numa cpu,node-id=1,socket_id=1 410 * will assign all child cores of socket 0 to node 0 and 411 * of socket 1 to node 1. 412 * 413 * On attempt of reassigning (already assigned) cpu slot to another NUMA node, 414 * return error. 415 * Empty subset is disallowed and function will return with error in this case. 416 */ 417 void machine_set_cpu_numa_node(MachineState *machine, 418 const CpuInstanceProperties *props, Error **errp) 419 { 420 MachineClass *mc = MACHINE_GET_CLASS(machine); 421 bool match = false; 422 int i; 423 424 if (!mc->possible_cpu_arch_ids) { 425 error_setg(errp, "mapping of CPUs to NUMA node is not supported"); 426 return; 427 } 428 429 /* disabling node mapping is not supported, forbid it */ 430 assert(props->has_node_id); 431 432 /* force board to initialize possible_cpus if it hasn't been done yet */ 433 mc->possible_cpu_arch_ids(machine); 434 435 for (i = 0; i < machine->possible_cpus->len; i++) { 436 CPUArchId *slot = &machine->possible_cpus->cpus[i]; 437 438 /* reject unsupported by board properties */ 439 if (props->has_thread_id && !slot->props.has_thread_id) { 440 error_setg(errp, "thread-id is not supported"); 441 return; 442 } 443 444 if (props->has_core_id && !slot->props.has_core_id) { 445 error_setg(errp, "core-id is not supported"); 446 return; 447 } 448 449 if (props->has_socket_id && !slot->props.has_socket_id) { 450 error_setg(errp, "socket-id is not supported"); 451 return; 452 } 453 454 /* skip slots with explicit mismatch */ 455 if (props->has_thread_id && props->thread_id != slot->props.thread_id) { 456 continue; 457 } 458 459 if (props->has_core_id && props->core_id != slot->props.core_id) { 460 continue; 461 } 462 463 if (props->has_socket_id && props->socket_id != slot->props.socket_id) { 464 continue; 465 } 466 467 /* reject assignment if slot is already assigned, for compatibility 468 * of legacy cpu_index mapping with SPAPR core based mapping do not 469 * error out if cpu thread and matched core have the same node-id */ 470 if (slot->props.has_node_id && 471 slot->props.node_id != props->node_id) { 472 error_setg(errp, "CPU is already assigned to node-id: %" PRId64, 473 slot->props.node_id); 474 return; 475 } 476 477 /* assign slot to node as it's matched '-numa cpu' key */ 478 match = true; 479 slot->props.node_id = props->node_id; 480 slot->props.has_node_id = props->has_node_id; 481 } 482 483 if (!match) { 484 error_setg(errp, "no match found"); 485 } 486 } 487 488 static void machine_class_init(ObjectClass *oc, void *data) 489 { 490 MachineClass *mc = MACHINE_CLASS(oc); 491 492 /* Default 128 MB as guest ram size */ 493 mc->default_ram_size = 128 * M_BYTE; 494 mc->rom_file_has_mr = true; 495 496 /* numa node memory size aligned on 8MB by default. 497 * On Linux, each node's border has to be 8MB aligned 498 */ 499 mc->numa_mem_align_shift = 23; 500 mc->numa_auto_assign_ram = numa_default_auto_assign_ram; 501 502 object_class_property_add_str(oc, "accel", 503 machine_get_accel, machine_set_accel, &error_abort); 504 object_class_property_set_description(oc, "accel", 505 "Accelerator list", &error_abort); 506 507 object_class_property_add(oc, "kernel-irqchip", "OnOffSplit", 508 NULL, machine_set_kernel_irqchip, 509 NULL, NULL, &error_abort); 510 object_class_property_set_description(oc, "kernel-irqchip", 511 "Configure KVM in-kernel irqchip", &error_abort); 512 513 object_class_property_add(oc, "kvm-shadow-mem", "int", 514 machine_get_kvm_shadow_mem, machine_set_kvm_shadow_mem, 515 NULL, NULL, &error_abort); 516 object_class_property_set_description(oc, "kvm-shadow-mem", 517 "KVM shadow MMU size", &error_abort); 518 519 object_class_property_add_str(oc, "kernel", 520 machine_get_kernel, machine_set_kernel, &error_abort); 521 object_class_property_set_description(oc, "kernel", 522 "Linux kernel image file", &error_abort); 523 524 object_class_property_add_str(oc, "initrd", 525 machine_get_initrd, machine_set_initrd, &error_abort); 526 object_class_property_set_description(oc, "initrd", 527 "Linux initial ramdisk file", &error_abort); 528 529 object_class_property_add_str(oc, "append", 530 machine_get_append, machine_set_append, &error_abort); 531 object_class_property_set_description(oc, "append", 532 "Linux kernel command line", &error_abort); 533 534 object_class_property_add_str(oc, "dtb", 535 machine_get_dtb, machine_set_dtb, &error_abort); 536 object_class_property_set_description(oc, "dtb", 537 "Linux kernel device tree file", &error_abort); 538 539 object_class_property_add_str(oc, "dumpdtb", 540 machine_get_dumpdtb, machine_set_dumpdtb, &error_abort); 541 object_class_property_set_description(oc, "dumpdtb", 542 "Dump current dtb to a file and quit", &error_abort); 543 544 object_class_property_add(oc, "phandle-start", "int", 545 machine_get_phandle_start, machine_set_phandle_start, 546 NULL, NULL, &error_abort); 547 object_class_property_set_description(oc, "phandle-start", 548 "The first phandle ID we may generate dynamically", &error_abort); 549 550 object_class_property_add_str(oc, "dt-compatible", 551 machine_get_dt_compatible, machine_set_dt_compatible, &error_abort); 552 object_class_property_set_description(oc, "dt-compatible", 553 "Overrides the \"compatible\" property of the dt root node", 554 &error_abort); 555 556 object_class_property_add_bool(oc, "dump-guest-core", 557 machine_get_dump_guest_core, machine_set_dump_guest_core, &error_abort); 558 object_class_property_set_description(oc, "dump-guest-core", 559 "Include guest memory in a core dump", &error_abort); 560 561 object_class_property_add_bool(oc, "mem-merge", 562 machine_get_mem_merge, machine_set_mem_merge, &error_abort); 563 object_class_property_set_description(oc, "mem-merge", 564 "Enable/disable memory merge support", &error_abort); 565 566 object_class_property_add_bool(oc, "usb", 567 machine_get_usb, machine_set_usb, &error_abort); 568 object_class_property_set_description(oc, "usb", 569 "Set on/off to enable/disable usb", &error_abort); 570 571 object_class_property_add_bool(oc, "graphics", 572 machine_get_graphics, machine_set_graphics, &error_abort); 573 object_class_property_set_description(oc, "graphics", 574 "Set on/off to enable/disable graphics emulation", &error_abort); 575 576 object_class_property_add_bool(oc, "igd-passthru", 577 machine_get_igd_gfx_passthru, machine_set_igd_gfx_passthru, 578 &error_abort); 579 object_class_property_set_description(oc, "igd-passthru", 580 "Set on/off to enable/disable igd passthrou", &error_abort); 581 582 object_class_property_add_str(oc, "firmware", 583 machine_get_firmware, machine_set_firmware, 584 &error_abort); 585 object_class_property_set_description(oc, "firmware", 586 "Firmware image", &error_abort); 587 588 object_class_property_add_bool(oc, "suppress-vmdesc", 589 machine_get_suppress_vmdesc, machine_set_suppress_vmdesc, 590 &error_abort); 591 object_class_property_set_description(oc, "suppress-vmdesc", 592 "Set on to disable self-describing migration", &error_abort); 593 594 object_class_property_add_bool(oc, "enforce-config-section", 595 machine_get_enforce_config_section, machine_set_enforce_config_section, 596 &error_abort); 597 object_class_property_set_description(oc, "enforce-config-section", 598 "Set on to enforce configuration section migration", &error_abort); 599 } 600 601 static void machine_class_base_init(ObjectClass *oc, void *data) 602 { 603 if (!object_class_is_abstract(oc)) { 604 MachineClass *mc = MACHINE_CLASS(oc); 605 const char *cname = object_class_get_name(oc); 606 assert(g_str_has_suffix(cname, TYPE_MACHINE_SUFFIX)); 607 mc->name = g_strndup(cname, 608 strlen(cname) - strlen(TYPE_MACHINE_SUFFIX)); 609 } 610 } 611 612 static void machine_initfn(Object *obj) 613 { 614 MachineState *ms = MACHINE(obj); 615 616 ms->kernel_irqchip_allowed = true; 617 ms->kvm_shadow_mem = -1; 618 ms->dump_guest_core = true; 619 ms->mem_merge = true; 620 ms->enable_graphics = true; 621 622 /* Register notifier when init is done for sysbus sanity checks */ 623 ms->sysbus_notifier.notify = machine_init_notify; 624 qemu_add_machine_init_done_notifier(&ms->sysbus_notifier); 625 } 626 627 static void machine_finalize(Object *obj) 628 { 629 MachineState *ms = MACHINE(obj); 630 631 g_free(ms->accel); 632 g_free(ms->kernel_filename); 633 g_free(ms->initrd_filename); 634 g_free(ms->kernel_cmdline); 635 g_free(ms->dtb); 636 g_free(ms->dumpdtb); 637 g_free(ms->dt_compatible); 638 g_free(ms->firmware); 639 } 640 641 bool machine_usb(MachineState *machine) 642 { 643 return machine->usb; 644 } 645 646 bool machine_kernel_irqchip_allowed(MachineState *machine) 647 { 648 return machine->kernel_irqchip_allowed; 649 } 650 651 bool machine_kernel_irqchip_required(MachineState *machine) 652 { 653 return machine->kernel_irqchip_required; 654 } 655 656 bool machine_kernel_irqchip_split(MachineState *machine) 657 { 658 return machine->kernel_irqchip_split; 659 } 660 661 int machine_kvm_shadow_mem(MachineState *machine) 662 { 663 return machine->kvm_shadow_mem; 664 } 665 666 int machine_phandle_start(MachineState *machine) 667 { 668 return machine->phandle_start; 669 } 670 671 bool machine_dump_guest_core(MachineState *machine) 672 { 673 return machine->dump_guest_core; 674 } 675 676 bool machine_mem_merge(MachineState *machine) 677 { 678 return machine->mem_merge; 679 } 680 681 static void machine_class_finalize(ObjectClass *klass, void *data) 682 { 683 MachineClass *mc = MACHINE_CLASS(klass); 684 685 if (mc->compat_props) { 686 g_array_free(mc->compat_props, true); 687 } 688 g_free(mc->name); 689 } 690 691 static void register_compat_prop(const char *driver, 692 const char *property, 693 const char *value) 694 { 695 GlobalProperty *p = g_new0(GlobalProperty, 1); 696 /* Machine compat_props must never cause errors: */ 697 p->errp = &error_abort; 698 p->driver = driver; 699 p->property = property; 700 p->value = value; 701 qdev_prop_register_global(p); 702 } 703 704 static void machine_register_compat_for_subclass(ObjectClass *oc, void *opaque) 705 { 706 GlobalProperty *p = opaque; 707 register_compat_prop(object_class_get_name(oc), p->property, p->value); 708 } 709 710 void machine_register_compat_props(MachineState *machine) 711 { 712 MachineClass *mc = MACHINE_GET_CLASS(machine); 713 int i; 714 GlobalProperty *p; 715 ObjectClass *oc; 716 717 if (!mc->compat_props) { 718 return; 719 } 720 721 for (i = 0; i < mc->compat_props->len; i++) { 722 p = g_array_index(mc->compat_props, GlobalProperty *, i); 723 oc = object_class_by_name(p->driver); 724 if (oc && object_class_is_abstract(oc)) { 725 /* temporary hack to make sure we do not override 726 * globals set explicitly on -global: if an abstract class 727 * is on compat_props, register globals for all its 728 * non-abstract subtypes instead. 729 * 730 * This doesn't solve the problem for cases where 731 * a non-abstract typename mentioned on compat_props 732 * has subclasses, like spapr-pci-host-bridge. 733 */ 734 object_class_foreach(machine_register_compat_for_subclass, 735 p->driver, false, p); 736 } else { 737 register_compat_prop(p->driver, p->property, p->value); 738 } 739 } 740 } 741 742 static const TypeInfo machine_info = { 743 .name = TYPE_MACHINE, 744 .parent = TYPE_OBJECT, 745 .abstract = true, 746 .class_size = sizeof(MachineClass), 747 .class_init = machine_class_init, 748 .class_base_init = machine_class_base_init, 749 .class_finalize = machine_class_finalize, 750 .instance_size = sizeof(MachineState), 751 .instance_init = machine_initfn, 752 .instance_finalize = machine_finalize, 753 }; 754 755 static void machine_register_types(void) 756 { 757 type_register_static(&machine_info); 758 } 759 760 type_init(machine_register_types) 761