#include "qemu/osdep.h"
#include "qemu-common.h"
#include "qemu/units.h"
+#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qemu-version.h"
#include "qemu/cutils.h"
#include "qemu/help_option.h"
#include "qemu/uuid.h"
+#include "sysemu/reset.h"
+#include "sysemu/runstate.h"
#include "sysemu/seccomp.h"
#include "sysemu/tcg.h"
#include "qemu/error-report.h"
#include "qemu/sockets.h"
-#include "hw/hw.h"
#include "sysemu/accel.h"
#include "hw/usb.h"
#include "hw/isa/isa.h"
#include "hw/firmware/smbios.h"
#include "hw/acpi/acpi.h"
#include "hw/xen/xen.h"
-#include "hw/qdev.h"
#include "hw/loader.h"
#include "monitor/qdev.h"
#include "sysemu/bt.h"
#include "trace-root.h"
#include "trace/control.h"
+#include "qemu/plugin.h"
#include "qemu/queue.h"
#include "sysemu/arch_init.h"
Chardev *parallel_hds[MAX_PARALLEL_PORTS];
int win2k_install_hack = 0;
int singlestep = 0;
-int smp_cpus;
-unsigned int max_cpus;
-int smp_cores = 1;
-int smp_threads = 1;
int acpi_enabled = 1;
int no_hpet = 0;
int fd_bootchk = 1;
switch (clock) {
case QEMU_CLOCK_REALTIME:
value -= rtc_realtime_clock_offset;
- /* no break */
+ /* fall through */
case QEMU_CLOCK_VIRTUAL:
value += rtc_ref_start_datetime;
break;
qapi_free_BlockdevOptions(bdo->bdo);
g_free(bdo);
}
- if (snapshot || replay_mode != REPLAY_MODE_NONE) {
+ if (snapshot) {
qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot,
NULL, NULL);
}
}, {
.name = "sockets",
.type = QEMU_OPT_NUMBER,
+ }, {
+ .name = "dies",
+ .type = QEMU_OPT_NUMBER,
}, {
.name = "cores",
.type = QEMU_OPT_NUMBER,
},
};
-static void smp_parse(QemuOpts *opts)
-{
- if (opts) {
- unsigned cpus = qemu_opt_get_number(opts, "cpus", 0);
- unsigned sockets = qemu_opt_get_number(opts, "sockets", 0);
- unsigned cores = qemu_opt_get_number(opts, "cores", 0);
- unsigned threads = qemu_opt_get_number(opts, "threads", 0);
-
- /* compute missing values, prefer sockets over cores over threads */
- if (cpus == 0 || sockets == 0) {
- cores = cores > 0 ? cores : 1;
- threads = threads > 0 ? threads : 1;
- if (cpus == 0) {
- sockets = sockets > 0 ? sockets : 1;
- cpus = cores * threads * sockets;
- } else {
- max_cpus = qemu_opt_get_number(opts, "maxcpus", cpus);
- sockets = max_cpus / (cores * threads);
- }
- } else if (cores == 0) {
- threads = threads > 0 ? threads : 1;
- cores = cpus / (sockets * threads);
- cores = cores > 0 ? cores : 1;
- } else if (threads == 0) {
- threads = cpus / (cores * sockets);
- threads = threads > 0 ? threads : 1;
- } else if (sockets * cores * threads < cpus) {
- error_report("cpu topology: "
- "sockets (%u) * cores (%u) * threads (%u) < "
- "smp_cpus (%u)",
- sockets, cores, threads, cpus);
- exit(1);
- }
-
- max_cpus = qemu_opt_get_number(opts, "maxcpus", cpus);
-
- if (max_cpus < cpus) {
- error_report("maxcpus must be equal to or greater than smp");
- exit(1);
- }
-
- if (sockets * cores * threads > max_cpus) {
- error_report("cpu topology: "
- "sockets (%u) * cores (%u) * threads (%u) > "
- "maxcpus (%u)",
- sockets, cores, threads, max_cpus);
- exit(1);
- }
-
- if (sockets * cores * threads != max_cpus) {
- warn_report("Invalid CPU topology deprecated: "
- "sockets (%u) * cores (%u) * threads (%u) "
- "!= maxcpus (%u)",
- sockets, cores, threads, max_cpus);
- }
-
- smp_cpus = cpus;
- smp_cores = cores;
- smp_threads = threads;
- }
-
- if (smp_cpus > 1) {
- Error *blocker = NULL;
- error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, "smp");
- replay_add_blocker(blocker);
- }
-}
-
static void realtime_init(void)
{
if (enable_mlock) {
return 1;
}
-struct vm_change_state_entry {
+struct VMChangeStateEntry {
VMChangeStateHandler *cb;
void *opaque;
- QLIST_ENTRY (vm_change_state_entry) entries;
+ QTAILQ_ENTRY(VMChangeStateEntry) entries;
+ int priority;
};
-static QLIST_HEAD(, vm_change_state_entry) vm_change_state_head;
+static QTAILQ_HEAD(, VMChangeStateEntry) vm_change_state_head;
-VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
- void *opaque)
+/**
+ * qemu_add_vm_change_state_handler_prio:
+ * @cb: the callback to invoke
+ * @opaque: user data passed to the callback
+ * @priority: low priorities execute first when the vm runs and the reverse is
+ * true when the vm stops
+ *
+ * Register a callback function that is invoked when the vm starts or stops
+ * running.
+ *
+ * Returns: an entry to be freed using qemu_del_vm_change_state_handler()
+ */
+VMChangeStateEntry *qemu_add_vm_change_state_handler_prio(
+ VMChangeStateHandler *cb, void *opaque, int priority)
{
VMChangeStateEntry *e;
+ VMChangeStateEntry *other;
- e = g_malloc0(sizeof (*e));
-
+ e = g_malloc0(sizeof(*e));
e->cb = cb;
e->opaque = opaque;
- QLIST_INSERT_HEAD(&vm_change_state_head, e, entries);
+ e->priority = priority;
+
+ /* Keep list sorted in ascending priority order */
+ QTAILQ_FOREACH(other, &vm_change_state_head, entries) {
+ if (priority < other->priority) {
+ QTAILQ_INSERT_BEFORE(other, e, entries);
+ return e;
+ }
+ }
+
+ QTAILQ_INSERT_TAIL(&vm_change_state_head, e, entries);
return e;
}
+VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
+ void *opaque)
+{
+ return qemu_add_vm_change_state_handler_prio(cb, opaque, 0);
+}
+
void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
{
- QLIST_REMOVE (e, entries);
- g_free (e);
+ QTAILQ_REMOVE(&vm_change_state_head, e, entries);
+ g_free(e);
}
void vm_state_notify(int running, RunState state)
trace_vm_state_notify(running, state, RunState_str(state));
- QLIST_FOREACH_SAFE(e, &vm_change_state_head, entries, next) {
- e->cb(e->opaque, running, state);
+ if (running) {
+ QTAILQ_FOREACH_SAFE(e, &vm_change_state_head, entries, next) {
+ e->cb(e->opaque, running, state);
+ }
+ } else {
+ QTAILQ_FOREACH_REVERSE_SAFE(e, &vm_change_state_head, entries, next) {
+ e->cb(e->opaque, running, state);
+ }
}
}
cpu_synchronize_all_states();
if (mc && mc->reset) {
- mc->reset();
+ mc->reset(current_machine);
} else {
qemu_devices_reset();
}
- if (reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
+ if (reason && reason != SHUTDOWN_CAUSE_SUBSYSTEM_RESET) {
qapi_event_send_reset(shutdown_caused_by_guest(reason), reason);
}
cpu_synchronize_all_post_reset();
}
+/*
+ * Wake the VM after suspend.
+ */
+static void qemu_system_wakeup(void)
+{
+ MachineClass *mc;
+
+ mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL;
+
+ if (mc && mc->wakeup) {
+ mc->wakeup(current_machine);
+ }
+}
+
void qemu_system_guest_panicked(GuestPanicInformation *info)
{
qemu_log_mask(LOG_GUEST_ERROR, "Guest crashed");
RunState r;
ShutdownCause request;
+ if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
+ return false;
+ }
if (preconfig_exit_requested) {
if (runstate_check(RUN_STATE_PRECONFIG)) {
runstate_set(RUN_STATE_PRELAUNCH);
}
if (qemu_wakeup_requested()) {
pause_all_vcpus();
- qemu_system_reset(SHUTDOWN_CAUSE_NONE);
+ qemu_system_wakeup();
notifier_list_notify(&wakeup_notifiers, &wakeup_reason);
wakeup_reason = QEMU_WAKEUP_REASON_NONE;
resume_all_vcpus();
DeviceState *dev;
dev = qdev_device_add(opts, errp);
- if (!dev) {
+ if (!dev && *errp) {
+ error_report_err(*errp);
return -1;
+ } else if (dev) {
+ object_unref(OBJECT(dev));
}
- object_unref(OBJECT(dev));
return 0;
}
*/
static bool object_create_initial(const char *type, QemuOpts *opts)
{
- ObjectClass *klass;
-
- if (is_help_option(type)) {
- GSList *l, *list;
-
- printf("List of user creatable objects:\n");
- list = object_class_get_list_sorted(TYPE_USER_CREATABLE, false);
- for (l = list; l != NULL; l = l->next) {
- ObjectClass *oc = OBJECT_CLASS(l->data);
- printf(" %s\n", object_class_get_name(oc));
- }
- g_slist_free(list);
- exit(0);
- }
-
- klass = object_class_by_name(type);
- if (klass && qemu_opt_has_help_opt(opts)) {
- ObjectPropertyIterator iter;
- ObjectProperty *prop;
- GPtrArray *array = g_ptr_array_new();
- int i;
-
- object_class_property_iter_init(&iter, klass);
- while ((prop = object_property_iter_next(&iter))) {
- GString *str;
-
- if (!prop->set) {
- continue;
- }
-
- str = g_string_new(NULL);
- g_string_append_printf(str, " %s=<%s>", prop->name, prop->type);
- if (prop->description) {
- if (str->len < 24) {
- g_string_append_printf(str, "%*s", 24 - (int)str->len, "");
- }
- g_string_append_printf(str, " - %s", prop->description);
- }
- g_ptr_array_add(array, g_string_free(str, false));
- }
- g_ptr_array_sort(array, (GCompareFunc)qemu_pstrcmp0);
- if (array->len > 0) {
- printf("%s options:\n", type);
- } else {
- printf("There are no options for %s.\n", type);
- }
- for (i = 0; i < array->len; i++) {
- printf("%s\n", (char *)array->pdata[i]);
- }
- g_ptr_array_set_free_func(array, g_free);
- g_ptr_array_free(array, true);
+ if (user_creatable_print_help(type, opts)) {
exit(0);
}
bool list_data_dirs = false;
char *dir, **dirs;
BlockdevOptionsQueue bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
+ QemuPluginList plugin_list = QTAILQ_HEAD_INITIALIZER(plugin_list);
+
+ os_set_line_buffering();
error_init(argv[0]);
module_call_init(MODULE_INIT_TRACE);
qemu_add_opts(&qemu_global_opts);
qemu_add_opts(&qemu_mon_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);
exit(1);
}
- QLIST_INIT (&vm_change_state_head);
+ QTAILQ_INIT(&vm_change_state_head);
os_setup_early_signal_handling();
cpu_option = NULL;
drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS);
break;
case QEMU_OPTION_snapshot:
- snapshot = 1;
+ {
+ Error *blocker = NULL;
+ snapshot = 1;
+ error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED,
+ "-snapshot");
+ replay_add_blocker(blocker);
+ }
break;
case QEMU_OPTION_numa:
opts = qemu_opts_parse_noisily(qemu_find_opts("numa"),
if (*p == 'x') {
p++;
depth = strtol(p, (char **)&p, 10);
- if (depth != 8 && depth != 15 && depth != 16 &&
+ if (depth != 1 && depth != 2 && depth != 4 &&
+ depth != 8 && depth != 15 && depth != 16 &&
depth != 24 && depth != 32)
goto graphic_error;
} else if (*p == '\0') {
case QEMU_OPTION_virtfs: {
QemuOpts *fsdev;
QemuOpts *device;
- const char *writeout, *sock_fd, *socket, *path, *security_model;
+ const char *writeout, *sock_fd, *socket, *path, *security_model,
+ *multidevs;
olist = qemu_find_opts("virtfs");
if (!olist) {
qemu_opt_set_bool(fsdev, "readonly",
qemu_opt_get_bool(opts, "readonly", 0),
&error_abort);
+ multidevs = qemu_opt_get(opts, "multidevs");
+ if (multidevs) {
+ qemu_opt_set(fsdev, "multidevs", multidevs, &error_abort);
+ }
device = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
&error_abort);
qemu_opt_set(device, "driver", "virtio-9p-pci", &error_abort);
qemu_opt_get(opts, "mount_tag"), &error_abort);
break;
}
- case QEMU_OPTION_virtfs_synth: {
- QemuOpts *fsdev;
- QemuOpts *device;
-
- warn_report("'-virtfs_synth' is deprecated, please use "
- "'-fsdev synth' and '-device virtio-9p-...' "
- "instead");
-
- fsdev = qemu_opts_create(qemu_find_opts("fsdev"), "v_synth",
- 1, NULL);
- if (!fsdev) {
- error_report("duplicate option: %s", "virtfs_synth");
- exit(1);
- }
- qemu_opt_set(fsdev, "fsdriver", "synth", &error_abort);
-
- device = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
- &error_abort);
- qemu_opt_set(device, "driver", "virtio-9p-pci", &error_abort);
- qemu_opt_set(device, "fsdev", "v_synth", &error_abort);
- qemu_opt_set(device, "mount_tag", "v_synth", &error_abort);
- break;
- }
case QEMU_OPTION_serial:
add_device_config(DEV_SERIAL, optarg);
default_serial = 0;
g_slist_free(accel_list);
exit(0);
}
+ if (optarg && strchr(optarg, ':')) {
+ error_report("Don't use ':' with -accel, "
+ "use -M accel=... for now instead");
+ exit(1);
+ }
opts = qemu_opts_create(qemu_find_opts("machine"), NULL,
false, &error_abort);
qemu_opt_set(opts, "accel", optarg, &error_abort);
g_free(trace_file);
trace_file = trace_opt_parse(optarg);
break;
+ case QEMU_OPTION_plugin:
+ qemu_plugin_opt_parse(optarg, &plugin_list);
+ break;
case QEMU_OPTION_readconfig:
{
int ret = qemu_read_config_file(optarg);
machine_class->default_cpus = machine_class->default_cpus ?: 1;
/* default to machine_class->default_cpus */
- smp_cpus = machine_class->default_cpus;
- max_cpus = machine_class->default_cpus;
+ current_machine->smp.cpus = machine_class->default_cpus;
+ current_machine->smp.max_cpus = machine_class->default_cpus;
+ current_machine->smp.cores = 1;
+ current_machine->smp.threads = 1;
- smp_parse(qemu_opts_find(qemu_find_opts("smp-opts"), NULL));
+ machine_class->smp_parse(current_machine,
+ qemu_opts_find(qemu_find_opts("smp-opts"), NULL));
/* sanity-check smp_cpus and max_cpus against machine_class */
- if (smp_cpus < machine_class->min_cpus) {
+ if (current_machine->smp.cpus < machine_class->min_cpus) {
error_report("Invalid SMP CPUs %d. The min CPUs "
- "supported by machine '%s' is %d", smp_cpus,
+ "supported by machine '%s' is %d",
+ current_machine->smp.cpus,
machine_class->name, machine_class->min_cpus);
exit(1);
}
- if (max_cpus > machine_class->max_cpus) {
+ if (current_machine->smp.max_cpus > machine_class->max_cpus) {
error_report("Invalid SMP CPUs %d. The max CPUs "
- "supported by machine '%s' is %d", max_cpus,
+ "supported by machine '%s' is %d",
+ current_machine->smp.max_cpus,
machine_class->name, machine_class->max_cpus);
exit(1);
}
machine_class->default_machine_opts, 0);
}
+ /* process plugin before CPUs are created, but once -smp has been parsed */
+ if (qemu_plugin_load_list(&plugin_list)) {
+ exit(1);
+ }
+
qemu_opts_foreach(qemu_find_opts("device"),
default_driver_check, NULL, NULL);
qemu_opts_foreach(qemu_find_opts("global"),
migration_object_init();
if (qtest_chrdev) {
- qtest_init(qtest_chrdev, qtest_log, &error_fatal);
+ qtest_server_init(qtest_chrdev, qtest_log, &error_fatal);
}
machine_opts = qemu_get_machine_opts();
semihosting_arg_fallback(kernel_filename, kernel_cmdline);
}
- os_set_line_buffering();
-
/* spice needs the timers to be initialized by this point */
qemu_spice_init();
*/
migration_shutdown();
+ /*
+ * We must cancel all block jobs while the block layer is drained,
+ * or cancelling will be affected by throttling and thus may block
+ * for an extended period of time.
+ * vm_shutdown() will bdrv_drain_all(), so we may as well include
+ * it in the drained section.
+ * We do not need to end this section, because we do not want any
+ * requests happening from here on anyway.
+ */
+ bdrv_drain_all_begin();
+
/* No more vcpu or device emulation activity beyond this point */
vm_shutdown();
+ replay_finish();
job_cancel_sync_all();
bdrv_close_all();