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 "qemu/error-report.h" 21 #include "qemu/cutils.h" 22 23 static char *machine_get_accel(Object *obj, Error **errp) 24 { 25 MachineState *ms = MACHINE(obj); 26 27 return g_strdup(ms->accel); 28 } 29 30 static void machine_set_accel(Object *obj, const char *value, Error **errp) 31 { 32 MachineState *ms = MACHINE(obj); 33 34 g_free(ms->accel); 35 ms->accel = g_strdup(value); 36 } 37 38 static void machine_set_kernel_irqchip(Object *obj, Visitor *v, 39 const char *name, void *opaque, 40 Error **errp) 41 { 42 Error *err = NULL; 43 MachineState *ms = MACHINE(obj); 44 OnOffSplit mode; 45 46 visit_type_OnOffSplit(v, name, &mode, &err); 47 if (err) { 48 error_propagate(errp, err); 49 return; 50 } else { 51 switch (mode) { 52 case ON_OFF_SPLIT_ON: 53 ms->kernel_irqchip_allowed = true; 54 ms->kernel_irqchip_required = true; 55 ms->kernel_irqchip_split = false; 56 break; 57 case ON_OFF_SPLIT_OFF: 58 ms->kernel_irqchip_allowed = false; 59 ms->kernel_irqchip_required = false; 60 ms->kernel_irqchip_split = false; 61 break; 62 case ON_OFF_SPLIT_SPLIT: 63 ms->kernel_irqchip_allowed = true; 64 ms->kernel_irqchip_required = true; 65 ms->kernel_irqchip_split = true; 66 break; 67 default: 68 abort(); 69 } 70 } 71 } 72 73 static void machine_get_kvm_shadow_mem(Object *obj, Visitor *v, 74 const char *name, void *opaque, 75 Error **errp) 76 { 77 MachineState *ms = MACHINE(obj); 78 int64_t value = ms->kvm_shadow_mem; 79 80 visit_type_int(v, name, &value, errp); 81 } 82 83 static void machine_set_kvm_shadow_mem(Object *obj, Visitor *v, 84 const char *name, void *opaque, 85 Error **errp) 86 { 87 MachineState *ms = MACHINE(obj); 88 Error *error = NULL; 89 int64_t value; 90 91 visit_type_int(v, name, &value, &error); 92 if (error) { 93 error_propagate(errp, error); 94 return; 95 } 96 97 ms->kvm_shadow_mem = value; 98 } 99 100 static char *machine_get_kernel(Object *obj, Error **errp) 101 { 102 MachineState *ms = MACHINE(obj); 103 104 return g_strdup(ms->kernel_filename); 105 } 106 107 static void machine_set_kernel(Object *obj, const char *value, Error **errp) 108 { 109 MachineState *ms = MACHINE(obj); 110 111 g_free(ms->kernel_filename); 112 ms->kernel_filename = g_strdup(value); 113 } 114 115 static char *machine_get_initrd(Object *obj, Error **errp) 116 { 117 MachineState *ms = MACHINE(obj); 118 119 return g_strdup(ms->initrd_filename); 120 } 121 122 static void machine_set_initrd(Object *obj, const char *value, Error **errp) 123 { 124 MachineState *ms = MACHINE(obj); 125 126 g_free(ms->initrd_filename); 127 ms->initrd_filename = g_strdup(value); 128 } 129 130 static char *machine_get_append(Object *obj, Error **errp) 131 { 132 MachineState *ms = MACHINE(obj); 133 134 return g_strdup(ms->kernel_cmdline); 135 } 136 137 static void machine_set_append(Object *obj, const char *value, Error **errp) 138 { 139 MachineState *ms = MACHINE(obj); 140 141 g_free(ms->kernel_cmdline); 142 ms->kernel_cmdline = g_strdup(value); 143 } 144 145 static char *machine_get_dtb(Object *obj, Error **errp) 146 { 147 MachineState *ms = MACHINE(obj); 148 149 return g_strdup(ms->dtb); 150 } 151 152 static void machine_set_dtb(Object *obj, const char *value, Error **errp) 153 { 154 MachineState *ms = MACHINE(obj); 155 156 g_free(ms->dtb); 157 ms->dtb = g_strdup(value); 158 } 159 160 static char *machine_get_dumpdtb(Object *obj, Error **errp) 161 { 162 MachineState *ms = MACHINE(obj); 163 164 return g_strdup(ms->dumpdtb); 165 } 166 167 static void machine_set_dumpdtb(Object *obj, const char *value, Error **errp) 168 { 169 MachineState *ms = MACHINE(obj); 170 171 g_free(ms->dumpdtb); 172 ms->dumpdtb = g_strdup(value); 173 } 174 175 static void machine_get_phandle_start(Object *obj, Visitor *v, 176 const char *name, void *opaque, 177 Error **errp) 178 { 179 MachineState *ms = MACHINE(obj); 180 int64_t value = ms->phandle_start; 181 182 visit_type_int(v, name, &value, errp); 183 } 184 185 static void machine_set_phandle_start(Object *obj, Visitor *v, 186 const char *name, void *opaque, 187 Error **errp) 188 { 189 MachineState *ms = MACHINE(obj); 190 Error *error = NULL; 191 int64_t value; 192 193 visit_type_int(v, name, &value, &error); 194 if (error) { 195 error_propagate(errp, error); 196 return; 197 } 198 199 ms->phandle_start = value; 200 } 201 202 static char *machine_get_dt_compatible(Object *obj, Error **errp) 203 { 204 MachineState *ms = MACHINE(obj); 205 206 return g_strdup(ms->dt_compatible); 207 } 208 209 static void machine_set_dt_compatible(Object *obj, const char *value, Error **errp) 210 { 211 MachineState *ms = MACHINE(obj); 212 213 g_free(ms->dt_compatible); 214 ms->dt_compatible = g_strdup(value); 215 } 216 217 static bool machine_get_dump_guest_core(Object *obj, Error **errp) 218 { 219 MachineState *ms = MACHINE(obj); 220 221 return ms->dump_guest_core; 222 } 223 224 static void machine_set_dump_guest_core(Object *obj, bool value, Error **errp) 225 { 226 MachineState *ms = MACHINE(obj); 227 228 ms->dump_guest_core = value; 229 } 230 231 static bool machine_get_mem_merge(Object *obj, Error **errp) 232 { 233 MachineState *ms = MACHINE(obj); 234 235 return ms->mem_merge; 236 } 237 238 static void machine_set_mem_merge(Object *obj, bool value, Error **errp) 239 { 240 MachineState *ms = MACHINE(obj); 241 242 ms->mem_merge = value; 243 } 244 245 static bool machine_get_usb(Object *obj, Error **errp) 246 { 247 MachineState *ms = MACHINE(obj); 248 249 return ms->usb; 250 } 251 252 static void machine_set_usb(Object *obj, bool value, Error **errp) 253 { 254 MachineState *ms = MACHINE(obj); 255 256 ms->usb = value; 257 ms->usb_disabled = !value; 258 } 259 260 static bool machine_get_graphics(Object *obj, Error **errp) 261 { 262 MachineState *ms = MACHINE(obj); 263 264 return ms->enable_graphics; 265 } 266 267 static void machine_set_graphics(Object *obj, bool value, Error **errp) 268 { 269 MachineState *ms = MACHINE(obj); 270 271 ms->enable_graphics = value; 272 } 273 274 static bool machine_get_igd_gfx_passthru(Object *obj, Error **errp) 275 { 276 MachineState *ms = MACHINE(obj); 277 278 return ms->igd_gfx_passthru; 279 } 280 281 static void machine_set_igd_gfx_passthru(Object *obj, bool value, Error **errp) 282 { 283 MachineState *ms = MACHINE(obj); 284 285 ms->igd_gfx_passthru = value; 286 } 287 288 static char *machine_get_firmware(Object *obj, Error **errp) 289 { 290 MachineState *ms = MACHINE(obj); 291 292 return g_strdup(ms->firmware); 293 } 294 295 static void machine_set_firmware(Object *obj, const char *value, Error **errp) 296 { 297 MachineState *ms = MACHINE(obj); 298 299 g_free(ms->firmware); 300 ms->firmware = g_strdup(value); 301 } 302 303 static void machine_set_suppress_vmdesc(Object *obj, bool value, Error **errp) 304 { 305 MachineState *ms = MACHINE(obj); 306 307 ms->suppress_vmdesc = value; 308 } 309 310 static bool machine_get_suppress_vmdesc(Object *obj, Error **errp) 311 { 312 MachineState *ms = MACHINE(obj); 313 314 return ms->suppress_vmdesc; 315 } 316 317 static void machine_set_enforce_config_section(Object *obj, bool value, 318 Error **errp) 319 { 320 MachineState *ms = MACHINE(obj); 321 322 ms->enforce_config_section = value; 323 } 324 325 static bool machine_get_enforce_config_section(Object *obj, Error **errp) 326 { 327 MachineState *ms = MACHINE(obj); 328 329 return ms->enforce_config_section; 330 } 331 332 static int error_on_sysbus_device(SysBusDevice *sbdev, void *opaque) 333 { 334 error_report("Option '-device %s' cannot be handled by this machine", 335 object_class_get_name(object_get_class(OBJECT(sbdev)))); 336 exit(1); 337 } 338 339 static void machine_init_notify(Notifier *notifier, void *data) 340 { 341 Object *machine = qdev_get_machine(); 342 ObjectClass *oc = object_get_class(machine); 343 MachineClass *mc = MACHINE_CLASS(oc); 344 345 if (mc->has_dynamic_sysbus) { 346 /* Our machine can handle dynamic sysbus devices, we're all good */ 347 return; 348 } 349 350 /* 351 * Loop through all dynamically created devices and check whether there 352 * are sysbus devices among them. If there are, error out. 353 */ 354 foreach_dynamic_sysbus_device(error_on_sysbus_device, NULL); 355 } 356 357 static void machine_class_init(ObjectClass *oc, void *data) 358 { 359 MachineClass *mc = MACHINE_CLASS(oc); 360 361 /* Default 128 MB as guest ram size */ 362 mc->default_ram_size = 128 * M_BYTE; 363 mc->rom_file_has_mr = true; 364 } 365 366 static void machine_class_base_init(ObjectClass *oc, void *data) 367 { 368 if (!object_class_is_abstract(oc)) { 369 MachineClass *mc = MACHINE_CLASS(oc); 370 const char *cname = object_class_get_name(oc); 371 assert(g_str_has_suffix(cname, TYPE_MACHINE_SUFFIX)); 372 mc->name = g_strndup(cname, 373 strlen(cname) - strlen(TYPE_MACHINE_SUFFIX)); 374 } 375 } 376 377 static void machine_initfn(Object *obj) 378 { 379 MachineState *ms = MACHINE(obj); 380 381 ms->kernel_irqchip_allowed = true; 382 ms->kvm_shadow_mem = -1; 383 ms->dump_guest_core = true; 384 ms->mem_merge = true; 385 ms->enable_graphics = true; 386 387 object_property_add_str(obj, "accel", 388 machine_get_accel, machine_set_accel, NULL); 389 object_property_set_description(obj, "accel", 390 "Accelerator list", 391 NULL); 392 object_property_add(obj, "kernel-irqchip", "OnOffSplit", 393 NULL, 394 machine_set_kernel_irqchip, 395 NULL, NULL, NULL); 396 object_property_set_description(obj, "kernel-irqchip", 397 "Configure KVM in-kernel irqchip", 398 NULL); 399 object_property_add(obj, "kvm-shadow-mem", "int", 400 machine_get_kvm_shadow_mem, 401 machine_set_kvm_shadow_mem, 402 NULL, NULL, NULL); 403 object_property_set_description(obj, "kvm-shadow-mem", 404 "KVM shadow MMU size", 405 NULL); 406 object_property_add_str(obj, "kernel", 407 machine_get_kernel, machine_set_kernel, NULL); 408 object_property_set_description(obj, "kernel", 409 "Linux kernel image file", 410 NULL); 411 object_property_add_str(obj, "initrd", 412 machine_get_initrd, machine_set_initrd, NULL); 413 object_property_set_description(obj, "initrd", 414 "Linux initial ramdisk file", 415 NULL); 416 object_property_add_str(obj, "append", 417 machine_get_append, machine_set_append, NULL); 418 object_property_set_description(obj, "append", 419 "Linux kernel command line", 420 NULL); 421 object_property_add_str(obj, "dtb", 422 machine_get_dtb, machine_set_dtb, NULL); 423 object_property_set_description(obj, "dtb", 424 "Linux kernel device tree file", 425 NULL); 426 object_property_add_str(obj, "dumpdtb", 427 machine_get_dumpdtb, machine_set_dumpdtb, NULL); 428 object_property_set_description(obj, "dumpdtb", 429 "Dump current dtb to a file and quit", 430 NULL); 431 object_property_add(obj, "phandle-start", "int", 432 machine_get_phandle_start, 433 machine_set_phandle_start, 434 NULL, NULL, NULL); 435 object_property_set_description(obj, "phandle-start", 436 "The first phandle ID we may generate dynamically", 437 NULL); 438 object_property_add_str(obj, "dt-compatible", 439 machine_get_dt_compatible, 440 machine_set_dt_compatible, 441 NULL); 442 object_property_set_description(obj, "dt-compatible", 443 "Overrides the \"compatible\" property of the dt root node", 444 NULL); 445 object_property_add_bool(obj, "dump-guest-core", 446 machine_get_dump_guest_core, 447 machine_set_dump_guest_core, 448 NULL); 449 object_property_set_description(obj, "dump-guest-core", 450 "Include guest memory in a core dump", 451 NULL); 452 object_property_add_bool(obj, "mem-merge", 453 machine_get_mem_merge, 454 machine_set_mem_merge, NULL); 455 object_property_set_description(obj, "mem-merge", 456 "Enable/disable memory merge support", 457 NULL); 458 object_property_add_bool(obj, "usb", 459 machine_get_usb, 460 machine_set_usb, NULL); 461 object_property_set_description(obj, "usb", 462 "Set on/off to enable/disable usb", 463 NULL); 464 object_property_add_bool(obj, "graphics", 465 machine_get_graphics, 466 machine_set_graphics, NULL); 467 object_property_set_description(obj, "graphics", 468 "Set on/off to enable/disable graphics emulation", 469 NULL); 470 object_property_add_bool(obj, "igd-passthru", 471 machine_get_igd_gfx_passthru, 472 machine_set_igd_gfx_passthru, NULL); 473 object_property_set_description(obj, "igd-passthru", 474 "Set on/off to enable/disable igd passthrou", 475 NULL); 476 object_property_add_str(obj, "firmware", 477 machine_get_firmware, 478 machine_set_firmware, NULL); 479 object_property_set_description(obj, "firmware", 480 "Firmware image", 481 NULL); 482 object_property_add_bool(obj, "suppress-vmdesc", 483 machine_get_suppress_vmdesc, 484 machine_set_suppress_vmdesc, NULL); 485 object_property_set_description(obj, "suppress-vmdesc", 486 "Set on to disable self-describing migration", 487 NULL); 488 object_property_add_bool(obj, "enforce-config-section", 489 machine_get_enforce_config_section, 490 machine_set_enforce_config_section, NULL); 491 object_property_set_description(obj, "enforce-config-section", 492 "Set on to enforce configuration section migration", 493 NULL); 494 495 /* Register notifier when init is done for sysbus sanity checks */ 496 ms->sysbus_notifier.notify = machine_init_notify; 497 qemu_add_machine_init_done_notifier(&ms->sysbus_notifier); 498 } 499 500 static void machine_finalize(Object *obj) 501 { 502 MachineState *ms = MACHINE(obj); 503 504 g_free(ms->accel); 505 g_free(ms->kernel_filename); 506 g_free(ms->initrd_filename); 507 g_free(ms->kernel_cmdline); 508 g_free(ms->dtb); 509 g_free(ms->dumpdtb); 510 g_free(ms->dt_compatible); 511 g_free(ms->firmware); 512 } 513 514 bool machine_usb(MachineState *machine) 515 { 516 return machine->usb; 517 } 518 519 bool machine_kernel_irqchip_allowed(MachineState *machine) 520 { 521 return machine->kernel_irqchip_allowed; 522 } 523 524 bool machine_kernel_irqchip_required(MachineState *machine) 525 { 526 return machine->kernel_irqchip_required; 527 } 528 529 bool machine_kernel_irqchip_split(MachineState *machine) 530 { 531 return machine->kernel_irqchip_split; 532 } 533 534 int machine_kvm_shadow_mem(MachineState *machine) 535 { 536 return machine->kvm_shadow_mem; 537 } 538 539 int machine_phandle_start(MachineState *machine) 540 { 541 return machine->phandle_start; 542 } 543 544 bool machine_dump_guest_core(MachineState *machine) 545 { 546 return machine->dump_guest_core; 547 } 548 549 bool machine_mem_merge(MachineState *machine) 550 { 551 return machine->mem_merge; 552 } 553 554 static void machine_class_finalize(ObjectClass *klass, void *data) 555 { 556 MachineClass *mc = MACHINE_CLASS(klass); 557 558 if (mc->compat_props) { 559 g_array_free(mc->compat_props, true); 560 } 561 } 562 563 void machine_register_compat_props(MachineState *machine) 564 { 565 MachineClass *mc = MACHINE_GET_CLASS(machine); 566 int i; 567 GlobalProperty *p; 568 569 if (!mc->compat_props) { 570 return; 571 } 572 573 for (i = 0; i < mc->compat_props->len; i++) { 574 p = g_array_index(mc->compat_props, GlobalProperty *, i); 575 /* Machine compat_props must never cause errors: */ 576 p->errp = &error_abort; 577 qdev_prop_register_global(p); 578 } 579 } 580 581 static const TypeInfo machine_info = { 582 .name = TYPE_MACHINE, 583 .parent = TYPE_OBJECT, 584 .abstract = true, 585 .class_size = sizeof(MachineClass), 586 .class_init = machine_class_init, 587 .class_base_init = machine_class_base_init, 588 .class_finalize = machine_class_finalize, 589 .instance_size = sizeof(MachineState), 590 .instance_init = machine_initfn, 591 .instance_finalize = machine_finalize, 592 }; 593 594 static void machine_register_types(void) 595 { 596 type_register_static(&machine_info); 597 } 598 599 type_init(machine_register_types) 600