X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=qemu%2Fvl.c;h=5fd22cb2e919462d676790d907dbf74f32865096;hb=a14b48d18a9ed03ec191cf16b162206998a895ce;hp=0adbbd6747ab9a9a8fe879863a5ba1d26cbc4b4d;hpb=e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb;p=kvmfornfv.git diff --git a/qemu/vl.c b/qemu/vl.c index 0adbbd674..5fd22cb2e 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -21,14 +21,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include -#include -#include -#include -#include -#include - -#include "config-host.h" +#include "qemu/osdep.h" +#include "qemu/cutils.h" +#include "qemu/help_option.h" #ifdef CONFIG_SECCOMP #include "sysemu/seccomp.h" @@ -68,7 +63,7 @@ int main(int argc, char **argv) #include "hw/isa/isa.h" #include "hw/bt.h" #include "sysemu/watchdog.h" -#include "hw/i386/smbios.h" +#include "hw/smbios/smbios.h" #include "hw/xen/xen.h" #include "hw/qdev.h" #include "hw/loader.h" @@ -78,6 +73,7 @@ int main(int argc, char **argv) #include "net/slirp.h" #include "monitor/monitor.h" #include "ui/console.h" +#include "ui/input.h" #include "sysemu/sysemu.h" #include "sysemu/numa.h" #include "exec/gdbstub.h" @@ -113,7 +109,6 @@ int main(int argc, char **argv) #include "qemu/queue.h" #include "sysemu/cpus.h" #include "sysemu/arch_init.h" -#include "qemu/osdep.h" #include "ui/qemu-spice.h" #include "qapi/string-input-visitor.h" @@ -122,6 +117,8 @@ int main(int argc, char **argv) #include "qapi-event.h" #include "exec/semihost.h" #include "crypto/init.h" +#include "sysemu/replay.h" +#include "qapi/qmp/qerror.h" #define MAX_VIRTIO_CONSOLES 1 #define MAX_SCLP_CONSOLES 1 @@ -225,7 +222,6 @@ static struct { { .driver = "ide-drive", .flag = &default_cdrom }, { .driver = "scsi-cd", .flag = &default_cdrom }, { .driver = "virtio-serial-pci", .flag = &default_virtcon }, - { .driver = "virtio-serial-s390", .flag = &default_virtcon }, { .driver = "virtio-serial", .flag = &default_virtcon }, { .driver = "VGA", .flag = &default_vga }, { .driver = "isa-vga", .flag = &default_vga }, @@ -269,9 +265,13 @@ static QemuOptsList qemu_sandbox_opts = { static QemuOptsList qemu_trace_opts = { .name = "trace", - .implied_opt_name = "trace", + .implied_opt_name = "enable", .head = QTAILQ_HEAD_INITIALIZER(qemu_trace_opts.head), .desc = { + { + .name = "enable", + .type = QEMU_OPT_STRING, + }, { .name = "events", .type = QEMU_OPT_STRING, @@ -474,6 +474,12 @@ static QemuOptsList qemu_icount_opts = { }, { .name = "sleep", .type = QEMU_OPT_BOOL, + }, { + .name = "rr", + .type = QEMU_OPT_STRING, + }, { + .name = "rrfile", + .type = QEMU_OPT_STRING, }, { /* end of list */ } }, @@ -512,6 +518,10 @@ static QemuOptsList qemu_fw_cfg_opts = { .type = QEMU_OPT_STRING, .help = "Sets the name of the file from which\n" "the fw_cfg blob will be loaded", + }, { + .name = "string", + .type = QEMU_OPT_STRING, + .help = "Sets content of the blob to be inserted from a string", }, { /* end of list */ } }, @@ -534,10 +544,8 @@ const char *qemu_get_vm_name(void) static void res_free(void) { - if (boot_splash_filedata != NULL) { - g_free(boot_splash_filedata); - boot_splash_filedata = NULL; - } + g_free(boot_splash_filedata); + boot_splash_filedata = NULL; } static int default_driver_check(void *opaque, QemuOpts *opts, Error **errp) @@ -560,8 +568,8 @@ static int default_driver_check(void *opaque, QemuOpts *opts, Error **errp) static RunState current_run_state = RUN_STATE_PRELAUNCH; -/* We use RUN_STATE_MAX but any invalid value will do */ -static RunState vmstop_requested = RUN_STATE_MAX; +/* We use RUN_STATE__MAX but any invalid value will do */ +static RunState vmstop_requested = RUN_STATE__MAX; static QemuMutex vmstop_lock; typedef struct { @@ -573,6 +581,7 @@ static const RunStateTransition runstate_transitions_def[] = { /* from -> to */ { RUN_STATE_DEBUG, RUN_STATE_RUNNING }, { RUN_STATE_DEBUG, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_DEBUG, RUN_STATE_PRELAUNCH }, { RUN_STATE_INMIGRATE, RUN_STATE_INTERNAL_ERROR }, { RUN_STATE_INMIGRATE, RUN_STATE_IO_ERROR }, @@ -582,18 +591,25 @@ static const RunStateTransition runstate_transitions_def[] = { { RUN_STATE_INMIGRATE, RUN_STATE_SUSPENDED }, { RUN_STATE_INMIGRATE, RUN_STATE_WATCHDOG }, { RUN_STATE_INMIGRATE, RUN_STATE_GUEST_PANICKED }, + { RUN_STATE_INMIGRATE, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH }, + { RUN_STATE_INMIGRATE, RUN_STATE_POSTMIGRATE }, { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED }, { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PRELAUNCH }, { RUN_STATE_IO_ERROR, RUN_STATE_RUNNING }, { RUN_STATE_IO_ERROR, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_IO_ERROR, RUN_STATE_PRELAUNCH }, { RUN_STATE_PAUSED, RUN_STATE_RUNNING }, { RUN_STATE_PAUSED, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_PAUSED, RUN_STATE_PRELAUNCH }, { RUN_STATE_POSTMIGRATE, RUN_STATE_RUNNING }, { RUN_STATE_POSTMIGRATE, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_POSTMIGRATE, RUN_STATE_PRELAUNCH }, { RUN_STATE_PRELAUNCH, RUN_STATE_RUNNING }, { RUN_STATE_PRELAUNCH, RUN_STATE_FINISH_MIGRATE }, @@ -601,8 +617,10 @@ static const RunStateTransition runstate_transitions_def[] = { { RUN_STATE_FINISH_MIGRATE, RUN_STATE_RUNNING }, { RUN_STATE_FINISH_MIGRATE, RUN_STATE_POSTMIGRATE }, + { RUN_STATE_FINISH_MIGRATE, RUN_STATE_PRELAUNCH }, { RUN_STATE_RESTORE_VM, RUN_STATE_RUNNING }, + { RUN_STATE_RESTORE_VM, RUN_STATE_PRELAUNCH }, { RUN_STATE_RUNNING, RUN_STATE_DEBUG }, { RUN_STATE_RUNNING, RUN_STATE_INTERNAL_ERROR }, @@ -619,22 +637,26 @@ static const RunStateTransition runstate_transitions_def[] = { { RUN_STATE_SHUTDOWN, RUN_STATE_PAUSED }, { RUN_STATE_SHUTDOWN, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_SHUTDOWN, RUN_STATE_PRELAUNCH }, { RUN_STATE_DEBUG, RUN_STATE_SUSPENDED }, { RUN_STATE_RUNNING, RUN_STATE_SUSPENDED }, { RUN_STATE_SUSPENDED, RUN_STATE_RUNNING }, { RUN_STATE_SUSPENDED, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_SUSPENDED, RUN_STATE_PRELAUNCH }, { RUN_STATE_WATCHDOG, RUN_STATE_RUNNING }, { RUN_STATE_WATCHDOG, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_WATCHDOG, RUN_STATE_PRELAUNCH }, { RUN_STATE_GUEST_PANICKED, RUN_STATE_RUNNING }, { RUN_STATE_GUEST_PANICKED, RUN_STATE_FINISH_MIGRATE }, + { RUN_STATE_GUEST_PANICKED, RUN_STATE_PRELAUNCH }, - { RUN_STATE_MAX, RUN_STATE_MAX }, + { RUN_STATE__MAX, RUN_STATE__MAX }, }; -static bool runstate_valid_transitions[RUN_STATE_MAX][RUN_STATE_MAX]; +static bool runstate_valid_transitions[RUN_STATE__MAX][RUN_STATE__MAX]; bool runstate_check(RunState state) { @@ -658,7 +680,7 @@ static void runstate_init(void) const RunStateTransition *p; memset(&runstate_valid_transitions, 0, sizeof(runstate_valid_transitions)); - for (p = &runstate_transitions_def[0]; p->from != RUN_STATE_MAX; p++) { + for (p = &runstate_transitions_def[0]; p->from != RUN_STATE__MAX; p++) { runstate_valid_transitions[p->from][p->to] = true; } @@ -668,12 +690,12 @@ static void runstate_init(void) /* This function will abort() on invalid state transitions */ void runstate_set(RunState new_state) { - assert(new_state < RUN_STATE_MAX); + assert(new_state < RUN_STATE__MAX); if (!runstate_valid_transitions[current_run_state][new_state]) { - fprintf(stderr, "ERROR: invalid runstate transition: '%s' -> '%s'\n", - RunState_lookup[current_run_state], - RunState_lookup[new_state]); + error_report("invalid runstate transition: '%s' -> '%s'", + RunState_lookup[current_run_state], + RunState_lookup[new_state]); abort(); } trace_runstate_set(new_state); @@ -706,9 +728,9 @@ static bool qemu_vmstop_requested(RunState *r) { qemu_mutex_lock(&vmstop_lock); *r = vmstop_requested; - vmstop_requested = RUN_STATE_MAX; + vmstop_requested = RUN_STATE__MAX; qemu_mutex_unlock(&vmstop_lock); - return *r < RUN_STATE_MAX; + return *r < RUN_STATE__MAX; } void qemu_system_vmstop_request_prepare(void) @@ -728,7 +750,7 @@ void vm_start(void) RunState requested; qemu_vmstop_requested(&requested); - if (runstate_is_running() && requested == RUN_STATE_MAX) { + if (runstate_is_running() && requested == RUN_STATE__MAX) { return; } @@ -825,8 +847,9 @@ static void configure_rtc_date_offset(const char *startdate, int legacy) rtc_start_date = mktimegm(&tm); if (rtc_start_date == -1) { date_fail: - fprintf(stderr, "Invalid date format. Valid formats are:\n" - "'2006-06-17T16:01:21' or '2006-06-17'\n"); + error_report("invalid date format"); + error_printf("valid formats: " + "'2006-06-17T16:01:21' or '2006-06-17'\n"); exit(1); } rtc_date_offset = qemu_time() - rtc_start_date; @@ -842,7 +865,11 @@ static void configure_rtc(QemuOpts *opts) if (!strcmp(value, "utc")) { rtc_utc = 1; } else if (!strcmp(value, "localtime")) { + Error *blocker = NULL; rtc_utc = 0; + error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, + "-rtc base=localtime"); + replay_add_blocker(blocker); } else { configure_rtc_date_offset(value, 0); } @@ -856,7 +883,7 @@ static void configure_rtc(QemuOpts *opts) } else if (!strcmp(value, "vm")) { rtc_clock = QEMU_CLOCK_VIRTUAL; } else { - fprintf(stderr, "qemu: invalid option value '%s'\n", value); + error_report("invalid option value '%s'", value); exit(1); } } @@ -876,7 +903,7 @@ static void configure_rtc(QemuOpts *opts) } else if (!strcmp(value, "none")) { /* discard is default */ } else { - fprintf(stderr, "qemu: invalid option value '%s'\n", value); + error_report("invalid option value '%s'", value); exit(1); } } @@ -902,7 +929,7 @@ static int bt_hci_parse(const char *str) bdaddr_t bdaddr; if (nb_hcis >= MAX_NICS) { - fprintf(stderr, "qemu: Too many bluetooth HCIs (max %i).\n", MAX_NICS); + error_report("too many bluetooth HCIs (max %i)", MAX_NICS); return -1; } @@ -928,8 +955,8 @@ static void bt_vhci_add(int vlan_id) struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id); if (!vlan->slave) - fprintf(stderr, "qemu: warning: adding a VHCI to " - "an empty scatternet %i\n", vlan_id); + error_report("warning: adding a VHCI to an empty scatternet %i", + vlan_id); bt_vhci_init(bt_new_hci(vlan)); } @@ -947,7 +974,7 @@ static struct bt_device_s *bt_device_add(const char *opt) if (endp) { vlan_id = strtol(endp + 6, &endp, 0); if (*endp) { - fprintf(stderr, "qemu: unrecognised bluetooth vlan Id\n"); + error_report("unrecognised bluetooth vlan Id"); return 0; } } @@ -955,13 +982,13 @@ static struct bt_device_s *bt_device_add(const char *opt) vlan = qemu_find_bt_vlan(vlan_id); if (!vlan->slave) - fprintf(stderr, "qemu: warning: adding a slave device to " - "an empty scatternet %i\n", vlan_id); + error_report("warning: adding a slave device to an empty scatternet %i", + vlan_id); if (!strcmp(devname, "keyboard")) return bt_keyboard_init(vlan); - fprintf(stderr, "qemu: unsupported bluetooth device `%s'\n", devname); + error_report("unsupported bluetooth device '%s'", devname); return 0; } @@ -984,11 +1011,11 @@ static int bt_parse(const char *opt) if (strstart(endp, ",vlan=", &p)) { vlan = strtol(p, (char **) &endp, 0); if (*endp) { - fprintf(stderr, "qemu: bad scatternet '%s'\n", p); + error_report("bad scatternet '%s'", p); return 1; } } else { - fprintf(stderr, "qemu: bad parameter '%s'\n", endp + 1); + error_report("bad parameter '%s'", endp + 1); return 1; } } else @@ -1000,7 +1027,7 @@ static int bt_parse(const char *opt) } else if (strstart(opt, "device:", &endp)) return !bt_device_add(endp); - fprintf(stderr, "qemu: bad bluetooth parameter '%s'\n", opt); + error_report("bad bluetooth parameter '%s'", opt); return 1; } @@ -1015,8 +1042,7 @@ static int parse_sandbox(void *opaque, QemuOpts *opts, Error **errp) return -1; } #else - error_report("sandboxing request but seccomp is not compiled " - "into this build"); + error_report("seccomp support is disabled"); return -1; #endif } @@ -1097,7 +1123,7 @@ static int parse_add_fd(void *opaque, QemuOpts *opts, Error **errp) } #endif if (dupfd == -1) { - error_report("Error duplicating fd: %s", strerror(errno)); + error_report("error duplicating fd: %s", strerror(errno)); return -1; } @@ -1217,14 +1243,21 @@ static void smp_parse(QemuOpts *opts) } else if (threads == 0) { threads = cpus / (cores * sockets); } else if (sockets * cores * threads < cpus) { - fprintf(stderr, "cpu topology: error: " - "sockets (%u) * cores (%u) * threads (%u) < " - "smp_cpus (%u)\n", - 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", 0); + max_cpus = qemu_opt_get_number(opts, "maxcpus", cpus); + 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); + } smp_cpus = cpus; smp_cores = cores > 0 ? cores : 1; @@ -1237,21 +1270,26 @@ static void smp_parse(QemuOpts *opts) } if (max_cpus > MAX_CPUMASK_BITS) { - fprintf(stderr, "Unsupported number of maxcpus\n"); + error_report("unsupported number of maxcpus"); exit(1); } if (max_cpus < smp_cpus) { - fprintf(stderr, "maxcpus must be equal to or greater than smp\n"); + error_report("maxcpus must be equal to or greater than smp"); exit(1); } + if (smp_cpus > 1 || smp_cores > 1 || smp_threads > 1) { + Error *blocker = NULL; + error_setg(&blocker, QERR_REPLAY_NOT_SUPPORTED, "smp"); + replay_add_blocker(blocker); + } } static void realtime_init(void) { if (enable_mlock) { if (os_mlock() < 0) { - fprintf(stderr, "qemu: locking memory failed\n"); + error_report("locking memory failed"); exit(1); } } @@ -1338,6 +1376,13 @@ static inline void semihosting_arg_fallback(const char *file, const char *cmd) } } +/* 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 */ @@ -1398,7 +1443,7 @@ static int usb_parse(const char *cmdline) int r; r = usb_device_add(cmdline); if (r < 0) { - fprintf(stderr, "qemu: could not add USB device '%s'\n", cmdline); + error_report("could not add USB device '%s'", cmdline); } return r; } @@ -1424,43 +1469,6 @@ void hmp_usb_del(Monitor *mon, const QDict *qdict) MachineState *current_machine; -/* - * Transitional class registration/init used for converting from - * legacy QEMUMachine to MachineClass. - */ -static void qemu_machine_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - QEMUMachine *qm = data; - mc->name = qm->name; - mc->desc = qm->desc; - mc->init = qm->init; - mc->kvm_type = qm->kvm_type; - mc->block_default_type = qm->block_default_type; - mc->max_cpus = qm->max_cpus; - mc->no_sdcard = qm->no_sdcard; - mc->has_dynamic_sysbus = qm->has_dynamic_sysbus; - mc->is_default = qm->is_default; - mc->default_machine_opts = qm->default_machine_opts; - mc->default_boot_order = qm->default_boot_order; -} - -int qemu_register_machine(QEMUMachine *m) -{ - char *name = g_strconcat(m->name, TYPE_MACHINE_SUFFIX, NULL); - TypeInfo ti = { - .name = name, - .parent = TYPE_MACHINE, - .class_init = qemu_machine_class_init, - .class_data = (void *)m, - }; - - type_register(&ti); - g_free(name); - - return 0; -} - static MachineClass *find_machine(const char *name) { GSList *el, *machines = object_class_get_list(TYPE_MACHINE, false); @@ -1539,12 +1547,14 @@ MachineInfoList *qmp_query_machines(Error **errp) static int machine_help_func(QemuOpts *opts, MachineState *machine) { ObjectProperty *prop; + ObjectPropertyIterator iter; if (!qemu_opt_has_help_opt(opts)) { return 0; } - QTAILQ_FOREACH(prop, &OBJECT(machine)->properties, node) { + object_property_iter_init(&iter, OBJECT(machine)); + while ((prop = object_property_iter_next(&iter))) { if (!prop->set) { continue; } @@ -1645,14 +1655,14 @@ static int qemu_shutdown_requested(void) static void qemu_kill_report(void) { if (!qtest_driver() && shutdown_signal != -1) { - fprintf(stderr, "qemu: terminating on signal %d", shutdown_signal); if (shutdown_pid == 0) { /* This happens for eg ^C at the terminal, so it's worth * avoiding printing an odd message in that case. */ - fputc('\n', stderr); + error_report("terminating on signal %d", shutdown_signal); } else { - fprintf(stderr, " from pid " FMT_pid "\n", shutdown_pid); + error_report("terminating on signal %d from pid " FMT_pid, + shutdown_signal, shutdown_pid); } shutdown_signal = -1; } @@ -1661,15 +1671,21 @@ static void qemu_kill_report(void) static int qemu_reset_requested(void) { int r = reset_requested; - reset_requested = 0; - return r; + if (r && replay_checkpoint(CHECKPOINT_RESET_REQUESTED)) { + reset_requested = 0; + return r; + } + return false; } static int qemu_suspend_requested(void) { int r = suspend_requested; - suspend_requested = 0; - return r; + if (r && replay_checkpoint(CHECKPOINT_SUSPEND_REQUESTED)) { + suspend_requested = 0; + return r; + } + return false; } static WakeupReason qemu_wakeup_requested(void) @@ -1729,6 +1745,8 @@ void qemu_system_reset(bool report) mc = current_machine ? MACHINE_GET_CLASS(current_machine) : NULL; + cpu_synchronize_all_states(); + if (mc && mc->reset) { mc->reset(); } else { @@ -1740,6 +1758,15 @@ void qemu_system_reset(bool report) cpu_synchronize_all_post_reset(); } +void qemu_system_guest_panicked(void) +{ + if (current_cpu) { + current_cpu->crash_occurred = true; + } + qapi_event_send_guest_panicked(GUEST_PANIC_ACTION_PAUSE, &error_abort); + vm_stop(RUN_STATE_GUEST_PANICKED); +} + void qemu_system_reset_request(void) { if (no_reboot) { @@ -1808,12 +1835,18 @@ void qemu_system_killed(int signal, pid_t pid) shutdown_signal = signal; shutdown_pid = pid; no_shutdown = 0; - qemu_system_shutdown_request(); + + /* Cannot call qemu_system_shutdown_request directly because + * we are in a signal handler. + */ + shutdown_requested = 1; + qemu_notify_event(); } void qemu_system_shutdown_request(void) { trace_qemu_system_shutdown_request(); + replay_shutdown_request(); shutdown_requested = 1; qemu_notify_event(); } @@ -1862,16 +1895,15 @@ static bool main_loop_should_exit(void) } if (qemu_reset_requested()) { pause_all_vcpus(); - cpu_synchronize_all_states(); qemu_system_reset(VMRESET_REPORT); resume_all_vcpus(); - if (runstate_needs_reset()) { - runstate_set(RUN_STATE_PAUSED); + if (!runstate_check(RUN_STATE_RUNNING) && + !runstate_check(RUN_STATE_INMIGRATE)) { + runstate_set(RUN_STATE_PRELAUNCH); } } if (qemu_wakeup_requested()) { pause_all_vcpus(); - cpu_synchronize_all_states(); qemu_system_reset(VMRESET_SILENT); notifier_list_notify(&wakeup_notifiers, &wakeup_reason); wakeup_reason = QEMU_WAKEUP_REASON_NONE; @@ -1992,28 +2024,28 @@ static void select_vgahw (const char *p) if (vga_available()) { vga_interface_type = VGA_STD; } else { - fprintf(stderr, "Error: standard VGA not available\n"); + error_report("standard VGA not available"); exit(0); } } else if (strstart(p, "cirrus", &opts)) { if (cirrus_vga_available()) { vga_interface_type = VGA_CIRRUS; } else { - fprintf(stderr, "Error: Cirrus VGA not available\n"); + error_report("Cirrus VGA not available"); exit(0); } } else if (strstart(p, "vmware", &opts)) { if (vmware_vga_available()) { vga_interface_type = VGA_VMWARE; } else { - fprintf(stderr, "Error: VMWare SVGA not available\n"); + error_report("VMWare SVGA not available"); exit(0); } } else if (strstart(p, "virtio", &opts)) { if (virtio_vga_available()) { vga_interface_type = VGA_VIRTIO; } else { - fprintf(stderr, "Error: Virtio VGA not available\n"); + error_report("Virtio VGA not available"); exit(0); } } else if (strstart(p, "xenfb", &opts)) { @@ -2022,26 +2054,26 @@ static void select_vgahw (const char *p) if (qxl_vga_available()) { vga_interface_type = VGA_QXL; } else { - fprintf(stderr, "Error: QXL VGA not available\n"); + error_report("QXL VGA not available"); exit(0); } } else if (strstart(p, "tcx", &opts)) { if (tcx_vga_available()) { vga_interface_type = VGA_TCX; } else { - fprintf(stderr, "Error: TCX framebuffer not available\n"); + error_report("TCX framebuffer not available"); exit(0); } } else if (strstart(p, "cg3", &opts)) { if (cg3_vga_available()) { vga_interface_type = VGA_CG3; } else { - fprintf(stderr, "Error: CG3 framebuffer not available\n"); + error_report("CG3 framebuffer not available"); exit(0); } } else if (!strstart(p, "none", &opts)) { invalid_vga: - fprintf(stderr, "Unknown vga type: %s\n", p); + error_report("unknown vga type: %s", p); exit(1); } while (*opts) { @@ -2117,7 +2149,7 @@ static DisplayType select_display(const char *p) } } else { invalid_sdl_args: - error_report("Invalid SDL option string"); + error_report("invalid SDL option string"); exit(1); } opts = nextopt; @@ -2146,7 +2178,7 @@ static DisplayType select_display(const char *p) #ifdef CONFIG_CURSES display = DT_CURSES; #else - error_report("Curses support is disabled"); + error_report("curses support is disabled"); exit(1); #endif } else if (strstart(p, "gtk", &opts)) { @@ -2175,7 +2207,7 @@ static DisplayType select_display(const char *p) } } else { invalid_gtk_args: - error_report("Invalid GTK option string"); + error_report("invalid GTK option string"); exit(1); } opts = nextopt; @@ -2187,7 +2219,7 @@ static DisplayType select_display(const char *p) } else if (strstart(p, "none", &opts)) { display = DT_NONE; } else { - error_report("Unknown display type"); + error_report("unknown display type"); exit(1); } @@ -2255,20 +2287,33 @@ char *qemu_find_file(int type, const char *name) return NULL; } +static inline bool nonempty_str(const char *str) +{ + return str && *str; +} + static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) { gchar *buf; size_t size; - const char *name, *file; + const char *name, *file, *str; + FWCfgState *fw_cfg = (FWCfgState *) opaque; - if (opaque == NULL) { + if (fw_cfg == NULL) { error_report("fw_cfg device not available"); return -1; } name = qemu_opt_get(opts, "name"); file = qemu_opt_get(opts, "file"); - if (name == NULL || *name == '\0' || file == NULL || *file == '\0') { - error_report("invalid argument value"); + str = qemu_opt_get(opts, "string"); + + /* we need name and either a file or the content string */ + if (!(nonempty_str(name) && (nonempty_str(file) || nonempty_str(str)))) { + error_report("invalid argument(s)"); + return -1; + } + if (nonempty_str(file) && nonempty_str(str)) { + error_report("file and string are mutually exclusive"); return -1; } if (strlen(name) > FW_CFG_MAX_FILE_PATH - 1) { @@ -2276,14 +2321,22 @@ static int parse_fw_cfg(void *opaque, QemuOpts *opts, Error **errp) return -1; } if (strncmp(name, "opt/", 4) != 0) { - error_report("WARNING: externally provided fw_cfg item names " - "should be prefixed with \"opt/\"!"); + error_report("warning: externally provided fw_cfg item names " + "should be prefixed with \"opt/\""); } - if (!g_file_get_contents(file, &buf, &size, NULL)) { - error_report("can't load %s", file); - return -1; + if (nonempty_str(str)) { + size = strlen(str); /* NUL terminator NOT included in fw_cfg blob */ + buf = g_memdup(str, size); + } else { + if (!g_file_get_contents(file, &buf, &size, NULL)) { + error_report("can't load %s", file); + return -1; + } } - fw_cfg_add_file((FWCfgState *)opaque, name, buf, size); + /* For legacy, keep user files in a specific global order. */ + fw_cfg_set_order_override(fw_cfg, FW_CFG_ORDER_OVERRIDE_USER); + fw_cfg_add_file(fw_cfg, name, buf, size); + fw_cfg_reset_order_override(fw_cfg); return 0; } @@ -2344,7 +2397,7 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp) } else if (strcmp(mode, "control") == 0) { flags = MONITOR_USE_CONTROL; } else { - fprintf(stderr, "unknown monitor mode \"%s\"\n", mode); + error_report("unknown monitor mode \"%s\"", mode); exit(1); } @@ -2357,7 +2410,7 @@ static int mon_init_func(void *opaque, QemuOpts *opts, Error **errp) chardev = qemu_opt_get(opts, "chardev"); chr = qemu_chr_find(chardev); if (chr == NULL) { - fprintf(stderr, "chardev \"%s\" not found\n", chardev); + error_report("chardev \"%s\" not found", chardev); exit(1); } @@ -2385,7 +2438,7 @@ static void monitor_parse(const char *optarg, const char *mode, bool pretty) } opts = qemu_chr_parse_compat(label, optarg); if (!opts) { - fprintf(stderr, "parse error: %s\n", optarg); + error_report("parse error: %s", optarg); exit(1); } } @@ -2459,14 +2512,14 @@ static int serial_parse(const char *devname) if (strcmp(devname, "none") == 0) return 0; if (index == MAX_SERIAL_PORTS) { - fprintf(stderr, "qemu: too many serial ports\n"); + error_report("too many serial ports"); exit(1); } snprintf(label, sizeof(label), "serial%d", index); serial_hds[index] = qemu_chr_new(label, devname, NULL); if (!serial_hds[index]) { - fprintf(stderr, "qemu: could not connect serial device" - " to character backend '%s'\n", devname); + error_report("could not connect serial device" + " to character backend '%s'", devname); return -1; } index++; @@ -2481,14 +2534,14 @@ static int parallel_parse(const char *devname) if (strcmp(devname, "none") == 0) return 0; if (index == MAX_PARALLEL_PORTS) { - fprintf(stderr, "qemu: too many parallel ports\n"); + error_report("too many parallel ports"); exit(1); } snprintf(label, sizeof(label), "parallel%d", index); parallel_hds[index] = qemu_chr_new(label, devname, NULL); if (!parallel_hds[index]) { - fprintf(stderr, "qemu: could not connect parallel device" - " to character backend '%s'\n", devname); + error_report("could not connect parallel device" + " to character backend '%s'", devname); return -1; } index++; @@ -2505,16 +2558,12 @@ static int virtcon_parse(const char *devname) if (strcmp(devname, "none") == 0) return 0; if (index == MAX_VIRTIO_CONSOLES) { - fprintf(stderr, "qemu: too many virtio consoles\n"); + error_report("too many virtio consoles"); exit(1); } bus_opts = qemu_opts_create(device, NULL, 0, &error_abort); - if (arch_type == QEMU_ARCH_S390X) { - qemu_opt_set(bus_opts, "driver", "virtio-serial-s390", &error_abort); - } else { - qemu_opt_set(bus_opts, "driver", "virtio-serial-pci", &error_abort); - } + qemu_opt_set(bus_opts, "driver", "virtio-serial", &error_abort); dev_opts = qemu_opts_create(device, NULL, 0, &error_abort); qemu_opt_set(dev_opts, "driver", "virtconsole", &error_abort); @@ -2522,8 +2571,8 @@ static int virtcon_parse(const char *devname) snprintf(label, sizeof(label), "virtcon%d", index); virtcon_hds[index] = qemu_chr_new(label, devname, NULL); if (!virtcon_hds[index]) { - fprintf(stderr, "qemu: could not connect virtio console" - " to character backend '%s'\n", devname); + error_report("could not connect virtio console" + " to character backend '%s'", devname); return -1; } qemu_opt_set(dev_opts, "chardev", label, &error_abort); @@ -2543,7 +2592,7 @@ static int sclp_parse(const char *devname) return 0; } if (index == MAX_SCLP_CONSOLES) { - fprintf(stderr, "qemu: too many sclp consoles\n"); + error_report("too many sclp consoles"); exit(1); } @@ -2555,8 +2604,8 @@ static int sclp_parse(const char *devname) snprintf(label, sizeof(label), "sclpcon%d", index); sclp_hds[index] = qemu_chr_new(label, devname, NULL); if (!sclp_hds[index]) { - fprintf(stderr, "qemu: could not connect sclp console" - " to character backend '%s'\n", devname); + error_report("could not connect sclp console" + " to character backend '%s'", devname); return -1; } qemu_opt_set(dev_opts, "chardev", label, &error_abort); @@ -2574,7 +2623,7 @@ static int debugcon_parse(const char *devname) } opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1, NULL); if (!opts) { - fprintf(stderr, "qemu: already have a debugcon device\n"); + error_report("already have a debugcon device"); exit(1); } qemu_opt_set(opts, "driver", "isa-debugcon", &error_abort); @@ -2629,8 +2678,8 @@ static gint machine_class_cmp(gconstpointer a, gconstpointer b) return mc; } if (name && !is_help_option(name)) { - error_report("Unsupported machine type"); - error_printf("Use -machine help to list supported machines!\n"); + error_report("unsupported machine type"); + error_printf("Use -machine help to list supported machines\n"); } else { printf("Supported machines are:\n"); machines = g_slist_sort(machines, machine_class_cmp); @@ -2719,24 +2768,31 @@ static const QEMUOption *lookup_opt(int argc, char **argv, return popt; } -static gpointer malloc_and_trace(gsize n_bytes) +static MachineClass *select_machine(void) { - void *ptr = malloc(n_bytes); - trace_g_malloc(n_bytes, ptr); - return ptr; -} + MachineClass *machine_class = find_default_machine(); + const char *optarg; + QemuOpts *opts; + Location loc; -static gpointer realloc_and_trace(gpointer mem, gsize n_bytes) -{ - void *ptr = realloc(mem, n_bytes); - trace_g_realloc(mem, n_bytes, ptr); - return ptr; -} + loc_push_none(&loc); -static void free_and_trace(gpointer mem) -{ - trace_g_free(mem); - free(mem); + opts = qemu_get_machine_opts(); + qemu_opts_loc_restore(opts); + + optarg = qemu_opt_get(opts, "type"); + if (optarg) { + machine_class = machine_parse(optarg); + } + + 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); + } + + loc_pop(&loc); + return machine_class; } static int machine_set_property(void *opaque, @@ -2783,13 +2839,25 @@ static bool object_create_initial(const char *type) if (g_str_equal(type, "rng-egd")) { return false; } + + /* + * return false for concrete netfilters since + * they depend on netdevs already existing + */ + if (g_str_equal(type, "filter-buffer") || + g_str_equal(type, "filter-dump") || + g_str_equal(type, "filter-mirror") || + g_str_equal(type, "filter-redirector")) { + return false; + } + return true; } /* * The remainder of object creation happens after the - * creation of chardev, fsdev and device data types. + * creation of chardev, fsdev, net clients and device data types. */ static bool object_create_delayed(const char *type) { @@ -2797,62 +2865,6 @@ static bool object_create_delayed(const char *type) } -static int object_create(void *opaque, QemuOpts *opts, Error **errp) -{ - Error *err = NULL; - char *type = NULL; - char *id = NULL; - void *dummy = NULL; - OptsVisitor *ov; - QDict *pdict; - bool (*type_predicate)(const char *) = opaque; - - ov = opts_visitor_new(opts); - pdict = qemu_opts_to_qdict(opts, NULL); - - visit_start_struct(opts_get_visitor(ov), &dummy, NULL, NULL, 0, &err); - if (err) { - goto out; - } - - qdict_del(pdict, "qom-type"); - visit_type_str(opts_get_visitor(ov), &type, "qom-type", &err); - if (err) { - goto out; - } - if (!type_predicate(type)) { - goto out; - } - - qdict_del(pdict, "id"); - visit_type_str(opts_get_visitor(ov), &id, "id", &err); - if (err) { - goto out; - } - - object_add(type, id, pdict, opts_get_visitor(ov), &err); - if (err) { - goto out; - } - visit_end_struct(opts_get_visitor(ov), &err); - if (err) { - qmp_object_del(id, NULL); - } - -out: - opts_visitor_cleanup(ov); - - QDECREF(pdict); - g_free(id); - g_free(type); - g_free(dummy); - if (err) { - error_report_err(err); - return -1; - } - return 0; -} - static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size, MachineClass *mc) { @@ -2861,6 +2873,10 @@ static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size, const char *maxmem_str, *slots_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); sz = 0; mem_str = qemu_opt_get(opts, "size"); @@ -2935,6 +2951,8 @@ static void set_memory_options(uint64_t *ram_slots, ram_addr_t *maxram_size, "'%s' option", slots_str ? "maxmem" : "slots"); exit(EXIT_FAILURE); } + + loc_pop(&loc); } int main(int argc, char **argv, char **envp) @@ -2966,13 +2984,7 @@ int main(int argc, char **argv, char **envp) bool userconfig = true; const char *log_mask = NULL; const char *log_file = NULL; - GMemVTable mem_trace = { - .malloc = malloc_and_trace, - .realloc = realloc_and_trace, - .free = free_and_trace, - }; - const char *trace_events = NULL; - const char *trace_file = NULL; + char *trace_file = NULL; ram_addr_t maxram_size; uint64_t ram_slots = 0; FILE *vmstate_dump_file = NULL; @@ -2986,8 +2998,6 @@ int main(int argc, char **argv, char **envp) error_set_progname(argv[0]); qemu_init_exec_dir(argv[0]); - g_mem_set_vtable(&mem_trace); - module_call_init(MODULE_INIT_QOM); qemu_add_opts(&qemu_drive_opts); @@ -3018,12 +3028,12 @@ int main(int argc, char **argv, char **envp) qemu_add_opts(&qemu_icount_opts); qemu_add_opts(&qemu_semihosting_config_opts); qemu_add_opts(&qemu_fw_cfg_opts); + module_call_init(MODULE_INIT_OPTS); runstate_init(); if (qcrypto_init(&err) < 0) { - fprintf(stderr, "Cannot initialize crypto: %s\n", - error_get_pretty(err)); + error_reportf_err(err, "cannot initialize crypto: "); exit(1); } rtc_clock = QEMU_CLOCK_HOST; @@ -3031,8 +3041,6 @@ int main(int argc, char **argv, char **envp) QLIST_INIT (&vm_change_state_head); os_setup_early_signal_handling(); - module_call_init(MODULE_INIT_MACHINE); - machine_class = find_default_machine(); cpu_model = NULL; snapshot = 0; cyls = heads = secs = 0; @@ -3181,7 +3189,7 @@ int main(int argc, char **argv, char **envp) } } else if (*p != '\0') { chs_fail: - fprintf(stderr, "qemu: invalid physical CHS format\n"); + error_report("invalid physical CHS format"); exit(1); } if (hda_opts != NULL) { @@ -3224,7 +3232,7 @@ int main(int argc, char **argv, char **envp) #ifdef CONFIG_CURSES display_type = DT_CURSES; #else - fprintf(stderr, "Curses support is disabled\n"); + error_report("curses support is disabled"); exit(1); #endif break; @@ -3235,8 +3243,7 @@ int main(int argc, char **argv, char **envp) graphic_rotate = strtol(optarg, (char **) &optarg, 10); if (graphic_rotate != 0 && graphic_rotate != 90 && graphic_rotate != 180 && graphic_rotate != 270) { - fprintf(stderr, - "qemu: only 90, 180, 270 deg rotation is available\n"); + error_report("only 90, 180, 270 deg rotation is available"); exit(1); } break; @@ -3295,12 +3302,18 @@ int main(int argc, char **argv, char **envp) #endif #ifdef CONFIG_SLIRP case QEMU_OPTION_tftp: + error_report("The -tftp option is deprecated. " + "Please use '-netdev user,tftp=...' instead."); legacy_tftp_prefix = optarg; break; case QEMU_OPTION_bootp: + error_report("The -bootp option is deprecated. " + "Please use '-netdev user,bootfile=...' instead."); legacy_bootp_filename = optarg; break; case QEMU_OPTION_redir: + error_report("The -redir option is deprecated. " + "Please use '-netdev user,hostfwd=...' instead."); if (net_slirp_redir(optarg) < 0) exit(1); break; @@ -3348,6 +3361,9 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_D: log_file = optarg; break; + case QEMU_OPTION_DFILTER: + qemu_set_dfilter_ranges(optarg); + break; case QEMU_OPTION_s: add_device_config(DEV_GDB, "tcp::" DEFAULT_GDBSTUB_PORT); break; @@ -3387,7 +3403,7 @@ int main(int argc, char **argv, char **envp) w = strtol(p, (char **)&p, 10); if (w <= 0) { graphic_error: - fprintf(stderr, "qemu: invalid resolution or depth\n"); + error_report("invalid resolution or depth"); exit(1); } if (*p != 'x') @@ -3453,7 +3469,7 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_fsdev: olist = qemu_find_opts("fsdev"); if (!olist) { - fprintf(stderr, "fsdev is not supported by this qemu build.\n"); + error_report("fsdev support is disabled"); exit(1); } opts = qemu_opts_parse_noisily(olist, optarg, true); @@ -3468,7 +3484,7 @@ int main(int argc, char **argv, char **envp) olist = qemu_find_opts("virtfs"); if (!olist) { - fprintf(stderr, "virtfs is not supported by this qemu build.\n"); + error_report("virtfs support is disabled"); exit(1); } opts = qemu_opts_parse_noisily(olist, optarg, true); @@ -3478,15 +3494,15 @@ int main(int argc, char **argv, char **envp) if (qemu_opt_get(opts, "fsdriver") == NULL || qemu_opt_get(opts, "mount_tag") == NULL) { - fprintf(stderr, "Usage: -virtfs fsdriver,mount_tag=tag.\n"); + error_report("Usage: -virtfs fsdriver,mount_tag=tag"); exit(1); } fsdev = qemu_opts_create(qemu_find_opts("fsdev"), qemu_opt_get(opts, "mount_tag"), 1, NULL); if (!fsdev) { - fprintf(stderr, "duplicate fsdev id: %s\n", - qemu_opt_get(opts, "mount_tag")); + error_report("duplicate fsdev id: %s", + qemu_opt_get(opts, "mount_tag")); exit(1); } @@ -3495,8 +3511,8 @@ int main(int argc, char **argv, char **envp) #ifdef CONFIG_SYNC_FILE_RANGE qemu_opt_set(fsdev, "writeout", writeout, &error_abort); #else - fprintf(stderr, "writeout=immediate not supported on " - "this platform\n"); + error_report("writeout=immediate not supported " + "on this platform"); exit(1); #endif } @@ -3535,7 +3551,7 @@ int main(int argc, char **argv, char **envp) fsdev = qemu_opts_create(qemu_find_opts("fsdev"), "v_synth", 1, NULL); if (!fsdev) { - fprintf(stderr, "duplicate option: %s\n", "virtfs_synth"); + error_report("duplicate option: %s", "virtfs_synth"); exit(1); } qemu_opt_set(fsdev, "fsdriver", "synth", &error_abort); @@ -3556,15 +3572,14 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_watchdog: if (watchdog) { - fprintf(stderr, - "qemu: only one watchdog option may be given\n"); + error_report("only one watchdog option may be given"); return 1; } watchdog = optarg; break; case QEMU_OPTION_watchdog_action: if (select_watchdog_action(optarg) == -1) { - fprintf(stderr, "Unknown -watchdog-action parameter\n"); + error_report("unknown -watchdog-action parameter"); exit(1); } break; @@ -3608,7 +3623,7 @@ int main(int argc, char **argv, char **envp) display_type = DT_SDL; break; #else - fprintf(stderr, "SDL support is disabled\n"); + error_report("SDL support is disabled"); exit(1); #endif case QEMU_OPTION_pidfile: @@ -3670,8 +3685,7 @@ int main(int argc, char **argv, char **envp) qemu_opts_parse_noisily(olist, "accel=tcg", false); break; case QEMU_OPTION_no_kvm_pit: { - fprintf(stderr, "Warning: KVM PIT can no longer be disabled " - "separately.\n"); + error_report("warning: ignoring deprecated option"); break; } case QEMU_OPTION_no_kvm_pit_reinjection: { @@ -3684,8 +3698,8 @@ int main(int argc, char **argv, char **envp) { /* end of list */ } }; - fprintf(stderr, "Warning: option deprecated, use " - "lost_tick_policy property of kvm-pit instead.\n"); + error_report("warning: deprecated, replaced by " + "-global kvm-pit.lost_tick_policy=discard"); qdev_prop_register_global_list(kvm_pit_lost_tick_policy); break; } @@ -3720,7 +3734,7 @@ int main(int argc, char **argv, char **envp) exit(1); } #else - fprintf(stderr, "VNC support is disabled\n"); + error_report("VNC support is disabled"); exit(1); #endif break; @@ -3733,7 +3747,7 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_balloon: if (balloon_parse(optarg) < 0) { - fprintf(stderr, "Unknown -balloon argument %s\n", optarg); + error_report("unknown -balloon argument %s", optarg); exit(1); } break; @@ -3748,15 +3762,14 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_uuid: if(qemu_uuid_parse(optarg, qemu_uuid) < 0) { - fprintf(stderr, "Fail to parse UUID string." - " Wrong format.\n"); + error_report("failed to parse UUID string: wrong format"); exit(1); } qemu_uuid_set = true; break; case QEMU_OPTION_option_rom: if (nb_option_roms >= MAX_OPTION_ROMS) { - fprintf(stderr, "Too many option ROMs\n"); + error_report("too many option ROMs"); exit(1); } opts = qemu_opts_parse_noisily(qemu_find_opts("option-rom"), @@ -3768,7 +3781,7 @@ int main(int argc, char **argv, char **envp) option_rom[nb_option_roms].bootindex = qemu_opt_get_number(opts, "bootindex", -1); if (!option_rom[nb_option_roms].name) { - fprintf(stderr, "Option ROM file is not specified\n"); + error_report("Option ROM file is not specified"); exit(1); } nb_option_roms++; @@ -3793,9 +3806,8 @@ int main(int argc, char **argv, char **envp) } else if (strcmp("auto", target) == 0) { semihosting.target = SEMIHOSTING_TARGET_AUTO; } else { - fprintf(stderr, "Unsupported semihosting-config" - " %s\n", - optarg); + error_report("unsupported semihosting-config %s", + optarg); exit(1); } } else { @@ -3805,14 +3817,12 @@ int main(int argc, char **argv, char **envp) qemu_opt_foreach(opts, add_semihosting_arg, &semihosting, NULL); } else { - fprintf(stderr, "Unsupported semihosting-config %s\n", - optarg); + error_report("unsupported semihosting-config %s", optarg); exit(1); } break; case QEMU_OPTION_tdf: - fprintf(stderr, "Warning: user space PIT time drift fix " - "is no longer supported.\n"); + error_report("warning: ignoring deprecated option"); break; case QEMU_OPTION_name: opts = qemu_opts_parse_noisily(qemu_find_opts("name"), @@ -3823,7 +3833,7 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_prom_env: if (nb_prom_envs >= MAX_PROM_ENVS) { - fprintf(stderr, "Too many prom variables\n"); + error_report("too many prom variables"); exit(1); } prom_envs[nb_prom_envs] = optarg; @@ -3894,20 +3904,27 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_trace: { opts = qemu_opts_parse_noisily(qemu_find_opts("trace"), - optarg, false); + optarg, true); if (!opts) { exit(1); } - trace_events = qemu_opt_get(opts, "events"); - trace_file = qemu_opt_get(opts, "file"); + if (qemu_opt_get(opts, "enable")) { + trace_enable_events(qemu_opt_get(opts, "enable")); + } + trace_init_events(qemu_opt_get(opts, "events")); + if (trace_file) { + g_free(trace_file); + } + trace_file = g_strdup(qemu_opt_get(opts, "file")); + qemu_opts_del(opts); break; } case QEMU_OPTION_readconfig: { int ret = qemu_read_config_file(optarg); if (ret < 0) { - fprintf(stderr, "read config %s: %s\n", optarg, - strerror(-ret)); + error_report("read config %s: %s", optarg, + strerror(-ret)); exit(1); } break; @@ -3915,7 +3932,7 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_spice: olist = qemu_find_opts("spice"); if (!olist) { - fprintf(stderr, "spice is not supported by this qemu build.\n"); + error_report("spice support is disabled"); exit(1); } opts = qemu_opts_parse_noisily(olist, optarg, false); @@ -3932,7 +3949,8 @@ int main(int argc, char **argv, char **envp) } else { fp = fopen(optarg, "w"); if (fp == NULL) { - fprintf(stderr, "open %s: %s\n", optarg, strerror(errno)); + error_report("open %s: %s", optarg, + strerror(errno)); exit(1); } } @@ -3993,13 +4011,13 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_dump_vmstate: if (vmstate_dump_file) { - fprintf(stderr, "qemu: only one '-dump-vmstate' " - "option may be given\n"); + error_report("only one '-dump-vmstate' " + "option may be given"); exit(1); } vmstate_dump_file = fopen(optarg, "w"); if (vmstate_dump_file == NULL) { - fprintf(stderr, "open %s: %s\n", optarg, strerror(errno)); + error_report("open %s: %s", optarg, strerror(errno)); exit(1); } break; @@ -4008,23 +4026,18 @@ int main(int argc, char **argv, char **envp) } } } + /* + * Clear error location left behind by the loop. + * Best done right after the loop. Do not insert code here! + */ + loc_set_none(); - opts = qemu_get_machine_opts(); - optarg = qemu_opt_get(opts, "type"); - if (optarg) { - machine_class = machine_parse(optarg); - } + replay_configure(icount_opts); - if (machine_class == NULL) { - fprintf(stderr, "No machine specified, and there is no default.\n" - "Use -machine help to list supported machines!\n"); - exit(1); - } + machine_class = select_machine(); set_memory_options(&ram_slots, &maxram_size, machine_class); - loc_set_none(); - os_daemonize(); if (qemu_init_main_loop(&main_loop_err)) { @@ -4064,7 +4077,7 @@ int main(int argc, char **argv, char **envp) cpu_exec_init_all(); if (machine_class->hw_version) { - qemu_set_version(machine_class->hw_version); + qemu_set_hw_version(machine_class->hw_version); } /* Init CPU def lists, based on config @@ -4079,6 +4092,11 @@ int main(int argc, char **argv, char **envp) exit(0); } + if (!trace_init_backends()) { + exit(1); + } + trace_init_file(trace_file); + /* Open the logfile at this point and set the log mask if necessary. */ if (log_file) { @@ -4093,12 +4111,8 @@ int main(int argc, char **argv, char **envp) exit(1); } qemu_set_log(mask); - } - - if (!is_daemonized()) { - if (!trace_init_backends(trace_events, trace_file)) { - exit(1); - } + } else { + qemu_set_log(0); } /* If no data_dir is specified then try to find it relative to the @@ -4118,9 +4132,9 @@ int main(int argc, char **argv, char **envp) machine_class->max_cpus = machine_class->max_cpus ?: 1; /* Default to UP */ if (max_cpus > machine_class->max_cpus) { - fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus " - "supported by machine `%s' (%d)\n", max_cpus, - machine_class->name, machine_class->max_cpus); + error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " + "supported by machine '%s' (%d)", max_cpus, + machine_class->name, machine_class->max_cpus); exit(1); } @@ -4181,12 +4195,12 @@ int main(int argc, char **argv, char **envp) if (display_type == DT_NOGRAPHIC && (default_parallel || default_serial || default_monitor || default_virtcon)) { - fprintf(stderr, "-nographic can not be used with -daemonize\n"); + error_report("-nographic cannot be used with -daemonize"); exit(1); } #ifdef CONFIG_CURSES if (display_type == DT_CURSES) { - fprintf(stderr, "curses display can not be used with -daemonize\n"); + error_report("curses display cannot be used with -daemonize"); exit(1); } #endif @@ -4245,12 +4259,12 @@ int main(int argc, char **argv, char **envp) } if ((no_frame || alt_grab || ctrl_grab) && display_type != DT_SDL) { - fprintf(stderr, "-no-frame, -alt-grab and -ctrl-grab are only valid " - "for SDL, ignoring option\n"); + error_report("-no-frame, -alt-grab and -ctrl-grab are only valid " + "for SDL, ignoring option"); } if (no_quit && (display_type != DT_GTK && display_type != DT_SDL)) { - fprintf(stderr, "-no-quit is only valid for GTK and SDL, " - "ignoring option\n"); + error_report("-no-quit is only valid for GTK and SDL, " + "ignoring option"); } #if defined(CONFIG_GTK) @@ -4265,17 +4279,18 @@ int main(int argc, char **argv, char **envp) #endif if (request_opengl == 1 && display_opengl == 0) { #if defined(CONFIG_OPENGL) - fprintf(stderr, "OpenGL is not supported by the display.\n"); + error_report("OpenGL is not supported by the display"); #else - fprintf(stderr, "QEMU was built without opengl support.\n"); + error_report("OpenGL support is disabled"); #endif exit(1); } + page_size_init(); socket_init(); if (qemu_opts_foreach(qemu_find_opts("object"), - object_create, + user_creatable_add_opts_foreach, object_create_initial, NULL)) { exit(1); } @@ -4293,7 +4308,7 @@ int main(int argc, char **argv, char **envp) #endif if (pid_file && qemu_create_pidfile(pid_file) != 0) { - fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno)); + error_report("could not acquire pid file: %s", strerror(errno)); exit(1); } @@ -4302,12 +4317,6 @@ int main(int argc, char **argv, char **envp) exit(0); } - if (qemu_opts_foreach(qemu_find_opts("object"), - object_create, - object_create_delayed, NULL)) { - exit(1); - } - machine_opts = qemu_get_machine_opts(); if (qemu_opt_foreach(machine_opts, machine_set_property, current_machine, NULL)) { @@ -4318,12 +4327,7 @@ int main(int argc, char **argv, char **envp) configure_accelerator(current_machine); if (qtest_chrdev) { - Error *local_err = NULL; - qtest_init(qtest_chrdev, qtest_log, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } + qtest_init(qtest_chrdev, qtest_log, &error_fatal); } machine_opts = qemu_get_machine_opts(); @@ -4334,24 +4338,14 @@ int main(int argc, char **argv, char **envp) opts = qemu_opts_find(qemu_find_opts("boot-opts"), NULL); if (opts) { - Error *local_err = NULL; - boot_order = qemu_opt_get(opts, "order"); if (boot_order) { - validate_bootdevices(boot_order, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } + validate_bootdevices(boot_order, &error_fatal); } boot_once = qemu_opt_get(opts, "once"); if (boot_once) { - validate_bootdevices(boot_once, &local_err); - if (local_err) { - error_report_err(local_err); - exit(1); - } + validate_bootdevices(boot_once, &error_fatal); } boot_menu = qemu_opt_get_bool(opts, "menu", boot_menu); @@ -4370,17 +4364,17 @@ int main(int argc, char **argv, char **envp) linux_boot = (kernel_filename != NULL); if (!linux_boot && *kernel_cmdline != '\0') { - fprintf(stderr, "-append only allowed with -kernel option\n"); + error_report("-append only allowed with -kernel option"); exit(1); } if (!linux_boot && initrd_filename != NULL) { - fprintf(stderr, "-initrd only allowed with -kernel option\n"); + error_report("-initrd only allowed with -kernel option"); exit(1); } if (!linux_boot && qemu_opt_get(machine_opts, "dtb")) { - fprintf(stderr, "-dtb only allowed with -kernel option\n"); + error_report("-dtb only allowed with -kernel option"); exit(1); } @@ -4399,7 +4393,7 @@ int main(int argc, char **argv, char **envp) cpu_ticks_init(); if (icount_opts) { if (kvm_enabled() || xen_enabled()) { - fprintf(stderr, "-icount is not allowed with kvm or xen\n"); + error_report("-icount is not allowed with kvm or xen"); exit(1); } configure_icount(icount_opts, &error_abort); @@ -4413,6 +4407,12 @@ int main(int argc, char **argv, char **envp) exit(1); } + if (qemu_opts_foreach(qemu_find_opts("object"), + user_creatable_add_opts_foreach, + object_create_delayed, NULL)) { + exit(1); + } + #ifdef CONFIG_TPM if (tpm_init() < 0) { exit(1); @@ -4426,7 +4426,7 @@ int main(int argc, char **argv, char **envp) if (!xen_enabled()) { /* On 32-bit hosts, QEMU is limited by virtual address space */ if (ram_size > (2047 << 20) && HOST_LONG_BITS == 32) { - fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n"); + error_report("at most 2047 MB RAM can be simulated"); exit(1); } } @@ -4442,9 +4442,10 @@ int main(int argc, char **argv, char **envp) } /* open the virtual block devices */ - if (snapshot) - qemu_opts_foreach(qemu_find_opts("drive"), - drive_enable_snapshot, NULL, NULL); + if (snapshot || replay_mode != REPLAY_MODE_NONE) { + qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, + NULL, NULL); + } if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, &machine_class->block_default_type, NULL)) { exit(1); @@ -4499,6 +4500,10 @@ int main(int argc, char **argv, char **envp) } qemu_add_globals(); + /* This checkpoint is required by replay to separate prior clock + reading from the other reads, because timer polling functions query + clock values from the log. */ + replay_checkpoint(CHECKPOINT_INIT); qdev_machine_init(); current_machine->ram_size = ram_size; @@ -4528,11 +4533,16 @@ int main(int argc, char **argv, char **envp) exit(1); } + /* Check if IGD GFX passthrough. */ + igd_gfx_passthru(); + /* init generic devices */ + rom_set_order_override(FW_CFG_ORDER_OVERRIDE_DEVICE); if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, NULL)) { exit(1); } + rom_reset_order_override(); /* Did we create any drives that we failed to create a device for? */ drive_check_orphaned(); @@ -4540,12 +4550,7 @@ int main(int argc, char **argv, char **envp) net_check_clients(); if (boot_once) { - Error *local_err = NULL; - qemu_boot_set(boot_once, &local_err); - if (local_err) { - error_report("%s", error_get_pretty(local_err)); - exit(1); - } + qemu_boot_set(boot_once, &error_fatal); qemu_register_reset(restore_boot_order, g_strdup(boot_order)); } @@ -4588,7 +4593,7 @@ int main(int argc, char **argv, char **envp) vnc_init_func, NULL, NULL); if (show_vnc_port) { char *ret = vnc_display_local_addr("default"); - printf("VNC server running on `%s'\n", ret); + printf("VNC server running on '%s'\n", ret); g_free(ret); } #endif @@ -4610,10 +4615,16 @@ int main(int argc, char **argv, char **envp) qemu_run_machine_init_done_notifiers(); if (rom_check_and_register_reset() != 0) { - fprintf(stderr, "rom check and register reset failed\n"); + error_report("rom check and register reset failed"); exit(1); } + replay_start(); + + /* This checkpoint is required by replay to separate prior clock + reading from the other reads, because timer polling functions query + clock values from the log. */ + replay_checkpoint(CHECKPOINT_RESET); qemu_system_reset(VMRESET_SILENT); register_global_state(); if (loadvm) { @@ -4633,9 +4644,7 @@ int main(int argc, char **argv, char **envp) Error *local_err = NULL; qemu_start_incoming_migration(incoming, &local_err); if (local_err) { - error_report("-incoming %s: %s", incoming, - error_get_pretty(local_err)); - error_free(local_err); + error_reportf_err(local_err, "-incoming %s: ", incoming); exit(1); } } else if (autostart) { @@ -4644,13 +4653,9 @@ int main(int argc, char **argv, char **envp) os_setup_post(); - if (is_daemonized()) { - if (!trace_init_backends(trace_events, trace_file)) { - exit(1); - } - } - main_loop(); + replay_disable_events(); + bdrv_close_all(); pause_all_vcpus(); res_free();