#ifndef _WIN32
#include <libgen.h>
-#include <pwd.h>
#include <sys/times.h>
#include <sys/wait.h>
#include <termios.h>
#include <sys/stat.h>
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#include <libutil.h>
+#include <sys/sysctl.h>
#else
#include <util.h>
#endif
#ifdef __linux__
#include <pty.h>
#include <malloc.h>
-#include <sys/prctl.h>
#include <linux/ppdev.h>
#include <linux/parport.h>
#include <sys/ethernet.h>
#include <sys/sockio.h>
#include <netinet/arp.h>
-#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h> // must come after ip.h
#include "hw/usb.h"
#include "hw/pcmcia.h"
#include "hw/pc.h"
-#include "hw/audiodev.h"
#include "hw/isa.h"
#include "hw/baum.h"
#include "hw/bt.h"
#include "qemu-char.h"
#include "cache-utils.h"
#include "block.h"
-#include "block_int.h"
+#include "blockdev.h"
#include "block-migration.h"
#include "dma.h"
#include "audio/audio.h"
#include "migration.h"
#include "kvm.h"
-#include "balloon.h"
#include "qemu-option.h"
#include "qemu-config.h"
#include "qemu-objects.h"
+#include "qemu-options.h"
+#ifdef CONFIG_VIRTFS
+#include "fsdev/qemu-fsdev.h"
+#endif
#include "disas.h"
-#include "exec-all.h"
-
#include "qemu_socket.h"
#include "slirp/libslirp.h"
#include "qemu-queue.h"
+#include "cpus.h"
+#include "arch_init.h"
//#define DEBUG_NET
//#define DEBUG_SLIRP
static const char *data_dir;
const char *bios_name = NULL;
-/* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
- to store the VM snapshots */
-struct drivelist drives = QTAILQ_HEAD_INITIALIZER(drives);
-struct driveoptlist driveopts = QTAILQ_HEAD_INITIALIZER(driveopts);
enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
DisplayType display_type = DT_DEFAULT;
const char* keyboard_layout = NULL;
NICInfo nd_table[MAX_NICS];
int vm_running;
int autostart;
+int incoming_expected; /* Started with -incoming and waiting for incoming */
static int rtc_utc = 1;
static int rtc_date_offset = -1; /* -1 means no change */
QEMUClock *rtc_clock;
int vga_interface_type = VGA_NONE;
-#ifdef TARGET_SPARC
-int graphic_width = 1024;
-int graphic_height = 768;
-int graphic_depth = 8;
-#else
-int graphic_width = 800;
-int graphic_height = 600;
-int graphic_depth = 15;
-#endif
static int full_screen = 0;
#ifdef CONFIG_SDL
static int no_frame = 0;
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
int win2k_install_hack = 0;
-#ifdef TARGET_I386
int rtc_td_hack = 0;
-#endif
int usb_enabled = 0;
int singlestep = 0;
int smp_cpus = 1;
int cursor_hide = 1;
int graphic_rotate = 0;
uint8_t irq0override = 1;
-#ifndef _WIN32
-int daemonize = 0;
-#endif
const char *watchdog;
const char *option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
int semihosting_enabled = 0;
-#ifdef TARGET_ARM
int old_param = 0;
-#endif
const char *qemu_name;
int alt_grab = 0;
int ctrl_grab = 0;
-#if defined(TARGET_SPARC) || defined(TARGET_PPC)
unsigned int nb_prom_envs = 0;
const char *prom_envs[MAX_PROM_ENVS];
-#endif
int boot_menu;
int nb_numa_nodes;
uint64_t node_mem[MAX_NODES];
uint64_t node_cpumask[MAX_NODES];
-static CPUState *cur_cpu;
-static CPUState *next_cpu;
static QEMUTimer *nographic_timer;
uint8_t qemu_uuid[16];
static QEMUBootSetHandler *boot_set_handler;
static void *boot_set_opaque;
-#ifdef SIGRTMIN
-#define SIG_IPI (SIGRTMIN+4)
-#else
-#define SIG_IPI SIGUSR1
-#endif
+static NotifierList exit_notifiers =
+ NOTIFIER_LIST_INITIALIZER(exit_notifiers);
+
+int kvm_allowed = 0;
+uint32_t xen_domid;
+enum xen_mode xen_mode = XEN_EMULATE;
static int default_serial = 1;
static int default_parallel = 1;
return 0;
}
-/***********************************************************/
-/* x86 ISA bus support */
-
-target_phys_addr_t isa_mem_base = 0;
-PicState2 *isa_pic;
-
-/***********************************************************/
-void hw_error(const char *fmt, ...)
-{
- va_list ap;
- CPUState *env;
-
- va_start(ap, fmt);
- fprintf(stderr, "qemu: hardware error: ");
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- for(env = first_cpu; env != NULL; env = env->next_cpu) {
- fprintf(stderr, "CPU #%d:\n", env->cpu_index);
-#ifdef TARGET_I386
- cpu_dump_state(env, stderr, fprintf, X86_DUMP_FPU);
-#else
- cpu_dump_state(env, stderr, fprintf, 0);
-#endif
- }
- va_end(ap);
- abort();
-}
-
-static void set_proc_name(const char *s)
-{
-#if defined(__linux__) && defined(PR_SET_NAME)
- char name[16];
- if (!s)
- return;
- name[sizeof(name) - 1] = 0;
- strncpy(name, s, sizeof(name));
- /* Could rewrite argv[0] too, but that's a bit more complicated.
- This simple way is enough for `top'. */
- prctl(PR_SET_NAME, name);
-#endif
-}
-
-/***************/
-/* ballooning */
-
-static QEMUBalloonEvent *qemu_balloon_event;
-void *qemu_balloon_event_opaque;
-
-void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
-{
- qemu_balloon_event = func;
- qemu_balloon_event_opaque = opaque;
-}
-
-int qemu_balloon(ram_addr_t target, MonitorCompletion cb, void *opaque)
-{
- if (qemu_balloon_event) {
- qemu_balloon_event(qemu_balloon_event_opaque, target, cb, opaque);
- return 1;
- } else {
- return 0;
- }
-}
-
-int qemu_balloon_status(MonitorCompletion cb, void *opaque)
-{
- if (qemu_balloon_event) {
- qemu_balloon_event(qemu_balloon_event_opaque, 0, cb, opaque);
- return 1;
- } else {
- return 0;
- }
-}
-
-
/***********************************************************/
/* real time host monotonic timer */
exit(1);
}
}
-#ifdef CONFIG_TARGET_I386
value = qemu_opt_get(opts, "driftfix");
if (value) {
- if (!strcmp(buf, "slew")) {
+ if (!strcmp(value, "slew")) {
rtc_td_hack = 1;
- } else if (!strcmp(buf, "none")) {
+ } else if (!strcmp(value, "none")) {
rtc_td_hack = 0;
} else {
fprintf(stderr, "qemu: invalid option value '%s'\n", value);
exit(1);
}
}
-#endif
-}
-
-#ifdef _WIN32
-static void socket_cleanup(void)
-{
- WSACleanup();
-}
-
-static int socket_init(void)
-{
- WSADATA Data;
- int ret, err;
-
- ret = WSAStartup(MAKEWORD(2,2), &Data);
- if (ret != 0) {
- err = WSAGetLastError();
- fprintf(stderr, "WSAStartup: %d\n", err);
- return -1;
- }
- atexit(socket_cleanup);
- return 0;
}
-#endif
/***********************************************************/
/* Bluetooth support */
#define MTD_ALIAS "if=mtd"
#define SD_ALIAS "index=0,if=sd"
-QemuOpts *drive_add(const char *file, const char *fmt, ...)
-{
- va_list ap;
- char optstr[1024];
- QemuOpts *opts;
-
- va_start(ap, fmt);
- vsnprintf(optstr, sizeof(optstr), fmt, ap);
- va_end(ap);
-
- opts = qemu_opts_parse(&qemu_drive_opts, optstr, 0);
- if (!opts) {
- fprintf(stderr, "%s: huh? duplicate? (%s)\n",
- __FUNCTION__, optstr);
- return NULL;
- }
- if (file)
- qemu_opt_set(opts, "file", file);
- return opts;
-}
-
-DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
-{
- DriveInfo *dinfo;
-
- /* seek interface, bus and unit */
-
- QTAILQ_FOREACH(dinfo, &drives, next) {
- if (dinfo->type == type &&
- dinfo->bus == bus &&
- dinfo->unit == unit)
- return dinfo;
- }
-
- return NULL;
-}
-
-DriveInfo *drive_get_by_id(const char *id)
-{
- DriveInfo *dinfo;
-
- QTAILQ_FOREACH(dinfo, &drives, next) {
- if (strcmp(id, dinfo->id))
- continue;
- return dinfo;
- }
- return NULL;
-}
-
-int drive_get_max_bus(BlockInterfaceType type)
-{
- int max_bus;
- DriveInfo *dinfo;
-
- max_bus = -1;
- QTAILQ_FOREACH(dinfo, &drives, next) {
- if(dinfo->type == type &&
- dinfo->bus > max_bus)
- max_bus = dinfo->bus;
- }
- return max_bus;
-}
-
-const char *drive_get_serial(BlockDriverState *bdrv)
-{
- DriveInfo *dinfo;
-
- QTAILQ_FOREACH(dinfo, &drives, next) {
- if (dinfo->bdrv == bdrv)
- return dinfo->serial;
- }
-
- return "\0";
-}
-
-BlockInterfaceErrorAction drive_get_on_error(
- BlockDriverState *bdrv, int is_read)
-{
- DriveInfo *dinfo;
-
- QTAILQ_FOREACH(dinfo, &drives, next) {
- if (dinfo->bdrv == bdrv)
- return is_read ? dinfo->on_read_error : dinfo->on_write_error;
- }
-
- return is_read ? BLOCK_ERR_REPORT : BLOCK_ERR_STOP_ENOSPC;
-}
-
-static void bdrv_format_print(void *opaque, const char *name)
-{
- fprintf(stderr, " %s", name);
-}
-
-void drive_uninit(DriveInfo *dinfo)
-{
- qemu_opts_del(dinfo->opts);
- bdrv_delete(dinfo->bdrv);
- QTAILQ_REMOVE(&drives, dinfo, next);
- qemu_free(dinfo);
-}
-
-static int parse_block_error_action(const char *buf, int is_read)
-{
- if (!strcmp(buf, "ignore")) {
- return BLOCK_ERR_IGNORE;
- } else if (!is_read && !strcmp(buf, "enospc")) {
- return BLOCK_ERR_STOP_ENOSPC;
- } else if (!strcmp(buf, "stop")) {
- return BLOCK_ERR_STOP_ANY;
- } else if (!strcmp(buf, "report")) {
- return BLOCK_ERR_REPORT;
- } else {
- fprintf(stderr, "qemu: '%s' invalid %s error action\n",
- buf, is_read ? "read" : "write");
- return -1;
- }
-}
-
-DriveInfo *drive_init(QemuOpts *opts, void *opaque,
- int *fatal_error)
-{
- const char *buf;
- const char *file = NULL;
- char devname[128];
- const char *serial;
- const char *mediastr = "";
- BlockInterfaceType type;
- enum { MEDIA_DISK, MEDIA_CDROM } media;
- int bus_id, unit_id;
- int cyls, heads, secs, translation;
- BlockDriver *drv = NULL;
- QEMUMachine *machine = opaque;
- int max_devs;
- int index;
- int cache;
- int aio = 0;
- int ro = 0;
- int bdrv_flags;
- int on_read_error, on_write_error;
- const char *devaddr;
- DriveInfo *dinfo;
- int snapshot = 0;
-
- *fatal_error = 1;
-
- translation = BIOS_ATA_TRANSLATION_AUTO;
- cache = 1;
-
- if (machine && machine->use_scsi) {
- type = IF_SCSI;
- max_devs = MAX_SCSI_DEVS;
- pstrcpy(devname, sizeof(devname), "scsi");
- } else {
- type = IF_IDE;
- max_devs = MAX_IDE_DEVS;
- pstrcpy(devname, sizeof(devname), "ide");
- }
- media = MEDIA_DISK;
-
- /* extract parameters */
- bus_id = qemu_opt_get_number(opts, "bus", 0);
- unit_id = qemu_opt_get_number(opts, "unit", -1);
- index = qemu_opt_get_number(opts, "index", -1);
-
- cyls = qemu_opt_get_number(opts, "cyls", 0);
- heads = qemu_opt_get_number(opts, "heads", 0);
- secs = qemu_opt_get_number(opts, "secs", 0);
-
- snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
- ro = qemu_opt_get_bool(opts, "readonly", 0);
-
- file = qemu_opt_get(opts, "file");
- serial = qemu_opt_get(opts, "serial");
-
- if ((buf = qemu_opt_get(opts, "if")) != NULL) {
- pstrcpy(devname, sizeof(devname), buf);
- if (!strcmp(buf, "ide")) {
- type = IF_IDE;
- max_devs = MAX_IDE_DEVS;
- } else if (!strcmp(buf, "scsi")) {
- type = IF_SCSI;
- max_devs = MAX_SCSI_DEVS;
- } else if (!strcmp(buf, "floppy")) {
- type = IF_FLOPPY;
- max_devs = 0;
- } else if (!strcmp(buf, "pflash")) {
- type = IF_PFLASH;
- max_devs = 0;
- } else if (!strcmp(buf, "mtd")) {
- type = IF_MTD;
- max_devs = 0;
- } else if (!strcmp(buf, "sd")) {
- type = IF_SD;
- max_devs = 0;
- } else if (!strcmp(buf, "virtio")) {
- type = IF_VIRTIO;
- max_devs = 0;
- } else if (!strcmp(buf, "xen")) {
- type = IF_XEN;
- max_devs = 0;
- } else if (!strcmp(buf, "none")) {
- type = IF_NONE;
- max_devs = 0;
- } else {
- fprintf(stderr, "qemu: unsupported bus type '%s'\n", buf);
- return NULL;
- }
- }
-
- if (cyls || heads || secs) {
- if (cyls < 1 || (type == IF_IDE && cyls > 16383)) {
- fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", buf);
- return NULL;
- }
- if (heads < 1 || (type == IF_IDE && heads > 16)) {
- fprintf(stderr, "qemu: '%s' invalid physical heads number\n", buf);
- return NULL;
- }
- if (secs < 1 || (type == IF_IDE && secs > 63)) {
- fprintf(stderr, "qemu: '%s' invalid physical secs number\n", buf);
- return NULL;
- }
- }
-
- if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
- if (!cyls) {
- fprintf(stderr,
- "qemu: '%s' trans must be used with cyls,heads and secs\n",
- buf);
- return NULL;
- }
- if (!strcmp(buf, "none"))
- translation = BIOS_ATA_TRANSLATION_NONE;
- else if (!strcmp(buf, "lba"))
- translation = BIOS_ATA_TRANSLATION_LBA;
- else if (!strcmp(buf, "auto"))
- translation = BIOS_ATA_TRANSLATION_AUTO;
- else {
- fprintf(stderr, "qemu: '%s' invalid translation type\n", buf);
- return NULL;
- }
- }
-
- if ((buf = qemu_opt_get(opts, "media")) != NULL) {
- if (!strcmp(buf, "disk")) {
- media = MEDIA_DISK;
- } else if (!strcmp(buf, "cdrom")) {
- if (cyls || secs || heads) {
- fprintf(stderr,
- "qemu: '%s' invalid physical CHS format\n", buf);
- return NULL;
- }
- media = MEDIA_CDROM;
- } else {
- fprintf(stderr, "qemu: '%s' invalid media\n", buf);
- return NULL;
- }
- }
-
- if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
- if (!strcmp(buf, "off") || !strcmp(buf, "none"))
- cache = 0;
- else if (!strcmp(buf, "writethrough"))
- cache = 1;
- else if (!strcmp(buf, "writeback"))
- cache = 2;
- else {
- fprintf(stderr, "qemu: invalid cache option\n");
- return NULL;
- }
- }
-
-#ifdef CONFIG_LINUX_AIO
- if ((buf = qemu_opt_get(opts, "aio")) != NULL) {
- if (!strcmp(buf, "threads"))
- aio = 0;
- else if (!strcmp(buf, "native"))
- aio = 1;
- else {
- fprintf(stderr, "qemu: invalid aio option\n");
- return NULL;
- }
- }
-#endif
-
- if ((buf = qemu_opt_get(opts, "format")) != NULL) {
- if (strcmp(buf, "?") == 0) {
- fprintf(stderr, "qemu: Supported formats:");
- bdrv_iterate_format(bdrv_format_print, NULL);
- fprintf(stderr, "\n");
- return NULL;
- }
- drv = bdrv_find_whitelisted_format(buf);
- if (!drv) {
- fprintf(stderr, "qemu: '%s' invalid format\n", buf);
- return NULL;
- }
- }
-
- on_write_error = BLOCK_ERR_STOP_ENOSPC;
- if ((buf = qemu_opt_get(opts, "werror")) != NULL) {
- if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO) {
- fprintf(stderr, "werror is no supported by this format\n");
- return NULL;
- }
-
- on_write_error = parse_block_error_action(buf, 0);
- if (on_write_error < 0) {
- return NULL;
- }
- }
-
- on_read_error = BLOCK_ERR_REPORT;
- if ((buf = qemu_opt_get(opts, "rerror")) != NULL) {
- if (type != IF_IDE && type != IF_VIRTIO) {
- fprintf(stderr, "rerror is no supported by this format\n");
- return NULL;
- }
-
- on_read_error = parse_block_error_action(buf, 1);
- if (on_read_error < 0) {
- return NULL;
- }
- }
-
- if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) {
- if (type != IF_VIRTIO) {
- fprintf(stderr, "addr is not supported\n");
- return NULL;
- }
- }
-
- /* compute bus and unit according index */
-
- if (index != -1) {
- if (bus_id != 0 || unit_id != -1) {
- fprintf(stderr,
- "qemu: index cannot be used with bus and unit\n");
- return NULL;
- }
- if (max_devs == 0)
- {
- unit_id = index;
- bus_id = 0;
- } else {
- unit_id = index % max_devs;
- bus_id = index / max_devs;
- }
- }
-
- /* if user doesn't specify a unit_id,
- * try to find the first free
- */
-
- if (unit_id == -1) {
- unit_id = 0;
- while (drive_get(type, bus_id, unit_id) != NULL) {
- unit_id++;
- if (max_devs && unit_id >= max_devs) {
- unit_id -= max_devs;
- bus_id++;
- }
- }
- }
-
- /* check unit id */
-
- if (max_devs && unit_id >= max_devs) {
- fprintf(stderr, "qemu: unit %d too big (max is %d)\n",
- unit_id, max_devs - 1);
- return NULL;
- }
-
- /*
- * ignore multiple definitions
- */
-
- if (drive_get(type, bus_id, unit_id) != NULL) {
- *fatal_error = 0;
- return NULL;
- }
-
- /* init */
-
- dinfo = qemu_mallocz(sizeof(*dinfo));
- if ((buf = qemu_opts_id(opts)) != NULL) {
- dinfo->id = qemu_strdup(buf);
- } else {
- /* no id supplied -> create one */
- dinfo->id = qemu_mallocz(32);
- if (type == IF_IDE || type == IF_SCSI)
- mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
- if (max_devs)
- snprintf(dinfo->id, 32, "%s%i%s%i",
- devname, bus_id, mediastr, unit_id);
- else
- snprintf(dinfo->id, 32, "%s%s%i",
- devname, mediastr, unit_id);
- }
- dinfo->bdrv = bdrv_new(dinfo->id);
- dinfo->devaddr = devaddr;
- dinfo->type = type;
- dinfo->bus = bus_id;
- dinfo->unit = unit_id;
- dinfo->on_read_error = on_read_error;
- dinfo->on_write_error = on_write_error;
- dinfo->opts = opts;
- if (serial)
- strncpy(dinfo->serial, serial, sizeof(serial));
- QTAILQ_INSERT_TAIL(&drives, dinfo, next);
-
- switch(type) {
- case IF_IDE:
- case IF_SCSI:
- case IF_XEN:
- case IF_NONE:
- switch(media) {
- case MEDIA_DISK:
- if (cyls != 0) {
- bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs);
- bdrv_set_translation_hint(dinfo->bdrv, translation);
- }
- break;
- case MEDIA_CDROM:
- bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_CDROM);
- break;
- }
- break;
- case IF_SD:
- /* FIXME: This isn't really a floppy, but it's a reasonable
- approximation. */
- case IF_FLOPPY:
- bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_FLOPPY);
- break;
- case IF_PFLASH:
- case IF_MTD:
- break;
- case IF_VIRTIO:
- /* add virtio block device */
- opts = qemu_opts_create(&qemu_device_opts, NULL, 0);
- qemu_opt_set(opts, "driver", "virtio-blk-pci");
- qemu_opt_set(opts, "drive", dinfo->id);
- if (devaddr)
- qemu_opt_set(opts, "addr", devaddr);
- break;
- case IF_COUNT:
- abort();
- }
- if (!file) {
- *fatal_error = 0;
- return NULL;
- }
- bdrv_flags = 0;
- if (snapshot) {
- bdrv_flags |= BDRV_O_SNAPSHOT;
- cache = 2; /* always use write-back with snapshot */
- }
- if (cache == 0) /* no caching */
- bdrv_flags |= BDRV_O_NOCACHE;
- else if (cache == 2) /* write-back */
- bdrv_flags |= BDRV_O_CACHE_WB;
-
- if (aio == 1) {
- bdrv_flags |= BDRV_O_NATIVE_AIO;
- } else {
- bdrv_flags &= ~BDRV_O_NATIVE_AIO;
- }
-
- if (ro == 1) {
- if (type != IF_SCSI && type != IF_VIRTIO && type != IF_FLOPPY) {
- fprintf(stderr, "qemu: readonly flag not supported for drive with this interface\n");
- return NULL;
- }
- }
- /*
- * cdrom is read-only. Set it now, after above interface checking
- * since readonly attribute not explicitly required, so no error.
- */
- if (media == MEDIA_CDROM) {
- ro = 1;
- }
- bdrv_flags |= ro ? 0 : BDRV_O_RDWR;
-
- if (bdrv_open2(dinfo->bdrv, file, bdrv_flags, drv) < 0) {
- fprintf(stderr, "qemu: could not open disk image %s: %s\n",
- file, strerror(errno));
- return NULL;
- }
-
- if (bdrv_key_required(dinfo->bdrv))
- autostart = 0;
- *fatal_error = 0;
- return dinfo;
-}
-
static int drive_init_func(QemuOpts *opts, void *opaque)
{
- QEMUMachine *machine = opaque;
+ int *use_scsi = opaque;
int fatal_error = 0;
- if (drive_init(opts, machine, &fatal_error) == NULL) {
+ if (drive_init(opts, *use_scsi, &fatal_error) == NULL) {
if (fatal_error)
return 1;
}
return boot_set_handler(boot_set_opaque, boot_devices);
}
-static int parse_bootdevices(char *devices)
+static void validate_bootdevices(char *devices)
{
/* We just do some generic consistency checks */
const char *p;
}
bitmap |= 1 << (*p - 'a');
}
- return bitmap;
}
static void restore_boot_devices(void *opaque)
{
char *standard_boot_devices = opaque;
+ static int first = 1;
+
+ /* Restore boot order and remove ourselves after the first boot */
+ if (first) {
+ first = 0;
+ return;
+ }
qemu_boot_set(standard_boot_devices);
/***********************************************************/
/* USB devices */
-static int usb_device_add(const char *devname, int is_hotplug)
+static int usb_device_add(const char *devname)
{
const char *p;
USBDevice *dev = NULL;
static int usb_parse(const char *cmdline)
{
int r;
- r = usb_device_add(cmdline, 0);
+ r = usb_device_add(cmdline);
if (r < 0) {
fprintf(stderr, "qemu: could not add USB device '%s'\n", cmdline);
}
void do_usb_add(Monitor *mon, const QDict *qdict)
{
const char *devname = qdict_get_str(qdict, "devname");
- if (usb_device_add(devname, 1) < 0) {
+ if (usb_device_add(devname) < 0) {
error_report("could not add USB device '%s'", devname);
}
}
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
}
-#ifdef _WIN32
/***********************************************************/
-/* Polling handling */
-
-typedef struct PollingEntry {
- PollingFunc *func;
- void *opaque;
- struct PollingEntry *next;
-} PollingEntry;
+/* machine registration */
-static PollingEntry *first_polling_entry;
+static QEMUMachine *first_machine = NULL;
+QEMUMachine *current_machine = NULL;
-int qemu_add_polling_cb(PollingFunc *func, void *opaque)
+int qemu_register_machine(QEMUMachine *m)
{
- PollingEntry **ppe, *pe;
- pe = qemu_mallocz(sizeof(PollingEntry));
- pe->func = func;
- pe->opaque = opaque;
- for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
- *ppe = pe;
+ QEMUMachine **pm;
+ pm = &first_machine;
+ while (*pm != NULL)
+ pm = &(*pm)->next;
+ m->next = NULL;
+ *pm = m;
return 0;
}
-void qemu_del_polling_cb(PollingFunc *func, void *opaque)
+static QEMUMachine *find_machine(const char *name)
{
- PollingEntry **ppe, *pe;
- for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
- pe = *ppe;
- if (pe->func == func && pe->opaque == opaque) {
- *ppe = pe->next;
- qemu_free(pe);
- break;
- }
+ QEMUMachine *m;
+
+ for(m = first_machine; m != NULL; m = m->next) {
+ if (!strcmp(m->name, name))
+ return m;
+ if (m->alias && !strcmp(m->alias, name))
+ return m;
}
+ return NULL;
}
-/***********************************************************/
-/* Wait objects support */
-typedef struct WaitObjects {
- int num;
- HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
- WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
- void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
-} WaitObjects;
-
-static WaitObjects wait_objects = {0};
-
-int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
+static QEMUMachine *find_default_machine(void)
{
- WaitObjects *w = &wait_objects;
-
- if (w->num >= MAXIMUM_WAIT_OBJECTS)
- return -1;
- w->events[w->num] = handle;
- w->func[w->num] = func;
- w->opaque[w->num] = opaque;
- w->num++;
- return 0;
-}
+ QEMUMachine *m;
-void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
-{
- int i, found;
- WaitObjects *w = &wait_objects;
-
- found = 0;
- for (i = 0; i < w->num; i++) {
- if (w->events[i] == handle)
- found = 1;
- if (found) {
- w->events[i] = w->events[i + 1];
- w->func[i] = w->func[i + 1];
- w->opaque[i] = w->opaque[i + 1];
+ for(m = first_machine; m != NULL; m = m->next) {
+ if (m->is_default) {
+ return m;
}
}
- if (found)
- w->num--;
+ return NULL;
}
-#endif
/***********************************************************/
-/* ram save/restore */
-
-#define RAM_SAVE_FLAG_FULL 0x01 /* Obsolete, not used anymore */
-#define RAM_SAVE_FLAG_COMPRESS 0x02
-#define RAM_SAVE_FLAG_MEM_SIZE 0x04
-#define RAM_SAVE_FLAG_PAGE 0x08
-#define RAM_SAVE_FLAG_EOS 0x10
+/* main execution loop */
-static int is_dup_page(uint8_t *page, uint8_t ch)
+static void gui_update(void *opaque)
{
- uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch;
- uint32_t *array = (uint32_t *)page;
- int i;
+ uint64_t interval = GUI_REFRESH_INTERVAL;
+ DisplayState *ds = opaque;
+ DisplayChangeListener *dcl = ds->listeners;
- for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) {
- if (array[i] != val)
- return 0;
- }
-
- return 1;
-}
-
-static int ram_save_block(QEMUFile *f)
-{
- static ram_addr_t current_addr = 0;
- ram_addr_t saved_addr = current_addr;
- ram_addr_t addr = 0;
- int found = 0;
-
- while (addr < last_ram_offset) {
- if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
- uint8_t *p;
-
- cpu_physical_memory_reset_dirty(current_addr,
- current_addr + TARGET_PAGE_SIZE,
- MIGRATION_DIRTY_FLAG);
-
- p = qemu_get_ram_ptr(current_addr);
-
- if (is_dup_page(p, *p)) {
- qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_COMPRESS);
- qemu_put_byte(f, *p);
- } else {
- qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_PAGE);
- qemu_put_buffer(f, p, TARGET_PAGE_SIZE);
- }
-
- found = 1;
- break;
- }
- addr += TARGET_PAGE_SIZE;
- current_addr = (saved_addr + addr) % last_ram_offset;
- }
-
- return found;
-}
-
-static uint64_t bytes_transferred;
-
-static ram_addr_t ram_save_remaining(void)
-{
- ram_addr_t addr;
- ram_addr_t count = 0;
-
- for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) {
- if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG))
- count++;
- }
-
- return count;
-}
-
-uint64_t ram_bytes_remaining(void)
-{
- return ram_save_remaining() * TARGET_PAGE_SIZE;
-}
-
-uint64_t ram_bytes_transferred(void)
-{
- return bytes_transferred;
-}
-
-uint64_t ram_bytes_total(void)
-{
- return last_ram_offset;
-}
-
-static int ram_save_live(Monitor *mon, QEMUFile *f, int stage, void *opaque)
-{
- ram_addr_t addr;
- uint64_t bytes_transferred_last;
- double bwidth = 0;
- uint64_t expected_time = 0;
-
- if (stage < 0) {
- cpu_physical_memory_set_dirty_tracking(0);
- return 0;
- }
-
- if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) {
- qemu_file_set_error(f);
- return 0;
- }
-
- if (stage == 1) {
- bytes_transferred = 0;
-
- /* Make sure all dirty bits are set */
- for (addr = 0; addr < last_ram_offset; addr += TARGET_PAGE_SIZE) {
- if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG))
- cpu_physical_memory_set_dirty(addr);
- }
-
- /* Enable dirty memory tracking */
- cpu_physical_memory_set_dirty_tracking(1);
-
- qemu_put_be64(f, last_ram_offset | RAM_SAVE_FLAG_MEM_SIZE);
- }
-
- bytes_transferred_last = bytes_transferred;
- bwidth = qemu_get_clock_ns(rt_clock);
-
- while (!qemu_file_rate_limit(f)) {
- int ret;
-
- ret = ram_save_block(f);
- bytes_transferred += ret * TARGET_PAGE_SIZE;
- if (ret == 0) /* no more blocks */
- break;
- }
-
- bwidth = qemu_get_clock_ns(rt_clock) - bwidth;
- bwidth = (bytes_transferred - bytes_transferred_last) / bwidth;
-
- /* if we haven't transferred anything this round, force expected_time to a
- * a very high value, but without crashing */
- if (bwidth == 0)
- bwidth = 0.000001;
-
- /* try transferring iterative blocks of memory */
- if (stage == 3) {
- /* flush all remaining blocks regardless of rate limiting */
- while (ram_save_block(f) != 0) {
- bytes_transferred += TARGET_PAGE_SIZE;
- }
- cpu_physical_memory_set_dirty_tracking(0);
- }
-
- qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
-
- expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth;
-
- return (stage == 2) && (expected_time <= migrate_max_downtime());
-}
-
-static int ram_load(QEMUFile *f, void *opaque, int version_id)
-{
- ram_addr_t addr;
- int flags;
-
- if (version_id != 3)
- return -EINVAL;
-
- do {
- addr = qemu_get_be64(f);
-
- flags = addr & ~TARGET_PAGE_MASK;
- addr &= TARGET_PAGE_MASK;
-
- if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
- if (addr != last_ram_offset)
- return -EINVAL;
- }
-
- if (flags & RAM_SAVE_FLAG_COMPRESS) {
- uint8_t ch = qemu_get_byte(f);
- memset(qemu_get_ram_ptr(addr), ch, TARGET_PAGE_SIZE);
-#ifndef _WIN32
- if (ch == 0 &&
- (!kvm_enabled() || kvm_has_sync_mmu())) {
- madvise(qemu_get_ram_ptr(addr), TARGET_PAGE_SIZE, MADV_DONTNEED);
- }
-#endif
- } else if (flags & RAM_SAVE_FLAG_PAGE) {
- qemu_get_buffer(f, qemu_get_ram_ptr(addr), TARGET_PAGE_SIZE);
- }
- if (qemu_file_has_error(f)) {
- return -EIO;
- }
- } while (!(flags & RAM_SAVE_FLAG_EOS));
-
- return 0;
-}
-
-void qemu_service_io(void)
-{
- qemu_notify_event();
-}
-
-/***********************************************************/
-/* machine registration */
-
-static QEMUMachine *first_machine = NULL;
-QEMUMachine *current_machine = NULL;
-
-int qemu_register_machine(QEMUMachine *m)
-{
- QEMUMachine **pm;
- pm = &first_machine;
- while (*pm != NULL)
- pm = &(*pm)->next;
- m->next = NULL;
- *pm = m;
- return 0;
-}
-
-static QEMUMachine *find_machine(const char *name)
-{
- QEMUMachine *m;
-
- for(m = first_machine; m != NULL; m = m->next) {
- if (!strcmp(m->name, name))
- return m;
- if (m->alias && !strcmp(m->alias, name))
- return m;
- }
- return NULL;
-}
-
-static QEMUMachine *find_default_machine(void)
-{
- QEMUMachine *m;
-
- for(m = first_machine; m != NULL; m = m->next) {
- if (m->is_default) {
- return m;
- }
- }
- return NULL;
-}
-
-/***********************************************************/
-/* main execution loop */
-
-static void gui_update(void *opaque)
-{
- uint64_t interval = GUI_REFRESH_INTERVAL;
- DisplayState *ds = opaque;
- DisplayChangeListener *dcl = ds->listeners;
-
- qemu_flush_coalesced_mmio_buffer();
- dpy_refresh(ds);
+ qemu_flush_coalesced_mmio_buffer();
+ dpy_refresh(ds);
while (dcl != NULL) {
if (dcl->gui_timer_interval &&
qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock));
}
-void cpu_synchronize_all_states(void)
-{
- CPUState *cpu;
-
- for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
- cpu_synchronize_state(cpu);
- }
-}
-
-void cpu_synchronize_all_post_reset(void)
-{
- CPUState *cpu;
-
- for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
- cpu_synchronize_post_reset(cpu);
- }
-}
-
-void cpu_synchronize_all_post_init(void)
-{
- CPUState *cpu;
-
- for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
- cpu_synchronize_post_init(cpu);
- }
-}
-
struct vm_change_state_entry {
VMChangeStateHandler *cb;
void *opaque;
qemu_free (e);
}
-static void vm_state_notify(int running, int reason)
+void vm_state_notify(int running, int reason)
{
VMChangeStateEntry *e;
}
}
-static void resume_all_vcpus(void);
-static void pause_all_vcpus(void);
-
void vm_start(void)
{
if (!vm_running) {
vm_running = 1;
vm_state_notify(1, 0);
resume_all_vcpus();
+ monitor_protocol_event(QEVENT_RESUME, NULL);
}
}
static int reset_requested;
static int shutdown_requested;
static int powerdown_requested;
-static int debug_requested;
-static int vmstop_requested;
+int debug_requested;
+int vmstop_requested;
int qemu_shutdown_requested(void)
{
return r;
}
-static void do_vm_stop(int reason)
-{
- if (vm_running) {
- cpu_disable_ticks();
- vm_running = 0;
- pause_all_vcpus();
- vm_state_notify(0, reason);
- monitor_protocol_event(QEVENT_STOP, NULL);
- }
-}
-
void qemu_register_reset(QEMUResetHandler *func, void *opaque)
{
QEMUResetEntry *re = qemu_mallocz(sizeof(QEMUResetEntry));
qemu_notify_event();
}
-static int cpu_can_run(CPUState *env)
-{
- if (env->stop)
- return 0;
- if (env->stopped)
- return 0;
- if (!vm_running)
- return 0;
- return 1;
-}
-
-static int cpu_has_work(CPUState *env)
-{
- if (env->stop)
- return 1;
- if (env->stopped)
- return 0;
- if (!env->halted)
- return 1;
- if (qemu_cpu_has_work(env))
- return 1;
- return 0;
-}
-
-static int tcg_has_work(void)
-{
- CPUState *env;
-
- for (env = first_cpu; env != NULL; env = env->next_cpu)
- if (cpu_has_work(env))
- return 1;
- return 0;
-}
-
-#ifndef _WIN32
-static int io_thread_fd = -1;
-
-static void qemu_event_increment(void)
-{
- /* Write 8 bytes to be compatible with eventfd. */
- static uint64_t val = 1;
- ssize_t ret;
-
- if (io_thread_fd == -1)
- return;
-
- do {
- ret = write(io_thread_fd, &val, sizeof(val));
- } while (ret < 0 && errno == EINTR);
-
- /* EAGAIN is fine, a read must be pending. */
- if (ret < 0 && errno != EAGAIN) {
- fprintf(stderr, "qemu_event_increment: write() filed: %s\n",
- strerror(errno));
- exit (1);
- }
-}
-
-static void qemu_event_read(void *opaque)
-{
- int fd = (unsigned long)opaque;
- ssize_t len;
- char buffer[512];
-
- /* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
- do {
- len = read(fd, buffer, sizeof(buffer));
- } while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
-}
-
-static int qemu_event_init(void)
-{
- int err;
- int fds[2];
-
- err = qemu_eventfd(fds);
- if (err == -1)
- return -errno;
-
- err = fcntl_setfl(fds[0], O_NONBLOCK);
- if (err < 0)
- goto fail;
-
- err = fcntl_setfl(fds[1], O_NONBLOCK);
- if (err < 0)
- goto fail;
-
- qemu_set_fd_handler2(fds[0], NULL, qemu_event_read, NULL,
- (void *)(unsigned long)fds[0]);
-
- io_thread_fd = fds[1];
- return 0;
-
-fail:
- close(fds[0]);
- close(fds[1]);
- return err;
-}
-#else
-HANDLE qemu_event_handle;
-
-static void dummy_event_handler(void *opaque)
-{
-}
-
-static int qemu_event_init(void)
-{
- qemu_event_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!qemu_event_handle) {
- fprintf(stderr, "Failed CreateEvent: %ld\n", GetLastError());
- return -1;
- }
- qemu_add_wait_object(qemu_event_handle, dummy_event_handler, NULL);
- return 0;
-}
-
-static void qemu_event_increment(void)
-{
- if (!SetEvent(qemu_event_handle)) {
- fprintf(stderr, "qemu_event_increment: SetEvent failed: %ld\n",
- GetLastError());
- exit (1);
- }
-}
-#endif
-
-#ifndef CONFIG_IOTHREAD
-static int qemu_init_main_loop(void)
-{
- return qemu_event_init();
-}
-
-void qemu_init_vcpu(void *_env)
-{
- CPUState *env = _env;
-
- env->nr_cores = smp_cores;
- env->nr_threads = smp_threads;
- if (kvm_enabled())
- kvm_init_vcpu(env);
- return;
-}
-
-int qemu_cpu_self(void *env)
-{
- return 1;
-}
-
-static void resume_all_vcpus(void)
-{
-}
-
-static void pause_all_vcpus(void)
-{
-}
-
-void qemu_cpu_kick(void *env)
-{
- return;
-}
-
-void qemu_notify_event(void)
-{
- CPUState *env = cpu_single_env;
-
- qemu_event_increment ();
- if (env) {
- cpu_exit(env);
- }
- if (next_cpu && env != next_cpu) {
- cpu_exit(next_cpu);
- }
-}
-
-void qemu_mutex_lock_iothread(void) {}
-void qemu_mutex_unlock_iothread(void) {}
-
-void vm_stop(int reason)
-{
- do_vm_stop(reason);
-}
-
-#else /* CONFIG_IOTHREAD */
-
-#include "qemu-thread.h"
-
-QemuMutex qemu_global_mutex;
-static QemuMutex qemu_fair_mutex;
-
-static QemuThread io_thread;
-
-static QemuThread *tcg_cpu_thread;
-static QemuCond *tcg_halt_cond;
-
-static int qemu_system_ready;
-/* cpu creation */
-static QemuCond qemu_cpu_cond;
-/* system init */
-static QemuCond qemu_system_cond;
-static QemuCond qemu_pause_cond;
-
-static void tcg_block_io_signals(void);
-static void kvm_block_io_signals(CPUState *env);
-static void unblock_io_signals(void);
-
-static int qemu_init_main_loop(void)
-{
- int ret;
-
- ret = qemu_event_init();
- if (ret)
- return ret;
-
- qemu_cond_init(&qemu_pause_cond);
- qemu_mutex_init(&qemu_fair_mutex);
- qemu_mutex_init(&qemu_global_mutex);
- qemu_mutex_lock(&qemu_global_mutex);
-
- unblock_io_signals();
- qemu_thread_self(&io_thread);
-
- return 0;
-}
-
-static void qemu_wait_io_event_common(CPUState *env)
-{
- if (env->stop) {
- env->stop = 0;
- env->stopped = 1;
- qemu_cond_signal(&qemu_pause_cond);
- }
-}
-
-static void qemu_wait_io_event(CPUState *env)
-{
- while (!tcg_has_work())
- qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);
-
- qemu_mutex_unlock(&qemu_global_mutex);
-
- /*
- * Users of qemu_global_mutex can be starved, having no chance
- * to acquire it since this path will get to it first.
- * So use another lock to provide fairness.
- */
- qemu_mutex_lock(&qemu_fair_mutex);
- qemu_mutex_unlock(&qemu_fair_mutex);
-
- qemu_mutex_lock(&qemu_global_mutex);
- qemu_wait_io_event_common(env);
-}
-
-static void qemu_kvm_eat_signal(CPUState *env, int timeout)
-{
- struct timespec ts;
- int r, e;
- siginfo_t siginfo;
- sigset_t waitset;
-
- ts.tv_sec = timeout / 1000;
- ts.tv_nsec = (timeout % 1000) * 1000000;
-
- sigemptyset(&waitset);
- sigaddset(&waitset, SIG_IPI);
-
- qemu_mutex_unlock(&qemu_global_mutex);
- r = sigtimedwait(&waitset, &siginfo, &ts);
- e = errno;
- qemu_mutex_lock(&qemu_global_mutex);
-
- if (r == -1 && !(e == EAGAIN || e == EINTR)) {
- fprintf(stderr, "sigtimedwait: %s\n", strerror(e));
- exit(1);
- }
-}
-
-static void qemu_kvm_wait_io_event(CPUState *env)
-{
- while (!cpu_has_work(env))
- qemu_cond_timedwait(env->halt_cond, &qemu_global_mutex, 1000);
-
- qemu_kvm_eat_signal(env, 0);
- qemu_wait_io_event_common(env);
-}
-
-static int qemu_cpu_exec(CPUState *env);
-
-static void *kvm_cpu_thread_fn(void *arg)
-{
- CPUState *env = arg;
-
- qemu_thread_self(env->thread);
- if (kvm_enabled())
- kvm_init_vcpu(env);
-
- kvm_block_io_signals(env);
-
- /* signal CPU creation */
- qemu_mutex_lock(&qemu_global_mutex);
- env->created = 1;
- qemu_cond_signal(&qemu_cpu_cond);
-
- /* and wait for machine initialization */
- while (!qemu_system_ready)
- qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
-
- while (1) {
- if (cpu_can_run(env))
- qemu_cpu_exec(env);
- qemu_kvm_wait_io_event(env);
- }
-
- return NULL;
-}
-
-static bool tcg_cpu_exec(void);
-
-static void *tcg_cpu_thread_fn(void *arg)
-{
- CPUState *env = arg;
-
- tcg_block_io_signals();
- qemu_thread_self(env->thread);
-
- /* signal CPU creation */
- qemu_mutex_lock(&qemu_global_mutex);
- for (env = first_cpu; env != NULL; env = env->next_cpu)
- env->created = 1;
- qemu_cond_signal(&qemu_cpu_cond);
-
- /* and wait for machine initialization */
- while (!qemu_system_ready)
- qemu_cond_timedwait(&qemu_system_cond, &qemu_global_mutex, 100);
-
- while (1) {
- tcg_cpu_exec();
- qemu_wait_io_event(cur_cpu);
- }
-
- return NULL;
-}
-
-void qemu_cpu_kick(void *_env)
-{
- CPUState *env = _env;
- qemu_cond_broadcast(env->halt_cond);
- if (kvm_enabled())
- qemu_thread_signal(env->thread, SIG_IPI);
-}
-
-int qemu_cpu_self(void *_env)
-{
- CPUState *env = _env;
- QemuThread this;
-
- qemu_thread_self(&this);
-
- return qemu_thread_equal(&this, env->thread);
-}
-
-static void cpu_signal(int sig)
-{
- if (cpu_single_env)
- cpu_exit(cpu_single_env);
-}
-
-static void tcg_block_io_signals(void)
-{
- sigset_t set;
- struct sigaction sigact;
-
- sigemptyset(&set);
- sigaddset(&set, SIGUSR2);
- sigaddset(&set, SIGIO);
- sigaddset(&set, SIGALRM);
- sigaddset(&set, SIGCHLD);
- pthread_sigmask(SIG_BLOCK, &set, NULL);
-
- sigemptyset(&set);
- sigaddset(&set, SIG_IPI);
- pthread_sigmask(SIG_UNBLOCK, &set, NULL);
-
- memset(&sigact, 0, sizeof(sigact));
- sigact.sa_handler = cpu_signal;
- sigaction(SIG_IPI, &sigact, NULL);
-}
-
-static void dummy_signal(int sig)
-{
-}
-
-static void kvm_block_io_signals(CPUState *env)
-{
- int r;
- sigset_t set;
- struct sigaction sigact;
-
- sigemptyset(&set);
- sigaddset(&set, SIGUSR2);
- sigaddset(&set, SIGIO);
- sigaddset(&set, SIGALRM);
- sigaddset(&set, SIGCHLD);
- sigaddset(&set, SIG_IPI);
- pthread_sigmask(SIG_BLOCK, &set, NULL);
-
- pthread_sigmask(SIG_BLOCK, NULL, &set);
- sigdelset(&set, SIG_IPI);
-
- memset(&sigact, 0, sizeof(sigact));
- sigact.sa_handler = dummy_signal;
- sigaction(SIG_IPI, &sigact, NULL);
-
- r = kvm_set_signal_mask(env, &set);
- if (r) {
- fprintf(stderr, "kvm_set_signal_mask: %s\n", strerror(r));
- exit(1);
- }
-}
-
-static void unblock_io_signals(void)
-{
- sigset_t set;
-
- sigemptyset(&set);
- sigaddset(&set, SIGUSR2);
- sigaddset(&set, SIGIO);
- sigaddset(&set, SIGALRM);
- pthread_sigmask(SIG_UNBLOCK, &set, NULL);
-
- sigemptyset(&set);
- sigaddset(&set, SIG_IPI);
- pthread_sigmask(SIG_BLOCK, &set, NULL);
-}
-
-static void qemu_signal_lock(unsigned int msecs)
-{
- qemu_mutex_lock(&qemu_fair_mutex);
-
- while (qemu_mutex_trylock(&qemu_global_mutex)) {
- qemu_thread_signal(tcg_cpu_thread, SIG_IPI);
- if (!qemu_mutex_timedlock(&qemu_global_mutex, msecs))
- break;
- }
- qemu_mutex_unlock(&qemu_fair_mutex);
-}
-
-void qemu_mutex_lock_iothread(void)
-{
- if (kvm_enabled()) {
- qemu_mutex_lock(&qemu_fair_mutex);
- qemu_mutex_lock(&qemu_global_mutex);
- qemu_mutex_unlock(&qemu_fair_mutex);
- } else
- qemu_signal_lock(100);
-}
-
-void qemu_mutex_unlock_iothread(void)
-{
- qemu_mutex_unlock(&qemu_global_mutex);
-}
-
-static int all_vcpus_paused(void)
-{
- CPUState *penv = first_cpu;
-
- while (penv) {
- if (!penv->stopped)
- return 0;
- penv = (CPUState *)penv->next_cpu;
- }
-
- return 1;
-}
-
-static void pause_all_vcpus(void)
-{
- CPUState *penv = first_cpu;
-
- while (penv) {
- penv->stop = 1;
- qemu_thread_signal(penv->thread, SIG_IPI);
- qemu_cpu_kick(penv);
- penv = (CPUState *)penv->next_cpu;
- }
-
- while (!all_vcpus_paused()) {
- qemu_cond_timedwait(&qemu_pause_cond, &qemu_global_mutex, 100);
- penv = first_cpu;
- while (penv) {
- qemu_thread_signal(penv->thread, SIG_IPI);
- penv = (CPUState *)penv->next_cpu;
- }
- }
-}
-
-static void resume_all_vcpus(void)
-{
- CPUState *penv = first_cpu;
-
- while (penv) {
- penv->stop = 0;
- penv->stopped = 0;
- qemu_thread_signal(penv->thread, SIG_IPI);
- qemu_cpu_kick(penv);
- penv = (CPUState *)penv->next_cpu;
- }
-}
-
-static void tcg_init_vcpu(void *_env)
-{
- CPUState *env = _env;
- /* share a single thread for all cpus with TCG */
- if (!tcg_cpu_thread) {
- env->thread = qemu_mallocz(sizeof(QemuThread));
- env->halt_cond = qemu_mallocz(sizeof(QemuCond));
- qemu_cond_init(env->halt_cond);
- qemu_thread_create(env->thread, tcg_cpu_thread_fn, env);
- while (env->created == 0)
- qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
- tcg_cpu_thread = env->thread;
- tcg_halt_cond = env->halt_cond;
- } else {
- env->thread = tcg_cpu_thread;
- env->halt_cond = tcg_halt_cond;
- }
-}
-
-static void kvm_start_vcpu(CPUState *env)
-{
- env->thread = qemu_mallocz(sizeof(QemuThread));
- env->halt_cond = qemu_mallocz(sizeof(QemuCond));
- qemu_cond_init(env->halt_cond);
- qemu_thread_create(env->thread, kvm_cpu_thread_fn, env);
- while (env->created == 0)
- qemu_cond_timedwait(&qemu_cpu_cond, &qemu_global_mutex, 100);
-}
-
-void qemu_init_vcpu(void *_env)
-{
- CPUState *env = _env;
-
- env->nr_cores = smp_cores;
- env->nr_threads = smp_threads;
- if (kvm_enabled())
- kvm_start_vcpu(env);
- else
- tcg_init_vcpu(env);
-}
-
-void qemu_notify_event(void)
-{
- qemu_event_increment();
-}
-
-static void qemu_system_vmstop_request(int reason)
-{
- vmstop_requested = reason;
- qemu_notify_event();
-}
-
-void vm_stop(int reason)
-{
- QemuThread me;
- qemu_thread_self(&me);
-
- if (!qemu_thread_equal(&me, &io_thread)) {
- qemu_system_vmstop_request(reason);
- /*
- * FIXME: should not return to device code in case
- * vm_stop() has been requested.
- */
- if (cpu_single_env) {
- cpu_exit(cpu_single_env);
- cpu_single_env->stop = 1;
- }
- return;
- }
- do_vm_stop(reason);
-}
-
-#endif
-
-
-#ifdef _WIN32
-static void host_main_loop_wait(int *timeout)
-{
- int ret, ret2, i;
- PollingEntry *pe;
-
-
- /* XXX: need to suppress polling by better using win32 events */
- ret = 0;
- for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
- ret |= pe->func(pe->opaque);
- }
- if (ret == 0) {
- int err;
- WaitObjects *w = &wait_objects;
-
- ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
- if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
- if (w->func[ret - WAIT_OBJECT_0])
- w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
-
- /* Check for additional signaled events */
- for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
-
- /* Check if event is signaled */
- ret2 = WaitForSingleObject(w->events[i], 0);
- if(ret2 == WAIT_OBJECT_0) {
- if (w->func[i])
- w->func[i](w->opaque[i]);
- } else if (ret2 == WAIT_TIMEOUT) {
- } else {
- err = GetLastError();
- fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
- }
- }
- } else if (ret == WAIT_TIMEOUT) {
- } else {
- err = GetLastError();
- fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
- }
- }
-
- *timeout = 0;
-}
-#else
-static void host_main_loop_wait(int *timeout)
-{
-}
-#endif
-
void main_loop_wait(int nonblocking)
{
IOHandlerRecord *ioh;
qemu_bh_update_timeout(&timeout);
}
- host_main_loop_wait(&timeout);
+ os_host_main_loop_wait(&timeout);
/* poll any events */
/* XXX: separate device handlers from system ones */
}
-static int qemu_cpu_exec(CPUState *env)
-{
- int ret;
-#ifdef CONFIG_PROFILER
- int64_t ti;
-#endif
-
-#ifdef CONFIG_PROFILER
- ti = profile_getclock();
-#endif
- if (use_icount) {
- int64_t count;
- int decr;
- qemu_icount -= (env->icount_decr.u16.low + env->icount_extra);
- env->icount_decr.u16.low = 0;
- env->icount_extra = 0;
- count = qemu_icount_round (qemu_next_deadline());
- qemu_icount += count;
- decr = (count > 0xffff) ? 0xffff : count;
- count -= decr;
- env->icount_decr.u16.low = decr;
- env->icount_extra = count;
- }
- ret = cpu_exec(env);
-#ifdef CONFIG_PROFILER
- qemu_time += profile_getclock() - ti;
-#endif
- if (use_icount) {
- /* Fold pending instructions back into the
- instruction counter, and clear the interrupt flag. */
- qemu_icount -= (env->icount_decr.u16.low
- + env->icount_extra);
- env->icount_decr.u32 = 0;
- env->icount_extra = 0;
- }
- return ret;
-}
-
-static bool tcg_cpu_exec(void)
-{
- int ret = 0;
-
- if (next_cpu == NULL)
- next_cpu = first_cpu;
- for (; next_cpu != NULL; next_cpu = next_cpu->next_cpu) {
- CPUState *env = cur_cpu = next_cpu;
-
- qemu_clock_enable(vm_clock,
- (cur_cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
-
- if (qemu_alarm_pending())
- break;
- if (cpu_can_run(env))
- ret = qemu_cpu_exec(env);
- else if (env->stop)
- break;
-
- if (ret == EXCP_DEBUG) {
- gdb_set_stop_cpu(env);
- debug_requested = 1;
- break;
- }
- }
- return tcg_has_work();
-}
-
static int vm_can_run(void)
{
if (powerdown_requested)
{
int r;
-#ifdef CONFIG_IOTHREAD
- qemu_system_ready = 1;
- qemu_cond_broadcast(&qemu_system_cond);
-#endif
+ qemu_main_loop_start();
for (;;) {
do {
int64_t ti;
#endif
#ifndef CONFIG_IOTHREAD
- nonblocking = tcg_cpu_exec();
+ nonblocking = cpu_exec_all();
#endif
#ifdef CONFIG_PROFILER
ti = profile_getclock();
#endif
} while (vm_can_run());
- if (qemu_debug_requested()) {
- vm_stop(EXCP_DEBUG);
+ if ((r = qemu_debug_requested())) {
+ vm_stop(r);
}
if (qemu_shutdown_requested()) {
monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
vm_stop(r);
}
}
+ bdrv_close_all();
pause_all_vcpus();
}
static void version(void)
{
- printf("QEMU PC emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
+ printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
}
static void help(int exitcode)
{
const char *options_help =
-#define DEF(option, opt_arg, opt_enum, opt_help) \
- opt_help
+#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
+ opt_help
#define DEFHEADING(text) stringify(text) "\n"
-#include "qemu-options.h"
+#include "qemu-options.def"
#undef DEF
#undef DEFHEADING
#undef GEN_DOCS
version();
printf("usage: %s [options] [disk_image]\n"
"\n"
- "'disk_image' is a raw hard image image for IDE hard disk 0\n"
+ "'disk_image' is a raw hard disk image for IDE hard disk 0\n"
"\n"
"%s\n"
"During emulation, the following keys are useful:\n"
#define HAS_ARG 0x0001
-enum {
-#define DEF(option, opt_arg, opt_enum, opt_help) \
- opt_enum,
-#define DEFHEADING(text)
-#include "qemu-options.h"
-#undef DEF
-#undef DEFHEADING
-#undef GEN_DOCS
-};
-
typedef struct QEMUOption {
const char *name;
int flags;
int index;
+ uint32_t arch_mask;
} QEMUOption;
static const QEMUOption qemu_options[] = {
- { "h", 0, QEMU_OPTION_h },
-#define DEF(option, opt_arg, opt_enum, opt_help) \
- { option, opt_arg, opt_enum },
+ { "h", 0, QEMU_OPTION_h, QEMU_ARCH_ALL },
+#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
+ { option, opt_arg, opt_enum, arch_mask },
#define DEFHEADING(text)
-#include "qemu-options.h"
+#include "qemu-options.def"
#undef DEF
#undef DEFHEADING
#undef GEN_DOCS
{ NULL },
};
-
-#ifdef HAS_AUDIO
-struct soundhw soundhw[] = {
-#ifdef HAS_AUDIO_CHOICE
-#if defined(TARGET_I386) || defined(TARGET_MIPS)
- {
- "pcspk",
- "PC speaker",
- 0,
- 1,
- { .init_isa = pcspk_audio_init }
- },
-#endif
-
-#ifdef CONFIG_SB16
- {
- "sb16",
- "Creative Sound Blaster 16",
- 0,
- 1,
- { .init_isa = SB16_init }
- },
-#endif
-
-#ifdef CONFIG_CS4231A
- {
- "cs4231a",
- "CS4231A",
- 0,
- 1,
- { .init_isa = cs4231a_init }
- },
-#endif
-
-#ifdef CONFIG_ADLIB
- {
- "adlib",
-#ifdef HAS_YMF262
- "Yamaha YMF262 (OPL3)",
-#else
- "Yamaha YM3812 (OPL2)",
-#endif
- 0,
- 1,
- { .init_isa = Adlib_init }
- },
-#endif
-
-#ifdef CONFIG_GUS
- {
- "gus",
- "Gravis Ultrasound GF1",
- 0,
- 1,
- { .init_isa = GUS_init }
- },
-#endif
-
-#ifdef CONFIG_AC97
- {
- "ac97",
- "Intel 82801AA AC97 Audio",
- 0,
- 0,
- { .init_pci = ac97_init }
- },
-#endif
-
-#ifdef CONFIG_ES1370
- {
- "es1370",
- "ENSONIQ AudioPCI ES1370",
- 0,
- 0,
- { .init_pci = es1370_init }
- },
-#endif
-
-#endif /* HAS_AUDIO_CHOICE */
-
- { NULL, NULL, 0, 0, { NULL } }
-};
-
-static void select_soundhw (const char *optarg)
-{
- struct soundhw *c;
-
- if (*optarg == '?') {
- show_valid_cards:
-
- printf ("Valid sound card names (comma separated):\n");
- for (c = soundhw; c->name; ++c) {
- printf ("%-11s %s\n", c->name, c->descr);
- }
- printf ("\n-soundhw all will enable all of the above\n");
- exit (*optarg != '?');
- }
- else {
- size_t l;
- const char *p;
- char *e;
- int bad_card = 0;
-
- if (!strcmp (optarg, "all")) {
- for (c = soundhw; c->name; ++c) {
- c->enabled = 1;
- }
- return;
- }
-
- p = optarg;
- while (*p) {
- e = strchr (p, ',');
- l = !e ? strlen (p) : (size_t) (e - p);
-
- for (c = soundhw; c->name; ++c) {
- if (!strncmp (c->name, p, l) && !c->name[l]) {
- c->enabled = 1;
- break;
- }
- }
-
- if (!c->name) {
- if (l > 80) {
- fprintf (stderr,
- "Unknown sound card name (too big to show)\n");
- }
- else {
- fprintf (stderr, "Unknown sound card name `%.*s'\n",
- (int) l, p);
- }
- bad_card = 1;
- }
- p += l + (e != NULL);
- }
-
- if (bad_card)
- goto show_valid_cards;
- }
-}
-#endif
-
static void select_vgahw (const char *p)
{
const char *opts;
}
}
-#ifdef TARGET_I386
static int balloon_parse(const char *arg)
{
QemuOpts *opts;
return -1;
}
-#endif
-
-#ifdef _WIN32
-static BOOL WINAPI qemu_ctrl_handler(DWORD type)
-{
- exit(STATUS_CONTROL_C_EXIT);
- return TRUE;
-}
-#endif
-
-int qemu_uuid_parse(const char *str, uint8_t *uuid)
-{
- int ret;
-
- if(strlen(str) != 36)
- return -1;
-
- ret = sscanf(str, UUID_FMT, &uuid[0], &uuid[1], &uuid[2], &uuid[3],
- &uuid[4], &uuid[5], &uuid[6], &uuid[7], &uuid[8], &uuid[9],
- &uuid[10], &uuid[11], &uuid[12], &uuid[13], &uuid[14], &uuid[15]);
-
- if(ret != 16)
- return -1;
-
-#ifdef TARGET_I386
- smbios_add_field(1, offsetof(struct smbios_type_1, uuid), 16, uuid);
-#endif
-
- return 0;
-}
-
-#ifndef _WIN32
-
-static void termsig_handler(int signal)
-{
- qemu_system_shutdown_request();
-}
-
-static void sigchld_handler(int signal)
-{
- waitpid(-1, NULL, WNOHANG);
-}
-
-static void sighandler_setup(void)
-{
- struct sigaction act;
-
- memset(&act, 0, sizeof(act));
- act.sa_handler = termsig_handler;
- sigaction(SIGINT, &act, NULL);
- sigaction(SIGHUP, &act, NULL);
- sigaction(SIGTERM, &act, NULL);
-
- act.sa_handler = sigchld_handler;
- act.sa_flags = SA_NOCLDSTOP;
- sigaction(SIGCHLD, &act, NULL);
-}
-
-#endif
-
-#ifdef _WIN32
-/* Look for support files in the same directory as the executable. */
-static char *find_datadir(const char *argv0)
-{
- char *p;
- char buf[MAX_PATH];
- DWORD len;
-
- len = GetModuleFileName(NULL, buf, sizeof(buf) - 1);
- if (len == 0) {
- return NULL;
- }
-
- buf[len] = 0;
- p = buf + len - 1;
- while (p != buf && *p != '\\')
- p--;
- *p = 0;
- if (access(buf, R_OK) == 0) {
- return qemu_strdup(buf);
- }
- return NULL;
-}
-#else /* !_WIN32 */
-
-/* Find a likely location for support files using the location of the binary.
- For installed binaries this will be "$bindir/../share/qemu". When
- running from the build tree this will be "$bindir/../pc-bios". */
-#define SHARE_SUFFIX "/share/qemu"
-#define BUILD_SUFFIX "/pc-bios"
-static char *find_datadir(const char *argv0)
-{
- char *dir;
- char *p = NULL;
- char *res;
- char buf[PATH_MAX];
- size_t max_len;
-
-#if defined(__linux__)
- {
- int len;
- len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
- if (len > 0) {
- buf[len] = 0;
- p = buf;
- }
- }
-#elif defined(__FreeBSD__)
- {
- int len;
- len = readlink("/proc/curproc/file", buf, sizeof(buf) - 1);
- if (len > 0) {
- buf[len] = 0;
- p = buf;
- }
- }
-#endif
- /* If we don't have any way of figuring out the actual executable
- location then try argv[0]. */
- if (!p) {
- p = realpath(argv0, buf);
- if (!p) {
- return NULL;
- }
- }
- dir = dirname(p);
- dir = dirname(dir);
-
- max_len = strlen(dir) +
- MAX(strlen(SHARE_SUFFIX), strlen(BUILD_SUFFIX)) + 1;
- res = qemu_mallocz(max_len);
- snprintf(res, max_len, "%s%s", dir, SHARE_SUFFIX);
- if (access(res, R_OK)) {
- snprintf(res, max_len, "%s%s", dir, BUILD_SUFFIX);
- if (access(res, R_OK)) {
- qemu_free(res);
- res = NULL;
- }
- }
-
- return res;
-}
-#undef SHARE_SUFFIX
-#undef BUILD_SUFFIX
-#endif
char *qemu_find_file(int type, const char *name)
{
return 0;
}
+#ifdef CONFIG_VIRTFS
+static int fsdev_init_func(QemuOpts *opts, void *opaque)
+{
+ int ret;
+ ret = qemu_fsdev_add(opts);
+
+ return ret;
+}
+#endif
+
static int mon_init_func(QemuOpts *opts, void *opaque)
{
CharDriverState *chr;
if (strstart(optarg, "chardev:", &p)) {
snprintf(label, sizeof(label), "%s", p);
} else {
- if (monitor_device_index) {
- snprintf(label, sizeof(label), "monitor%d",
- monitor_device_index);
- } else {
- snprintf(label, sizeof(label), "monitor");
+ snprintf(label, sizeof(label), "compat_monitor%d",
+ monitor_device_index);
+ if (monitor_device_index == 0) {
def = 1;
}
opts = qemu_chr_parse_compat(label, optarg);
return 0;
}
+void qemu_add_exit_notifier(Notifier *notify)
+{
+ notifier_list_add(&exit_notifiers, notify);
+}
+
+void qemu_remove_exit_notifier(Notifier *notify)
+{
+ notifier_list_remove(&exit_notifiers, notify);
+}
+
+static void qemu_run_exit_notifiers(void)
+{
+ notifier_list_notify(&exit_notifiers);
+}
+
static const QEMUOption *lookup_opt(int argc, char **argv,
const char **poptarg, int *poptind)
{
int main(int argc, char **argv, char **envp)
{
const char *gdbstub_dev = NULL;
- uint32_t boot_devices_bitmap = 0;
int i;
- int snapshot, linux_boot, net_boot;
+ int snapshot, linux_boot;
const char *icount_option = NULL;
const char *initrd_filename;
const char *kernel_filename, *kernel_cmdline;
const char *loadvm = NULL;
QEMUMachine *machine;
const char *cpu_model;
-#ifndef _WIN32
- int fds[2];
-#endif
int tb_size;
const char *pid_file = NULL;
const char *incoming = NULL;
-#ifndef _WIN32
- int fd = 0;
- struct passwd *pwd = NULL;
- const char *chroot_dir = NULL;
- const char *run_as = NULL;
-#endif
- CPUState *env;
int show_vnc_port = 0;
int defconfig = 1;
+ atexit(qemu_run_exit_notifiers);
error_set_progname(argv[0]);
init_clocks();
qemu_cache_utils_init(envp);
QLIST_INIT (&vm_change_state_head);
-#ifndef _WIN32
- {
- struct sigaction act;
- sigfillset(&act.sa_mask);
- act.sa_flags = 0;
- act.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &act, NULL);
- }
-#else
- SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
- /* Note: cpu_interrupt() is currently not SMP safe, so we force
- QEMU to run on a single CPU */
- {
- HANDLE h;
- DWORD mask, smask;
- int i;
- h = GetCurrentProcess();
- if (GetProcessAffinityMask(h, &mask, &smask)) {
- for(i = 0; i < 32; i++) {
- if (mask & (1 << i))
- break;
- }
- if (i != 32) {
- mask = 1 << i;
- SetProcessAffinityMask(h, mask);
- }
- }
- }
-#endif
+ os_setup_early_signal_handling();
module_call_init(MODULE_INIT_MACHINE);
machine = find_default_machine();
}
if (defconfig) {
- const char *fname;
- FILE *fp;
+ int ret;
- fname = CONFIG_QEMU_CONFDIR "/qemu.conf";
- fp = fopen(fname, "r");
- if (fp) {
- if (qemu_config_parse(fp, fname) != 0) {
- exit(1);
- }
- fclose(fp);
+ ret = qemu_read_config_file(CONFIG_QEMU_CONFDIR "/qemu.conf");
+ if (ret < 0 && ret != -ENOENT) {
+ exit(1);
}
- fname = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".conf";
- fp = fopen(fname, "r");
- if (fp) {
- if (qemu_config_parse(fp, fname) != 0) {
- exit(1);
- }
- fclose(fp);
+ ret = qemu_read_config_file(arch_config_name);
+ if (ret < 0 && ret != -ENOENT) {
+ exit(1);
}
}
-#if defined(cpudef_setup)
- cpudef_setup(); /* parse cpu definitions in target config file */
-#endif
+ cpudef_init();
/* second pass of option parsing */
optind = 1;
const QEMUOption *popt;
popt = lookup_opt(argc, argv, &optarg, &optind);
+ if (!(popt->arch_mask & arch_type)) {
+ printf("Option %s not supported for this target\n", popt->name);
+ exit(1);
+ }
switch(popt->index) {
case QEMU_OPTION_M:
machine = find_machine(optarg);
case QEMU_OPTION_cpu:
/* hw initialization will check this */
if (*optarg == '?') {
-/* XXX: implement xxx_cpu_list for targets that still miss it */
-#if defined(cpu_list_id)
- cpu_list_id(stdout, &fprintf, optarg);
-#elif defined(cpu_list)
- cpu_list(stdout, &fprintf); /* deprecated */
-#endif
+ list_cpus(stdout, &fprintf, optarg);
exit(0);
} else {
cpu_model = optarg;
if (legacy ||
get_param_value(buf, sizeof(buf), "order", optarg)) {
- boot_devices_bitmap = parse_bootdevices(buf);
+ validate_bootdevices(buf);
pstrcpy(boot_devices, sizeof(boot_devices), buf);
}
if (!legacy) {
if (get_param_value(buf, sizeof(buf),
"once", optarg)) {
- boot_devices_bitmap |= parse_bootdevices(buf);
+ validate_bootdevices(buf);
standard_boot_devices = qemu_strdup(boot_devices);
pstrcpy(boot_devices, sizeof(boot_devices), buf);
qemu_register_reset(restore_boot_devices,
case QEMU_OPTION_fdb:
drive_add(optarg, FD_ALIAS, popt->index - QEMU_OPTION_fda);
break;
-#ifdef TARGET_I386
case QEMU_OPTION_no_fd_bootchk:
fd_bootchk = 0;
break;
-#endif
case QEMU_OPTION_netdev:
if (net_client_parse(&qemu_netdev_opts, optarg) == -1) {
exit(1);
case QEMU_OPTION_bootp:
legacy_bootp_filename = optarg;
break;
-#ifndef _WIN32
- case QEMU_OPTION_smb:
- if (net_slirp_smb(optarg) < 0)
- exit(1);
- break;
-#endif
case QEMU_OPTION_redir:
if (net_slirp_redir(optarg) < 0)
exit(1);
case QEMU_OPTION_bt:
add_device_config(DEV_BT, optarg);
break;
-#ifdef HAS_AUDIO
case QEMU_OPTION_audio_help:
+ if (!(audio_available())) {
+ printf("Option %s not supported for this target\n", popt->name);
+ exit(1);
+ }
AUD_help ();
exit (0);
break;
case QEMU_OPTION_soundhw:
+ if (!(audio_available())) {
+ printf("Option %s not supported for this target\n", popt->name);
+ exit(1);
+ }
select_soundhw (optarg);
break;
-#endif
case QEMU_OPTION_h:
help(0);
break;
break;
#endif
case QEMU_OPTION_d:
- {
- int mask;
- const CPULogItem *item;
-
- mask = cpu_str_to_log_mask(optarg);
- if (!mask) {
- printf("Log items (comma separated):\n");
- for(item = cpu_log_items; item->mask != 0; item++) {
- printf("%-10s %s\n", item->name, item->help);
- }
- exit(1);
- }
- cpu_set_log(mask);
- }
+ set_cpu_log(optarg);
break;
case QEMU_OPTION_s:
gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT;
case QEMU_OPTION_vga:
select_vgahw (optarg);
break;
-#if defined(TARGET_PPC) || defined(TARGET_SPARC)
case QEMU_OPTION_g:
{
const char *p;
graphic_depth = depth;
}
break;
-#endif
case QEMU_OPTION_echr:
{
char *r;
case QEMU_OPTION_mon:
opts = qemu_opts_parse(&qemu_mon_opts, optarg, 1);
if (!opts) {
- fprintf(stderr, "parse error: %s\n", optarg);
exit(1);
}
default_monitor = 0;
break;
case QEMU_OPTION_chardev:
opts = qemu_opts_parse(&qemu_chardev_opts, optarg, 1);
+ if (!opts) {
+ exit(1);
+ }
+ break;
+#ifdef CONFIG_VIRTFS
+ case QEMU_OPTION_fsdev:
+ opts = qemu_opts_parse(&qemu_fsdev_opts, optarg, 1);
if (!opts) {
fprintf(stderr, "parse error: %s\n", optarg);
exit(1);
}
break;
+ case QEMU_OPTION_virtfs: {
+ char *arg_fsdev = NULL;
+ char *arg_9p = NULL;
+ int len = 0;
+
+ opts = qemu_opts_parse(&qemu_virtfs_opts, optarg, 1);
+ if (!opts) {
+ fprintf(stderr, "parse error: %s\n", optarg);
+ exit(1);
+ }
+
+ if (qemu_opt_get(opts, "fstype") == NULL ||
+ qemu_opt_get(opts, "mount_tag") == NULL ||
+ qemu_opt_get(opts, "path") == NULL ||
+ qemu_opt_get(opts, "security_model") == NULL) {
+ fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/,"
+ "security_model=[mapped|passthrough],"
+ "mnt_tag=tag.\n");
+ exit(1);
+ }
+
+ len = strlen(",id=,path=,security_model=");
+ len += strlen(qemu_opt_get(opts, "fstype"));
+ len += strlen(qemu_opt_get(opts, "mount_tag"));
+ len += strlen(qemu_opt_get(opts, "path"));
+ len += strlen(qemu_opt_get(opts, "security_model"));
+ arg_fsdev = qemu_malloc((len + 1) * sizeof(*arg_fsdev));
+
+ if (!arg_fsdev) {
+ fprintf(stderr, "No memory to parse -fsdev for %s\n",
+ optarg);
+ exit(1);
+ }
+
+ sprintf(arg_fsdev, "%s,id=%s,path=%s,security_model=%s",
+ qemu_opt_get(opts, "fstype"),
+ qemu_opt_get(opts, "mount_tag"),
+ qemu_opt_get(opts, "path"),
+ qemu_opt_get(opts, "security_model"));
+
+ len = strlen("virtio-9p-pci,fsdev=,mount_tag=");
+ len += 2*strlen(qemu_opt_get(opts, "mount_tag"));
+ arg_9p = qemu_malloc((len + 1) * sizeof(*arg_9p));
+
+ if (!arg_9p) {
+ fprintf(stderr, "No memory to parse -device for %s\n",
+ optarg);
+ exit(1);
+ }
+
+ sprintf(arg_9p, "virtio-9p-pci,fsdev=%s,mount_tag=%s",
+ qemu_opt_get(opts, "mount_tag"),
+ qemu_opt_get(opts, "mount_tag"));
+
+ if (!qemu_opts_parse(&qemu_fsdev_opts, arg_fsdev, 1)) {
+ fprintf(stderr, "parse error [fsdev]: %s\n", optarg);
+ exit(1);
+ }
+
+ if (!qemu_opts_parse(&qemu_device_opts, arg_9p, 1)) {
+ fprintf(stderr, "parse error [device]: %s\n", optarg);
+ exit(1);
+ }
+
+ qemu_free(arg_fsdev);
+ qemu_free(arg_9p);
+ break;
+ }
+#endif
case QEMU_OPTION_serial:
add_device_config(DEV_SERIAL, optarg);
default_serial = 0;
case QEMU_OPTION_pidfile:
pid_file = optarg;
break;
-#ifdef TARGET_I386
case QEMU_OPTION_win2k_hack:
win2k_install_hack = 1;
break;
rtc_td_hack = 1;
break;
case QEMU_OPTION_acpitable:
- if(acpi_table_add(optarg) < 0) {
- fprintf(stderr, "Wrong acpi table provided\n");
- exit(1);
- }
+ do_acpitable_option(optarg);
break;
case QEMU_OPTION_smbios:
- if(smbios_entry_add(optarg) < 0) {
- fprintf(stderr, "Wrong smbios provided\n");
- exit(1);
- }
+ do_smbios_option(optarg);
break;
-#endif
-#ifdef CONFIG_KVM
case QEMU_OPTION_enable_kvm:
kvm_allowed = 1;
break;
-#endif
case QEMU_OPTION_usb:
usb_enabled = 1;
break;
display_type = DT_VNC;
vnc_display = optarg;
break;
-#ifdef TARGET_I386
case QEMU_OPTION_no_acpi:
acpi_enabled = 0;
break;
exit(1);
}
break;
-#endif
case QEMU_OPTION_no_reboot:
no_reboot = 1;
break;
exit(1);
}
break;
-#ifndef _WIN32
- case QEMU_OPTION_daemonize:
- daemonize = 1;
- break;
-#endif
case QEMU_OPTION_option_rom:
if (nb_option_roms >= MAX_OPTION_ROMS) {
fprintf(stderr, "Too many option ROMs\n");
option_rom[nb_option_roms] = optarg;
nb_option_roms++;
break;
-#if defined(TARGET_ARM) || defined(TARGET_M68K)
case QEMU_OPTION_semihosting:
semihosting_enabled = 1;
break;
-#endif
case QEMU_OPTION_name:
qemu_name = qemu_strdup(optarg);
{
exit(1);
}
p += 8;
- set_proc_name(p);
+ os_set_proc_name(p);
}
}
break;
-#if defined(TARGET_SPARC) || defined(TARGET_PPC)
case QEMU_OPTION_prom_env:
if (nb_prom_envs >= MAX_PROM_ENVS) {
fprintf(stderr, "Too many prom variables\n");
prom_envs[nb_prom_envs] = optarg;
nb_prom_envs++;
break;
-#endif
-#ifdef TARGET_ARM
case QEMU_OPTION_old_param:
old_param = 1;
break;
-#endif
case QEMU_OPTION_clock:
configure_alarms(optarg);
break;
case QEMU_OPTION_rtc:
opts = qemu_opts_parse(&qemu_rtc_opts, optarg, 0);
if (!opts) {
- fprintf(stderr, "parse error: %s\n", optarg);
exit(1);
}
configure_rtc(opts);
break;
case QEMU_OPTION_incoming:
incoming = optarg;
+ incoming_expected = true;
break;
case QEMU_OPTION_nodefaults:
default_serial = 0;
default_cdrom = 0;
default_sdcard = 0;
break;
-#ifndef _WIN32
- case QEMU_OPTION_chroot:
- chroot_dir = optarg;
- break;
- case QEMU_OPTION_runas:
- run_as = optarg;
- break;
-#endif
-#ifdef CONFIG_XEN
case QEMU_OPTION_xen_domid:
+ if (!(xen_available())) {
+ printf("Option %s not supported for this target\n", popt->name);
+ exit(1);
+ }
xen_domid = atoi(optarg);
break;
case QEMU_OPTION_xen_create:
+ if (!(xen_available())) {
+ printf("Option %s not supported for this target\n", popt->name);
+ exit(1);
+ }
xen_mode = XEN_CREATE;
break;
case QEMU_OPTION_xen_attach:
+ if (!(xen_available())) {
+ printf("Option %s not supported for this target\n", popt->name);
+ exit(1);
+ }
xen_mode = XEN_ATTACH;
break;
-#endif
case QEMU_OPTION_readconfig:
{
- FILE *fp;
- fp = fopen(optarg, "r");
- if (fp == NULL) {
- fprintf(stderr, "open %s: %s\n", optarg, strerror(errno));
- exit(1);
- }
- if (qemu_config_parse(fp, optarg) != 0) {
+ int ret = qemu_read_config_file(optarg);
+ if (ret < 0) {
+ fprintf(stderr, "read config %s: %s\n", optarg,
+ strerror(-ret));
exit(1);
}
- fclose(fp);
break;
}
case QEMU_OPTION_writeconfig:
fclose(fp);
break;
}
+ default:
+ os_parse_cmd_args(popt->index, optarg);
}
}
}
/* If no data_dir is specified then try to find it relative to the
executable path. */
if (!data_dir) {
- data_dir = find_datadir(argv[0]);
+ data_dir = os_find_datadir(argv[0]);
}
/* If all else fails use the install patch specified when building. */
if (!data_dir) {
- data_dir = CONFIG_QEMU_SHAREDIR;
+ data_dir = CONFIG_QEMU_DATADIR;
}
/*
if (default_vga)
vga_interface_type = VGA_CIRRUS;
+ socket_init();
+
if (qemu_opts_foreach(&qemu_chardev_opts, chardev_init_func, NULL, 1) != 0)
exit(1);
-
-#ifndef _WIN32
- if (daemonize) {
- pid_t pid;
-
- if (pipe(fds) == -1)
- exit(1);
-
- pid = fork();
- if (pid > 0) {
- uint8_t status;
- ssize_t len;
-
- close(fds[1]);
-
- again:
- len = read(fds[0], &status, 1);
- if (len == -1 && (errno == EINTR))
- goto again;
-
- if (len != 1)
- exit(1);
- else if (status == 1) {
- fprintf(stderr, "Could not acquire pidfile: %s\n", strerror(errno));
- exit(1);
- } else
- exit(0);
- } else if (pid < 0)
- exit(1);
-
- close(fds[0]);
- qemu_set_cloexec(fds[1]);
-
- setsid();
-
- pid = fork();
- if (pid > 0)
- exit(0);
- else if (pid < 0)
- exit(1);
-
- umask(027);
-
- signal(SIGTSTP, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
- signal(SIGTTIN, SIG_IGN);
+#ifdef CONFIG_VIRTFS
+ if (qemu_opts_foreach(&qemu_fsdev_opts, fsdev_init_func, NULL, 1) != 0) {
+ exit(1);
}
#endif
+ os_daemonize();
+
if (pid_file && qemu_create_pidfile(pid_file) != 0) {
-#ifndef _WIN32
- if (daemonize) {
- uint8_t status = 1;
- if (write(fds[1], &status, 1) != 1) {
- perror("daemonize. Writing to pipe\n");
- }
- } else
-#endif
- fprintf(stderr, "Could not acquire pid file: %s\n", strerror(errno));
+ os_pidfile_error();
exit(1);
}
- if (kvm_enabled()) {
- int ret;
-
- ret = kvm_init(smp_cpus);
+ if (kvm_allowed) {
+ int ret = kvm_init(smp_cpus);
if (ret < 0) {
- fprintf(stderr, "failed to initialize KVM\n");
+ if (!kvm_available()) {
+ printf("KVM not supported for this target\n");
+ } else {
+ fprintf(stderr, "failed to initialize KVM: %s\n", strerror(-ret));
+ }
exit(1);
}
}
exit(1);
}
-#ifndef _WIN32
- /* Win32 doesn't support line-buffering and requires size >= 2 */
- setvbuf(stdout, NULL, _IOLBF, 0);
-#endif
+ os_set_line_buffering();
if (init_timer_alarm() < 0) {
fprintf(stderr, "could not initialize alarm timer\n");
}
configure_icount(icount_option);
-#ifdef _WIN32
- socket_init();
-#endif
-
if (net_init_clients() < 0) {
exit(1);
}
- net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
- net_set_boot_mask(net_boot);
-
/* init the bluetooth world */
if (foreach_device_config(DEV_BT, bt_parse))
exit(1);
/* open the virtual block devices */
if (snapshot)
qemu_opts_foreach(&qemu_drive_opts, drive_enable_snapshot, NULL, 0);
- if (qemu_opts_foreach(&qemu_drive_opts, drive_init_func, machine, 1) != 0)
+ if (qemu_opts_foreach(&qemu_drive_opts, drive_init_func, &machine->use_scsi, 1) != 0)
exit(1);
- register_savevm_live("ram", 0, 3, NULL, ram_save_live, NULL,
+ register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL,
ram_load, NULL);
if (nb_numa_nodes > 0) {
}
}
+ if (qemu_opts_foreach(&qemu_mon_opts, mon_init_func, NULL, 1) != 0) {
+ exit(1);
+ }
+
if (foreach_device_config(DEV_SERIAL, serial_parse) < 0)
exit(1);
if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0)
cpu_synchronize_all_post_init();
-#ifndef _WIN32
/* must be after terminal init, SDL library changes signal handlers */
- sighandler_setup();
-#endif
+ os_setup_signal_handling();
- for (env = first_cpu; env != NULL; env = env->next_cpu) {
- for (i = 0; i < nb_numa_nodes; i++) {
- if (node_cpumask[i] & (1 << env->cpu_index)) {
- env->numa_node = i;
- }
- }
- }
+ set_numa_modes();
current_machine = machine;
if (dcl->dpy_refresh != NULL) {
ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds);
qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock));
+ break;
}
dcl = dcl->next;
}
text_consoles_set_display(ds);
- if (qemu_opts_foreach(&qemu_mon_opts, mon_init_func, NULL, 1) != 0)
- exit(1);
-
if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n",
gdbstub_dev);
}
if (incoming) {
- qemu_start_incoming_migration(incoming);
+ int ret = qemu_start_incoming_migration(incoming);
+ if (ret < 0) {
+ fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n",
+ incoming, ret);
+ exit(ret);
+ }
} else if (autostart) {
vm_start();
}
-#ifndef _WIN32
- if (daemonize) {
- uint8_t status = 0;
- ssize_t len;
-
- again1:
- len = write(fds[1], &status, 1);
- if (len == -1 && (errno == EINTR))
- goto again1;
-
- if (len != 1)
- exit(1);
-
- if (chdir("/")) {
- perror("not able to chdir to /");
- exit(1);
- }
- TFR(fd = qemu_open("/dev/null", O_RDWR));
- if (fd == -1)
- exit(1);
- }
-
- if (run_as) {
- pwd = getpwnam(run_as);
- if (!pwd) {
- fprintf(stderr, "User \"%s\" doesn't exist\n", run_as);
- exit(1);
- }
- }
-
- if (chroot_dir) {
- if (chroot(chroot_dir) < 0) {
- fprintf(stderr, "chroot failed\n");
- exit(1);
- }
- if (chdir("/")) {
- perror("not able to chdir to /");
- exit(1);
- }
- }
-
- if (run_as) {
- if (setgid(pwd->pw_gid) < 0) {
- fprintf(stderr, "Failed to setgid(%d)\n", pwd->pw_gid);
- exit(1);
- }
- if (setuid(pwd->pw_uid) < 0) {
- fprintf(stderr, "Failed to setuid(%d)\n", pwd->pw_uid);
- exit(1);
- }
- if (setuid(0) != -1) {
- fprintf(stderr, "Dropping privileges failed\n");
- exit(1);
- }
- }
-
- if (daemonize) {
- dup2(fd, 0);
- dup2(fd, 1);
- dup2(fd, 2);
-
- close(fd);
- }
-#endif
+ os_setup_post();
main_loop();
quit_timers();