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