X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=vl.c;h=a89428573bc0fcaf33f54def45e45373855faea6;hb=2191dffcf6ba7df884ac902e829415d55a0b2b68;hp=c9b2aa4d251754a22cc52ca7f9d5c337334f9993;hpb=d3f243676addaef6c8d818934565292c698f91cc;p=qemu diff --git a/vl.c b/vl.c index c9b2aa4..a894285 100644 --- a/vl.c +++ b/vl.c @@ -29,10 +29,13 @@ #include #include -/* Needed early for HOST_BSD etc. */ +/* Needed early for CONFIG_BSD etc. */ #include "config-host.h" +/* Needed early to override system queue definitions on BSD */ +#include "sys-queue.h" #ifndef _WIN32 +#include #include #include #include @@ -53,7 +56,7 @@ #include #include #include -#ifdef HOST_BSD +#ifdef CONFIG_BSD #include #if defined(__FreeBSD__) || defined(__DragonFly__) #include @@ -67,6 +70,7 @@ #include #include #include +#include /* For the benefit of older linux systems which don't supply it, we use a local copy of hpet.h. */ @@ -104,20 +108,16 @@ #ifdef _WIN32 #include -#include -#include #include -#define getopt_long_only getopt_long -#define memalign(align, size) malloc(size) #endif #ifdef CONFIG_SDL -#ifdef __APPLE__ -#include +#if defined(__APPLE__) || defined(main) +#include int qemu_main(int argc, char **argv, char **envp); int main(int argc, char **argv) { - qemu_main(argc, argv, NULL); + return qemu_main(argc, argv, NULL); } #undef main #define main qemu_main @@ -141,6 +141,7 @@ int main(int argc, char **argv) #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" @@ -157,6 +158,7 @@ int main(int argc, char **argv) #include "kvm.h" #include "balloon.h" #include "qemu-option.h" +#include "qemu-config.h" #include "disas.h" @@ -164,42 +166,19 @@ int main(int argc, char **argv) #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 - -const char *bios_dir = CONFIG_QEMU_SHAREDIR; +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; @@ -209,13 +188,10 @@ ram_addr_t ram_size; int nb_nics; NICInfo nd_table[MAX_NICS]; int vm_running; -static int autostart; +int autostart; static int rtc_utc = 1; static int rtc_date_offset = -1; /* -1 means no change */ -int cirrus_vga_enabled = 1; -int std_vga_enabled = 0; -int vmsvga_enabled = 0; -int xenfb_enabled = 0; +int vga_interface_type = VGA_CIRRUS; #ifdef TARGET_SPARC int graphic_width = 1024; int graphic_height = 768; @@ -240,6 +216,9 @@ int rtc_td_hack = 0; int usb_enabled = 0; int singlestep = 0; int smp_cpus = 1; +int max_cpus = 0; +int smp_cores = 1; +int smp_threads = 1; const char *vnc_display; int acpi_enabled = 1; int no_hpet = 0; @@ -248,11 +227,11 @@ int no_reboot = 0; int no_shutdown = 0; int cursor_hide = 1; int graphic_rotate = 0; +uint8_t irq0override = 1; #ifndef _WIN32 int daemonize = 0; #endif -WatchdogTimerModel *watchdog = NULL; -int watchdog_action = WDT_RESET; +const char *watchdog; const char *option_rom[MAX_OPTION_ROMS]; int nb_option_roms; int semihosting_enabled = 0; @@ -265,8 +244,7 @@ int alt_grab = 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]; @@ -287,223 +265,15 @@ static QEMUTimer *nographic_timer; 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, ...) { @@ -525,6 +295,20 @@ void hw_error(const char *fmt, ...) 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 */ @@ -720,7 +504,7 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) union { uint64_t ll; struct { -#ifdef WORDS_BIGENDIAN +#ifdef HOST_WORDS_BIGENDIAN uint32_t high, low; #else uint32_t low, high; @@ -1205,7 +989,7 @@ int qemu_timer_pending(QEMUTimer *ts) return 0; } -static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) +int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time) { if (!timer_head) return 0; @@ -1354,11 +1138,6 @@ static void host_alarm_handler(int host_signum) if (next_cpu) { /* stop the currently executing cpu because a timer occured */ cpu_exit(next_cpu); -#ifdef CONFIG_KQEMU - if (next_cpu->kqemu_enabled) { - kqemu_cpu_interrupt(next_cpu); - } -#endif } #endif timer_alarm_pending = 1; @@ -1810,72 +1589,6 @@ static int socket_init(void) } #endif -int get_param_value(char *buf, int buf_size, - const char *tag, const char *str) -{ - const char *p; - char option[128]; - - p = str; - for(;;) { - p = get_opt_name(option, sizeof(option), p, '='); - if (*p != '=') - break; - p++; - if (!strcmp(tag, option)) { - (void)get_opt_value(buf, buf_size, p); - return strlen(buf); - } else { - p = get_opt_value(NULL, 0, p); - } - if (*p != ',') - break; - p++; - } - return 0; -} - -int check_params(const char * const *params, const char *str) -{ - int name_buf_size = 1; - const char *p; - char *name_buf; - int i, len; - int ret = 0; - - for (i = 0; params[i] != NULL; i++) { - len = strlen(params[i]) + 1; - if (len > name_buf_size) { - name_buf_size = len; - } - } - name_buf = qemu_malloc(name_buf_size); - - p = str; - while (*p != '\0') { - p = get_opt_name(name_buf, name_buf_size, p, '='); - if (*p != '=') { - ret = -1; - break; - } - p++; - for(i = 0; params[i] != NULL; i++) - if (!strcmp(params[i], name_buf)) - break; - if (params[i] == NULL) { - ret = -1; - break; - } - p = get_opt_value(NULL, 0, p); - if (*p != ',') - break; - p++; - } - - qemu_free(name_buf); - return ret; -} - /***********************************************************/ /* Bluetooth support */ static int nb_hcis; @@ -2077,106 +1790,89 @@ static int bt_parse(const char *opt) #define MTD_ALIAS "if=mtd" #define SD_ALIAS "index=0,if=sd" -static int drive_opt_get_free_idx(void) +QemuOpts *drive_add(const char *file, const char *fmt, ...) { - int index; + va_list ap; + char optstr[1024]; + QemuOpts *opts; - for (index = 0; index < MAX_DRIVES; index++) - if (!drives_opt[index].used) { - drives_opt[index].used = 1; - return index; - } + va_start(ap, fmt); + vsnprintf(optstr, sizeof(optstr), fmt, ap); + va_end(ap); - return -1; + opts = qemu_opts_parse(&qemu_drive_opts, 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; } -static int drive_get_free_idx(void) +DriveInfo *drive_get(BlockInterfaceType type, int bus, int unit) { - int index; + DriveInfo *dinfo; - for (index = 0; index < MAX_DRIVES; index++) - if (!drives_table[index].used) { - drives_table[index].used = 1; - return index; - } - - return -1; -} - -int drive_add(const char *file, const char *fmt, ...) -{ - va_list ap; - int index = drive_opt_get_free_idx(); + /* seek interface, bus and unit */ - if (nb_drives_opt >= MAX_DRIVES || index == -1) { - fprintf(stderr, "qemu: too many drives\n"); - return -1; + TAILQ_FOREACH(dinfo, &drives, next) { + if (dinfo->type == type && + dinfo->bus == bus && + dinfo->unit == unit) + return dinfo; } - drives_opt[index].file = file; - va_start(ap, fmt); - vsnprintf(drives_opt[index].opt, - sizeof(drives_opt[0].opt), fmt, ap); - va_end(ap); - - nb_drives_opt++; - return index; -} - -void drive_remove(int index) -{ - drives_opt[index].used = 0; - nb_drives_opt--; + return NULL; } -int drive_get_index(BlockInterfaceType type, int bus, int unit) +DriveInfo *drive_get_by_id(const char *id) { - int index; - - /* seek interface, bus and unit */ + DriveInfo *dinfo; - 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; - - return -1; + 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; } @@ -2188,57 +1884,45 @@ static void bdrv_format_print(void *opaque, const char *name) 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 index; int cache; + int aio = 0; int bdrv_flags, onerror; - 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", - NULL }; + const char *devaddr; + DriveInfo *dinfo; + int snapshot = 0; - if (check_params(params, str) < 0) { - fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n", - buf, str); - return -1; - } + *fatal_error = 1; - file[0] = 0; - cyls = heads = secs = 0; - bus_id = 0; - unit_id = -1; translation = BIOS_ATA_TRANSLATION_AUTO; - index = -1; - cache = 3; + cache = 1; if (machine->use_scsi) { type = IF_SCSI; @@ -2252,24 +1936,20 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) 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); - if (get_param_value(buf, sizeof(buf), "if", str)) { + 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; @@ -2295,53 +1975,36 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) } 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: '%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; @@ -2350,39 +2013,28 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) 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")) @@ -2391,37 +2043,42 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) cache = 2; else { fprintf(stderr, "qemu: invalid cache option\n"); - return -1; + return NULL; } } - if (get_param_value(buf, sizeof(buf), "format", str)) { +#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 -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; @@ -2433,7 +2090,14 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) onerror = BLOCK_ERR_REPORT; else { fprintf(stderr, "qemu: '%s' invalid write error action\n", buf); - return -1; + return NULL; + } + } + + if ((devaddr = qemu_opt_get(opts, "addr")) != NULL) { + if (type != IF_VIRTIO) { + fprintf(stderr, "addr is not supported\n"); + return NULL; } } @@ -2442,8 +2106,8 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) 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) { @@ -2461,7 +2125,7 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) 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; @@ -2473,38 +2137,47 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) /* 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].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_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->onerror = onerror; + dinfo->opts = opts; + if (serial) + strncpy(dinfo->serial, serial, sizeof(serial)); + TAILQ_INSERT_TAIL(&drives, dinfo, next); switch(type) { case IF_IDE: @@ -2513,12 +2186,12 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) 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; @@ -2526,17 +2199,27 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) /* 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_NONE: + 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[0]) - return -2; + if (!file) { + *fatal_error = 0; + return NULL; + } bdrv_flags = 0; if (snapshot) { bdrv_flags |= BDRV_O_SNAPSHOT; @@ -2546,16 +2229,96 @@ int drive_init(struct drive_opt *arg, int snapshot, void *opaque) 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 (aio == 1) { + bdrv_flags |= BDRV_O_NATIVE_AIO; + } else { + bdrv_flags &= ~BDRV_O_NATIVE_AIO; + } + + 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) @@ -2614,6 +2377,56 @@ static void numa_add(const char *optarg) return; } +static void smp_parse(const char *optarg) +{ + int smp, sockets = 0, threads = 0, cores = 0; + char *endptr; + char option[128]; + + smp = strtoul(optarg, &endptr, 10); + if (endptr != optarg) { + if (*endptr == ',') { + endptr++; + } + } + if (get_param_value(option, 128, "sockets", endptr) != 0) + sockets = strtoull(option, NULL, 10); + if (get_param_value(option, 128, "cores", endptr) != 0) + cores = strtoull(option, NULL, 10); + if (get_param_value(option, 128, "threads", endptr) != 0) + threads = strtoull(option, NULL, 10); + if (get_param_value(option, 128, "maxcpus", endptr) != 0) + max_cpus = strtoull(option, NULL, 10); + + /* compute missing values, prefer sockets over cores over threads */ + if (smp == 0 || sockets == 0) { + sockets = sockets > 0 ? sockets : 1; + cores = cores > 0 ? cores : 1; + threads = threads > 0 ? threads : 1; + if (smp == 0) { + smp = cores * threads * sockets; + } else { + sockets = smp / (cores * threads); + } + } else { + if (cores == 0) { + threads = threads > 0 ? threads : 1; + cores = smp / (sockets * threads); + } else { + if (sockets == 0) { + sockets = smp / (cores * threads); + } else { + threads = smp / (cores * sockets); + } + } + } + smp_cpus = smp; + smp_cores = cores > 0 ? cores : 1; + smp_threads = threads > 0 ? threads : 1; + if (max_cpus == 0) + max_cpus = smp_cpus; +} + /***********************************************************/ /* USB devices */ @@ -2709,7 +2522,7 @@ static int usb_device_add(const char *devname, int is_hotplug) } else if (strstart(devname, "net:", &p)) { int nic = nb_nics; - if (net_client_init("nic", p) < 0) + if (net_client_init(NULL, "nic", p) < 0) return -1; nd_table[nic].model = "usb"; dev = usb_net_init(&nd_table[nic]); @@ -2776,6 +2589,11 @@ static int usb_device_del(const char *devname) 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); @@ -3197,7 +3015,6 @@ static int ram_save_block(QEMUFile *f) return found; } -static ram_addr_t ram_save_threshold = 10; static uint64_t bytes_transferred = 0; static ram_addr_t ram_save_remaining(void) @@ -3231,6 +3048,14 @@ uint64_t ram_bytes_total(void) static int ram_save_live(QEMUFile *f, int stage, void *opaque) { ram_addr_t addr; + uint64_t bytes_transferred_last; + double bwidth = 0; + uint64_t expected_time = 0; + + if (cpu_physical_sync_dirty_bitmap(0, TARGET_PHYS_ADDR_MAX) != 0) { + qemu_file_set_error(f); + return 0; + } if (stage == 1) { /* Make sure all dirty bits are set */ @@ -3238,13 +3063,16 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) 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 = get_clock(); + while (!qemu_file_rate_limit(f)) { int ret; @@ -3254,6 +3082,14 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) break; } + bwidth = get_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) { @@ -3267,7 +3103,9 @@ static int ram_save_live(QEMUFile *f, int stage, void *opaque) qemu_put_be64(f, RAM_SAVE_FLAG_EOS); - return (stage == 2) && (ram_save_remaining() < ram_save_threshold); + expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + + return (stage == 2) && (expected_time <= migrate_max_downtime()); } static int ram_load_dead(QEMUFile *f, void *opaque) @@ -3336,6 +3174,12 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) 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); } while (!(flags & RAM_SAVE_FLAG_EOS)); @@ -3476,6 +3320,8 @@ static QEMUMachine *find_machine(const char *name) 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; } @@ -3572,12 +3418,13 @@ void vm_start(void) /* reset/shutdown handler */ typedef struct QEMUResetEntry { + TAILQ_ENTRY(QEMUResetEntry) entry; QEMUResetHandler *func; void *opaque; - 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; @@ -3631,28 +3478,34 @@ static void do_vm_stop(int reason) 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 = &(*pre)->next; - re = qemu_mallocz(sizeof(QEMUResetEntry)); re->func = func; re->opaque = opaque; - 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); } - if (kvm_enabled()) - kvm_sync_vcpus(); } void qemu_system_reset_request(void) @@ -3783,6 +3636,8 @@ void qemu_init_vcpu(void *_env) if (kvm_enabled()) kvm_init_vcpu(env); + env->nr_cores = smp_cores; + env->nr_threads = smp_threads; return; } @@ -3810,11 +3665,7 @@ void qemu_notify_event(void) if (env) { cpu_exit(env); -#ifdef USE_KQEMU - if (env->kqemu_enabled) - kqemu_cpu_interrupt(env); -#endif - } + } } #define qemu_mutex_lock_iothread() do { } while (0) @@ -4110,6 +3961,8 @@ void qemu_init_vcpu(void *_env) kvm_start_vcpu(env); else tcg_init_vcpu(env); + env->nr_cores = smp_cores; + env->nr_threads = smp_threads; } void qemu_notify_event(void) @@ -4227,11 +4080,8 @@ void main_loop_wait(int timeout) 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(); @@ -4258,16 +4108,8 @@ void main_loop_wait(int timeout) 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) { @@ -4382,6 +4224,7 @@ static int tcg_has_work(void) static int qemu_calculate_timeout(void) { +#ifndef CONFIG_IOTHREAD int timeout; if (!vm_running) @@ -4427,6 +4270,9 @@ static int qemu_calculate_timeout(void) } return timeout; +#else /* CONFIG_IOTHREAD */ + return 1000; +#endif } static int vm_can_run(void) @@ -4442,6 +4288,8 @@ static int vm_can_run(void) return 1; } +qemu_irq qemu_system_powerdown; + static void main_loop(void) { int r; @@ -4462,11 +4310,7 @@ static void main_loop(void) #ifdef CONFIG_PROFILER ti = profile_getclock(); #endif -#ifdef CONFIG_IOTHREAD - main_loop_wait(1000); -#else main_loop_wait(qemu_calculate_timeout()); -#endif #ifdef CONFIG_PROFILER dev_time += profile_getclock() - ti; #endif @@ -4486,8 +4330,9 @@ static void main_loop(void) qemu_system_reset(); resume_all_vcpus(); } - if (qemu_powerdown_requested()) - qemu_system_powerdown(); + if (qemu_powerdown_requested()) { + qemu_irq_raise(qemu_system_powerdown); + } if ((r = qemu_vmstop_requested())) vm_stop(r); } @@ -4707,18 +4552,15 @@ static void select_vgahw (const char *p) { const char *opts; - cirrus_vga_enabled = 0; - std_vga_enabled = 0; - vmsvga_enabled = 0; - xenfb_enabled = 0; + vga_interface_type = VGA_NONE; if (strstart(p, "std", &opts)) { - std_vga_enabled = 1; + vga_interface_type = VGA_STD; } else if (strstart(p, "cirrus", &opts)) { - cirrus_vga_enabled = 1; + vga_interface_type = VGA_CIRRUS; } else if (strstart(p, "vmware", &opts)) { - vmsvga_enabled = 1; + vga_interface_type = VGA_VMWARE; } else if (strstart(p, "xenfb", &opts)) { - xenfb_enabled = 1; + vga_interface_type = VGA_XENFB; } else if (!strstart(p, "none", &opts)) { invalid_vga: fprintf(stderr, "Unknown vga type: %s\n", p); @@ -4739,6 +4581,33 @@ static void select_vgahw (const char *p) } } +#ifdef TARGET_I386 +static int balloon_parse(const char *arg) +{ + QemuOpts *opts; + + if (strcmp(arg, "none") == 0) { + return 0; + } + + if (!strncmp(arg, "virtio", 6)) { + if (arg[6] == ',') { + /* have params -> parse them */ + opts = qemu_opts_parse(&qemu_device_opts, arg+7, NULL); + if (!opts) + return -1; + } else { + /* create empty opts */ + opts = qemu_opts_create(&qemu_device_opts, NULL, 0); + } + qemu_opt_set(opts, "driver", "virtio-balloon-pci"); + return 0; + } + + return -1; +} +#endif + #ifdef _WIN32 static BOOL WINAPI qemu_ctrl_handler(DWORD type) { @@ -4777,7 +4646,12 @@ static void termsig_handler(int signal) qemu_system_shutdown_request(); } -static void termsig_setup(void) +static void sigchld_handler(int signal) +{ + waitpid(-1, NULL, WNOHANG); +} + +static void sighandler_setup(void) { struct sigaction act; @@ -4786,10 +4660,183 @@ static void termsig_setup(void) 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; +#ifdef PATH_MAX + char buf[PATH_MAX]; +#endif + 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) { +#ifdef PATH_MAX + p = buf; +#endif + p = realpath(argv0, p); + 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; + } + } +#ifndef PATH_MAX + free(p); +#endif + return res; +} +#undef SHARE_SUFFIX +#undef BUILD_SUFFIX +#endif + +char *qemu_find_file(int type, const char *name) +{ + int len; + const char *subdir; + char *buf; + + /* If name contains path separators then try it as a straight path. */ + if ((strchr(name, '/') || strchr(name, '\\')) + && access(name, R_OK) == 0) { + return strdup(name); + } + switch (type) { + case QEMU_FILE_TYPE_BIOS: + subdir = ""; + break; + case QEMU_FILE_TYPE_KEYMAP: + subdir = "keymaps/"; + break; + default: + abort(); + } + len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2; + buf = qemu_mallocz(len); + snprintf(buf, len, "%s/%s%s", data_dir, subdir, name); + if (access(buf, R_OK)) { + qemu_free(buf); + return NULL; + } + return buf; +} + +static int device_init_func(QemuOpts *opts, void *opaque) +{ + DeviceState *dev; + + dev = qdev_device_add(opts); + if (!dev) + return -1; + return 0; +} + +struct device_config { + enum { + 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; +} + int main(int argc, char **argv, char **envp) { const char *gdbstub_dev = NULL; @@ -4798,15 +4845,13 @@ int main(int argc, char **argv, char **envp) 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, *opts; int optind; const char *r, *optarg; CharDriverState *monitor_hd = NULL; @@ -4820,8 +4865,6 @@ int main(int argc, char **argv, char **envp) 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 @@ -4837,6 +4880,7 @@ int main(int argc, char **argv, char **envp) CPUState *env; int show_vnc_port = 0; + qemu_errors_to_file(stderr); qemu_cache_utils_init(envp); LIST_INIT (&vm_change_state_head); @@ -4901,29 +4945,20 @@ int main(int argc, char **argv, char **envp) 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; autostart= 1; - register_watchdogs(); - optind = 1; for(;;) { if (optind >= argc) 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; @@ -4960,6 +4995,9 @@ int main(int argc, char **argv, char **envp) 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)" : ""); @@ -4984,9 +5022,9 @@ int main(int argc, char **argv, char **envp) 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 ? @@ -5002,6 +5040,10 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_drive: drive_add(NULL, "%s", optarg); break; + case QEMU_OPTION_set: + if (qemu_set_option(optarg) != 0) + exit(1); + break; case QEMU_OPTION_mtdblock: drive_add(optarg, MTD_ALIAS); break; @@ -5048,15 +5090,19 @@ int main(int argc, char **argv, char **envp) 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: @@ -5087,33 +5133,51 @@ int main(int argc, char **argv, char **envp) 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; @@ -5136,26 +5200,22 @@ int main(int argc, char **argv, char **envp) break; #ifdef CONFIG_SLIRP case QEMU_OPTION_tftp: - tftp_prefix = optarg; + legacy_tftp_prefix = optarg; break; case QEMU_OPTION_bootp: - bootp_filename = optarg; + legacy_bootp_filename = optarg; break; #ifndef _WIN32 case QEMU_OPTION_smb: - net_slirp_smb(optarg); + net_slirp_smb(optarg); break; #endif case QEMU_OPTION_redir: - net_slirp_redir(NULL, optarg); + 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: @@ -5191,11 +5251,7 @@ int main(int argc, char **argv, char **envp) } /* On 32-bit hosts, QEMU is limited by virtual address space */ - if (value > (2047 << 20) -#ifndef CONFIG_KQEMU - && HOST_LONG_BITS == 32 -#endif - ) { + if (value > (2047 << 20) && HOST_LONG_BITS == 32) { fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n"); exit(1); } @@ -5229,7 +5285,7 @@ int main(int argc, char **argv, char **envp) gdbstub_dev = optarg; break; case QEMU_OPTION_L: - bios_dir = optarg; + data_dir = optarg; break; case QEMU_OPTION_bios: bios_name = optarg; @@ -5307,9 +5363,12 @@ int main(int argc, char **argv, char **envp) serial_device_index++; break; case QEMU_OPTION_watchdog: - i = select_watchdog(optarg); - if (i > 0) - exit (i == 1 ? 1 : 0); + if (watchdog) { + fprintf(stderr, + "qemu: only one watchdog option may be given\n"); + return 1; + } + watchdog = optarg; break; case QEMU_OPTION_watchdog_action: if (select_watchdog_action(optarg) == -1) { @@ -5376,20 +5435,9 @@ int main(int argc, char **argv, char **envp) } break; #endif -#ifdef CONFIG_KQEMU - case QEMU_OPTION_no_kqemu: - kqemu_allowed = 0; - break; - case QEMU_OPTION_kernel_kqemu: - kqemu_allowed = 2; - break; -#endif #ifdef CONFIG_KVM case QEMU_OPTION_enable_kvm: kvm_allowed = 1; -#ifdef CONFIG_KQEMU - kqemu_allowed = 0; -#endif break; #endif case QEMU_OPTION_usb: @@ -5397,19 +5445,30 @@ int main(int argc, char **argv, char **envp) break; case QEMU_OPTION_usbdevice: usb_enabled = 1; - if (usb_devices_index >= MAX_USB_CMDLINE) { - fprintf(stderr, "Too many USB devices\n"); + add_device_config(DEV_USB, optarg); + break; + case QEMU_OPTION_device: + opts = qemu_opts_parse(&qemu_device_opts, optarg, "driver"); + if (!opts) { + fprintf(stderr, "parse error: %s\n", optarg); exit(1); } - usb_devices[usb_devices_index] = optarg; - usb_devices_index++; break; case QEMU_OPTION_smp: - smp_cpus = atoi(optarg); + smp_parse(optarg); if (smp_cpus < 1) { fprintf(stderr, "Invalid number of CPUs\n"); exit(1); } + 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; @@ -5422,6 +5481,12 @@ int main(int argc, char **argv, char **envp) case QEMU_OPTION_no_hpet: no_hpet = 1; break; + 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: no_reboot = 1; @@ -5458,7 +5523,19 @@ int main(int argc, char **argv, char **envp) 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: @@ -5555,13 +5632,22 @@ int main(int argc, char **argv, char **envp) } } -#if defined(CONFIG_KVM) && defined(CONFIG_KQEMU) - if (kvm_allowed && kqemu_allowed) { - fprintf(stderr, - "You can not enable both KVM and kqemu at the same time\n"); - exit(1); + /* 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]); + } + /* If all else fails use the install patch specified when building. */ + if (!data_dir) { + data_dir = CONFIG_QEMU_SHAREDIR; } -#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) { @@ -5634,16 +5720,11 @@ int main(int argc, char **argv, char **envp) } #endif -#ifdef CONFIG_KQEMU - if (smp_cpus > 1) - kqemu_allowed = 0; -#endif if (qemu_init_main_loop()) { fprintf(stderr, "qemu_init_main_loop failed\n"); exit(1); } linux_boot = (kernel_filename != NULL); - net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF; if (!linux_boot && *kernel_cmdline != '\0') { fprintf(stderr, "-append only allowed with -kernel option\n"); @@ -5655,11 +5736,10 @@ int main(int argc, char **argv, char **envp) 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) { @@ -5691,92 +5771,46 @@ int main(int argc, char **argv, char **envp) if (net_client_parse(net_clients[i]) < 0) exit(1); } - net_client_check(); -#ifdef TARGET_I386 - /* XXX: this should be moved in the PC machine instantiation code */ - if (net_boot != 0) { - int netroms = 0; - for (i = 0; i < nb_nics && i < 4; i++) { - const char *model = nd_table[i].model; - char buf[1024]; - if (net_boot & (1 << i)) { - if (model == NULL) - model = "ne2k_pci"; - snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model); - if (get_image_size(buf) > 0) { - if (nb_option_roms >= MAX_OPTION_ROMS) { - fprintf(stderr, "Too many option ROMs\n"); - exit(1); - } - option_rom[nb_option_roms] = strdup(buf); - nb_option_roms++; - netroms++; - } - } - } - if (netroms == 0) { - fprintf(stderr, "No valid PXE rom found for network device\n"); - exit(1); - } - } -#endif + net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF; + net_set_boot_mask(net_boot); + + 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) ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; -#ifdef CONFIG_KQEMU - /* FIXME: This is a nasty hack because kqemu can't cope with dynamic - guest ram allocation. It needs to go away. */ - if (kqemu_allowed) { - kqemu_phys_ram_size = ram_size + 8 * 1024 * 1024 + 4 * 1024 * 1024; - kqemu_phys_ram_base = qemu_vmalloc(kqemu_phys_ram_size); - if (!kqemu_phys_ram_base) { - fprintf(stderr, "Could not allocate physical memory\n"); - exit(1); - } - } -#endif - /* init the dynamic translator */ cpu_exec_init_all(tb_size * 1024 * 1024); bdrv_init(); - dma_helper_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(&qemu_drive_opts, drive_enable_snapshot, NULL, 0); + if (qemu_opts_foreach(&qemu_drive_opts, 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); #ifndef _WIN32 /* must be after terminal init, SDL library changes signal handlers */ - termsig_setup(); + sighandler_setup(); #endif /* Maintain compatibility with multiple stdio monitors */ @@ -5898,6 +5932,15 @@ int main(int argc, char **argv, char **envp) module_call_init(MODULE_INIT_DEVICE); + if (watchdog) { + i = select_watchdog(watchdog); + if (i > 0) + exit (i == 1 ? 1 : 0); + } + + 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); @@ -5912,27 +5955,15 @@ int main(int argc, char **argv, char **envp) 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 (qemu_opts_foreach(&qemu_device_opts, device_init_func, NULL, 1) != 0) + exit(1); + if (!display_state) dumb_display_init(); /* just use the first displaystate for the moment */ @@ -6003,8 +6034,6 @@ int main(int argc, char **argv, char **envp) for(i = 0; i < MAX_SERIAL_PORTS; i++) { const char *devname = serial_devices[i]; if (devname && strcmp(devname, "none")) { - char label[32]; - snprintf(label, sizeof(label), "serial%d", i); if (strstart(devname, "vc", 0)) qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i); } @@ -6013,8 +6042,6 @@ int main(int argc, char **argv, char **envp) for(i = 0; i < MAX_PARALLEL_PORTS; i++) { const char *devname = parallel_devices[i]; if (devname && strcmp(devname, "none")) { - char label[32]; - snprintf(label, sizeof(label), "parallel%d", i); if (strstart(devname, "vc", 0)) qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i); } @@ -6023,8 +6050,6 @@ int main(int argc, char **argv, char **envp) for(i = 0; i < MAX_VIRTIO_CONSOLES; i++) { const char *devname = virtio_consoles[i]; if (virtcon_hds[i] && devname) { - char label[32]; - snprintf(label, sizeof(label), "virtcon%d", i); if (strstart(devname, "vc", 0)) qemu_chr_printf(virtcon_hds[i], "virtio console%d\r\n", i); } @@ -6036,16 +6061,17 @@ int main(int argc, char **argv, char **envp) exit(1); } - if (loadvm) - do_loadvm(cur_mon, loadvm); + if (loadvm) { + if (load_vmstate(cur_mon, loadvm) < 0) { + autostart = 0; + } + } if (incoming) { - autostart = 0; /* fixme how to deal with -daemonize */ qemu_start_incoming_migration(incoming); - } - - if (autostart) + } else if (autostart) { vm_start(); + } #ifndef _WIN32 if (daemonize) {