From 97ec4d21e09b5e4a59f00c471a7f76533b08ce56 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 14 Apr 2022 12:52:56 -0400 Subject: machine: use QAPI struct for boot configuration As part of converting -boot to a property with a QAPI type, define the struct and use it throughout QEMU to access boot configuration. machine_boot_parse takes care of doing the QemuOpts->QAPI conversion by hand, for now. Signed-off-by: Paolo Bonzini Message-Id: <20220414165300.555321-2-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 3 deletions(-) (limited to 'hw/core') diff --git a/hw/core/machine.c b/hw/core/machine.c index 700c1e7..b3deb81 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -784,6 +784,68 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name, machine_parse_smp_config(ms, config, errp); } +void machine_boot_parse(MachineState *ms, QemuOpts *opts, Error **errp) +{ + MachineClass *machine_class = MACHINE_GET_CLASS(ms); + const char *s; + ERRP_GUARD(); + + ms->boot_config = (BootConfiguration) { + .has_order = true, + .order = (char *)machine_class->default_boot_order, + .has_strict = true, + .strict = false, + }; + if (!opts) { + return; + } + + s = qemu_opt_get(opts, "order"); + if (s) { + validate_bootdevices(s, errp); + if (*errp) { + return; + } + ms->boot_config.order = (char *)s; + } + + s = qemu_opt_get(opts, "once"); + if (s) { + validate_bootdevices(s, errp); + if (*errp) { + return; + } + ms->boot_config.has_once = true; + ms->boot_config.once = (char *)s; + } + + s = qemu_opt_get(opts, "splash"); + if (s) { + ms->boot_config.has_splash = true; + ms->boot_config.splash = (char *)s; + } + + s = qemu_opt_get(opts, "splash-time"); + if (s) { + ms->boot_config.has_splash_time = true; + ms->boot_config.splash_time = qemu_opt_get_number(opts, "splash-time", -1); + } + + s = qemu_opt_get(opts, "reboot-timeout"); + if (s) { + ms->boot_config.has_reboot_timeout = true; + ms->boot_config.reboot_timeout = qemu_opt_get_number(opts, "reboot-timeout", -1); + } + + s = qemu_opt_get(opts, "menu"); + if (s) { + ms->boot_config.has_menu = true; + ms->boot_config.menu = qemu_opt_get_bool(opts, "menu", false); + } + + ms->boot_config.strict = qemu_opt_get_bool(opts, "strict", false); +} + static void machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -1229,9 +1291,9 @@ void qdev_machine_creation_done(void) { cpu_synchronize_all_post_init(); - if (current_machine->boot_once) { - qemu_boot_set(current_machine->boot_once, &error_fatal); - qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_order)); + if (current_machine->boot_config.has_once) { + qemu_boot_set(current_machine->boot_config.once, &error_fatal); + qemu_register_reset(restore_boot_order, g_strdup(current_machine->boot_config.order)); } /* -- cgit v1.1 From 8c4da4b52186e9d0c7233b0ffc796e78fdf3e7b3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 14 Apr 2022 12:52:57 -0400 Subject: machine: add boot compound property Make -boot syntactic sugar for a compound property "-machine boot.{order,menu,...}". machine_boot_parse is replaced by the setter for the property. Signed-off-by: Paolo Bonzini Message-Id: <20220414165300.555321-3-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 98 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 52 insertions(+), 46 deletions(-) (limited to 'hw/core') diff --git a/hw/core/machine.c b/hw/core/machine.c index b3deb81..8cea945 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -784,66 +784,63 @@ static void machine_set_smp(Object *obj, Visitor *v, const char *name, machine_parse_smp_config(ms, config, errp); } -void machine_boot_parse(MachineState *ms, QemuOpts *opts, Error **errp) +static void machine_get_boot(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + MachineState *ms = MACHINE(obj); + BootConfiguration *config = &ms->boot_config; + visit_type_BootConfiguration(v, name, &config, &error_abort); +} + +static void machine_free_boot_config(MachineState *ms) +{ + g_free(ms->boot_config.order); + g_free(ms->boot_config.once); + g_free(ms->boot_config.splash); +} + +static void machine_copy_boot_config(MachineState *ms, BootConfiguration *config) { MachineClass *machine_class = MACHINE_GET_CLASS(ms); - const char *s; + + machine_free_boot_config(ms); + ms->boot_config = *config; + if (!config->has_order) { + ms->boot_config.has_order = true; + ms->boot_config.order = g_strdup(machine_class->default_boot_order); + } +} + +static void machine_set_boot(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ ERRP_GUARD(); + MachineState *ms = MACHINE(obj); + BootConfiguration *config = NULL; - ms->boot_config = (BootConfiguration) { - .has_order = true, - .order = (char *)machine_class->default_boot_order, - .has_strict = true, - .strict = false, - }; - if (!opts) { + if (!visit_type_BootConfiguration(v, name, &config, errp)) { return; } - - s = qemu_opt_get(opts, "order"); - if (s) { - validate_bootdevices(s, errp); + if (config->has_order) { + validate_bootdevices(config->order, errp); if (*errp) { - return; + goto out_free; } - ms->boot_config.order = (char *)s; } - - s = qemu_opt_get(opts, "once"); - if (s) { - validate_bootdevices(s, errp); + if (config->has_once) { + validate_bootdevices(config->once, errp); if (*errp) { - return; + goto out_free; } - ms->boot_config.has_once = true; - ms->boot_config.once = (char *)s; - } - - s = qemu_opt_get(opts, "splash"); - if (s) { - ms->boot_config.has_splash = true; - ms->boot_config.splash = (char *)s; } - s = qemu_opt_get(opts, "splash-time"); - if (s) { - ms->boot_config.has_splash_time = true; - ms->boot_config.splash_time = qemu_opt_get_number(opts, "splash-time", -1); - } + machine_copy_boot_config(ms, config); + /* Strings live in ms->boot_config. */ + free(config); + return; - s = qemu_opt_get(opts, "reboot-timeout"); - if (s) { - ms->boot_config.has_reboot_timeout = true; - ms->boot_config.reboot_timeout = qemu_opt_get_number(opts, "reboot-timeout", -1); - } - - s = qemu_opt_get(opts, "menu"); - if (s) { - ms->boot_config.has_menu = true; - ms->boot_config.menu = qemu_opt_get_bool(opts, "menu", false); - } - - ms->boot_config.strict = qemu_opt_get_bool(opts, "strict", false); +out_free: + qapi_free_BootConfiguration(config); } static void machine_class_init(ObjectClass *oc, void *data) @@ -884,6 +881,12 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "dumpdtb", "Dump current dtb to a file and quit"); + object_class_property_add(oc, "boot", "BootConfiguration", + machine_get_boot, machine_set_boot, + NULL, NULL); + object_class_property_set_description(oc, "boot", + "Boot configuration"); + object_class_property_add(oc, "smp", "SMPConfiguration", machine_get_smp, machine_set_smp, NULL, NULL); @@ -1017,12 +1020,15 @@ static void machine_initfn(Object *obj) ms->smp.clusters = 1; ms->smp.cores = 1; ms->smp.threads = 1; + + machine_copy_boot_config(ms, &(BootConfiguration){ 0 }); } static void machine_finalize(Object *obj) { MachineState *ms = MACHINE(obj); + machine_free_boot_config(ms); g_free(ms->kernel_filename); g_free(ms->initrd_filename); g_free(ms->kernel_cmdline); -- cgit v1.1 From ce9d03fb3f7a87f46a1a2fc3597f2f44541a0c9c Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 14 Apr 2022 12:52:58 -0400 Subject: machine: add mem compound property Make -m syntactic sugar for a compound property "-machine mem.{size,max-size,slots}". The new property does not have the magic conversion to megabytes of unsuffixed arguments, and also does not understand that "0" means the default size (you have to leave it out to get the default). This means that we need to convert the QemuOpts by hand to a QDict. Signed-off-by: Paolo Bonzini Message-Id: <20220414165300.555321-4-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) (limited to 'hw/core') diff --git a/hw/core/machine.c b/hw/core/machine.c index 8cea945..46b8d0e 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -523,6 +523,78 @@ static void machine_set_hmat(Object *obj, bool value, Error **errp) ms->numa_state->hmat_enabled = value; } +static void machine_get_mem(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + MachineState *ms = MACHINE(obj); + MemorySizeConfiguration mem = { + .has_size = true, + .size = ms->ram_size, + .has_max_size = !!ms->ram_slots, + .max_size = ms->maxram_size, + .has_slots = !!ms->ram_slots, + .slots = ms->ram_slots, + }; + MemorySizeConfiguration *p_mem = &mem; + + visit_type_MemorySizeConfiguration(v, name, &p_mem, &error_abort); +} + +static void machine_set_mem(Object *obj, Visitor *v, const char *name, + void *opaque, Error **errp) +{ + MachineState *ms = MACHINE(obj); + MachineClass *mc = MACHINE_GET_CLASS(obj); + MemorySizeConfiguration *mem; + + ERRP_GUARD(); + + if (!visit_type_MemorySizeConfiguration(v, name, &mem, errp)) { + return; + } + + if (!mem->has_size) { + mem->has_size = true; + mem->size = mc->default_ram_size; + } + mem->size = QEMU_ALIGN_UP(mem->size, 8192); + if (mc->fixup_ram_size) { + mem->size = mc->fixup_ram_size(mem->size); + } + if ((ram_addr_t)mem->size != mem->size) { + error_setg(errp, "ram size too large"); + goto out_free; + } + + if (mem->has_max_size) { + if (mem->max_size < mem->size) { + error_setg(errp, "invalid value of maxmem: " + "maximum memory size (0x%" PRIx64 ") must be at least " + "the initial memory size (0x%" PRIx64 ")", + mem->max_size, mem->size); + goto out_free; + } + if (mem->has_slots && mem->slots && mem->max_size == mem->size) { + error_setg(errp, "invalid value of maxmem: " + "memory slots were specified but maximum memory size " + "(0x%" PRIx64 ") is equal to the initial memory size " + "(0x%" PRIx64 ")", mem->max_size, mem->size); + goto out_free; + } + ms->maxram_size = mem->max_size; + } else { + if (mem->has_slots) { + error_setg(errp, "slots specified but no max-size"); + goto out_free; + } + ms->maxram_size = mem->size; + } + ms->ram_size = mem->size; + ms->ram_slots = mem->has_slots ? mem->slots : 0; +out_free: + qapi_free_MemorySizeConfiguration(mem); +} + static char *machine_get_nvdimm_persistence(Object *obj, Error **errp) { MachineState *ms = MACHINE(obj); @@ -953,6 +1025,12 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "memory-backend", "Set RAM backend" "Valid value is ID of hostmem based backend"); + + object_class_property_add(oc, "memory", "MemorySizeConfiguration", + machine_get_mem, machine_set_mem, + NULL, NULL); + object_class_property_set_description(oc, "memory", + "Memory size configuration"); } static void machine_class_base_init(ObjectClass *oc, void *data) @@ -983,6 +1061,8 @@ static void machine_initfn(Object *obj) ms->mem_merge = true; ms->enable_graphics = true; ms->kernel_cmdline = g_strdup(""); + ms->ram_size = mc->default_ram_size; + ms->maxram_size = mc->default_ram_size; if (mc->nvdimm_supported) { Object *obj = OBJECT(ms); -- cgit v1.1 From 26f88d84dab62e6eb3ec72737ccb155d06049e3a Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 14 Apr 2022 12:52:59 -0400 Subject: machine: make memory-backend a link property Handle HostMemoryBackend creation and setting of ms->ram entirely in machine_run_board_init. Signed-off-by: Paolo Bonzini Message-Id: <20220414165300.555321-5-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 70 +++++++++++++++++++++++++++++++++++++------------------ hw/core/numa.c | 2 +- 2 files changed, 48 insertions(+), 24 deletions(-) (limited to 'hw/core') diff --git a/hw/core/machine.c b/hw/core/machine.c index 46b8d0e..8aab541 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -36,6 +36,7 @@ #include "exec/confidential-guest-support.h" #include "hw/virtio/virtio.h" #include "hw/virtio/virtio-pci.h" +#include "qom/object_interfaces.h" GlobalProperty hw_compat_7_0[] = {}; const size_t hw_compat_7_0_len = G_N_ELEMENTS(hw_compat_7_0); @@ -653,21 +654,6 @@ bool device_type_is_dynamic_sysbus(MachineClass *mc, const char *type) return allowed; } -static char *machine_get_memdev(Object *obj, Error **errp) -{ - MachineState *ms = MACHINE(obj); - - return g_strdup(ms->ram_memdev_id); -} - -static void machine_set_memdev(Object *obj, const char *value, Error **errp) -{ - MachineState *ms = MACHINE(obj); - - g_free(ms->ram_memdev_id); - ms->ram_memdev_id = g_strdup(value); -} - HotpluggableCPUList *machine_query_hotpluggable_cpus(MachineState *machine) { int i; @@ -1020,8 +1006,9 @@ static void machine_class_init(ObjectClass *oc, void *data) object_class_property_set_description(oc, "memory-encryption", "Set memory encryption object to use"); - object_class_property_add_str(oc, "memory-backend", - machine_get_memdev, machine_set_memdev); + object_class_property_add_link(oc, "memory-backend", TYPE_MEMORY_BACKEND, + offsetof(MachineState, memdev), object_property_allow_set_link, + OBJ_PROP_LINK_STRONG); object_class_property_set_description(oc, "memory-backend", "Set RAM backend" "Valid value is ID of hostmem based backend"); @@ -1270,7 +1257,40 @@ MemoryRegion *machine_consume_memdev(MachineState *machine, return ret; } -void machine_run_board_init(MachineState *machine) +static bool create_default_memdev(MachineState *ms, const char *path, Error **errp) +{ + Object *obj; + MachineClass *mc = MACHINE_GET_CLASS(ms); + bool r = false; + + obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM); + if (path) { + if (!object_property_set_str(obj, "mem-path", path, errp)) { + goto out; + } + } + if (!object_property_set_int(obj, "size", ms->ram_size, errp)) { + goto out; + } + object_property_add_child(object_get_objects_root(), mc->default_ram_id, + obj); + /* Ensure backend's memory region name is equal to mc->default_ram_id */ + if (!object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id", + false, errp)) { + goto out; + } + if (!user_creatable_complete(USER_CREATABLE(obj), errp)) { + goto out; + } + r = object_property_set_link(OBJECT(ms), "memory-backend", obj, errp); + +out: + object_unref(obj); + return r; +} + + +void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp) { MachineClass *machine_class = MACHINE_GET_CLASS(machine); ObjectClass *oc = object_class_by_name(machine->cpu_type); @@ -1281,11 +1301,11 @@ void machine_run_board_init(MachineState *machine) clock values from the log. */ replay_checkpoint(CHECKPOINT_INIT); - if (machine->ram_memdev_id) { - Object *o; - o = object_resolve_path_type(machine->ram_memdev_id, - TYPE_MEMORY_BACKEND, NULL); - machine->ram = machine_consume_memdev(machine, MEMORY_BACKEND(o)); + if (machine_class->default_ram_id && machine->ram_size && + numa_uses_legacy_mem() && !machine->memdev) { + if (!create_default_memdev(current_machine, mem_path, errp)) { + return; + } } if (machine->numa_state) { @@ -1295,6 +1315,10 @@ void machine_run_board_init(MachineState *machine) } } + if (!machine->ram && machine->memdev) { + machine->ram = machine_consume_memdev(machine, machine->memdev); + } + /* If the machine supports the valid_cpu_types check and the user * specified a CPU with -cpu check here that the user CPU is supported. */ diff --git a/hw/core/numa.c b/hw/core/numa.c index 1aa05dc..26d8e5f 100644 --- a/hw/core/numa.c +++ b/hw/core/numa.c @@ -695,7 +695,7 @@ void numa_complete_configuration(MachineState *ms) } if (!numa_uses_legacy_mem() && mc->default_ram_id) { - if (ms->ram_memdev_id) { + if (ms->memdev) { error_report("'-machine memory-backend' and '-numa memdev'" " properties are mutually exclusive"); exit(1); -- cgit v1.1 From fb56b7a052e1443409334c579e617e287a7250d3 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 14 Apr 2022 12:53:00 -0400 Subject: machine: move more memory validation to Machine object This allows setting memory properties without going through vl.c, and have them validated just the same. Signed-off-by: Paolo Bonzini Message-Id: <20220414165300.555321-6-pbonzini@redhat.com> Signed-off-by: Paolo Bonzini --- hw/core/machine.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) (limited to 'hw/core') diff --git a/hw/core/machine.c b/hw/core/machine.c index 8aab541..3264c1e 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -21,12 +21,14 @@ #include "qapi/qapi-visit-common.h" #include "qapi/qapi-visit-machine.h" #include "qapi/visitor.h" +#include "qom/object_interfaces.h" #include "hw/sysbus.h" #include "sysemu/cpus.h" #include "sysemu/sysemu.h" #include "sysemu/reset.h" #include "sysemu/runstate.h" #include "sysemu/numa.h" +#include "sysemu/xen.h" #include "qemu/error-report.h" #include "sysemu/qtest.h" #include "hw/pci/pci.h" @@ -1301,8 +1303,23 @@ void machine_run_board_init(MachineState *machine, const char *mem_path, Error * clock values from the log. */ replay_checkpoint(CHECKPOINT_INIT); - if (machine_class->default_ram_id && machine->ram_size && - numa_uses_legacy_mem() && !machine->memdev) { + if (!xen_enabled()) { + /* On 32-bit hosts, QEMU is limited by virtual address space */ + if (machine->ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { + error_setg(errp, "at most 2047 MB RAM can be simulated"); + return; + } + } + + if (machine->memdev) { + ram_addr_t backend_size = object_property_get_uint(OBJECT(machine->memdev), + "size", &error_abort); + if (backend_size != machine->ram_size) { + error_setg(errp, "Machine memory size does not match the size of the memory backend"); + return; + } + } else if (machine_class->default_ram_id && machine->ram_size && + numa_uses_legacy_mem()) { if (!create_default_memdev(current_machine, mem_path, errp)) { return; } -- cgit v1.1