#include "sysemu/iothread.h"
#include "qemu/guest-random.h"
+#include "config-host.h"
+
#define MAX_VIRTIO_CONSOLES 1
typedef struct BlockdevOptionsQueueEntry {
static const char *mem_path;
static const char *incoming;
static const char *loadvm;
+static const char *accelerators;
+static QDict *machine_opts_dict;
static QTAILQ_HEAD(, ObjectOption) object_opts = QTAILQ_HEAD_INITIALIZER(object_opts);
static ram_addr_t maxram_size;
static uint64_t ram_slots;
{ .driver = "virtio-vga", .flag = &default_vga },
{ .driver = "ati-vga", .flag = &default_vga },
{ .driver = "vhost-user-vga", .flag = &default_vga },
+ { .driver = "virtio-vga-gl", .flag = &default_vga },
};
static QemuOptsList qemu_rtc_opts = {
},
};
-static QemuOptsList qemu_machine_opts = {
- .name = "machine",
- .implied_opt_name = "type",
- .merge_lists = true,
- .head = QTAILQ_HEAD_INITIALIZER(qemu_machine_opts.head),
- .desc = {
- /*
- * no elements => accept any
- * sanity checking will happen later
- * when setting machine properties
- */
- { }
- },
-};
-
static QemuOptsList qemu_accel_opts = {
.name = "accel",
.implied_opt_name = "accel",
},
};
-/**
- * Get machine options
- *
- * Returns: machine options (never null).
- */
-static QemuOpts *qemu_get_machine_opts(void)
-{
- return qemu_find_opts_singleton("machine");
-}
-
const char *qemu_get_vm_name(void)
{
return qemu_name;
return default_machineclass;
}
-static int machine_help_func(QemuOpts *opts, MachineState *machine)
-{
- ObjectProperty *prop;
- ObjectPropertyIterator iter;
-
- if (!qemu_opt_has_help_opt(opts)) {
- return 0;
- }
-
- object_property_iter_init(&iter, OBJECT(machine));
- while ((prop = object_property_iter_next(&iter))) {
- if (!prop->set) {
- continue;
- }
-
- printf("%s.%s=%s", MACHINE_GET_CLASS(machine)->name,
- prop->name, prop->type);
- if (prop->description) {
- printf(" (%s)\n", prop->description);
- } else {
- printf("\n");
- }
- }
-
- return 1;
-}
-
static void version(void)
{
printf("QEMU emulator version " QEMU_FULL_VERSION "\n"
* sdl DisplayType needs hand-crafted parser instead of
* parse_display_qapi() due to some options not in
* DisplayOptions, specifically:
- * - frame
- * Already deprecated.
* - ctrl_grab + alt_grab
* Not clear yet what happens to them long-term. Should
* replaced by something better or deprecated and dropped.
} else {
goto invalid_sdl_args;
}
- } else if (strstart(opts, ",window_close=", &nextopt)) {
+ } else if (strstart(opts, ",window_close=", &nextopt) ||
+ strstart(opts, ",window-close=", &nextopt)) {
+ if (strstart(opts, ",window_close=", NULL)) {
+ warn_report("window_close with an underscore is deprecated,"
+ " please use window-close instead.");
+ }
opts = nextopt;
dpy.has_window_close = true;
if (strstart(opts, "on", &nextopt)) {
object_class_get_name(OBJECT_CLASS(mc1)));
}
-static MachineClass *machine_parse(const char *name, GSList *machines)
+static void machine_help_func(const QDict *qdict)
{
- MachineClass *mc;
- GSList *el;
+ GSList *machines, *el;
+ const char *type = qdict_get_try_str(qdict, "type");
- if (is_help_option(name)) {
- printf("Supported machines are:\n");
- machines = g_slist_sort(machines, machine_class_cmp);
- for (el = machines; el; el = el->next) {
- MachineClass *mc = el->data;
- if (mc->alias) {
- printf("%-20s %s (alias of %s)\n", mc->alias, mc->desc, mc->name);
- }
- printf("%-20s %s%s%s\n", mc->name, mc->desc,
- mc->is_default ? " (default)" : "",
- mc->deprecation_reason ? " (deprecated)" : "");
+ machines = object_class_get_list(TYPE_MACHINE, false);
+ if (type) {
+ ObjectClass *machine_class = OBJECT_CLASS(find_machine(type, machines));
+ if (machine_class) {
+ type_print_class_properties(object_class_get_name(machine_class));
+ return;
}
- exit(0);
}
- mc = find_machine(name, machines);
- if (!mc) {
- error_report("unsupported machine type");
- error_printf("Use -machine help to list supported machines\n");
- exit(1);
+ printf("Supported machines are:\n");
+ machines = g_slist_sort(machines, machine_class_cmp);
+ for (el = machines; el; el = el->next) {
+ MachineClass *mc = el->data;
+ if (mc->alias) {
+ printf("%-20s %s (alias of %s)\n", mc->alias, mc->desc, mc->name);
+ }
+ printf("%-20s %s%s%s\n", mc->name, mc->desc,
+ mc->is_default ? " (default)" : "",
+ mc->deprecation_reason ? " (deprecated)" : "");
}
- return mc;
+}
+
+static void
+machine_parse_property_opt(QemuOptsList *opts_list, const char *propname,
+ const char *arg, Error **errp)
+{
+ QDict *opts, *prop;
+ bool help = false;
+ ERRP_GUARD();
+
+ prop = keyval_parse(arg, opts_list->implied_opt_name, &help, errp);
+ if (help) {
+ qemu_opts_print_help(opts_list, true);
+ return;
+ }
+ opts = qdict_new();
+ qdict_put(opts, propname, prop);
+ keyval_merge(machine_opts_dict, opts, errp);
+ qobject_unref(opts);
}
static const char *pid_file;
return popt;
}
-static MachineClass *select_machine(void)
+static MachineClass *select_machine(QDict *qdict, Error **errp)
{
+ const char *optarg = qdict_get_try_str(qdict, "type");
GSList *machines = object_class_get_list(TYPE_MACHINE, false);
- MachineClass *machine_class = find_default_machine(machines);
- const char *optarg;
- QemuOpts *opts;
- Location loc;
-
- loc_push_none(&loc);
-
- opts = qemu_get_machine_opts();
- qemu_opts_loc_restore(opts);
+ MachineClass *machine_class;
+ Error *local_err = NULL;
- optarg = qemu_opt_get(opts, "type");
if (optarg) {
- machine_class = machine_parse(optarg, machines);
- }
-
- if (!machine_class) {
- error_report("No machine specified, and there is no default");
- error_printf("Use -machine help to list supported machines\n");
- exit(1);
+ machine_class = find_machine(optarg, machines);
+ qdict_del(qdict, "type");
+ if (!machine_class) {
+ error_setg(&local_err, "unsupported machine type");
+ }
+ } else {
+ machine_class = find_default_machine(machines);
+ if (!machine_class) {
+ error_setg(&local_err, "No machine specified, and there is no default");
+ }
}
- loc_pop(&loc);
g_slist_free(machines);
+ if (local_err) {
+ error_append_hint(&local_err, "Use -machine help to list supported machines\n");
+ error_propagate(errp, local_err);
+ }
return machine_class;
}
return 0;
}
-static int machine_set_property(void *opaque,
- const char *name, const char *value,
- Error **errp)
+/* *Non*recursively replace underscores with dashes in QDict keys. */
+static void keyval_dashify(QDict *qdict, Error **errp)
{
- g_autofree char *qom_name = g_strdup(name);
+ const QDictEntry *ent, *next;
char *p;
- for (p = qom_name; *p; p++) {
- if (*p == '_') {
- *p = '-';
+ for (ent = qdict_first(qdict); ent; ent = next) {
+ g_autofree char *new_key = NULL;
+
+ next = qdict_next(qdict, ent);
+ if (!strchr(ent->key, '_')) {
+ continue;
}
+ new_key = g_strdup(ent->key);
+ for (p = new_key; *p; p++) {
+ if (*p == '_') {
+ *p = '-';
+ }
+ }
+ if (qdict_haskey(qdict, new_key)) {
+ error_setg(errp, "Conflict between '%s' and '%s'", ent->key, new_key);
+ return;
+ }
+ qobject_ref(ent->value);
+ qdict_put_obj(qdict, new_key, ent->value);
+ qdict_del(qdict, ent->key);
}
+}
+
+static void qemu_apply_legacy_machine_options(QDict *qdict)
+{
+ const char *value;
+
+ keyval_dashify(qdict, &error_fatal);
/* Legacy options do not correspond to MachineState properties. */
- if (g_str_equal(qom_name, "accel")) {
- return 0;
+ value = qdict_get_try_str(qdict, "accel");
+ if (value) {
+ accelerators = g_strdup(value);
+ qdict_del(qdict, "accel");
}
- if (g_str_equal(qom_name, "igd-passthru")) {
- object_register_sugar_prop(ACCEL_CLASS_NAME("xen"), qom_name, value,
+
+ value = qdict_get_try_str(qdict, "igd-passthru");
+ if (value) {
+ object_register_sugar_prop(ACCEL_CLASS_NAME("xen"), "igd-passthru", value,
false);
- return 0;
+ qdict_del(qdict, "igd-passthru");
}
- if (g_str_equal(qom_name, "kvm-shadow-mem")) {
- object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), qom_name, value,
+
+ value = qdict_get_try_str(qdict, "kvm-shadow-mem");
+ if (value) {
+ object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), "kvm-shadow-mem", value,
false);
- return 0;
+ qdict_del(qdict, "kvm-shadow-mem");
}
- if (g_str_equal(qom_name, "kernel-irqchip")) {
- object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), qom_name, value,
+
+ value = qdict_get_try_str(qdict, "kernel-irqchip");
+ if (value) {
+ object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), "kernel-irqchip", value,
false);
- object_register_sugar_prop(ACCEL_CLASS_NAME("whpx"), qom_name, value,
+ object_register_sugar_prop(ACCEL_CLASS_NAME("whpx"), "kernel-irqchip", value,
false);
- return 0;
+ qdict_del(qdict, "kernel-irqchip");
}
-
- return object_parse_property_opt(opaque, name, value, "type", errp);
}
static void object_option_foreach_add(bool (*type_opt_predicate)(const char *))
return true;
}
-static void qemu_apply_machine_options(void)
+static void qemu_apply_machine_options(QDict *qdict)
{
MachineClass *machine_class = MACHINE_GET_CLASS(current_machine);
- QemuOpts *machine_opts = qemu_get_machine_opts();
const char *boot_order = NULL;
const char *boot_once = NULL;
QemuOpts *opts;
- qemu_opt_foreach(machine_opts, machine_set_property, current_machine,
- &error_fatal);
+ 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;
current_machine->boot_once = boot_once;
if (semihosting_enabled() && !semihosting_get_argc()) {
- const char *kernel_filename = qemu_opt_get(machine_opts, "kernel");
- const char *kernel_cmdline = qemu_opt_get(machine_opts, "append") ?: "";
/* fall back to the -kernel/-append */
- semihosting_arg_fallback(kernel_filename, kernel_cmdline);
+ semihosting_arg_fallback(current_machine->kernel_filename, current_machine->kernel_cmdline);
+ }
+
+ if (current_machine->smp.cpus > 1) {
+ Error *blocker = NULL;
+ error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, "smp");
+ replay_add_blocker(blocker);
}
}
/*
* Note: we need to create audio and block backends before
- * machine_set_property(), so machine properties can refer to
- * them.
+ * setting machine properties, so they can be referred to.
*/
configure_blockdev(&bdo_queue, machine_class, snapshot);
audio_init_audiodevs();
loc_pop(&loc);
}
-static void qemu_create_machine(MachineClass *machine_class)
+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)));
- if (machine_help_func(qemu_get_machine_opts(), current_machine)) {
- exit(0);
- }
object_property_add_child(object_get_root(), "machine",
OBJECT(current_machine));
object_property_add_child(container_get(OBJECT(current_machine),
qemu_set_hw_version(machine_class->hw_version);
}
- machine_smp_parse(current_machine,
- qemu_opts_find(qemu_find_opts("smp-opts"), NULL), &error_fatal);
-
/*
* Get the default machine options from the machine if it is not already
* specified either by the configuration file or by the command line.
*/
if (machine_class->default_machine_opts) {
- qemu_opts_set_defaults(qemu_find_opts("machine"),
- machine_class->default_machine_opts, 0);
+ QDict *default_opts =
+ keyval_parse(machine_class->default_machine_opts, NULL, NULL,
+ &error_abort);
+ qemu_apply_legacy_machine_options(default_opts);
+ object_set_properties_from_keyval(OBJECT(current_machine), default_opts,
+ false, &error_abort);
+ qobject_unref(default_opts);
}
}
*/
static bool is_qemuopts_group(const char *group)
{
- if (g_str_equal(group, "object")) {
+ if (g_str_equal(group, "object") ||
+ g_str_equal(group, "machine")) {
return false;
}
return true;
Visitor *v = qobject_input_visitor_new_keyval(QOBJECT(dict));
object_option_add_visitor(v);
visit_free(v);
+ } else if (g_str_equal(group, "machine")) {
+ /*
+ * Cannot merge string-valued and type-safe dictionaries, so JSON
+ * is not accepted yet for -M.
+ */
+ assert(!from_json);
+ keyval_merge(machine_opts_dict, dict, errp);
} else {
abort();
}
if (!crumpled) {
return;
}
- if (qobject_type(crumpled) != QTYPE_QDICT) {
- assert(qobject_type(crumpled) == QTYPE_QLIST);
+ switch (qobject_type(crumpled)) {
+ case QTYPE_QDICT:
+ qemu_record_config_group(group, qobject_to(QDict, crumpled), false, errp);
+ break;
+ case QTYPE_QLIST:
error_setg(errp, "Lists cannot be at top level of a configuration section");
- return;
+ break;
+ default:
+ g_assert_not_reached();
}
- qemu_record_config_group(group, qobject_to(QDict, crumpled), false, errp);
+ qobject_unref(crumpled);
}
static void qemu_read_default_config_file(Error **errp)
static void configure_accelerators(const char *progname)
{
- const char *accelerators;
bool init_failed = false;
qemu_opts_foreach(qemu_find_opts("icount"),
do_configure_icount, NULL, &error_fatal);
- accelerators = qemu_opt_get(qemu_get_machine_opts(), "accel");
if (QTAILQ_EMPTY(&qemu_accel_opts.head)) {
char **accel_list, **tmp;
&error_fatal);
}
-static void qemu_validate_options(void)
+static void qemu_validate_options(const QDict *machine_opts)
{
- QemuOpts *machine_opts = qemu_get_machine_opts();
- const char *kernel_filename = qemu_opt_get(machine_opts, "kernel");
- const char *initrd_filename = qemu_opt_get(machine_opts, "initrd");
- const char *kernel_cmdline = qemu_opt_get(machine_opts, "append");
+ const char *kernel_filename = qdict_get_try_str(machine_opts, "kernel");
+ const char *initrd_filename = qdict_get_try_str(machine_opts, "initrd");
+ const char *kernel_cmdline = qdict_get_try_str(machine_opts, "append");
if (kernel_filename == NULL) {
if (kernel_cmdline != NULL) {
}
}
-#ifdef CONFIG_MODULES
-void qemu_load_module_for_opts(const char *group)
-{
- static bool spice_tried;
- if (g_str_equal(group, "spice") && !spice_tried) {
- ui_module_load_one("spice-core");
- spice_tried = true;
- }
-
- static bool iscsi_tried;
- if (g_str_equal(group, "iscsi") && !iscsi_tried) {
- block_module_load_one("iscsi");
- iscsi_tried = true;
- }
-}
-#endif
-
void qemu_init(int argc, char **argv, char **envp)
{
QemuOpts *opts;
qemu_add_opts(&qemu_trace_opts);
qemu_plugin_add_opts();
qemu_add_opts(&qemu_option_rom_opts);
- qemu_add_opts(&qemu_machine_opts);
qemu_add_opts(&qemu_accel_opts);
qemu_add_opts(&qemu_mem_opts);
qemu_add_opts(&qemu_smp_opts);
error_init(argv[0]);
qemu_init_exec_dir(argv[0]);
+#ifdef CONFIG_MODULES
+ module_init_info(qemu_modinfo);
+ module_allow_arch(TARGET_NAME);
+#endif
+
qemu_init_subsystems();
/* first pass of option parsing */
}
}
+ machine_opts_dict = qdict_new();
if (userconfig) {
qemu_read_default_config_file(&error_fatal);
}
parse_display(optarg);
break;
case QEMU_OPTION_nographic:
- olist = qemu_find_opts("machine");
- qemu_opts_parse_noisily(olist, "graphics=off", false);
+ qdict_put_str(machine_opts_dict, "graphics", "off");
nographic = true;
dpy.type = DISPLAY_TYPE_NONE;
break;
}
break;
case QEMU_OPTION_kernel:
- qemu_opts_set(qemu_find_opts("machine"), "kernel", optarg, &error_abort);
+ qdict_put_str(machine_opts_dict, "kernel", optarg);
break;
case QEMU_OPTION_initrd:
- qemu_opts_set(qemu_find_opts("machine"), "initrd", optarg, &error_abort);
+ qdict_put_str(machine_opts_dict, "initrd", optarg);
break;
case QEMU_OPTION_append:
- qemu_opts_set(qemu_find_opts("machine"), "append", optarg, &error_abort);
+ qdict_put_str(machine_opts_dict, "append", optarg);
break;
case QEMU_OPTION_dtb:
- qemu_opts_set(qemu_find_opts("machine"), "dtb", optarg, &error_abort);
+ qdict_put_str(machine_opts_dict, "dtb", optarg);
break;
case QEMU_OPTION_cdrom:
drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
}
break;
case QEMU_OPTION_bios:
- qemu_opts_set(qemu_find_opts("machine"), "firmware", optarg, &error_abort);
+ qdict_put_str(machine_opts_dict, "firmware", optarg);
break;
case QEMU_OPTION_singlestep:
singlestep = 1;
case QEMU_OPTION_no_quit:
dpy.has_window_close = true;
dpy.window_close = false;
+ warn_report("-no-quit is deprecated, please use "
+ "-display ...,window-close=off instead.");
break;
case QEMU_OPTION_sdl:
#ifdef CONFIG_SDL
preconfig_requested = true;
break;
case QEMU_OPTION_enable_kvm:
- olist = qemu_find_opts("machine");
- qemu_opts_parse_noisily(olist, "accel=kvm", false);
+ qdict_put_str(machine_opts_dict, "accel", "kvm");
break;
case QEMU_OPTION_M:
case QEMU_OPTION_machine:
- olist = qemu_find_opts("machine");
- opts = qemu_opts_parse_noisily(olist, optarg, true);
- if (!opts) {
- exit(1);
+ {
+ bool help;
+
+ keyval_parse_into(machine_opts_dict, optarg, "type", &help, &error_fatal);
+ if (help) {
+ machine_help_func(machine_opts_dict);
+ exit(EXIT_SUCCESS);
+ }
+ break;
}
- break;
case QEMU_OPTION_accel:
accel_opts = qemu_opts_parse_noisily(qemu_find_opts("accel"),
optarg, true);
}
break;
case QEMU_OPTION_usb:
- olist = qemu_find_opts("machine");
- qemu_opts_parse_noisily(olist, "usb=on", false);
+ qdict_put_str(machine_opts_dict, "usb", "on");
break;
case QEMU_OPTION_usbdevice:
- olist = qemu_find_opts("machine");
- qemu_opts_parse_noisily(olist, "usb=on", false);
+ qdict_put_str(machine_opts_dict, "usb", "on");
add_device_config(DEV_USB, optarg);
break;
case QEMU_OPTION_device:
}
break;
case QEMU_OPTION_smp:
- if (!qemu_opts_parse_noisily(qemu_find_opts("smp-opts"),
- optarg, true)) {
- exit(1);
- }
+ machine_parse_property_opt(qemu_find_opts("smp-opts"), "smp", optarg, &error_fatal);
break;
case QEMU_OPTION_vnc:
vnc_parse(optarg);
break;
case QEMU_OPTION_no_acpi:
- olist = qemu_find_opts("machine");
- qemu_opts_parse_noisily(olist, "acpi=off", false);
+ qdict_put_str(machine_opts_dict, "acpi", "off");
break;
case QEMU_OPTION_no_hpet:
- olist = qemu_find_opts("machine");
- qemu_opts_parse_noisily(olist, "hpet=off", false);
+ qdict_put_str(machine_opts_dict, "hpet", "off");
break;
case QEMU_OPTION_no_reboot:
olist = qemu_find_opts("action");
*/
loc_set_none();
- qemu_validate_options();
+ qemu_validate_options(machine_opts_dict);
qemu_process_sugar_options();
/*
configure_rtc(qemu_find_opts_singleton("rtc"));
- qemu_create_machine(select_machine());
+ qemu_create_machine(machine_opts_dict);
suspend_mux_open();
qemu_create_default_devices();
qemu_create_early_backends();
- qemu_apply_machine_options();
+ qemu_apply_legacy_machine_options(machine_opts_dict);
+ qemu_apply_machine_options(machine_opts_dict);
+ qobject_unref(machine_opts_dict);
phase_advance(PHASE_MACHINE_CREATED);
/*
* Note: uses machine properties such as kernel-irqchip, must run
- * after machine_set_property().
+ * after qemu_apply_machine_options.
*/
configure_accelerators(argv[0]);
phase_advance(PHASE_ACCEL_CREATED);