/* Needed early for HOST_BSD etc. */
#include "config-host.h"
+/* Needed early to override system queue definitions on BSD */
+#include "sys-queue.h"
#ifndef _WIN32
#include <libgen.h>
#include <pty.h>
#include <malloc.h>
#include <linux/rtc.h>
+#include <sys/prctl.h>
/* For the benefit of older linux systems which don't supply it,
we use a local copy of hpet.h. */
#ifdef _WIN32
#include <windows.h>
-#include <malloc.h>
-#include <sys/timeb.h>
#include <mmsystem.h>
-#define getopt_long_only getopt_long
-#define memalign(align, size) malloc(size)
#endif
#ifdef CONFIG_SDL
#include "hw/watchdog.h"
#include "hw/smbios.h"
#include "hw/xen.h"
+#include "hw/qdev.h"
#include "bt-host.h"
#include "net.h"
#include "monitor.h"
#include "qemu_socket.h"
-#if defined(CONFIG_SLIRP)
-#include "libslirp.h"
-#endif
+#include "slirp/libslirp.h"
-//#define DEBUG_UNUSED_IOPORT
-//#define DEBUG_IOPORT
//#define DEBUG_NET
//#define DEBUG_SLIRP
-
-#ifdef DEBUG_IOPORT
-# define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__)
-#else
-# define LOG_IOPORT(...) do { } while (0)
-#endif
-
#define DEFAULT_RAM_SIZE 128
-/* Max number of USB devices that can be specified on the commandline. */
-#define MAX_USB_CMDLINE 8
-
-/* Max number of bluetooth switches on the commandline. */
-#define MAX_BT_CMDLINE 10
-
-/* XXX: use a two level table to limit memory usage */
-#define MAX_IOPORTS 65536
-
static const char *data_dir;
const char *bios_name = NULL;
-static void *ioport_opaque[MAX_IOPORTS];
-static IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
-static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
/* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
to store the VM snapshots */
-DriveInfo drives_table[MAX_DRIVES+1];
-int nb_drives;
+struct drivelist drives = TAILQ_HEAD_INITIALIZER(drives);
+struct driveoptlist driveopts = TAILQ_HEAD_INITIALIZER(driveopts);
enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
static DisplayState *display_state;
DisplayType display_type = DT_DEFAULT;
int usb_enabled = 0;
int singlestep = 0;
int smp_cpus = 1;
+int max_cpus = 0;
const char *vnc_display;
int acpi_enabled = 1;
int no_hpet = 0;
-int no_virtio_balloon = 0;
+int virtio_balloon = 1;
+const char *virtio_balloon_devaddr;
int fd_bootchk = 1;
int no_reboot = 0;
int no_shutdown = 0;
unsigned int nb_prom_envs = 0;
const char *prom_envs[MAX_PROM_ENVS];
#endif
-int nb_drives_opt;
-struct drive_opt drives_opt[MAX_DRIVES];
+int boot_menu;
int nb_numa_nodes;
uint64_t node_mem[MAX_NODES];
uint8_t qemu_uuid[16];
+static QEMUBootSetHandler *boot_set_handler;
+static void *boot_set_opaque;
+
/***********************************************************/
/* x86 ISA bus support */
target_phys_addr_t isa_mem_base = 0;
PicState2 *isa_pic;
-static IOPortReadFunc default_ioport_readb, default_ioport_readw, default_ioport_readl;
-static IOPortWriteFunc default_ioport_writeb, default_ioport_writew, default_ioport_writel;
-
-static uint32_t ioport_read(int index, uint32_t address)
-{
- static IOPortReadFunc *default_func[3] = {
- default_ioport_readb,
- default_ioport_readw,
- default_ioport_readl
- };
- IOPortReadFunc *func = ioport_read_table[index][address];
- if (!func)
- func = default_func[index];
- return func(ioport_opaque[address], address);
-}
-
-static void ioport_write(int index, uint32_t address, uint32_t data)
-{
- static IOPortWriteFunc *default_func[3] = {
- default_ioport_writeb,
- default_ioport_writew,
- default_ioport_writel
- };
- IOPortWriteFunc *func = ioport_write_table[index][address];
- if (!func)
- func = default_func[index];
- func(ioport_opaque[address], address, data);
-}
-
-static uint32_t default_ioport_readb(void *opaque, uint32_t address)
-{
-#ifdef DEBUG_UNUSED_IOPORT
- fprintf(stderr, "unused inb: port=0x%04x\n", address);
-#endif
- return 0xff;
-}
-
-static void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
-{
-#ifdef DEBUG_UNUSED_IOPORT
- fprintf(stderr, "unused outb: port=0x%04x data=0x%02x\n", address, data);
-#endif
-}
-
-/* default is to make two byte accesses */
-static uint32_t default_ioport_readw(void *opaque, uint32_t address)
-{
- uint32_t data;
- data = ioport_read(0, address);
- address = (address + 1) & (MAX_IOPORTS - 1);
- data |= ioport_read(0, address) << 8;
- return data;
-}
-
-static void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
-{
- ioport_write(0, address, data & 0xff);
- address = (address + 1) & (MAX_IOPORTS - 1);
- ioport_write(0, address, (data >> 8) & 0xff);
-}
-
-static uint32_t default_ioport_readl(void *opaque, uint32_t address)
-{
-#ifdef DEBUG_UNUSED_IOPORT
- fprintf(stderr, "unused inl: port=0x%04x\n", address);
-#endif
- return 0xffffffff;
-}
-
-static void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
-{
-#ifdef DEBUG_UNUSED_IOPORT
- fprintf(stderr, "unused outl: port=0x%04x data=0x%02x\n", address, data);
-#endif
-}
-
-/* size is the word size in byte */
-int register_ioport_read(int start, int length, int size,
- IOPortReadFunc *func, void *opaque)
-{
- int i, bsize;
-
- if (size == 1) {
- bsize = 0;
- } else if (size == 2) {
- bsize = 1;
- } else if (size == 4) {
- bsize = 2;
- } else {
- hw_error("register_ioport_read: invalid size");
- return -1;
- }
- for(i = start; i < start + length; i += size) {
- ioport_read_table[bsize][i] = func;
- if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
- hw_error("register_ioport_read: invalid opaque");
- ioport_opaque[i] = opaque;
- }
- return 0;
-}
-
-/* size is the word size in byte */
-int register_ioport_write(int start, int length, int size,
- IOPortWriteFunc *func, void *opaque)
-{
- int i, bsize;
-
- if (size == 1) {
- bsize = 0;
- } else if (size == 2) {
- bsize = 1;
- } else if (size == 4) {
- bsize = 2;
- } else {
- hw_error("register_ioport_write: invalid size");
- return -1;
- }
- for(i = start; i < start + length; i += size) {
- ioport_write_table[bsize][i] = func;
- if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
- hw_error("register_ioport_write: invalid opaque");
- ioport_opaque[i] = opaque;
- }
- return 0;
-}
-
-void isa_unassign_ioport(int start, int length)
-{
- int i;
-
- for(i = start; i < start + length; i++) {
- ioport_read_table[0][i] = default_ioport_readb;
- ioport_read_table[1][i] = default_ioport_readw;
- ioport_read_table[2][i] = default_ioport_readl;
-
- ioport_write_table[0][i] = default_ioport_writeb;
- ioport_write_table[1][i] = default_ioport_writew;
- ioport_write_table[2][i] = default_ioport_writel;
-
- ioport_opaque[i] = NULL;
- }
-}
-
-/***********************************************************/
-
-void cpu_outb(CPUState *env, int addr, int val)
-{
- LOG_IOPORT("outb: %04x %02x\n", addr, val);
- ioport_write(0, addr, val);
-#ifdef CONFIG_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
-}
-
-void cpu_outw(CPUState *env, int addr, int val)
-{
- LOG_IOPORT("outw: %04x %04x\n", addr, val);
- ioport_write(1, addr, val);
-#ifdef CONFIG_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
-}
-
-void cpu_outl(CPUState *env, int addr, int val)
-{
- LOG_IOPORT("outl: %04x %08x\n", addr, val);
- ioport_write(2, addr, val);
-#ifdef CONFIG_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
-}
-
-int cpu_inb(CPUState *env, int addr)
-{
- int val;
- val = ioport_read(0, addr);
- LOG_IOPORT("inb : %04x %02x\n", addr, val);
-#ifdef CONFIG_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
- return val;
-}
-
-int cpu_inw(CPUState *env, int addr)
-{
- int val;
- val = ioport_read(1, addr);
- LOG_IOPORT("inw : %04x %04x\n", addr, val);
-#ifdef CONFIG_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
- return val;
-}
-
-int cpu_inl(CPUState *env, int addr)
-{
- int val;
- val = ioport_read(2, addr);
- LOG_IOPORT("inl : %04x %08x\n", addr, val);
-#ifdef CONFIG_KQEMU
- if (env)
- env->last_io_time = cpu_get_time_fast();
-#endif
- return val;
-}
-
/***********************************************************/
void hw_error(const char *fmt, ...)
{
va_end(ap);
abort();
}
+
+static void set_proc_name(const char *s)
+{
+#ifdef __linux__
+ 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 */
}
#endif
-int get_next_param_value(char *buf, int buf_size,
- const char *tag, const char **pstr)
-{
- const char *p;
- char option[128];
-
- p = *pstr;
- for(;;) {
- p = get_opt_name(option, sizeof(option), p, '=');
- if (*p != '=')
- break;
- p++;
- if (!strcmp(tag, option)) {
- *pstr = get_opt_value(buf, buf_size, p);
- if (**pstr == ',') {
- (*pstr)++;
- }
- return strlen(buf);
- } else {
- p = get_opt_value(NULL, 0, p);
- }
- if (*p != ',')
- break;
- p++;
- }
- return 0;
-}
-
-int get_param_value(char *buf, int buf_size,
- const char *tag, const char *str)
-{
- return get_next_param_value(buf, buf_size, tag, &str);
-}
-
-int check_params(char *buf, int buf_size,
- const char * const *params, const char *str)
-{
- const char *p;
- int i;
-
- p = str;
- while (*p != '\0') {
- p = get_opt_name(buf, buf_size, p, '=');
- if (*p != '=') {
- return -1;
- }
- p++;
- for (i = 0; params[i] != NULL; i++) {
- if (!strcmp(params[i], buf)) {
- break;
- }
- }
- if (params[i] == NULL) {
- return -1;
- }
- p = get_opt_value(NULL, 0, p);
- if (*p != ',') {
- break;
- }
- p++;
- }
- return 0;
-}
-
/***********************************************************/
/* Bluetooth support */
static int nb_hcis;
#define MTD_ALIAS "if=mtd"
#define SD_ALIAS "index=0,if=sd"
-static int drive_opt_get_free_idx(void)
-{
- int index;
-
- for (index = 0; index < MAX_DRIVES; index++)
- if (!drives_opt[index].used) {
- drives_opt[index].used = 1;
- return index;
- }
-
- return -1;
-}
-
-static int drive_get_free_idx(void)
-{
- int index;
-
- for (index = 0; index < MAX_DRIVES; index++)
- if (!drives_table[index].used) {
- drives_table[index].used = 1;
- return index;
- }
-
- return -1;
-}
+static QemuOptsList drive_opt_list = {
+ .name = "drive",
+ .head = TAILQ_HEAD_INITIALIZER(drive_opt_list.head),
+ .desc = {
+ {
+ .name = "bus",
+ .type = QEMU_OPT_NUMBER,
+ .help = "bus number",
+ },{
+ .name = "unit",
+ .type = QEMU_OPT_NUMBER,
+ .help = "unit number (i.e. lun for scsi)",
+ },{
+ .name = "if",
+ .type = QEMU_OPT_STRING,
+ .help = "interface (ide, scsi, sd, mtd, floppy, pflash, virtio)",
+ },{
+ .name = "index",
+ .type = QEMU_OPT_NUMBER,
+ },{
+ .name = "cyls",
+ .type = QEMU_OPT_NUMBER,
+ .help = "number of cylinders (ide disk geometry)",
+ },{
+ .name = "heads",
+ .type = QEMU_OPT_NUMBER,
+ .help = "number of heads (ide disk geometry)",
+ },{
+ .name = "secs",
+ .type = QEMU_OPT_NUMBER,
+ .help = "number of sectors (ide disk geometry)",
+ },{
+ .name = "trans",
+ .type = QEMU_OPT_STRING,
+ .help = "chs translation (auto, lba. none)",
+ },{
+ .name = "media",
+ .type = QEMU_OPT_STRING,
+ .help = "media type (disk, cdrom)",
+ },{
+ .name = "snapshot",
+ .type = QEMU_OPT_BOOL,
+ },{
+ .name = "file",
+ .type = QEMU_OPT_STRING,
+ .help = "disk image",
+ },{
+ .name = "cache",
+ .type = QEMU_OPT_STRING,
+ .help = "host cache usage (none, writeback, writethrough)",
+ },{
+ .name = "format",
+ .type = QEMU_OPT_STRING,
+ .help = "disk format (raw, qcow2, ...)",
+ },{
+ .name = "serial",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "werror",
+ .type = QEMU_OPT_STRING,
+ },{
+ .name = "addr",
+ .type = QEMU_OPT_STRING,
+ .help = "pci address (virtio only)",
+ },
+ { /* end if list */ }
+ },
+};
-int drive_add(const char *file, const char *fmt, ...)
+QemuOpts *drive_add(const char *file, const char *fmt, ...)
{
va_list ap;
- int index = drive_opt_get_free_idx();
-
- if (nb_drives_opt >= MAX_DRIVES || index == -1) {
- fprintf(stderr, "qemu: too many drives\n");
- return -1;
- }
+ char optstr[1024];
+ QemuOpts *opts;
- drives_opt[index].file = file;
va_start(ap, fmt);
- vsnprintf(drives_opt[index].opt,
- sizeof(drives_opt[0].opt), fmt, ap);
+ vsnprintf(optstr, sizeof(optstr), fmt, ap);
va_end(ap);
- nb_drives_opt++;
- return index;
-}
-
-void drive_remove(int index)
-{
- drives_opt[index].used = 0;
- nb_drives_opt--;
+ opts = qemu_opts_parse(&drive_opt_list, optstr, NULL);
+ if (!opts) {
+ fprintf(stderr, "%s: huh? duplicate? (%s)\n",
+ __FUNCTION__, optstr);
+ return NULL;
+ }
+ if (file)
+ qemu_opt_set(opts, "file", file);
+ return opts;
}
-int drive_get_index(BlockInterfaceType type, int bus, int unit)
+DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit)
{
- int index;
+ DriveInfo *dinfo;
/* seek interface, bus and unit */
- for (index = 0; index < MAX_DRIVES; index++)
- if (drives_table[index].type == type &&
- drives_table[index].bus == bus &&
- drives_table[index].unit == unit &&
- drives_table[index].used)
- return index;
+ TAILQ_FOREACH(dinfo, &drives, next) {
+ if (dinfo->type == type &&
+ dinfo->bus == bus &&
+ dinfo->unit == unit)
+ return dinfo;
+ }
- return -1;
+ return NULL;
+}
+
+DriveInfo *drive_get_by_id(char *id)
+{
+ DriveInfo *dinfo;
+
+ TAILQ_FOREACH(dinfo, &drives, next) {
+ if (strcmp(id, dinfo->id))
+ continue;
+ return dinfo;
+ }
+ return NULL;
}
int drive_get_max_bus(BlockInterfaceType type)
{
int max_bus;
- int index;
+ DriveInfo *dinfo;
max_bus = -1;
- for (index = 0; index < nb_drives; index++) {
- if(drives_table[index].type == type &&
- drives_table[index].bus > max_bus)
- max_bus = drives_table[index].bus;
+ TAILQ_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)
{
- int index;
+ DriveInfo *dinfo;
- for (index = 0; index < nb_drives; index++)
- if (drives_table[index].bdrv == bdrv)
- return drives_table[index].serial;
+ TAILQ_FOREACH(dinfo, &drives, next) {
+ if (dinfo->bdrv == bdrv)
+ return dinfo->serial;
+ }
return "\0";
}
BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv)
{
- int index;
+ DriveInfo *dinfo;
- for (index = 0; index < nb_drives; index++)
- if (drives_table[index].bdrv == bdrv)
- return drives_table[index].onerror;
+ TAILQ_FOREACH(dinfo, &drives, next) {
+ if (dinfo->bdrv == bdrv)
+ return dinfo->onerror;
+ }
return BLOCK_ERR_STOP_ENOSPC;
}
void drive_uninit(BlockDriverState *bdrv)
{
- int i;
+ DriveInfo *dinfo;
- for (i = 0; i < MAX_DRIVES; i++)
- if (drives_table[i].bdrv == bdrv) {
- drives_table[i].bdrv = NULL;
- drives_table[i].used = 0;
- drive_remove(drives_table[i].drive_opt_idx);
- nb_drives--;
- break;
- }
+ TAILQ_FOREACH(dinfo, &drives, next) {
+ if (dinfo->bdrv != bdrv)
+ continue;
+ qemu_opts_del(dinfo->opts);
+ TAILQ_REMOVE(&drives, dinfo, next);
+ qemu_free(dinfo);
+ break;
+ }
}
-int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
+DriveInfo *drive_init(QemuOpts *opts, void *opaque,
+ int *fatal_error)
{
- char buf[128];
- char file[1024];
+ const char *buf;
+ const char *file = NULL;
char devname[128];
- char serial[21];
+ const char *serial;
const char *mediastr = "";
BlockInterfaceType type;
enum { MEDIA_DISK, MEDIA_CDROM } media;
int bus_id, unit_id;
int cyls, heads, secs, translation;
- BlockDriverState *bdrv;
BlockDriver *drv = NULL;
QEMUMachine *machine = opaque;
int max_devs;
int cache;
int bdrv_flags, onerror;
const char *devaddr;
- int drives_table_idx;
- char *str = arg->opt;
- static const char * const params[] = { "bus", "unit", "if", "index",
- "cyls", "heads", "secs", "trans",
- "media", "snapshot", "file",
- "cache", "format", "serial",
- "werror", "addr",
- NULL };
-
- if (check_params(buf, sizeof(buf), params, str) < 0) {
- fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n",
- buf, str);
- return -1;
- }
-
- file[0] = 0;
- cyls = heads = secs = 0;
- bus_id = 0;
- unit_id = -1;
+ DriveInfo *dinfo;
+ int snapshot = 0;
+
+ *fatal_error = 1;
+
translation = BIOS_ATA_TRANSLATION_AUTO;
- index = -1;
- cache = 3;
+ cache = 1;
if (machine->use_scsi) {
type = IF_SCSI;
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);
- if (get_param_value(buf, sizeof(buf), "bus", str)) {
- bus_id = strtol(buf, NULL, 0);
- if (bus_id < 0) {
- fprintf(stderr, "qemu: '%s' invalid bus id\n", str);
- return -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);
- if (get_param_value(buf, sizeof(buf), "unit", str)) {
- unit_id = strtol(buf, NULL, 0);
- if (unit_id < 0) {
- fprintf(stderr, "qemu: '%s' invalid unit id\n", str);
- return -1;
- }
- }
+ snapshot = qemu_opt_get_bool(opts, "snapshot", 0);
+
+ file = qemu_opt_get(opts, "file");
+ serial = qemu_opt_get(opts, "serial");
- if (get_param_value(buf, sizeof(buf), "if", str)) {
+ if ((buf = qemu_opt_get(opts, "if")) != NULL) {
pstrcpy(devname, sizeof(devname), buf);
if (!strcmp(buf, "ide")) {
type = IF_IDE;
type = IF_XEN;
max_devs = 0;
} else {
- fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
- return -1;
- }
- }
-
- if (get_param_value(buf, sizeof(buf), "index", str)) {
- index = strtol(buf, NULL, 0);
- if (index < 0) {
- fprintf(stderr, "qemu: '%s' invalid index\n", str);
- return -1;
+ fprintf(stderr, "qemu: unsupported bus type '%s'\n", buf);
+ return NULL;
}
}
- if (get_param_value(buf, sizeof(buf), "cyls", str)) {
- cyls = strtol(buf, NULL, 0);
- }
-
- if (get_param_value(buf, sizeof(buf), "heads", str)) {
- heads = strtol(buf, NULL, 0);
- }
-
- if (get_param_value(buf, sizeof(buf), "secs", str)) {
- secs = strtol(buf, NULL, 0);
- }
-
if (cyls || heads || secs) {
if (cyls < 1 || cyls > 16383) {
- fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", str);
- return -1;
+ fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", buf);
+ return NULL;
}
if (heads < 1 || heads > 16) {
- fprintf(stderr, "qemu: '%s' invalid physical heads number\n", str);
- return -1;
+ fprintf(stderr, "qemu: '%s' invalid physical heads number\n", buf);
+ return NULL;
}
if (secs < 1 || secs > 63) {
- fprintf(stderr, "qemu: '%s' invalid physical secs number\n", str);
- return -1;
+ fprintf(stderr, "qemu: '%s' invalid physical secs number\n", buf);
+ return NULL;
}
}
- if (get_param_value(buf, sizeof(buf), "trans", str)) {
+ if ((buf = qemu_opt_get(opts, "trans")) != NULL) {
if (!cyls) {
fprintf(stderr,
"qemu: '%s' trans must be used with cyls,heads and secs\n",
- str);
- return -1;
+ buf);
+ return NULL;
}
if (!strcmp(buf, "none"))
translation = BIOS_ATA_TRANSLATION_NONE;
else if (!strcmp(buf, "auto"))
translation = BIOS_ATA_TRANSLATION_AUTO;
else {
- fprintf(stderr, "qemu: '%s' invalid translation type\n", str);
- return -1;
+ fprintf(stderr, "qemu: '%s' invalid translation type\n", buf);
+ return NULL;
}
}
- if (get_param_value(buf, sizeof(buf), "media", str)) {
+ 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", str);
- return -1;
+ "qemu: '%s' invalid physical CHS format\n", buf);
+ return NULL;
}
media = MEDIA_CDROM;
} else {
- fprintf(stderr, "qemu: '%s' invalid media\n", str);
- return -1;
- }
- }
-
- if (get_param_value(buf, sizeof(buf), "snapshot", str)) {
- if (!strcmp(buf, "on"))
- snapshot = 1;
- else if (!strcmp(buf, "off"))
- snapshot = 0;
- else {
- fprintf(stderr, "qemu: '%s' invalid snapshot option\n", str);
- return -1;
+ fprintf(stderr, "qemu: '%s' invalid media\n", buf);
+ return NULL;
}
}
- if (get_param_value(buf, sizeof(buf), "cache", str)) {
+ if ((buf = qemu_opt_get(opts, "cache")) != NULL) {
if (!strcmp(buf, "off") || !strcmp(buf, "none"))
cache = 0;
else if (!strcmp(buf, "writethrough"))
cache = 2;
else {
fprintf(stderr, "qemu: invalid cache option\n");
- return -1;
+ return NULL;
}
}
- if (get_param_value(buf, sizeof(buf), "format", str)) {
+ 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 -1;
+ return NULL;
}
drv = bdrv_find_format(buf);
if (!drv) {
fprintf(stderr, "qemu: '%s' invalid format\n", buf);
- return -1;
+ return NULL;
}
}
- if (arg->file == NULL)
- get_param_value(file, sizeof(file), "file", str);
- else
- pstrcpy(file, sizeof(file), arg->file);
-
- if (!get_param_value(serial, sizeof(serial), "serial", str))
- memset(serial, 0, sizeof(serial));
-
onerror = BLOCK_ERR_STOP_ENOSPC;
- if (get_param_value(buf, sizeof(serial), "werror", str)) {
+ 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 -1;
+ return NULL;
}
if (!strcmp(buf, "ignore"))
onerror = BLOCK_ERR_IGNORE;
onerror = BLOCK_ERR_REPORT;
else {
fprintf(stderr, "qemu: '%s' invalid write error action\n", buf);
- return -1;
+ return NULL;
}
}
- devaddr = NULL;
- if (get_param_value(buf, sizeof(buf), "addr", str)) {
+ if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) {
if (type != IF_VIRTIO) {
- fprintf(stderr, "addr is not supported by in '%s'\n", str);
- return -1;
+ fprintf(stderr, "addr is not supported\n");
+ return NULL;
}
- devaddr = strdup(buf);
}
/* compute bus and unit according index */
if (index != -1) {
if (bus_id != 0 || unit_id != -1) {
fprintf(stderr,
- "qemu: '%s' index cannot be used with bus and unit\n", str);
- return -1;
+ "qemu: index cannot be used with bus and unit\n");
+ return NULL;
}
if (max_devs == 0)
{
if (unit_id == -1) {
unit_id = 0;
- while (drive_get_index(type, bus_id, unit_id) != -1) {
+ while (drive_get(type, bus_id, unit_id) != NULL) {
unit_id++;
if (max_devs && unit_id >= max_devs) {
unit_id -= max_devs;
/* check unit id */
if (max_devs && unit_id >= max_devs) {
- fprintf(stderr, "qemu: '%s' unit %d too big (max is %d)\n",
- str, unit_id, max_devs - 1);
- return -1;
+ fprintf(stderr, "qemu: unit %d too big (max is %d)\n",
+ unit_id, max_devs - 1);
+ return NULL;
}
/*
* ignore multiple definitions
*/
- if (drive_get_index(type, bus_id, unit_id) != -1)
- return -2;
+ if (drive_get(type, bus_id, unit_id) != NULL) {
+ *fatal_error = 0;
+ return NULL;
+ }
/* init */
- if (type == IF_IDE || type == IF_SCSI)
- mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
- if (max_devs)
- snprintf(buf, sizeof(buf), "%s%i%s%i",
- devname, bus_id, mediastr, unit_id);
- else
- snprintf(buf, sizeof(buf), "%s%s%i",
- devname, mediastr, unit_id);
- bdrv = bdrv_new(buf);
- drives_table_idx = drive_get_free_idx();
- drives_table[drives_table_idx].bdrv = bdrv;
- drives_table[drives_table_idx].devaddr = devaddr;
- drives_table[drives_table_idx].type = type;
- drives_table[drives_table_idx].bus = bus_id;
- drives_table[drives_table_idx].unit = unit_id;
- drives_table[drives_table_idx].onerror = onerror;
- drives_table[drives_table_idx].drive_opt_idx = arg - drives_opt;
- strncpy(drives_table[drives_table_idx].serial, serial, sizeof(serial));
- nb_drives++;
+ dinfo = qemu_mallocz(sizeof(*dinfo));
+ if ((buf = qemu_opt_get(opts, "id")) != 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->onerror = onerror;
+ dinfo->opts = opts;
+ if (serial)
+ strncpy(dinfo->serial, serial, sizeof(serial));
+ TAILQ_INSERT_TAIL(&drives, dinfo, next);
switch(type) {
case IF_IDE:
switch(media) {
case MEDIA_DISK:
if (cyls != 0) {
- bdrv_set_geometry_hint(bdrv, cyls, heads, secs);
- bdrv_set_translation_hint(bdrv, translation);
+ bdrv_set_geometry_hint(dinfo->bdrv, cyls, heads, secs);
+ bdrv_set_translation_hint(dinfo->bdrv, translation);
}
break;
case MEDIA_CDROM:
- bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);
+ bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_CDROM);
break;
}
break;
/* FIXME: This isn't really a floppy, but it's a reasonable
approximation. */
case IF_FLOPPY:
- bdrv_set_type_hint(bdrv, BDRV_TYPE_FLOPPY);
+ bdrv_set_type_hint(dinfo->bdrv, BDRV_TYPE_FLOPPY);
break;
case IF_PFLASH:
case IF_MTD:
case IF_COUNT:
abort();
}
- if (!file[0])
- return -2;
+ if (!file) {
+ *fatal_error = 0;
+ return NULL;
+ }
bdrv_flags = 0;
if (snapshot) {
bdrv_flags |= BDRV_O_SNAPSHOT;
bdrv_flags |= BDRV_O_NOCACHE;
else if (cache == 2) /* write-back */
bdrv_flags |= BDRV_O_CACHE_WB;
- else if (cache == 3) /* not specified */
- bdrv_flags |= BDRV_O_CACHE_DEF;
- if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0) {
+ if (bdrv_open2(dinfo->bdrv, file, bdrv_flags, drv) < 0) {
fprintf(stderr, "qemu: could not open disk image %s\n",
file);
- return -1;
+ return NULL;
}
- if (bdrv_key_required(bdrv))
+ if (bdrv_key_required(dinfo->bdrv))
autostart = 0;
- return drives_table_idx;
+ *fatal_error = 0;
+ return dinfo;
+}
+
+static int drive_init_func(QemuOpts *opts, void *opaque)
+{
+ QEMUMachine *machine = opaque;
+ int fatal_error = 0;
+
+ if (drive_init(opts, machine, &fatal_error) == NULL) {
+ if (fatal_error)
+ return 1;
+ }
+ return 0;
+}
+
+static int drive_enable_snapshot(QemuOpts *opts, void *opaque)
+{
+ if (NULL == qemu_opt_get(opts, "snapshot")) {
+ qemu_opt_set(opts, "snapshot", "on");
+ }
+ return 0;
+}
+
+void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
+{
+ boot_set_handler = func;
+ boot_set_opaque = opaque;
+}
+
+int qemu_boot_set(const char *boot_devices)
+{
+ if (!boot_set_handler) {
+ return -EINVAL;
+ }
+ return boot_set_handler(boot_set_opaque, boot_devices);
+}
+
+static int parse_bootdevices(char *devices)
+{
+ /* We just do some generic consistency checks */
+ const char *p;
+ int bitmap = 0;
+
+ for (p = devices; *p != '\0'; p++) {
+ /* Allowed boot devices are:
+ * a-b: floppy disk drives
+ * c-f: IDE disk drives
+ * g-m: machine implementation dependant drives
+ * n-p: network devices
+ * It's up to each machine implementation to check if the given boot
+ * devices match the actual hardware implementation and firmware
+ * features.
+ */
+ if (*p < 'a' || *p > 'p') {
+ fprintf(stderr, "Invalid boot device '%c'\n", *p);
+ exit(1);
+ }
+ if (bitmap & (1 << (*p - 'a'))) {
+ fprintf(stderr, "Boot device '%c' was given twice\n", *p);
+ exit(1);
+ }
+ bitmap |= 1 << (*p - 'a');
+ }
+ return bitmap;
+}
+
+static void restore_boot_devices(void *opaque)
+{
+ char *standard_boot_devices = opaque;
+
+ qemu_boot_set(standard_boot_devices);
+
+ qemu_unregister_reset(restore_boot_devices, standard_boot_devices);
+ qemu_free(standard_boot_devices);
}
static void numa_add(const char *optarg)
return usb_device_del_addr(bus_num, addr);
}
+static int usb_parse(const char *cmdline)
+{
+ return usb_device_add(cmdline, 0);
+}
+
void do_usb_add(Monitor *mon, const char *devname)
{
usb_device_add(devname, 1);
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;
}
/* reset/shutdown handler */
typedef struct QEMUResetEntry {
+ TAILQ_ENTRY(QEMUResetEntry) entry;
QEMUResetHandler *func;
void *opaque;
- int order;
- struct QEMUResetEntry *next;
} QEMUResetEntry;
-static QEMUResetEntry *first_reset_entry;
+static TAILQ_HEAD(reset_handlers, QEMUResetEntry) reset_handlers =
+ TAILQ_HEAD_INITIALIZER(reset_handlers);
static int reset_requested;
static int shutdown_requested;
static int powerdown_requested;
}
}
-void qemu_register_reset(QEMUResetHandler *func, int order, void *opaque)
+void qemu_register_reset(QEMUResetHandler *func, void *opaque)
{
- QEMUResetEntry **pre, *re;
+ QEMUResetEntry *re = qemu_mallocz(sizeof(QEMUResetEntry));
- pre = &first_reset_entry;
- while (*pre != NULL && (*pre)->order >= order) {
- pre = &(*pre)->next;
- }
- re = qemu_mallocz(sizeof(QEMUResetEntry));
re->func = func;
re->opaque = opaque;
- re->order = order;
- re->next = NULL;
- *pre = re;
+ TAILQ_INSERT_TAIL(&reset_handlers, re, entry);
}
-void qemu_system_reset(void)
+void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
{
QEMUResetEntry *re;
+ TAILQ_FOREACH(re, &reset_handlers, entry) {
+ if (re->func == func && re->opaque == opaque) {
+ TAILQ_REMOVE(&reset_handlers, re, entry);
+ qemu_free(re);
+ return;
+ }
+ }
+}
+
+void qemu_system_reset(void)
+{
+ QEMUResetEntry *re, *nre;
+
/* reset all devices */
- for(re = first_reset_entry; re != NULL; re = re->next) {
+ TAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) {
re->func(re->opaque);
}
}
tv.tv_sec = timeout / 1000;
tv.tv_usec = (timeout % 1000) * 1000;
-#if defined(CONFIG_SLIRP)
- if (slirp_is_inited()) {
- slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
- }
-#endif
+ slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
+
qemu_mutex_unlock_iothread();
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
qemu_mutex_lock_iothread();
pioh = &ioh->next;
}
}
-#if defined(CONFIG_SLIRP)
- if (slirp_is_inited()) {
- if (ret < 0) {
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_ZERO(&xfds);
- }
- slirp_select_poll(&rfds, &wfds, &xfds);
- }
-#endif
+
+ slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
/* rearm timer, if not periodic */
if (alarm_timer->flags & ALARM_FLAG_EXPIRED) {
}
}
+#ifdef TARGET_I386
+static int balloon_parse(const char *arg)
+{
+ char buf[128];
+ const char *p;
+
+ if (!strcmp(arg, "none")) {
+ virtio_balloon = 0;
+ } else if (!strncmp(arg, "virtio", 6)) {
+ virtio_balloon = 1;
+ if (arg[6] == ',') {
+ p = arg + 7;
+ if (get_param_value(buf, sizeof(buf), "addr", p)) {
+ virtio_balloon_devaddr = strdup(buf);
+ }
+ }
+ } else {
+ return -1;
+ }
+ return 0;
+}
+#endif
+
#ifdef _WIN32
static BOOL WINAPI qemu_ctrl_handler(DWORD type)
{
return buf;
}
+struct device_config {
+ enum {
+ DEV_GENERIC, /* -device */
+ DEV_USB, /* -usbdevice */
+ DEV_BT, /* -bt */
+ } type;
+ const char *cmdline;
+ TAILQ_ENTRY(device_config) next;
+};
+TAILQ_HEAD(, device_config) device_configs = TAILQ_HEAD_INITIALIZER(device_configs);
+
+static void add_device_config(int type, const char *cmdline)
+{
+ struct device_config *conf;
+
+ conf = qemu_mallocz(sizeof(*conf));
+ conf->type = type;
+ conf->cmdline = cmdline;
+ TAILQ_INSERT_TAIL(&device_configs, conf, next);
+}
+
+static int foreach_device_config(int type, int (*func)(const char *cmdline))
+{
+ struct device_config *conf;
+ int rc;
+
+ TAILQ_FOREACH(conf, &device_configs, next) {
+ if (conf->type != type)
+ continue;
+ rc = func(conf->cmdline);
+ if (0 != rc)
+ return rc;
+ }
+ return 0;
+}
+
+static int generic_parse(const char *cmdline)
+{
+ DeviceState *dev;
+
+ dev = qdev_device_add(cmdline);
+ if (!dev)
+ return -1;
+ return 0;
+}
+
int main(int argc, char **argv, char **envp)
{
const char *gdbstub_dev = NULL;
int snapshot, linux_boot, net_boot;
const char *initrd_filename;
const char *kernel_filename, *kernel_cmdline;
- const char *boot_devices = "";
+ char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */
DisplayState *ds;
DisplayChangeListener *dcl;
int cyls, heads, secs, translation;
const char *net_clients[MAX_NET_CLIENTS];
int nb_net_clients;
- const char *bt_opts[MAX_BT_CMDLINE];
- int nb_bt_opts;
- int hda_index;
+ QemuOpts *hda_opts = NULL;
int optind;
const char *r, *optarg;
CharDriverState *monitor_hd = NULL;
const char *loadvm = NULL;
QEMUMachine *machine;
const char *cpu_model;
- const char *usb_devices[MAX_USB_CMDLINE];
- int usb_devices_index;
#ifndef _WIN32
int fds[2];
#endif
node_cpumask[i] = 0;
}
- usb_devices_index = 0;
-
nb_net_clients = 0;
- nb_bt_opts = 0;
- nb_drives = 0;
- nb_drives_opt = 0;
nb_numa_nodes = 0;
- hda_index = -1;
-
nb_nics = 0;
tb_size = 0;
break;
r = argv[optind];
if (r[0] != '-') {
- hda_index = drive_add(argv[optind++], HD_ALIAS, 0);
+ hda_opts = drive_add(argv[optind++], HD_ALIAS, 0);
} else {
const QEMUOption *popt;
QEMUMachine *m;
printf("Supported machines are:\n");
for(m = first_machine; m != NULL; m = m->next) {
+ if (m->alias)
+ printf("%-10s %s (alias of %s)\n",
+ m->alias, m->desc, m->name);
printf("%-10s %s%s\n",
m->name, m->desc,
m->is_default ? " (default)" : "");
break;
case QEMU_OPTION_hda:
if (cyls == 0)
- hda_index = drive_add(optarg, HD_ALIAS, 0);
+ hda_opts = drive_add(optarg, HD_ALIAS, 0);
else
- hda_index = drive_add(optarg, HD_ALIAS
+ hda_opts = drive_add(optarg, HD_ALIAS
",cyls=%d,heads=%d,secs=%d%s",
0, cyls, heads, secs,
translation == BIOS_ATA_TRANSLATION_LBA ?
fprintf(stderr, "qemu: invalid physical CHS format\n");
exit(1);
}
- if (hda_index != -1)
- snprintf(drives_opt[hda_index].opt,
- sizeof(drives_opt[hda_index].opt),
- HD_ALIAS ",cyls=%d,heads=%d,secs=%d%s",
- 0, cyls, heads, secs,
- translation == BIOS_ATA_TRANSLATION_LBA ?
- ",trans=lba" :
- translation == BIOS_ATA_TRANSLATION_NONE ?
- ",trans=none" : "");
+ if (hda_opts != NULL) {
+ char num[16];
+ snprintf(num, sizeof(num), "%d", cyls);
+ qemu_opt_set(hda_opts, "cyls", num);
+ snprintf(num, sizeof(num), "%d", heads);
+ qemu_opt_set(hda_opts, "heads", num);
+ snprintf(num, sizeof(num), "%d", secs);
+ qemu_opt_set(hda_opts, "secs", num);
+ if (translation == BIOS_ATA_TRANSLATION_LBA)
+ qemu_opt_set(hda_opts, "trans", "lba");
+ if (translation == BIOS_ATA_TRANSLATION_NONE)
+ qemu_opt_set(hda_opts, "trans", "none");
+ }
}
break;
case QEMU_OPTION_numa:
drive_add(optarg, CDROM_ALIAS);
break;
case QEMU_OPTION_boot:
- boot_devices = optarg;
- /* We just do some generic consistency checks */
{
- /* Could easily be extended to 64 devices if needed */
- const char *p;
-
- boot_devices_bitmap = 0;
- for (p = boot_devices; *p != '\0'; p++) {
- /* Allowed boot devices are:
- * a b : floppy disk drives
- * c ... f : IDE disk drives
- * g ... m : machine implementation dependant drives
- * n ... p : network devices
- * It's up to each machine implementation to check
- * if the given boot devices match the actual hardware
- * implementation and firmware features.
- */
- if (*p < 'a' || *p > 'q') {
- fprintf(stderr, "Invalid boot device '%c'\n", *p);
- exit(1);
+ static const char * const params[] = {
+ "order", "once", "menu", NULL
+ };
+ char buf[sizeof(boot_devices)];
+ char *standard_boot_devices;
+ int legacy = 0;
+
+ if (!strchr(optarg, '=')) {
+ legacy = 1;
+ pstrcpy(buf, sizeof(buf), optarg);
+ } else if (check_params(buf, sizeof(buf), params, optarg) < 0) {
+ fprintf(stderr,
+ "qemu: unknown boot parameter '%s' in '%s'\n",
+ buf, optarg);
+ exit(1);
+ }
+
+ if (legacy ||
+ get_param_value(buf, sizeof(buf), "order", optarg)) {
+ boot_devices_bitmap = parse_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);
+ standard_boot_devices = qemu_strdup(boot_devices);
+ pstrcpy(boot_devices, sizeof(boot_devices), buf);
+ qemu_register_reset(restore_boot_devices,
+ standard_boot_devices);
}
- if (boot_devices_bitmap & (1 << (*p - 'a'))) {
- fprintf(stderr,
- "Boot device '%c' was given twice\n",*p);
- exit(1);
+ if (get_param_value(buf, sizeof(buf),
+ "menu", optarg)) {
+ if (!strcmp(buf, "on")) {
+ boot_menu = 1;
+ } else if (!strcmp(buf, "off")) {
+ boot_menu = 0;
+ } else {
+ fprintf(stderr,
+ "qemu: invalid option value '%s'\n",
+ buf);
+ exit(1);
+ }
}
- boot_devices_bitmap |= 1 << (*p - 'a');
}
}
break;
break;
#endif
case QEMU_OPTION_redir:
- net_slirp_redir(NULL, optarg, NULL);
+ net_slirp_redir(optarg);
break;
#endif
case QEMU_OPTION_bt:
- if (nb_bt_opts >= MAX_BT_CMDLINE) {
- fprintf(stderr, "qemu: too many bluetooth options\n");
- exit(1);
- }
- bt_opts[nb_bt_opts++] = optarg;
+ add_device_config(DEV_BT, optarg);
break;
#ifdef HAS_AUDIO
case QEMU_OPTION_audio_help:
break;
#endif
#ifdef CONFIG_KQEMU
- case QEMU_OPTION_no_kqemu:
- kqemu_allowed = 0;
+ case QEMU_OPTION_enable_kqemu:
+ kqemu_allowed = 1;
break;
case QEMU_OPTION_kernel_kqemu:
kqemu_allowed = 2;
break;
case QEMU_OPTION_usbdevice:
usb_enabled = 1;
- if (usb_devices_index >= MAX_USB_CMDLINE) {
- fprintf(stderr, "Too many USB devices\n");
- exit(1);
- }
- usb_devices[usb_devices_index] = optarg;
- usb_devices_index++;
+ add_device_config(DEV_USB, optarg);
+ break;
+ case QEMU_OPTION_device:
+ add_device_config(DEV_GENERIC, optarg);
break;
case QEMU_OPTION_smp:
- smp_cpus = atoi(optarg);
+ {
+ char *p;
+ char option[128];
+ smp_cpus = strtol(optarg, &p, 10);
if (smp_cpus < 1) {
fprintf(stderr, "Invalid number of CPUs\n");
exit(1);
}
+ if (*p++ != ',')
+ break;
+ if (get_param_value(option, 128, "maxcpus", p))
+ max_cpus = strtol(option, NULL, 0);
+ if (max_cpus < smp_cpus) {
+ fprintf(stderr, "maxcpus must be equal to or greater than "
+ "smp\n");
+ exit(1);
+ }
+ if (max_cpus > 255) {
+ fprintf(stderr, "Unsupported number of maxcpus\n");
+ exit(1);
+ }
break;
+ }
case QEMU_OPTION_vnc:
display_type = DT_VNC;
vnc_display = optarg;
case QEMU_OPTION_no_hpet:
no_hpet = 1;
break;
- case QEMU_OPTION_no_virtio_balloon:
- no_virtio_balloon = 1;
+ case QEMU_OPTION_balloon:
+ if (balloon_parse(optarg) < 0) {
+ fprintf(stderr, "Unknown -balloon argument %s\n", optarg);
+ exit(1);
+ }
break;
#endif
case QEMU_OPTION_no_reboot:
break;
#endif
case QEMU_OPTION_name:
- qemu_name = optarg;
+ qemu_name = qemu_strdup(optarg);
+ {
+ char *p = strchr(qemu_name, ',');
+ if (p != NULL) {
+ *p++ = 0;
+ if (strncmp(p, "process=", 8)) {
+ fprintf(stderr, "Unknown subargument %s to -name", p);
+ exit(1);
+ }
+ p += 8;
+ set_proc_name(p);
+ }
+ }
break;
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
case QEMU_OPTION_prom_env:
}
#endif
+ /*
+ * Default to max_cpus = smp_cpus, in case the user doesn't
+ * specify a max_cpus value.
+ */
+ if (!max_cpus)
+ max_cpus = smp_cpus;
+
machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
if (smp_cpus > machine->max_cpus) {
fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus "
exit(1);
}
- /* boot to floppy or the default cd if no hard disk defined yet */
- if (!boot_devices[0]) {
- boot_devices = "cad";
- }
+#ifndef _WIN32
+ /* Win32 doesn't support line-buffering and requires size >= 2 */
setvbuf(stdout, NULL, _IOLBF, 0);
+#endif
init_timers();
if (init_timer_alarm() < 0) {
net_client_check();
/* init the bluetooth world */
- for (i = 0; i < nb_bt_opts; i++)
- if (bt_parse(bt_opts[i]))
- exit(1);
+ if (foreach_device_config(DEV_BT, bt_parse))
+ exit(1);
/* init the memory */
if (ram_size == 0)
bdrv_init();
/* we always create the cdrom drive, even if no disk is there */
-
- if (nb_drives_opt < MAX_DRIVES)
- drive_add(NULL, CDROM_ALIAS);
+ drive_add(NULL, CDROM_ALIAS);
/* we always create at least one floppy */
-
- if (nb_drives_opt < MAX_DRIVES)
- drive_add(NULL, FD_ALIAS, 0);
+ drive_add(NULL, FD_ALIAS, 0);
/* we always create one sd slot, even if no card is in it */
-
- if (nb_drives_opt < MAX_DRIVES)
- drive_add(NULL, SD_ALIAS);
+ drive_add(NULL, SD_ALIAS);
/* open the virtual block devices */
-
- for(i = 0; i < nb_drives_opt; i++)
- if (drive_init(&drives_opt[i], snapshot, machine) == -1)
- exit(1);
+ if (snapshot)
+ qemu_opts_foreach(&drive_opt_list, drive_enable_snapshot, NULL, 0);
+ if (qemu_opts_foreach(&drive_opt_list, drive_init_func, machine, 1) != 0)
+ exit(1);
register_savevm("timer", 0, 2, timer_save, timer_load, NULL);
register_savevm_live("ram", 0, 3, ram_save_live, NULL, ram_load, NULL);
module_call_init(MODULE_INIT_DEVICE);
+ if (machine->compat_props) {
+ qdev_prop_register_compat(machine->compat_props);
+ }
machine->init(ram_size, boot_devices,
kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
current_machine = machine;
- /* Set KVM's vcpu state to qemu's initial CPUState. */
- if (kvm_enabled()) {
- int ret;
-
- ret = kvm_sync_vcpus();
- if (ret < 0) {
- fprintf(stderr, "failed to initialize vcpus\n");
- exit(1);
- }
- }
-
/* init USB devices */
if (usb_enabled) {
- for(i = 0; i < usb_devices_index; i++) {
- if (usb_device_add(usb_devices[i], 0) < 0) {
- fprintf(stderr, "Warning: could not add USB device %s\n",
- usb_devices[i]);
- }
- }
+ foreach_device_config(DEV_USB, usb_parse);
}
+ /* init generic devices */
+ if (foreach_device_config(DEV_GENERIC, generic_parse))
+ exit(1);
+
if (!display_state)
dumb_display_init();
/* just use the first displaystate for the moment */
do_loadvm(cur_mon, loadvm);
if (incoming) {
- autostart = 0; /* fixme how to deal with -daemonize */
+ autostart = 0;
qemu_start_incoming_migration(incoming);
}