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