X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/452dfbef600837c0e430564ea9e35138ef48f24c..af13ae03f8dbc02974d53b11b80b3ae4dd9f30b4:/vl.c diff --git a/vl.c b/vl.c index 1010248dcd..5a3d316980 100644 --- a/vl.c +++ b/vl.c @@ -203,7 +203,6 @@ CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES]; int win2k_install_hack = 0; -int usb_enabled = 0; int singlestep = 0; int smp_cpus = 1; int max_cpus = 0; @@ -341,7 +340,7 @@ static const RunStateTransition runstate_transitions_def[] = { { RUN_STATE_DEBUG, RUN_STATE_RUNNING }, { RUN_STATE_INMIGRATE, RUN_STATE_RUNNING }, - { RUN_STATE_INMIGRATE, RUN_STATE_PRELAUNCH }, + { RUN_STATE_INMIGRATE, RUN_STATE_PAUSED }, { RUN_STATE_INTERNAL_ERROR, RUN_STATE_PAUSED }, { RUN_STATE_INTERNAL_ERROR, RUN_STATE_FINISH_MIGRATE }, @@ -770,6 +769,109 @@ static int bt_parse(const char *opt) return 1; } +static int parse_sandbox(QemuOpts *opts, void *opaque) +{ + /* FIXME: change this to true for 1.3 */ + if (qemu_opt_get_bool(opts, "enable", false)) { +#ifdef CONFIG_SECCOMP + if (seccomp_start() < 0) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "failed to install seccomp syscall filter in the kernel"); + return -1; + } +#else + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "sandboxing request but seccomp is not compiled into this build"); + return -1; +#endif + } + + return 0; +} + +/*********QEMU USB setting******/ +bool usb_enabled(bool default_usb) +{ + QemuOpts *mach_opts; + mach_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (mach_opts) { + return qemu_opt_get_bool(mach_opts, "usb", default_usb); + } + return default_usb; +} + +#ifndef _WIN32 +static int parse_add_fd(QemuOpts *opts, void *opaque) +{ + int fd, dupfd, flags; + int64_t fdset_id; + const char *fd_opaque = NULL; + + fd = qemu_opt_get_number(opts, "fd", -1); + fdset_id = qemu_opt_get_number(opts, "set", -1); + fd_opaque = qemu_opt_get(opts, "opaque"); + + if (fd < 0) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "fd option is required and must be non-negative"); + return -1; + } + + if (fd <= STDERR_FILENO) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "fd cannot be a standard I/O stream"); + return -1; + } + + /* + * All fds inherited across exec() necessarily have FD_CLOEXEC + * clear, while qemu sets FD_CLOEXEC on all other fds used internally. + */ + flags = fcntl(fd, F_GETFD); + if (flags == -1 || (flags & FD_CLOEXEC)) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "fd is not valid or already in use"); + return -1; + } + + if (fdset_id < 0) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "set option is required and must be non-negative"); + return -1; + } + +#ifdef F_DUPFD_CLOEXEC + dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0); +#else + dupfd = dup(fd); + if (dupfd != -1) { + qemu_set_cloexec(dupfd); + } +#endif + if (dupfd == -1) { + qerror_report(ERROR_CLASS_GENERIC_ERROR, + "Error duplicating fd: %s", strerror(errno)); + return -1; + } + + /* add the duplicate fd, and optionally the opaque string, to the fd set */ + monitor_fdset_add_fd(dupfd, true, fdset_id, fd_opaque ? true : false, + fd_opaque, NULL); + + return 0; +} + +static int cleanup_add_fd(QemuOpts *opts, void *opaque) +{ + int fd; + + fd = qemu_opt_get_number(opts, "fd", -1); + close(fd); + + return 0; +} +#endif + /***********************************************************/ /* QEMU Block devices */ @@ -1003,7 +1105,6 @@ static void numa_add(const char *optarg) } nb_numa_nodes++; } - return; } static void smp_parse(const char *optarg) @@ -1058,8 +1159,9 @@ static int usb_device_add(const char *devname) const char *p; USBDevice *dev = NULL; - if (!usb_enabled) + if (!usb_enabled(false)) { return -1; + } /* drivers with .usbdevice_name entry in USBDeviceInfo */ dev = usbdevice_create(devname); @@ -1095,8 +1197,9 @@ static int usb_device_del(const char *devname) if (strstart(devname, "host:", &p)) return usb_host_device_close(p); - if (!usb_enabled) + if (!usb_enabled(false)) { return -1; + } p = strchr(devname, '.'); if (!p) @@ -1335,6 +1438,8 @@ static int powerdown_requested; static int debug_requested; static int suspend_requested; static int wakeup_requested; +static NotifierList powerdown_notifiers = + NOTIFIER_LIST_INITIALIZER(powerdown_notifiers); static NotifierList suspend_notifiers = NOTIFIER_LIST_INITIALIZER(suspend_notifiers); static NotifierList wakeup_notifiers = @@ -1444,7 +1549,7 @@ void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) } } -void qemu_system_reset(bool report) +void qemu_devices_reset(void) { QEMUResetEntry *re, *nre; @@ -1452,6 +1557,15 @@ void qemu_system_reset(bool report) QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) { re->func(re->opaque); } +} + +void qemu_system_reset(bool report) +{ + if (current_machine && current_machine->reset) { + current_machine->reset(); + } else { + qemu_devices_reset(); + } if (report) { monitor_protocol_event(QEVENT_RESET, NULL); } @@ -1534,12 +1648,23 @@ void qemu_system_shutdown_request(void) qemu_notify_event(); } +static void qemu_system_powerdown(void) +{ + monitor_protocol_event(QEVENT_POWERDOWN, NULL); + notifier_list_notify(&powerdown_notifiers, NULL); +} + void qemu_system_powerdown_request(void) { powerdown_requested = 1; qemu_notify_event(); } +void qemu_register_powerdown_notifier(Notifier *notifier) +{ + notifier_list_add(&powerdown_notifiers, notifier); +} + void qemu_system_debug_request(void) { debug_requested = 1; @@ -1552,8 +1677,6 @@ void qemu_system_vmstop_request(RunState state) qemu_notify_event(); } -qemu_irq qemu_system_powerdown; - static bool main_loop_should_exit(void) { RunState r; @@ -1590,8 +1713,7 @@ static bool main_loop_should_exit(void) monitor_protocol_event(QEVENT_WAKEUP, NULL); } if (qemu_powerdown_requested()) { - monitor_protocol_event(QEVENT_POWERDOWN, NULL); - qemu_irq_raise(qemu_system_powerdown); + qemu_system_powerdown(); } if (qemu_vmstop_requested(&r)) { vm_stop(r); @@ -1661,17 +1783,23 @@ static const QEMUOption qemu_options[] = { static bool vga_available(void) { - return qdev_exists("VGA") || qdev_exists("isa-vga"); + return object_class_by_name("VGA") || object_class_by_name("isa-vga"); } static bool cirrus_vga_available(void) { - return qdev_exists("cirrus-vga") || qdev_exists("isa-cirrus-vga"); + return object_class_by_name("cirrus-vga") + || object_class_by_name("isa-cirrus-vga"); } static bool vmware_vga_available(void) { - return qdev_exists("vmware-svga"); + return object_class_by_name("vmware-svga"); +} + +static bool qxl_vga_available(void) +{ + return object_class_by_name("qxl-vga"); } static void select_vgahw (const char *p) @@ -1703,7 +1831,12 @@ static void select_vgahw (const char *p) } else if (strstart(p, "xenfb", &opts)) { vga_interface_type = VGA_XENFB; } else if (strstart(p, "qxl", &opts)) { - vga_interface_type = VGA_QXL; + if (qxl_vga_available()) { + vga_interface_type = VGA_QXL; + } else { + fprintf(stderr, "Error: QXL VGA not available\n"); + exit(0); + } } else if (!strstart(p, "none", &opts)) { invalid_vga: fprintf(stderr, "Unknown vga type: %s\n", p); @@ -2349,14 +2482,6 @@ int main(int argc, char **argv, char **envp) const char *trace_events = NULL; const char *trace_file = NULL; -#ifdef CONFIG_SECCOMP - if (seccomp_start() < 0) { - fprintf(stderr, - "seccomp: failed to install syscall filter in the kernel\n"); - exit(1); - } -#endif - atexit(qemu_run_exit_notifiers); error_set_progname(argv[0]); @@ -2601,7 +2726,8 @@ int main(int argc, char **argv, char **envp) { static const char * const params[] = { "order", "once", "menu", - "splash", "splash-time", NULL + "splash", "splash-time", + "reboot-timeout", NULL }; char buf[sizeof(boot_devices)]; char *standard_boot_devices; @@ -2714,6 +2840,7 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_m: { int64_t value; + uint64_t sz; char *end; value = strtosz(optarg, &end); @@ -2721,12 +2848,12 @@ int main(int argc, char **argv, char **envp) fprintf(stderr, "qemu: invalid ram size: %s\n", optarg); exit(1); } - - if (value != (uint64_t)(ram_addr_t)value) { + sz = QEMU_ALIGN_UP((uint64_t)value, 8192); + ram_size = sz; + if (ram_size != sz) { fprintf(stderr, "qemu: ram size too large\n"); exit(1); } - ram_size = value; break; } case QEMU_OPTION_mempath: @@ -3040,10 +3167,16 @@ int main(int argc, char **argv, char **envp) } break; case QEMU_OPTION_usb: - usb_enabled = 1; + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + qemu_opt_set_bool(machine_opts, "usb", true); + } break; case QEMU_OPTION_usbdevice: - usb_enabled = 1; + machine_opts = qemu_opts_find(qemu_find_opts("machine"), 0); + if (machine_opts) { + qemu_opt_set_bool(machine_opts, "usb", true); + } add_device_config(DEV_USB, optarg); break; case QEMU_OPTION_device: @@ -3260,6 +3393,24 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_qtest_log: qtest_log = optarg; break; + case QEMU_OPTION_sandbox: + opts = qemu_opts_parse(qemu_find_opts("sandbox"), optarg, 1); + if (!opts) { + exit(0); + } + break; + case QEMU_OPTION_add_fd: +#ifndef _WIN32 + opts = qemu_opts_parse(qemu_find_opts("add-fd"), optarg, 0); + if (!opts) { + exit(0); + } +#else + error_report("File descriptor passing is disabled on this " + "platform"); + exit(1); +#endif + break; default: os_parse_cmd_args(popt->index, optarg); } @@ -3267,6 +3418,20 @@ int main(int argc, char **argv, char **envp) } loc_set_none(); + if (qemu_opts_foreach(qemu_find_opts("sandbox"), parse_sandbox, NULL, 0)) { + exit(1); + } + +#ifndef _WIN32 + if (qemu_opts_foreach(qemu_find_opts("add-fd"), parse_add_fd, NULL, 1)) { + exit(1); + } + + if (qemu_opts_foreach(qemu_find_opts("add-fd"), cleanup_add_fd, NULL, 1)) { + exit(1); + } +#endif + if (machine == NULL) { fprintf(stderr, "No machine found.\n"); exit(1); @@ -3563,8 +3728,12 @@ int main(int argc, char **argv, char **envp) exit(1); /* If no default VGA is requested, the default is "none". */ - if (default_vga && cirrus_vga_available()) { - vga_model = "cirrus"; + if (default_vga) { + if (cirrus_vga_available()) { + vga_model = "cirrus"; + } else if (vga_available()) { + vga_model = "std"; + } } select_vgahw(vga_model); @@ -3581,8 +3750,13 @@ int main(int argc, char **argv, char **envp) qdev_machine_init(); - machine->init(ram_size, boot_devices, - kernel_filename, kernel_cmdline, initrd_filename, cpu_model); + QEMUMachineInitArgs args = { .ram_size = ram_size, + .boot_device = boot_devices, + .kernel_filename = kernel_filename, + .kernel_cmdline = kernel_cmdline, + .initrd_filename = initrd_filename, + .cpu_model = cpu_model }; + machine->init(&args); cpu_synchronize_all_post_init(); @@ -3591,7 +3765,7 @@ int main(int argc, char **argv, char **envp) current_machine = machine; /* init USB devices */ - if (usb_enabled) { + if (usb_enabled(false)) { if (foreach_device_config(DEV_USB, usb_parse) < 0) exit(1); } @@ -3625,7 +3799,9 @@ int main(int argc, char **argv, char **envp) break; #if defined(CONFIG_CURSES) case DT_CURSES: - curses_display_init(ds, full_screen); + if (!is_daemonized()) { + curses_display_init(ds, full_screen); + } break; #endif #if defined(CONFIG_SDL) @@ -3647,10 +3823,13 @@ int main(int argc, char **argv, char **envp) #ifdef CONFIG_VNC /* init remote displays */ if (vnc_display) { + Error *local_err = NULL; vnc_display_init(ds); - if (vnc_display_open(ds, vnc_display) < 0) { - fprintf(stderr, "Failed to start VNC server on `%s'\n", - vnc_display); + vnc_display_open(ds, vnc_display, &local_err); + if (local_err != NULL) { + fprintf(stderr, "Failed to start VNC server on `%s': %s\n", + vnc_display, error_get_pretty(local_err)); + error_free(local_err); exit(1); } @@ -3702,16 +3881,12 @@ int main(int argc, char **argv, char **envp) } if (incoming) { - Error *errp = NULL; - int ret = qemu_start_incoming_migration(incoming, &errp); - if (ret < 0) { - if (error_is_set(&errp)) { - fprintf(stderr, "Migrate: %s\n", error_get_pretty(errp)); - error_free(errp); - } - fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n", - incoming, ret); - exit(ret); + Error *local_err = NULL; + qemu_start_incoming_migration(incoming, &local_err); + if (local_err) { + fprintf(stderr, "-incoming %s: %s\n", incoming, error_get_pretty(local_err)); + error_free(local_err); + exit(1); } } else if (autostart) { vm_start();