#include "hw/isa/isa.h"
#include "hw/scsi/scsi.h"
#include "hw/display/vga.h"
-#include "hw/bt.h"
#include "sysemu/watchdog.h"
#include "hw/firmware/smbios.h"
#include "hw/acpi/acpi.h"
#include "hw/xen/xen.h"
#include "hw/loader.h"
#include "monitor/qdev.h"
-#include "sysemu/bt.h"
#include "net/net.h"
#include "net/slirp.h"
#include "monitor/monitor.h"
#include "trace-root.h"
#include "trace/control.h"
+#include "qemu/plugin.h"
#include "qemu/queue.h"
#include "sysemu/arch_init.h"
.name = "accel",
.implied_opt_name = "accel",
.head = QTAILQ_HEAD_INITIALIZER(qemu_accel_opts.head),
- .merge_lists = true,
.desc = {
- {
- .name = "accel",
- .type = QEMU_OPT_STRING,
- .help = "Select the type of accelerator",
- },
- {
- .name = "thread",
- .type = QEMU_OPT_STRING,
- .help = "Enable/disable multi-threaded TCG",
- },
- { /* end of list */ }
+ /*
+ * no elements => accept any
+ * sanity checking will happen later
+ * when setting accelerator properties
+ */
+ { }
},
};
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;
value = qemu_opt_get(opts, "driftfix");
if (value) {
if (!strcmp(value, "slew")) {
- static GlobalProperty slew_lost_ticks = {
- .driver = "mc146818rtc",
- .property = "lost_tick_policy",
- .value = "slew",
- };
-
- qdev_prop_register_global(&slew_lost_ticks);
+ object_register_sugar_prop("mc146818rtc",
+ "lost_tick_policy",
+ "slew");
} else if (!strcmp(value, "none")) {
/* discard is default */
} else {
}
}
-/***********************************************************/
-/* Bluetooth support */
-static int nb_hcis;
-static int cur_hci;
-static struct HCIInfo *hci_table[MAX_NICS];
-
-struct HCIInfo *qemu_next_hci(void)
-{
- if (cur_hci == nb_hcis)
- return &null_hci;
-
- return hci_table[cur_hci++];
-}
-
-static int bt_hci_parse(const char *str)
-{
- struct HCIInfo *hci;
- bdaddr_t bdaddr;
-
- if (nb_hcis >= MAX_NICS) {
- error_report("too many bluetooth HCIs (max %i)", MAX_NICS);
- return -1;
- }
-
- hci = hci_init(str);
- if (!hci)
- return -1;
-
- bdaddr.b[0] = 0x52;
- bdaddr.b[1] = 0x54;
- bdaddr.b[2] = 0x00;
- bdaddr.b[3] = 0x12;
- bdaddr.b[4] = 0x34;
- bdaddr.b[5] = 0x56 + nb_hcis;
- hci->bdaddr_set(hci, bdaddr.b);
-
- hci_table[nb_hcis++] = hci;
-
- return 0;
-}
-
-static void bt_vhci_add(int vlan_id)
-{
- struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id);
-
- if (!vlan->slave)
- warn_report("adding a VHCI to an empty scatternet %i",
- vlan_id);
-
- bt_vhci_init(bt_new_hci(vlan));
-}
-
-static struct bt_device_s *bt_device_add(const char *opt)
-{
- struct bt_scatternet_s *vlan;
- int vlan_id = 0;
- char *endp = strstr(opt, ",vlan=");
- int len = (endp ? endp - opt : strlen(opt)) + 1;
- char devname[10];
-
- pstrcpy(devname, MIN(sizeof(devname), len), opt);
-
- if (endp) {
- vlan_id = strtol(endp + 6, &endp, 0);
- if (*endp) {
- error_report("unrecognised bluetooth vlan Id");
- return 0;
- }
- }
-
- vlan = qemu_find_bt_vlan(vlan_id);
-
- if (!vlan->slave)
- warn_report("adding a slave device to an empty scatternet %i",
- vlan_id);
-
- if (!strcmp(devname, "keyboard"))
- return bt_keyboard_init(vlan);
-
- error_report("unsupported bluetooth device '%s'", devname);
- return 0;
-}
-
-static int bt_parse(const char *opt)
-{
- const char *endp, *p;
- int vlan;
-
- if (strstart(opt, "hci", &endp)) {
- if (!*endp || *endp == ',') {
- if (*endp)
- if (!strstart(endp, ",vlan=", 0))
- opt = endp + 1;
-
- return bt_hci_parse(opt);
- }
- } else if (strstart(opt, "vhci", &endp)) {
- if (!*endp || *endp == ',') {
- if (*endp) {
- if (strstart(endp, ",vlan=", &p)) {
- vlan = strtol(p, (char **) &endp, 0);
- if (*endp) {
- error_report("bad scatternet '%s'", p);
- return 1;
- }
- } else {
- error_report("bad parameter '%s'", endp + 1);
- return 1;
- }
- } else
- vlan = 0;
-
- bt_vhci_add(vlan);
- return 0;
- }
- } else if (strstart(opt, "device:", &endp))
- return !bt_device_add(endp);
-
- error_report("bad bluetooth parameter '%s'", opt);
- return 1;
-}
-
static int parse_name(void *opaque, QemuOpts *opts, Error **errp)
{
const char *proc_name;
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);
}
static void configure_msg(QemuOpts *opts)
{
- enable_timestamp_msg = qemu_opt_get_bool(opts, "timestamp", true);
+ error_with_timestamp = qemu_opt_get_bool(opts, "timestamp", false);
}
-/* Now we still need this for compatibility with XEN. */
-bool has_igd_gfx_passthru;
-static void igd_gfx_passthru(void)
-{
- has_igd_gfx_passthru = current_machine->igd_gfx_passthru;
-}
-
/***********************************************************/
/* USB devices */
pause_all_vcpus();
qemu_system_reset(request);
resume_all_vcpus();
+ /*
+ * runstate can change in pause_all_vcpus()
+ * as iothread mutex is unlocked
+ */
if (!runstate_check(RUN_STATE_RUNNING) &&
- !runstate_check(RUN_STATE_INMIGRATE)) {
+ !runstate_check(RUN_STATE_INMIGRATE) &&
+ !runstate_check(RUN_STATE_FINISH_MIGRATE)) {
runstate_set(RUN_STATE_PRELAUNCH);
}
}
{
const char *opts;
+ if (is_help_option(p)) {
+ qemu_display_help();
+ exit(0);
+ }
+
if (strstart(p, "sdl", &opts)) {
/*
* sdl DisplayType needs hand-crafted parser instead of
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;
}
struct device_config {
enum {
DEV_USB, /* -usbdevice */
- DEV_BT, /* -bt */
DEV_SERIAL, /* -serial */
DEV_PARALLEL, /* -parallel */
DEV_DEBUGCON, /* -debugcon */
return machine_class;
}
-static int machine_set_property(void *opaque,
- const char *name, const char *value,
- Error **errp)
+static int object_parse_property_opt(Object *obj,
+ const char *name, const char *value,
+ const char *skip, Error **errp)
{
- Object *obj = OBJECT(opaque);
Error *local_err = NULL;
- char *p, *qom_name;
- if (strcmp(name, "type") == 0) {
+ if (g_str_equal(name, skip)) {
return 0;
}
- qom_name = g_strdup(name);
- for (p = qom_name; *p; p++) {
- if (*p == '_') {
- *p = '-';
- }
- }
-
- object_property_parse(obj, value, qom_name, &local_err);
- g_free(qom_name);
+ object_property_parse(obj, value, name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return 0;
}
+static int machine_set_property(void *opaque,
+ const char *name, const char *value,
+ Error **errp)
+{
+ g_autofree char *qom_name = g_strdup(name);
+ char *p;
+
+ for (p = qom_name; *p; p++) {
+ if (*p == '_') {
+ *p = '-';
+ }
+ }
+
+ /* Legacy options do not correspond to MachineState properties. */
+ if (g_str_equal(qom_name, "accel")) {
+ return 0;
+ }
+ if (g_str_equal(qom_name, "igd-passthru")) {
+ object_register_sugar_prop(ACCEL_CLASS_NAME("xen"), qom_name, value);
+ return 0;
+ }
+ if (g_str_equal(qom_name, "kvm-shadow-mem") ||
+ g_str_equal(qom_name, "kernel-irqchip")) {
+ object_register_sugar_prop(ACCEL_CLASS_NAME("kvm"), qom_name, value);
+ return 0;
+ }
+
+ return object_parse_property_opt(opaque, name, value, "type", errp);
+}
/*
* Initial object creation happens before all other
*/
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);
}
global_init_func, NULL, NULL);
}
+static int do_configure_icount(void *opaque, QemuOpts *opts, Error **errp)
+{
+ configure_icount(opts, errp);
+ return 0;
+}
+
+static int accelerator_set_property(void *opaque,
+ const char *name, const char *value,
+ Error **errp)
+{
+ return object_parse_property_opt(opaque, name, value, "accel", errp);
+}
+
+static int do_configure_accelerator(void *opaque, QemuOpts *opts, Error **errp)
+{
+ bool *p_init_failed = opaque;
+ const char *acc = qemu_opt_get(opts, "accel");
+ AccelClass *ac = accel_find(acc);
+ AccelState *accel;
+ int ret;
+
+ if (!ac) {
+ *p_init_failed = true;
+ error_report("invalid accelerator %s", acc);
+ return 0;
+ }
+ accel = ACCEL(object_new_with_class(OBJECT_CLASS(ac)));
+ object_apply_compat_props(OBJECT(accel));
+ qemu_opt_foreach(opts, accelerator_set_property,
+ accel,
+ &error_fatal);
+
+ ret = accel_init_machine(accel, current_machine);
+ if (ret < 0) {
+ *p_init_failed = true;
+ error_report("failed to initialize %s: %s",
+ acc, strerror(-ret));
+ return 0;
+ }
+
+ return 1;
+}
+
+static void configure_accelerators(const char *progname)
+{
+ const char *accel;
+ bool init_failed = false;
+
+ qemu_opts_foreach(qemu_find_opts("icount"),
+ do_configure_icount, NULL, &error_fatal);
+
+ accel = qemu_opt_get(qemu_get_machine_opts(), "accel");
+ if (QTAILQ_EMPTY(&qemu_accel_opts.head)) {
+ char **accel_list, **tmp;
+
+ if (accel == NULL) {
+ /* Select the default accelerator */
+ bool have_tcg = accel_find("tcg");
+ bool have_kvm = accel_find("kvm");
+
+ if (have_tcg && have_kvm) {
+ if (g_str_has_suffix(progname, "kvm")) {
+ /* If the program name ends with "kvm", we prefer KVM */
+ accel = "kvm:tcg";
+ } else {
+ accel = "tcg:kvm";
+ }
+ } else if (have_kvm) {
+ accel = "kvm";
+ } else if (have_tcg) {
+ accel = "tcg";
+ } else {
+ error_report("No accelerator selected and"
+ " no default accelerator available");
+ exit(1);
+ }
+ }
+ accel_list = g_strsplit(accel, ":", 0);
+
+ for (tmp = accel_list; *tmp; tmp++) {
+ /*
+ * Filter invalid accelerators here, to prevent obscenities
+ * such as "-machine accel=tcg,,thread=single".
+ */
+ if (accel_find(*tmp)) {
+ qemu_opts_parse_noisily(qemu_find_opts("accel"), *tmp, true);
+ } else {
+ init_failed = true;
+ error_report("invalid accelerator %s", *tmp);
+ }
+ }
+ g_strfreev(accel_list);
+ } else {
+ if (accel != NULL) {
+ error_report("The -accel and \"-machine accel=\" options are incompatible");
+ exit(1);
+ }
+ }
+
+ if (!qemu_opts_foreach(qemu_find_opts("accel"),
+ do_configure_accelerator, &init_failed, &error_fatal)) {
+ if (!init_failed) {
+ error_report("no accelerator found");
+ }
+ exit(1);
+ }
+
+ if (init_failed) {
+ AccelClass *ac = ACCEL_GET_CLASS(current_machine->accelerator);
+ error_report("falling back to %s", ac->name);
+ }
+
+ if (use_icount && !(tcg_enabled() || qtest_enabled())) {
+ error_report("-icount is not allowed with hardware virtualization");
+ exit(1);
+ }
+}
+
int main(int argc, char **argv, char **envp)
{
int i;
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();
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);
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"),
}
break;
#endif
- case QEMU_OPTION_bt:
- warn_report("The bluetooth subsystem is deprecated and will "
- "be removed soon. If the bluetooth subsystem is "
- "still useful for you, please send a mail to "
- add_device_config(DEV_BT, optarg);
- break;
case QEMU_OPTION_audio_help:
audio_legacy_help();
exit (0);
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);
}
- opts = qemu_opts_create(qemu_find_opts("machine"), NULL,
- false, &error_abort);
- qemu_opt_set(opts, "accel", optarg, &error_abort);
+ if (optarg && strchr(optarg, ':')) {
+ error_report("Don't use ':' with -accel, "
+ "use -M accel=... for now instead");
+ exit(1);
+ }
break;
case QEMU_OPTION_usb:
olist = qemu_find_opts("machine");
error_report("TCG is disabled");
exit(1);
#endif
- if (qemu_strtoul(optarg, NULL, 0, &tcg_tb_size) < 0) {
- error_report("Invalid argument to -tb-size");
- exit(1);
- }
+ warn_report("The -tb-size option is deprecated, use -accel tcg,tb-size instead");
+ object_register_sugar_prop(ACCEL_CLASS_NAME("tcg"), "tb-size", optarg);
break;
case QEMU_OPTION_icount:
icount_opts = qemu_opts_parse_noisily(qemu_find_opts("icount"),
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);
cleanup_add_fd, NULL, &error_fatal);
#endif
- current_machine = MACHINE(object_new(object_class_get_name(
- OBJECT_CLASS(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);
}
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"),
* Note: uses machine properties such as kernel-irqchip, must run
* after machine_set_property().
*/
- configure_accelerator(current_machine, argv[0]);
+ configure_accelerators(argv[0]);
/*
* Beware, QOM objects created before this point miss global and
qemu_spice_init();
cpu_ticks_init();
- if (icount_opts) {
- if (!tcg_enabled()) {
- error_report("-icount is not allowed with hardware virtualization");
- exit(1);
- }
- configure_icount(icount_opts, &error_abort);
- qemu_opts_del(icount_opts);
- }
-
- if (tcg_enabled()) {
- qemu_tcg_configure(accel_opts, &error_fatal);
- }
if (default_net) {
QemuOptsList *net = qemu_find_opts("net");
tpm_init();
- /* init the bluetooth world */
- if (foreach_device_config(DEV_BT, bt_parse))
- exit(1);
-
if (!xen_enabled()) {
/* On 32-bit hosts, QEMU is limited by virtual address space */
if (ram_size > (2047 << 20) && HOST_LONG_BITS == 32) {
qemu_opts_foreach(qemu_find_opts("mon"),
mon_init_func, NULL, &error_fatal);
+ /* connect semihosting console input if requested */
+ qemu_semihosting_console_init();
+
if (foreach_device_config(DEV_SERIAL, serial_parse) < 0)
exit(1);
if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0)
exit(1);
}
- /* Check if IGD GFX passthrough. */
- igd_gfx_passthru();
-
/* init generic devices */
rom_set_order_override(FW_CFG_ORDER_OVERRIDE_DEVICE);
qemu_opts_foreach(qemu_find_opts("device"),
/* No more vcpu or device emulation activity beyond this point */
vm_shutdown();
+ replay_finish();
job_cancel_sync_all();
bdrv_close_all();