+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;
+ char **accel_list, **tmp;
+ bool accel_initialised = false;
+ 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)) {
+ if (accel == NULL) {
+ /* Select the default accelerator */
+ if (!accel_find("tcg") && !accel_find("kvm")) {
+ error_report("No accelerator selected and"
+ " no default accelerator available");
+ exit(1);
+ } else {
+ int pnlen = strlen(progname);
+ if (pnlen >= 3 && g_str_equal(&progname[pnlen - 3], "kvm")) {
+ /* If the program name ends with "kvm", we prefer KVM */
+ accel = "kvm:tcg";
+ } else {
+ accel = "tcg:kvm";
+ }
+ }
+ }
+
+ accel_list = g_strsplit(accel, ":", 0);
+
+ for (tmp = accel_list; !accel_initialised && tmp && *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);
+ }
+}
+