#include <errno.h>
#include <sys/time.h>
#include <zlib.h>
+#include "bitmap.h"
/* Needed early for CONFIG_BSD etc. */
#include "config-host.h"
#include <linux/ppdev.h>
#include <linux/parport.h>
#endif
+
+#ifdef CONFIG_SECCOMP
+#include "qemu-seccomp.h"
+#endif
+
#ifdef __sun__
#include <sys/stat.h>
#include <sys/ethernet.h>
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;
int nb_numa_nodes;
uint64_t node_mem[MAX_NODES];
-uint64_t node_cpumask[MAX_NODES];
+unsigned long *node_cpumask[MAX_NODES];
uint8_t qemu_uuid[16];
{ .driver = "qxl-vga", .flag = &default_vga },
};
+const char *qemu_get_vm_name(void)
+{
+ return qemu_name;
+}
+
static void res_free(void)
{
if (boot_splash_filedata != NULL) {
{ 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 },
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 */
unsigned long long value, endvalue;
int nodenr;
+ value = endvalue = 0ULL;
+
optarg = get_opt_name(option, 128, optarg, ',') + 1;
if (!strcmp(option, "node")) {
if (get_param_value(option, 128, "nodeid", optarg) == 0) {
}
node_mem[nodenr] = sval;
}
- if (get_param_value(option, 128, "cpus", optarg) == 0) {
- node_cpumask[nodenr] = 0;
- } else {
+ if (get_param_value(option, 128, "cpus", optarg) != 0) {
value = strtoull(option, &endptr, 10);
- if (value >= 64) {
- value = 63;
- fprintf(stderr, "only 64 CPUs in NUMA mode supported.\n");
+ if (*endptr == '-') {
+ endvalue = strtoull(endptr+1, &endptr, 10);
} else {
- if (*endptr == '-') {
- endvalue = strtoull(endptr+1, &endptr, 10);
- if (endvalue >= 63) {
- endvalue = 62;
- fprintf(stderr,
- "only 63 CPUs in NUMA mode supported.\n");
- }
- value = (2ULL << endvalue) - (1ULL << value);
- } else {
- value = 1ULL << value;
- }
+ endvalue = value;
+ }
+
+ if (!(endvalue < MAX_CPUMASK_BITS)) {
+ endvalue = MAX_CPUMASK_BITS - 1;
+ fprintf(stderr,
+ "A max of %d CPUs are supported in a guest\n",
+ MAX_CPUMASK_BITS);
}
- node_cpumask[nodenr] = value;
+
+ bitmap_set(node_cpumask[nodenr], value, endvalue-value+1);
}
nb_numa_nodes++;
}
- return;
}
static void smp_parse(const char *optarg)
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);
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)
return NULL;
}
+MachineInfoList *qmp_query_machines(Error **errp)
+{
+ MachineInfoList *mach_list = NULL;
+ QEMUMachine *m;
+
+ for (m = first_machine; m; m = m->next) {
+ MachineInfoList *entry;
+ MachineInfo *info;
+
+ info = g_malloc0(sizeof(*info));
+ if (m->is_default) {
+ info->has_is_default = true;
+ info->is_default = true;
+ }
+
+ if (m->alias) {
+ info->has_alias = true;
+ info->alias = g_strdup(m->alias);
+ }
+
+ info->name = g_strdup(m->name);
+
+ entry = g_malloc0(sizeof(*entry));
+ entry->value = info;
+ entry->next = mach_list;
+ mach_list = entry;
+ }
+
+ return mach_list;
+}
+
/***********************************************************/
/* main execution loop */
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 =
return r;
}
+static int qemu_wakeup_requested(void)
+{
+ int r = wakeup_requested;
+ wakeup_requested = 0;
+ return r;
+}
+
int qemu_powerdown_requested(void)
{
int r = powerdown_requested;
}
}
-void qemu_system_reset(bool report)
+void qemu_devices_reset(void)
{
QEMUResetEntry *re, *nre;
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);
}
return;
}
runstate_set(RUN_STATE_RUNNING);
- monitor_protocol_event(QEVENT_WAKEUP, NULL);
notifier_list_notify(&wakeup_notifiers, &reason);
- reset_requested = 1;
+ wakeup_requested = 1;
qemu_notify_event();
}
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;
qemu_notify_event();
}
-qemu_irq qemu_system_powerdown;
-
static bool main_loop_should_exit(void)
{
RunState r;
runstate_set(RUN_STATE_PAUSED);
}
}
+ if (qemu_wakeup_requested()) {
+ pause_all_vcpus();
+ cpu_synchronize_all_states();
+ qemu_system_reset(VMRESET_SILENT);
+ resume_all_vcpus();
+ 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);
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)
} 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);
for (i = 0; i < MAX_NODES; i++) {
node_mem[i] = 0;
- node_cpumask[i] = 0;
+ node_cpumask[i] = bitmap_new(MAX_CPUMASK_BITS);
}
nb_numa_nodes = 0;
{
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;
break;
case QEMU_OPTION_m: {
int64_t value;
+ uint64_t sz;
char *end;
value = strtosz(optarg, &end);
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:
}
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:
case QEMU_OPTION_qtest_log:
qtest_log = optarg;
break;
- case QEMU_OPTION_enablefips:
- fips_set_state(true);
+ 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);
}
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);
+ }
+
if (machine->hw_version) {
qemu_set_version(machine->hw_version);
}
data_dir = CONFIG_QEMU_DATADIR;
}
- if (machine == NULL) {
- fprintf(stderr, "No machine found.\n");
- exit(1);
- }
-
/*
* Default to max_cpus = smp_cpus, in case the user doesn't
* specify a max_cpus value.
ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
}
+ if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0)
+ != 0) {
+ exit(0);
+ }
+
configure_accelerator();
qemu_init_cpu_loop();
}
for (i = 0; i < nb_numa_nodes; i++) {
- if (node_cpumask[i] != 0)
+ if (!bitmap_empty(node_cpumask[i], MAX_CPUMASK_BITS)) {
break;
+ }
}
/* assigning the VCPUs round-robin is easier to implement, guest OSes
* must cope with this anyway, because there are BIOSes out there in
*/
if (i == nb_numa_nodes) {
for (i = 0; i < max_cpus; i++) {
- node_cpumask[i % nb_numa_nodes] |= 1 << i;
+ set_bit(i, node_cpumask[i % nb_numa_nodes]);
}
}
}
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);
- if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0)
- exit(0);
-
if (watchdog) {
i = select_watchdog(watchdog);
if (i > 0)
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();
current_machine = machine;
/* init USB devices */
- if (usb_enabled) {
+ if (usb_enabled(false)) {
if (foreach_device_config(DEV_USB, usb_parse) < 0)
exit(1);
}
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)
#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);
}
}
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();