xref: /qemu/hw/core/machine.c (revision 7c88e65d9e9ff7df7fa9cff1869d64a0eaac63a1)
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