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/machine.c') diff --git a/hw/core/machine.c b/hw/core/machine.c index 700c1e76b8..b3deb8146f 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 1.4.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 ++++++++++++++++++++++++++++------------------------- include/hw/boards.h | 1 - softmmu/vl.c | 16 +++------ 3 files changed, 57 insertions(+), 58 deletions(-) (limited to 'hw/core/machine.c') diff --git a/hw/core/machine.c b/hw/core/machine.c index b3deb8146f..8cea94537d 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); diff --git a/include/hw/boards.h b/include/hw/boards.h index 6cda7e4308..910c3ffde2 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -26,7 +26,6 @@ OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE) extern MachineState *current_machine; void machine_run_board_init(MachineState *machine); -void machine_boot_parse(MachineState *ms, QemuOpts *opts, Error **errp); bool machine_usb(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); diff --git a/softmmu/vl.c b/softmmu/vl.c index dd90df3ed1..13ae31e92f 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -1884,16 +1884,11 @@ static bool object_create_early(const char *type) static void qemu_apply_machine_options(QDict *qdict) { - QemuOpts *opts; - object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal); current_machine->ram_size = ram_size; current_machine->maxram_size = maxram_size; current_machine->ram_slots = ram_slots; - opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL); - machine_boot_parse(current_machine, opts, &error_fatal); - if (semihosting_enabled() && !semihosting_get_argc()) { /* fall back to the -kernel/-append */ semihosting_arg_fallback(current_machine->kernel_filename, current_machine->kernel_cmdline); @@ -2189,7 +2184,8 @@ static bool is_qemuopts_group(const char *group) { if (g_str_equal(group, "object") || g_str_equal(group, "machine") || - g_str_equal(group, "smp-opts")) { + g_str_equal(group, "smp-opts") || + g_str_equal(group, "boot-opts")) { return false; } return true; @@ -2211,6 +2207,8 @@ static void qemu_record_config_group(const char *group, QDict *dict, keyval_merge(machine_opts_dict, dict, errp); } else if (g_str_equal(group, "smp-opts")) { machine_merge_property("smp", dict, &error_fatal); + } else if (g_str_equal(group, "boot-opts")) { + machine_merge_property("boot", dict, &error_fatal); } else { abort(); } @@ -2956,11 +2954,7 @@ void qemu_init(int argc, char **argv, char **envp) drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS); break; case QEMU_OPTION_boot: - opts = qemu_opts_parse_noisily(qemu_find_opts("boot-opts"), - optarg, true); - if (!opts) { - exit(1); - } + machine_parse_property_opt(qemu_find_opts("boot-opts"), "boot", optarg); break; case QEMU_OPTION_fda: case QEMU_OPTION_fdb: -- cgit 1.4.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 +++++++++++++++++++++++++++++++++++ qapi/machine.json | 18 ++++++++ softmmu/vl.c | 123 ++++++++++++++++++------------------------------------ 3 files changed, 138 insertions(+), 83 deletions(-) (limited to 'hw/core/machine.c') diff --git a/hw/core/machine.c b/hw/core/machine.c index 8cea94537d..46b8d0effa 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); diff --git a/qapi/machine.json b/qapi/machine.json index e3dcf5a119..92480d4044 100644 --- a/qapi/machine.json +++ b/qapi/machine.json @@ -1614,3 +1614,21 @@ ## { 'enum': 'SmbiosEntryPointType', 'data': [ '32', '64' ] } + +## +# @MemorySizeConfiguration: +# +# Schema for memory size configuration. +# +# @size: memory size in bytes +# +# @max-size: maximum hotpluggable memory size in bytes +# +# @slots: number of available memory slots for hotplug +# +# Since: 7.1 +## +{ 'struct': 'MemorySizeConfiguration', 'data': { + '*size': 'size', + '*max-size': 'size', + '*slots': 'uint64' } } diff --git a/softmmu/vl.c b/softmmu/vl.c index 13ae31e92f..65a665e0bc 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -159,11 +159,10 @@ static const char *mem_path; static const char *incoming; static const char *loadvm; static const char *accelerators; +static bool have_custom_ram_size; static QDict *machine_opts_dict; static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts); static QTAILQ_HEAD(, DeviceOption) device_opts = QTAILQ_HEAD_INITIALIZER(device_opts); -static ram_addr_t maxram_size; -static uint64_t ram_slots; static int display_remote; static int snapshot; static bool preconfig_requested; @@ -171,7 +170,6 @@ static QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list); static BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue); static bool nographic = false; static int mem_prealloc; /* force preallocation of physical target memory */ -static ram_addr_t ram_size; static const char *vga_model = NULL; static DisplayOptions dpy; static int num_serial_hds; @@ -1736,6 +1734,7 @@ static void keyval_dashify(QDict *qdict, Error **errp) static void qemu_apply_legacy_machine_options(QDict *qdict) { const char *value; + QObject *prop; keyval_dashify(qdict, &error_fatal); @@ -1768,6 +1767,13 @@ static void qemu_apply_legacy_machine_options(QDict *qdict) false); qdict_del(qdict, "kernel-irqchip"); } + + prop = qdict_get(qdict, "memory"); + if (prop) { + have_custom_ram_size = + qobject_type(prop) == QTYPE_QDICT && + qdict_haskey(qobject_to(QDict, prop), "size"); + } } static void object_option_foreach_add(bool (*type_opt_predicate)(const char *)) @@ -1885,9 +1891,6 @@ static bool object_create_early(const char *type) static void qemu_apply_machine_options(QDict *qdict) { object_set_properties_from_keyval(OBJECT(current_machine), qdict, false, &error_fatal); - current_machine->ram_size = ram_size; - current_machine->maxram_size = maxram_size; - current_machine->ram_slots = ram_slots; if (semihosting_enabled() && !semihosting_get_argc()) { /* fall back to the -kernel/-append */ @@ -1998,12 +2001,6 @@ static void qemu_create_late_backends(void) qemu_semihosting_console_init(); } -static bool have_custom_ram_size(void) -{ - QemuOpts *opts = qemu_find_opts_singleton("memory"); - return !!qemu_opt_get_size(opts, "size", 0); -} - static void qemu_resolve_machine_memdev(void) { if (current_machine->ram_memdev_id) { @@ -2018,7 +2015,7 @@ static void qemu_resolve_machine_memdev(void) exit(EXIT_FAILURE); } backend_size = object_property_get_uint(backend, "size", &error_abort); - if (have_custom_ram_size() && backend_size != ram_size) { + if (have_custom_ram_size && backend_size != current_machine->ram_size) { error_report("Size specified by -m option must match size of " "explicitly specified 'memory-backend' property"); exit(EXIT_FAILURE); @@ -2028,95 +2025,58 @@ static void qemu_resolve_machine_memdev(void) "'-machine memory-backend'"); exit(EXIT_FAILURE); } - ram_size = backend_size; + current_machine->ram_size = backend_size; } if (!xen_enabled()) { /* On 32-bit hosts, QEMU is limited by virtual address space */ - if (ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { + if (current_machine->ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { error_report("at most 2047 MB RAM can be simulated"); exit(1); } } } -static void set_memory_options(MachineClass *mc) +static void parse_memory_options(const char *arg) { - uint64_t sz; + QemuOpts *opts; + QDict *dict, *prop; const char *mem_str; - const ram_addr_t default_ram_size = mc->default_ram_size; - QemuOpts *opts = qemu_find_opts_singleton("memory"); - Location loc; - loc_push_none(&loc); - qemu_opts_loc_restore(opts); + opts = qemu_opts_parse_noisily(qemu_find_opts("memory"), arg, true); + if (!opts) { + exit(EXIT_FAILURE); + } + + prop = qdict_new(); - sz = 0; - mem_str = qemu_opt_get(opts, "size"); - if (mem_str) { + if (qemu_opt_get_size(opts, "size", 0) != 0) { + mem_str = qemu_opt_get(opts, "size"); if (!*mem_str) { error_report("missing 'size' option value"); exit(EXIT_FAILURE); } - sz = qemu_opt_get_size(opts, "size", ram_size); - /* Fix up legacy suffix-less format */ if (g_ascii_isdigit(mem_str[strlen(mem_str) - 1])) { - uint64_t overflow_check = sz; - - sz *= MiB; - if (sz / MiB != overflow_check) { - error_report("too large 'size' option value"); - exit(EXIT_FAILURE); - } + g_autofree char *mib_str = g_strdup_printf("%sM", mem_str); + qdict_put_str(prop, "size", mib_str); + } else { + qdict_put_str(prop, "size", mem_str); } } - /* backward compatibility behaviour for case "-m 0" */ - if (sz == 0) { - sz = default_ram_size; - } - - sz = QEMU_ALIGN_UP(sz, 8192); - if (mc->fixup_ram_size) { - sz = mc->fixup_ram_size(sz); - } - ram_size = sz; - if (ram_size != sz) { - error_report("ram size too large"); - exit(EXIT_FAILURE); - } - - maxram_size = ram_size; - if (qemu_opt_get(opts, "maxmem")) { - uint64_t slots; - - sz = qemu_opt_get_size(opts, "maxmem", 0); - slots = qemu_opt_get_number(opts, "slots", 0); - if (sz < ram_size) { - error_report("invalid value of -m option maxmem: " - "maximum memory size (0x%" PRIx64 ") must be at least " - "the initial memory size (0x" RAM_ADDR_FMT ")", - sz, ram_size); - exit(EXIT_FAILURE); - } else if (slots && sz == ram_size) { - error_report("invalid value of -m option maxmem: " - "memory slots were specified but maximum memory size " - "(0x%" PRIx64 ") is equal to the initial memory size " - "(0x" RAM_ADDR_FMT ")", sz, ram_size); - exit(EXIT_FAILURE); - } - - maxram_size = sz; - ram_slots = slots; - } else if (qemu_opt_get(opts, "slots")) { - error_report("invalid -m option value: missing 'maxmem' option"); - exit(EXIT_FAILURE); + qdict_put_str(prop, "max-size", qemu_opt_get(opts, "maxmem")); + } + if (qemu_opt_get(opts, "slots")) { + qdict_put_str(prop, "slots", qemu_opt_get(opts, "slots")); } - loc_pop(&loc); + dict = qdict_new(); + qdict_put(dict, "memory", prop); + keyval_merge(machine_opts_dict, dict, &error_fatal); + qobject_unref(dict); } static void qemu_create_machine(QDict *qdict) @@ -2124,8 +2084,6 @@ static void qemu_create_machine(QDict *qdict) MachineClass *machine_class = select_machine(qdict, &error_fatal); object_set_machine_compat_props(machine_class->compat_props); - set_memory_options(machine_class); - current_machine = MACHINE(object_new_with_class(OBJECT_CLASS(machine_class))); object_property_add_child(object_get_root(), "machine", OBJECT(current_machine)); @@ -2185,7 +2143,8 @@ static bool is_qemuopts_group(const char *group) if (g_str_equal(group, "object") || g_str_equal(group, "machine") || g_str_equal(group, "smp-opts") || - g_str_equal(group, "boot-opts")) { + g_str_equal(group, "boot-opts") || + g_str_equal(group, "memory")) { return false; } return true; @@ -2209,6 +2168,8 @@ static void qemu_record_config_group(const char *group, QDict *dict, machine_merge_property("smp", dict, &error_fatal); } else if (g_str_equal(group, "boot-opts")) { machine_merge_property("boot", dict, &error_fatal); + } else if (g_str_equal(group, "memory")) { + machine_merge_property("memory", dict, &error_fatal); } else { abort(); } @@ -3009,11 +2970,7 @@ void qemu_init(int argc, char **argv, char **envp) exit(0); break; case QEMU_OPTION_m: - opts = qemu_opts_parse_noisily(qemu_find_opts("memory"), - optarg, true); - if (!opts) { - exit(EXIT_FAILURE); - } + parse_memory_options(optarg); break; #ifdef CONFIG_TPM case QEMU_OPTION_tpmdev: -- cgit 1.4.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 +- hw/sparc/sun4m.c | 5 ++-- include/hw/boards.h | 4 +-- softmmu/vl.c | 62 +++++++++++++++++------------------------------ 5 files changed, 74 insertions(+), 69 deletions(-) (limited to 'hw/core/machine.c') diff --git a/hw/core/machine.c b/hw/core/machine.c index 46b8d0effa..8aab5416dd 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 1aa05dcf42..26d8e5f616 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); diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c index 9d57491f68..d9288326d6 100644 --- a/hw/sparc/sun4m.c +++ b/hw/sparc/sun4m.c @@ -831,8 +831,7 @@ static void sun4m_hw_init(MachineState *machine) SysBusDevice *s; unsigned int smp_cpus = machine->smp.cpus; unsigned int max_cpus = machine->smp.max_cpus; - Object *ram_memdev = object_resolve_path_type(machine->ram_memdev_id, - TYPE_MEMORY_BACKEND, NULL); + HostMemoryBackend *ram_memdev = machine->memdev; NICInfo *nd = &nd_table[0]; if (machine->ram_size > hwdef->max_mem) { @@ -852,7 +851,7 @@ static void sun4m_hw_init(MachineState *machine) /* Create and map RAM frontend */ dev = qdev_new("memory"); - object_property_set_link(OBJECT(dev), "memdev", ram_memdev, &error_fatal); + object_property_set_link(OBJECT(dev), "memdev", OBJECT(ram_memdev), &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0); diff --git a/include/hw/boards.h b/include/hw/boards.h index 910c3ffde2..7b416c9787 100644 --- a/include/hw/boards.h +++ b/include/hw/boards.h @@ -25,7 +25,7 @@ OBJECT_DECLARE_TYPE(MachineState, MachineClass, MACHINE) extern MachineState *current_machine; -void machine_run_board_init(MachineState *machine); +void machine_run_board_init(MachineState *machine, const char *mem_path, Error **errp); bool machine_usb(MachineState *machine); int machine_phandle_start(MachineState *machine); bool machine_dump_guest_core(MachineState *machine); @@ -339,7 +339,7 @@ struct MachineState { bool suppress_vmdesc; bool enable_graphics; ConfidentialGuestSupport *cgs; - char *ram_memdev_id; + HostMemoryBackend *memdev; /* * convenience alias to ram_memdev_id backend memory region * or to numa container memory region diff --git a/softmmu/vl.c b/softmmu/vl.c index 65a665e0bc..f6deec9380 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -160,6 +160,7 @@ static const char *incoming; static const char *loadvm; static const char *accelerators; static bool have_custom_ram_size; +static const char *ram_memdev_id; static QDict *machine_opts_dict; static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts); static QTAILQ_HEAD(, DeviceOption) device_opts = QTAILQ_HEAD_INITIALIZER(device_opts); @@ -1768,6 +1769,19 @@ static void qemu_apply_legacy_machine_options(QDict *qdict) qdict_del(qdict, "kernel-irqchip"); } + value = qdict_get_try_str(qdict, "memory-backend"); + if (value) { + if (mem_path) { + error_report("'-mem-path' can't be used together with" + "'-machine memory-backend'"); + exit(EXIT_FAILURE); + } + + /* Resolved later. */ + ram_memdev_id = g_strdup(value); + qdict_del(qdict, "memory-backend"); + } + prop = qdict_get(qdict, "memory"); if (prop) { have_custom_ram_size = @@ -2003,29 +2017,25 @@ static void qemu_create_late_backends(void) static void qemu_resolve_machine_memdev(void) { - if (current_machine->ram_memdev_id) { + if (ram_memdev_id) { Object *backend; ram_addr_t backend_size; - backend = object_resolve_path_type(current_machine->ram_memdev_id, + backend = object_resolve_path_type(ram_memdev_id, TYPE_MEMORY_BACKEND, NULL); if (!backend) { - error_report("Memory backend '%s' not found", - current_machine->ram_memdev_id); + error_report("Memory backend '%s' not found", ram_memdev_id); exit(EXIT_FAILURE); } backend_size = object_property_get_uint(backend, "size", &error_abort); if (have_custom_ram_size && backend_size != current_machine->ram_size) { - error_report("Size specified by -m option must match size of " - "explicitly specified 'memory-backend' property"); - exit(EXIT_FAILURE); - } - if (mem_path) { - error_report("'-mem-path' can't be used together with" - "'-machine memory-backend'"); + error_report("Size specified by -m option must match size of " + "explicitly specified 'memory-backend' property"); exit(EXIT_FAILURE); } current_machine->ram_size = backend_size; + object_property_set_link(OBJECT(current_machine), + "memory-backend", backend, &error_fatal); } if (!xen_enabled()) { @@ -2376,27 +2386,6 @@ static void configure_accelerators(const char *progname) } } -static void create_default_memdev(MachineState *ms, const char *path) -{ - Object *obj; - MachineClass *mc = MACHINE_GET_CLASS(ms); - - obj = object_new(path ? TYPE_MEMORY_BACKEND_FILE : TYPE_MEMORY_BACKEND_RAM); - if (path) { - object_property_set_str(obj, "mem-path", path, &error_fatal); - } - object_property_set_int(obj, "size", ms->ram_size, &error_fatal); - 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 */ - object_property_set_bool(obj, "x-use-canonical-path-for-ramblock-id", - false, &error_fatal); - user_creatable_complete(USER_CREATABLE(obj), &error_fatal); - object_unref(obj); - object_property_set_str(OBJECT(ms), "memory-backend", mc->default_ram_id, - &error_fatal); -} - static void qemu_validate_options(const QDict *machine_opts) { const char *kernel_filename = qdict_get_try_str(machine_opts, "kernel"); @@ -2581,18 +2570,11 @@ static void qemu_init_displays(void) static void qemu_init_board(void) { - MachineClass *machine_class = MACHINE_GET_CLASS(current_machine); - - if (machine_class->default_ram_id && current_machine->ram_size && - numa_uses_legacy_mem() && !current_machine->ram_memdev_id) { - create_default_memdev(current_machine, mem_path); - } - /* process plugin before CPUs are created, but once -smp has been parsed */ qemu_plugin_load_list(&plugin_list, &error_fatal); /* From here on we enter MACHINE_PHASE_INITIALIZED. */ - machine_run_board_init(current_machine); + machine_run_board_init(current_machine, mem_path, &error_fatal); drive_check_orphaned(); -- cgit 1.4.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 +++++++++++++++++++-- softmmu/vl.c | 17 +++-------------- 2 files changed, 22 insertions(+), 16 deletions(-) (limited to 'hw/core/machine.c') diff --git a/hw/core/machine.c b/hw/core/machine.c index 8aab5416dd..3264c1e11d 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; } diff --git a/softmmu/vl.c b/softmmu/vl.c index f6deec9380..edba74f075 100644 --- a/softmmu/vl.c +++ b/softmmu/vl.c @@ -2027,24 +2027,13 @@ static void qemu_resolve_machine_memdev(void) error_report("Memory backend '%s' not found", ram_memdev_id); exit(EXIT_FAILURE); } - backend_size = object_property_get_uint(backend, "size", &error_abort); - if (have_custom_ram_size && backend_size != current_machine->ram_size) { - error_report("Size specified by -m option must match size of " - "explicitly specified 'memory-backend' property"); - exit(EXIT_FAILURE); + if (!have_custom_ram_size) { + backend_size = object_property_get_uint(backend, "size", &error_abort); + current_machine->ram_size = backend_size; } - current_machine->ram_size = backend_size; object_property_set_link(OBJECT(current_machine), "memory-backend", backend, &error_fatal); } - - if (!xen_enabled()) { - /* On 32-bit hosts, QEMU is limited by virtual address space */ - if (current_machine->ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { - error_report("at most 2047 MB RAM can be simulated"); - exit(1); - } - } } static void parse_memory_options(const char *arg) -- cgit 1.4.1