#include <dirent.h>
#include <netdb.h>
#include <sys/select.h>
+
#ifdef CONFIG_BSD
#include <sys/stat.h>
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
#include <net/if.h>
#include <syslog.h>
#include <stropts.h>
-/* See MySQL bug #7156 (http://bugs.mysql.com/bug.php?id=7156) for
- discussion about Solaris header problems */
-extern int madvise(caddr_t, size_t, int);
#endif
#endif
#endif
#include "slirp/libslirp.h"
+#include "trace.h"
+#include "simpletrace.h"
#include "qemu-queue.h"
#include "cpus.h"
#include "arch_init.h"
+#include "ui/qemu-spice.h"
+
//#define DEBUG_NET
//#define DEBUG_SLIRP
const char *bios_name = NULL;
enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
DisplayType display_type = DT_DEFAULT;
+int display_remote = 0;
const char* keyboard_layout = NULL;
ram_addr_t ram_size;
const char *mem_path = NULL;
int graphic_rotate = 0;
uint8_t irq0override = 1;
const char *watchdog;
-const char *option_rom[MAX_OPTION_ROMS];
+QEMUOptionRom option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
int semihosting_enabled = 0;
int old_param = 0;
const char *prom_envs[MAX_PROM_ENVS];
int boot_menu;
+typedef struct FWBootEntry FWBootEntry;
+
+struct FWBootEntry {
+ QTAILQ_ENTRY(FWBootEntry) link;
+ int32_t bootindex;
+ DeviceState *dev;
+ char *suffix;
+};
+
+QTAILQ_HEAD(, FWBootEntry) fw_boot_order = QTAILQ_HEAD_INITIALIZER(fw_boot_order);
+
int nb_numa_nodes;
uint64_t node_mem[MAX_NODES];
uint64_t node_cpumask[MAX_NODES];
static NotifierList exit_notifiers =
NOTIFIER_LIST_INITIALIZER(exit_notifiers);
+static NotifierList machine_init_done_notifiers =
+ NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers);
+
int kvm_allowed = 0;
uint32_t xen_domid;
enum xen_mode xen_mode = XEN_EMULATE;
/***********************************************************/
/* real time host monotonic timer */
-/* compute with 96 bit intermediate result: (a*b)/c */
-uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
-{
- union {
- uint64_t ll;
- struct {
-#ifdef HOST_WORDS_BIGENDIAN
- uint32_t high, low;
-#else
- uint32_t low, high;
-#endif
- } l;
- } u, res;
- uint64_t rl, rh;
-
- u.ll = a;
- rl = (uint64_t)u.l.low * (uint64_t)b;
- rh = (uint64_t)u.l.high * (uint64_t)b;
- rh += (rl >> 32);
- res.l.high = rh / c;
- res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
- return res.ll;
-}
-
/***********************************************************/
/* host time/date access */
void qemu_get_timedate(struct tm *tm, int offset)
/***********************************************************/
/* QEMU Block devices */
-#define HD_ALIAS "index=%d,media=disk"
-#define CDROM_ALIAS "index=2,media=cdrom"
-#define FD_ALIAS "index=%d,if=floppy"
-#define PFLASH_ALIAS "if=pflash"
-#define MTD_ALIAS "if=mtd"
-#define SD_ALIAS "index=0,if=sd"
+#define HD_OPTS "media=disk"
+#define CDROM_OPTS "media=cdrom"
+#define FD_OPTS ""
+#define PFLASH_OPTS ""
+#define MTD_OPTS ""
+#define SD_OPTS ""
static int drive_init_func(QemuOpts *opts, void *opaque)
{
int *use_scsi = opaque;
- int fatal_error = 0;
- if (drive_init(opts, *use_scsi, &fatal_error) == NULL) {
- if (fatal_error)
- return 1;
- }
- return 0;
+ return drive_init(opts, *use_scsi) == NULL;
}
static int drive_enable_snapshot(QemuOpts *opts, void *opaque)
return 0;
}
+static void default_drive(int enable, int snapshot, int use_scsi,
+ BlockInterfaceType type, int index,
+ const char *optstr)
+{
+ QemuOpts *opts;
+
+ if (type == IF_DEFAULT) {
+ type = use_scsi ? IF_SCSI : IF_IDE;
+ }
+
+ if (!enable || drive_get_by_index(type, index)) {
+ return;
+ }
+
+ opts = drive_add(type, index, NULL, optstr);
+ if (snapshot) {
+ drive_enable_snapshot(opts, NULL);
+ }
+ if (!drive_init(opts, use_scsi)) {
+ exit(1);
+ }
+}
+
void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque)
{
boot_set_handler = func;
qemu_free(standard_boot_devices);
}
+void add_boot_device_path(int32_t bootindex, DeviceState *dev,
+ const char *suffix)
+{
+ FWBootEntry *node, *i;
+
+ if (bootindex < 0) {
+ return;
+ }
+
+ assert(dev != NULL || suffix != NULL);
+
+ node = qemu_mallocz(sizeof(FWBootEntry));
+ node->bootindex = bootindex;
+ node->suffix = suffix ? qemu_strdup(suffix) : NULL;
+ node->dev = dev;
+
+ QTAILQ_FOREACH(i, &fw_boot_order, link) {
+ if (i->bootindex == bootindex) {
+ fprintf(stderr, "Two devices with same boot index %d\n", bootindex);
+ exit(1);
+ } else if (i->bootindex < bootindex) {
+ continue;
+ }
+ QTAILQ_INSERT_BEFORE(i, node, link);
+ return;
+ }
+ QTAILQ_INSERT_TAIL(&fw_boot_order, node, link);
+}
+
+/*
+ * This function returns null terminated string that consist of new line
+ * separated device pathes.
+ *
+ * memory pointed by "size" is assigned total length of the array in bytes
+ *
+ */
+char *get_boot_devices_list(uint32_t *size)
+{
+ FWBootEntry *i;
+ uint32_t total = 0;
+ char *list = NULL;
+
+ QTAILQ_FOREACH(i, &fw_boot_order, link) {
+ char *devpath = NULL, *bootpath;
+ int len;
+
+ if (i->dev) {
+ devpath = qdev_get_fw_dev_path(i->dev);
+ assert(devpath);
+ }
+
+ if (i->suffix && devpath) {
+ size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1;
+
+ bootpath = qemu_malloc(bootpathlen);
+ snprintf(bootpath, bootpathlen, "%s%s", devpath, i->suffix);
+ qemu_free(devpath);
+ } else if (devpath) {
+ bootpath = devpath;
+ } else {
+ bootpath = qemu_strdup(i->suffix);
+ assert(bootpath);
+ }
+
+ if (total) {
+ list[total-1] = '\n';
+ }
+ len = strlen(bootpath) + 1;
+ list = qemu_realloc(list, total + len);
+ memcpy(&list[total], bootpath, len);
+ total += len;
+ qemu_free(bootpath);
+ }
+
+ *size = total;
+
+ return list;
+}
+
static void numa_add(const char *optarg)
{
char option[128];
if (get_param_value(option, 128, "mem", optarg) == 0) {
node_mem[nodenr] = 0;
} else {
- value = strtoull(option, &endptr, 0);
- switch (*endptr) {
- case 0: case 'M': case 'm':
- value <<= 20;
- break;
- case 'G': case 'g':
- value <<= 30;
- break;
+ int64_t sval;
+ sval = strtosz(option, NULL);
+ if (sval < 0) {
+ fprintf(stderr, "qemu: invalid numa mem size: %s\n", optarg);
+ exit(1);
}
- node_mem[nodenr] = value;
+ node_mem[nodenr] = sval;
}
if (get_param_value(option, 128, "cpus", optarg) == 0) {
node_cpumask[nodenr] = 0;
{
VMChangeStateEntry *e;
+ trace_vm_state_notify(running, reason);
+
for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
e->cb(e->opaque, running, reason);
}
static int reset_requested;
static int shutdown_requested;
static int powerdown_requested;
-int debug_requested;
-int vmstop_requested;
+static int debug_requested;
+static int vmstop_requested;
int qemu_shutdown_requested(void)
{
} else {
reset_requested = 1;
}
+ cpu_stop_current();
qemu_notify_event();
}
qemu_notify_event();
}
+void qemu_system_debug_request(void)
+{
+ debug_requested = 1;
+ qemu_notify_event();
+}
+
+void qemu_system_vmstop_request(int reason)
+{
+ vmstop_requested = reason;
+ qemu_notify_event();
+}
+
void main_loop_wait(int nonblocking)
{
IOHandlerRecord *ioh;
IOHandlerRecord *pioh;
QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
- if (ioh->deleted) {
- QLIST_REMOVE(ioh, next);
- qemu_free(ioh);
- continue;
- }
- if (ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
+ if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
ioh->fd_read(ioh->opaque);
}
- if (ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
+ if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
ioh->fd_write(ioh->opaque);
}
+
+ /* Do this last in case read/write handlers marked it for deletion */
+ if (ioh->deleted) {
+ QLIST_REMOVE(ioh, next);
+ qemu_free(ioh);
+ }
}
}
}
-static int vm_can_run(void)
+#ifndef CONFIG_IOTHREAD
+static int vm_request_pending(void)
{
- if (powerdown_requested)
- return 0;
- if (reset_requested)
- return 0;
- if (shutdown_requested)
- return 0;
- if (debug_requested)
- return 0;
- return 1;
+ return powerdown_requested ||
+ reset_requested ||
+ shutdown_requested ||
+ debug_requested ||
+ vmstop_requested;
}
+#endif
qemu_irq qemu_system_powerdown;
static void main_loop(void)
{
+ bool nonblocking = false;
+#ifdef CONFIG_PROFILER
+ int64_t ti;
+#endif
int r;
qemu_main_loop_start();
for (;;) {
- do {
- bool nonblocking = false;
-#ifdef CONFIG_PROFILER
- int64_t ti;
-#endif
#ifndef CONFIG_IOTHREAD
- nonblocking = cpu_exec_all();
+ nonblocking = cpu_exec_all();
+ if (vm_request_pending()) {
+ nonblocking = true;
+ }
#endif
#ifdef CONFIG_PROFILER
- ti = profile_getclock();
+ ti = profile_getclock();
#endif
- main_loop_wait(nonblocking);
+ main_loop_wait(nonblocking);
#ifdef CONFIG_PROFILER
- dev_time += profile_getclock() - ti;
+ dev_time += profile_getclock() - ti;
#endif
- } while (vm_can_run());
- if ((r = qemu_debug_requested())) {
- vm_stop(r);
+ if (qemu_debug_requested()) {
+ vm_stop(VMSTOP_DEBUG);
}
if (qemu_shutdown_requested()) {
monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
if (no_shutdown) {
- vm_stop(0);
+ vm_stop(VMSTOP_SHUTDOWN);
no_shutdown = 0;
} else
break;
}
if (qemu_reset_requested()) {
pause_all_vcpus();
+ cpu_synchronize_all_states();
qemu_system_reset();
resume_all_vcpus();
}
vga_interface_type = VGA_VMWARE;
} else if (strstart(p, "xenfb", &opts)) {
vga_interface_type = VGA_XENFB;
+ } else if (strstart(p, "qxl", &opts)) {
+ vga_interface_type = VGA_QXL;
} else if (!strstart(p, "none", &opts)) {
invalid_vga:
fprintf(stderr, "Unknown vga type: %s\n", p);
exit(1);
}
+ if (qemu_opt_get_bool(opts, "pretty", 0))
+ flags |= MONITOR_USE_PRETTY;
+
if (qemu_opt_get_bool(opts, "default", 0))
flags |= MONITOR_IS_DEFAULT;
notifier_list_notify(&exit_notifiers);
}
+void qemu_add_machine_init_done_notifier(Notifier *notify)
+{
+ notifier_list_add(&machine_init_done_notifiers, notify);
+}
+
+static void qemu_run_machine_init_done_notifiers(void)
+{
+ notifier_list_notify(&machine_init_done_notifiers);
+}
+
static const QEMUOption *lookup_opt(int argc, char **argv,
const char **poptarg, int *poptind)
{
const char *incoming = NULL;
int show_vnc_port = 0;
int defconfig = 1;
+ const char *trace_file = NULL;
atexit(qemu_run_exit_notifiers);
error_set_progname(argv[0]);
tb_size = 0;
autostart= 1;
-#ifdef CONFIG_VIRTFS
- qemu_add_opts(&qemu_fsdev_opts);
- qemu_add_opts(&qemu_virtfs_opts);
-#endif
-
/* first pass of option parsing */
optind = 1;
while (optind < argc) {
if (optind >= argc)
break;
if (argv[optind][0] != '-') {
- hda_opts = drive_add(argv[optind++], HD_ALIAS, 0);
+ hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
} else {
const QEMUOption *popt;
initrd_filename = optarg;
break;
case QEMU_OPTION_hda:
- if (cyls == 0)
- hda_opts = drive_add(optarg, HD_ALIAS, 0);
- else
- hda_opts = drive_add(optarg, HD_ALIAS
- ",cyls=%d,heads=%d,secs=%d%s",
- 0, cyls, heads, secs,
- translation == BIOS_ATA_TRANSLATION_LBA ?
+ {
+ char buf[256];
+ if (cyls == 0)
+ snprintf(buf, sizeof(buf), "%s", HD_OPTS);
+ else
+ snprintf(buf, sizeof(buf),
+ "%s,cyls=%d,heads=%d,secs=%d%s",
+ HD_OPTS , cyls, heads, secs,
+ translation == BIOS_ATA_TRANSLATION_LBA ?
",trans=lba" :
- translation == BIOS_ATA_TRANSLATION_NONE ?
+ translation == BIOS_ATA_TRANSLATION_NONE ?
",trans=none" : "");
- break;
+ drive_add(IF_DEFAULT, 0, optarg, buf);
+ break;
+ }
case QEMU_OPTION_hdb:
case QEMU_OPTION_hdc:
case QEMU_OPTION_hdd:
- drive_add(optarg, HD_ALIAS, popt->index - QEMU_OPTION_hda);
+ drive_add(IF_DEFAULT, popt->index - QEMU_OPTION_hda, optarg,
+ HD_OPTS);
break;
case QEMU_OPTION_drive:
- drive_add(NULL, "%s", optarg);
+ drive_def(optarg);
break;
case QEMU_OPTION_set:
if (qemu_set_option(optarg) != 0)
exit(1);
break;
case QEMU_OPTION_mtdblock:
- drive_add(optarg, MTD_ALIAS);
+ drive_add(IF_MTD, -1, optarg, MTD_OPTS);
break;
case QEMU_OPTION_sd:
- drive_add(optarg, SD_ALIAS);
+ drive_add(IF_SD, 0, optarg, SD_OPTS);
break;
case QEMU_OPTION_pflash:
- drive_add(optarg, PFLASH_ALIAS);
+ drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS);
break;
case QEMU_OPTION_snapshot:
snapshot = 1;
kernel_cmdline = optarg;
break;
case QEMU_OPTION_cdrom:
- drive_add(optarg, CDROM_ALIAS);
+ drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
break;
case QEMU_OPTION_boot:
{
break;
case QEMU_OPTION_fda:
case QEMU_OPTION_fdb:
- drive_add(optarg, FD_ALIAS, popt->index - QEMU_OPTION_fda);
+ drive_add(IF_FLOPPY, popt->index - QEMU_OPTION_fda,
+ optarg, FD_OPTS);
break;
case QEMU_OPTION_no_fd_bootchk:
fd_bootchk = 0;
exit(0);
break;
case QEMU_OPTION_m: {
- uint64_t value;
- char *ptr;
+ int64_t value;
- value = strtoul(optarg, &ptr, 10);
- switch (*ptr) {
- case 0: case 'M': case 'm':
- value <<= 20;
- break;
- case 'G': case 'g':
- value <<= 30;
- break;
- default:
+ value = strtosz(optarg, NULL);
+ if (value < 0) {
fprintf(stderr, "qemu: invalid ram size: %s\n", optarg);
exit(1);
}
}
break;
case QEMU_OPTION_vnc:
- display_type = DT_VNC;
+ display_remote++;
vnc_display = optarg;
break;
case QEMU_OPTION_no_acpi:
fprintf(stderr, "Too many option ROMs\n");
exit(1);
}
- option_rom[nb_option_roms] = optarg;
+ opts = qemu_opts_parse(qemu_find_opts("option-rom"), optarg, 1);
+ option_rom[nb_option_roms].name = qemu_opt_get(opts, "romfile");
+ option_rom[nb_option_roms].bootindex =
+ qemu_opt_get_number(opts, "bootindex", -1);
+ if (!option_rom[nb_option_roms].name) {
+ fprintf(stderr, "Option ROM file is not specified\n");
+ exit(1);
+ }
nb_option_roms++;
break;
case QEMU_OPTION_semihosting:
if (p != NULL) {
*p++ = 0;
if (strncmp(p, "process=", 8)) {
- fprintf(stderr, "Unknown subargument %s to -name", p);
+ fprintf(stderr, "Unknown subargument %s to -name\n", p);
exit(1);
}
p += 8;
}
xen_mode = XEN_ATTACH;
break;
+#ifdef CONFIG_SIMPLE_TRACE
+ case QEMU_OPTION_trace:
+ opts = qemu_opts_parse(qemu_find_opts("trace"), optarg, 0);
+ if (opts) {
+ trace_file = qemu_opt_get(opts, "file");
+ }
+ break;
+#endif
case QEMU_OPTION_readconfig:
{
int ret = qemu_read_config_file(optarg);
}
break;
}
+ case QEMU_OPTION_spice:
+ olist = qemu_find_opts("spice");
+ if (!olist) {
+ fprintf(stderr, "spice is not supported by this qemu build.\n");
+ exit(1);
+ }
+ opts = qemu_opts_parse(olist, optarg, 0);
+ if (!opts) {
+ fprintf(stderr, "parse error: %s\n", optarg);
+ exit(1);
+ }
+ break;
case QEMU_OPTION_writeconfig:
{
FILE *fp;
}
loc_set_none();
+ st_init(trace_file);
+
/* If no data_dir is specified then try to find it relative to the
executable path. */
if (!data_dir) {
}
if (kvm_allowed) {
- int ret = kvm_init(smp_cpus);
+ int ret = kvm_init();
if (ret < 0) {
if (!kvm_available()) {
printf("KVM not supported for this target\n");
blk_mig_init();
- if (default_cdrom) {
- /* we always create the cdrom drive, even if no disk is there */
- drive_add(NULL, CDROM_ALIAS);
- }
-
- if (default_floppy) {
- /* we always create at least one floppy */
- drive_add(NULL, FD_ALIAS, 0);
- }
-
- if (default_sdcard) {
- /* we always create one sd slot, even if no card is in it */
- drive_add(NULL, SD_ALIAS);
- }
-
/* open the virtual block devices */
if (snapshot)
qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, 0);
if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func, &machine->use_scsi, 1) != 0)
exit(1);
+ default_drive(default_cdrom, snapshot, machine->use_scsi,
+ IF_DEFAULT, 2, CDROM_OPTS);
+ default_drive(default_floppy, snapshot, machine->use_scsi,
+ IF_FLOPPY, 0, FD_OPTS);
+ default_drive(default_sdcard, snapshot, machine->use_scsi,
+ IF_SD, 0, SD_OPTS);
+
register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL,
ram_load, NULL);
/* just use the first displaystate for the moment */
ds = get_displaystate();
- if (display_type == DT_DEFAULT) {
+ if (using_spice)
+ display_remote++;
+ if (display_type == DT_DEFAULT && !display_remote) {
#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
display_type = DT_SDL;
#else
- display_type = DT_VNC;
vnc_display = "localhost:0,to=99";
show_vnc_port = 1;
#endif
}
+ /* init local displays */
switch (display_type) {
case DT_NOGRAPHIC:
break;
cocoa_display_init(ds, full_screen);
break;
#endif
- case DT_VNC:
+ default:
+ break;
+ }
+
+ /* init remote displays */
+ if (vnc_display) {
vnc_display_init(ds);
if (vnc_display_open(ds, vnc_display) < 0)
exit(1);
if (show_vnc_port) {
printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
}
- break;
- default:
- break;
}
- dpy_resize(ds);
+#ifdef CONFIG_SPICE
+ if (using_spice && !qxl_enabled) {
+ qemu_spice_display_init(ds);
+ }
+#endif
+ /* display setup */
+ dpy_resize(ds);
dcl = ds->listeners;
while (dcl != NULL) {
if (dcl->dpy_refresh != NULL) {
}
dcl = dcl->next;
}
-
- if (display_type == DT_NOGRAPHIC || display_type == DT_VNC) {
+ if (ds->gui_timer == NULL) {
nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL);
qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock));
}
-
text_consoles_set_display(ds);
if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
exit(1);
}
+ /* TODO: once all bus devices are qdevified, this should be done
+ * when bus is created by qdev.c */
+ qemu_register_reset(qbus_reset_all_fn, sysbus_get_default());
+ qemu_run_machine_init_done_notifiers();
+
qemu_system_reset();
if (loadvm) {
if (load_vmstate(loadvm) < 0) {