2003-06-24 21:42:40 +08:00
|
|
|
/*
|
2004-03-14 20:20:30 +08:00
|
|
|
* QEMU System Emulator
|
2007-09-17 05:08:06 +08:00
|
|
|
*
|
2008-01-07 01:21:48 +08:00
|
|
|
* Copyright (c) 2003-2008 Fabrice Bellard
|
2007-09-17 05:08:06 +08:00
|
|
|
*
|
2003-06-26 00:20:35 +08:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
2003-06-24 21:42:40 +08:00
|
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <errno.h>
|
2004-04-01 07:37:16 +08:00
|
|
|
#include <sys/time.h>
|
2006-08-06 21:36:11 +08:00
|
|
|
#include <zlib.h>
|
2004-04-01 07:37:16 +08:00
|
|
|
|
2009-07-27 22:12:56 +08:00
|
|
|
/* Needed early for CONFIG_BSD etc. */
|
2009-03-08 00:52:02 +08:00
|
|
|
#include "config-host.h"
|
|
|
|
|
2004-04-01 07:37:16 +08:00
|
|
|
#ifndef _WIN32
|
2009-05-30 07:52:44 +08:00
|
|
|
#include <libgen.h>
|
2004-04-01 07:37:16 +08:00
|
|
|
#include <sys/times.h>
|
2003-06-25 08:07:40 +08:00
|
|
|
#include <sys/wait.h>
|
2004-04-01 07:37:16 +08:00
|
|
|
#include <termios.h>
|
|
|
|
#include <sys/mman.h>
|
2003-06-25 08:07:40 +08:00
|
|
|
#include <sys/ioctl.h>
|
2008-11-08 00:55:48 +08:00
|
|
|
#include <sys/resource.h>
|
2003-06-25 08:07:40 +08:00
|
|
|
#include <sys/socket.h>
|
2004-09-14 05:37:34 +08:00
|
|
|
#include <netinet/in.h>
|
2008-11-08 00:55:48 +08:00
|
|
|
#include <net/if.h>
|
|
|
|
#include <arpa/inet.h>
|
2004-09-06 07:09:03 +08:00
|
|
|
#include <dirent.h>
|
2005-11-16 06:16:05 +08:00
|
|
|
#include <netdb.h>
|
2007-09-13 20:39:35 +08:00
|
|
|
#include <sys/select.h>
|
2010-08-09 18:48:32 +08:00
|
|
|
#ifdef CONFIG_SIMPLE_TRACE
|
|
|
|
#include "trace.h"
|
|
|
|
#endif
|
|
|
|
|
2009-07-27 22:12:56 +08:00
|
|
|
#ifdef CONFIG_BSD
|
2004-05-13 03:32:15 +08:00
|
|
|
#include <sys/stat.h>
|
2009-11-30 01:00:41 +08:00
|
|
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
|
2004-05-13 03:32:15 +08:00
|
|
|
#include <libutil.h>
|
2010-03-26 05:07:12 +08:00
|
|
|
#include <sys/sysctl.h>
|
2008-11-08 00:55:48 +08:00
|
|
|
#else
|
|
|
|
#include <util.h>
|
2008-08-16 02:33:42 +08:00
|
|
|
#endif
|
2009-11-30 22:42:59 +08:00
|
|
|
#else
|
2008-10-01 02:12:18 +08:00
|
|
|
#ifdef __linux__
|
2004-05-13 03:32:15 +08:00
|
|
|
#include <pty.h>
|
|
|
|
#include <malloc.h>
|
2007-09-17 04:03:23 +08:00
|
|
|
|
2005-11-11 07:58:52 +08:00
|
|
|
#include <linux/ppdev.h>
|
2007-02-18 07:44:43 +08:00
|
|
|
#include <linux/parport.h>
|
2008-10-01 02:12:18 +08:00
|
|
|
#endif
|
|
|
|
#ifdef __sun__
|
2007-02-18 06:54:49 +08:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/ethernet.h>
|
|
|
|
#include <sys/sockio.h>
|
|
|
|
#include <netinet/arp.h>
|
|
|
|
#include <netinet/in_systm.h>
|
|
|
|
#include <netinet/ip.h>
|
|
|
|
#include <netinet/ip_icmp.h> // must come after ip.h
|
|
|
|
#include <netinet/udp.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <net/if.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
#include <stropts.h>
|
2004-04-01 07:37:16 +08:00
|
|
|
#endif
|
2004-05-13 03:32:15 +08:00
|
|
|
#endif
|
2006-04-26 06:36:06 +08:00
|
|
|
#endif
|
2004-04-01 07:37:16 +08:00
|
|
|
|
2008-08-24 18:34:20 +08:00
|
|
|
#if defined(__OpenBSD__)
|
|
|
|
#include <util.h>
|
|
|
|
#endif
|
|
|
|
|
2008-07-19 17:56:24 +08:00
|
|
|
#if defined(CONFIG_VDE)
|
|
|
|
#include <libvdeplug.h>
|
|
|
|
#endif
|
|
|
|
|
2004-04-01 07:37:16 +08:00
|
|
|
#ifdef _WIN32
|
2009-03-09 00:26:59 +08:00
|
|
|
#include <windows.h>
|
2004-04-01 07:37:16 +08:00
|
|
|
#endif
|
|
|
|
|
2004-04-05 04:22:28 +08:00
|
|
|
#ifdef CONFIG_SDL
|
2009-06-19 02:11:03 +08:00
|
|
|
#if defined(__APPLE__) || defined(main)
|
2009-06-13 19:19:11 +08:00
|
|
|
#include <SDL.h>
|
2009-02-16 04:18:41 +08:00
|
|
|
int qemu_main(int argc, char **argv, char **envp);
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2009-06-19 02:11:03 +08:00
|
|
|
return qemu_main(argc, argv, NULL);
|
2009-02-16 04:18:41 +08:00
|
|
|
}
|
|
|
|
#undef main
|
|
|
|
#define main qemu_main
|
2004-07-11 00:26:15 +08:00
|
|
|
#endif
|
2004-04-05 04:22:28 +08:00
|
|
|
#endif /* CONFIG_SDL */
|
2003-06-24 21:42:40 +08:00
|
|
|
|
2005-03-02 05:37:28 +08:00
|
|
|
#ifdef CONFIG_COCOA
|
|
|
|
#undef main
|
|
|
|
#define main qemu_main
|
|
|
|
#endif /* CONFIG_COCOA */
|
|
|
|
|
2009-03-07 23:32:56 +08:00
|
|
|
#include "hw/hw.h"
|
|
|
|
#include "hw/boards.h"
|
|
|
|
#include "hw/usb.h"
|
|
|
|
#include "hw/pcmcia.h"
|
|
|
|
#include "hw/pc.h"
|
|
|
|
#include "hw/isa.h"
|
|
|
|
#include "hw/baum.h"
|
|
|
|
#include "hw/bt.h"
|
2009-04-25 20:56:19 +08:00
|
|
|
#include "hw/watchdog.h"
|
qemu: Add support for SMBIOS command line otions (Alex Williamson)
Create a new -smbios option (x86-only) to allow binary SMBIOS entries
to be passed through to the BIOS or modify the default values of
individual fields of type 0 and 1 entries on the command line.
Binary SMBIOS entries can be generated as follows:
dmidecode -t 1 -u | grep $'^\t\t[^"]' | xargs -n1 | \
perl -lne 'printf "%c", hex($_)' > smbios_type_1.bin
These can then be passed to the BIOS using this switch:
-smbios file=smbios_type_1.bin
Command line generation supports the following syntax:
-smbios type=0[,vendor=str][,version=str][,date=str][,release=%d.%d]
-smbios type=1[,manufacturer=str][,product=str][,version=str][,serial=str]
[,uuid=$(uuidgen)][,sku=str][,family=str]
For instance, to add a serial number to the type 1 table:
-smbios type=1,serial=0123456789
Interface is extensible to support more fields/tables as needed.
aliguori: remove texi formatting from help output
Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7163 c046a42c-6fe2-441c-8c8c-71466251a162
2009-04-18 02:59:56 +08:00
|
|
|
#include "hw/smbios.h"
|
2009-04-22 23:19:10 +08:00
|
|
|
#include "hw/xen.h"
|
2009-07-15 19:59:26 +08:00
|
|
|
#include "hw/qdev.h"
|
2009-10-01 22:42:33 +08:00
|
|
|
#include "hw/loader.h"
|
2009-03-11 05:43:35 +08:00
|
|
|
#include "bt-host.h"
|
2009-03-07 23:32:56 +08:00
|
|
|
#include "net.h"
|
2009-11-26 02:48:54 +08:00
|
|
|
#include "net/slirp.h"
|
2009-03-07 23:32:56 +08:00
|
|
|
#include "monitor.h"
|
|
|
|
#include "console.h"
|
|
|
|
#include "sysemu.h"
|
|
|
|
#include "gdbstub.h"
|
|
|
|
#include "qemu-timer.h"
|
|
|
|
#include "qemu-char.h"
|
|
|
|
#include "cache-utils.h"
|
|
|
|
#include "block.h"
|
2010-06-03 00:48:27 +08:00
|
|
|
#include "blockdev.h"
|
2009-11-02 21:40:58 +08:00
|
|
|
#include "block-migration.h"
|
2009-03-28 16:24:44 +08:00
|
|
|
#include "dma.h"
|
2009-03-07 23:32:56 +08:00
|
|
|
#include "audio/audio.h"
|
|
|
|
#include "migration.h"
|
|
|
|
#include "kvm.h"
|
2009-05-18 22:42:09 +08:00
|
|
|
#include "qemu-option.h"
|
2009-07-31 18:25:35 +08:00
|
|
|
#include "qemu-config.h"
|
2009-12-11 03:16:04 +08:00
|
|
|
#include "qemu-objects.h"
|
2010-06-10 17:42:25 +08:00
|
|
|
#include "qemu-options.h"
|
2010-06-15 04:34:41 +08:00
|
|
|
#ifdef CONFIG_VIRTFS
|
2010-04-29 20:14:43 +08:00
|
|
|
#include "fsdev/qemu-fsdev.h"
|
|
|
|
#endif
|
2009-03-07 23:32:56 +08:00
|
|
|
|
2003-06-24 21:42:40 +08:00
|
|
|
#include "disas.h"
|
2003-06-30 18:03:06 +08:00
|
|
|
|
2009-03-07 23:32:56 +08:00
|
|
|
#include "qemu_socket.h"
|
|
|
|
|
2009-06-24 20:42:30 +08:00
|
|
|
#include "slirp/libslirp.h"
|
2009-03-07 23:32:56 +08:00
|
|
|
|
2010-11-16 20:20:25 +08:00
|
|
|
#include "trace.h"
|
2009-09-12 15:36:22 +08:00
|
|
|
#include "qemu-queue.h"
|
2010-03-30 03:23:50 +08:00
|
|
|
#include "cpus.h"
|
2010-03-30 03:23:52 +08:00
|
|
|
#include "arch_init.h"
|
2009-09-12 15:36:22 +08:00
|
|
|
|
2010-03-11 22:13:27 +08:00
|
|
|
#include "ui/qemu-spice.h"
|
|
|
|
|
2008-10-04 15:25:46 +08:00
|
|
|
//#define DEBUG_NET
|
|
|
|
//#define DEBUG_SLIRP
|
2003-07-27 02:11:40 +08:00
|
|
|
|
2004-07-09 05:17:50 +08:00
|
|
|
#define DEFAULT_RAM_SIZE 128
|
2003-08-11 05:52:11 +08:00
|
|
|
|
virtio-console: qdev conversion, new virtio-serial-bus
This commit converts the virtio-console device to create a new
virtio-serial bus that can host console and generic serial ports. The
file hosting this code is now called virtio-serial-bus.c.
The virtio console is now a very simple qdev device that sits on the
virtio-serial-bus and communicates between the bus and qemu's chardevs.
This commit also includes a few changes to the virtio backing code for
pci and s390 to spawn the virtio-serial bus.
As a result of the qdev conversion, we get rid of a lot of legacy code.
The old-style way of instantiating a virtio console using
-virtioconsole ...
is maintained, but the new, preferred way is to use
-device virtio-serial -device virtconsole,chardev=...
With this commit, multiple devices as well as multiple ports with a
single device can be supported.
For multiple ports support, each port gets an IO vq pair. Since the
guest needs to know in advance how many vqs a particular device will
need, we have to set this number as a property of the virtio-serial
device and also as a config option.
In addition, we also spawn a pair of control IO vqs. This is an internal
channel meant for guest-host communication for things like port
open/close, sending port properties over to the guest, etc.
This commit is a part of a series of other commits to get the full
implementation of multiport support. Future commits will add other
support as well as ride on the savevm version that we bump up here.
Signed-off-by: Amit Shah <amit.shah@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-01-20 03:06:52 +08:00
|
|
|
#define MAX_VIRTIO_CONSOLES 1
|
|
|
|
|
2009-05-30 07:52:44 +08:00
|
|
|
static const char *data_dir;
|
2007-10-05 21:08:35 +08:00
|
|
|
const char *bios_name = NULL;
|
2008-09-28 08:42:12 +08:00
|
|
|
enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
|
2009-05-22 05:54:00 +08:00
|
|
|
DisplayType display_type = DT_DEFAULT;
|
2010-08-25 16:51:06 +08:00
|
|
|
int display_remote = 0;
|
2004-12-13 00:56:30 +08:00
|
|
|
const char* keyboard_layout = NULL;
|
2009-10-02 05:12:16 +08:00
|
|
|
ram_addr_t ram_size;
|
2010-03-02 07:25:08 +08:00
|
|
|
const char *mem_path = NULL;
|
|
|
|
#ifdef MAP_POPULATE
|
|
|
|
int mem_prealloc = 0; /* force preallocation of physical target memory */
|
|
|
|
#endif
|
2004-03-15 05:44:30 +08:00
|
|
|
int nb_nics;
|
2005-11-16 06:16:05 +08:00
|
|
|
NICInfo nd_table[MAX_NICS];
|
2004-04-01 03:00:16 +08:00
|
|
|
int vm_running;
|
2009-07-28 05:17:51 +08:00
|
|
|
int autostart;
|
2010-07-27 18:19:19 +08:00
|
|
|
int incoming_expected; /* Started with -incoming and waiting for incoming */
|
2008-02-17 19:42:19 +08:00
|
|
|
static int rtc_utc = 1;
|
|
|
|
static int rtc_date_offset = -1; /* -1 means no change */
|
2009-09-15 19:36:04 +08:00
|
|
|
QEMUClock *rtc_clock;
|
2009-12-08 20:11:45 +08:00
|
|
|
int vga_interface_type = VGA_NONE;
|
2008-10-02 03:38:09 +08:00
|
|
|
static int full_screen = 0;
|
2008-11-16 19:34:07 +08:00
|
|
|
#ifdef CONFIG_SDL
|
2008-10-02 03:38:09 +08:00
|
|
|
static int no_frame = 0;
|
2008-11-16 19:34:07 +08:00
|
|
|
#endif
|
2006-12-11 10:08:05 +08:00
|
|
|
int no_quit = 0;
|
2004-08-25 05:13:40 +08:00
|
|
|
CharDriverState *serial_hds[MAX_SERIAL_PORTS];
|
2005-01-15 20:02:56 +08:00
|
|
|
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
|
2009-01-16 04:05:25 +08:00
|
|
|
CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
|
2005-05-01 00:10:35 +08:00
|
|
|
int win2k_install_hack = 0;
|
2009-01-16 04:11:34 +08:00
|
|
|
int rtc_td_hack = 0;
|
2005-11-05 22:22:28 +08:00
|
|
|
int usb_enabled = 0;
|
2009-04-06 04:08:59 +08:00
|
|
|
int singlestep = 0;
|
2005-11-22 07:25:50 +08:00
|
|
|
int smp_cpus = 1;
|
2009-07-23 23:03:42 +08:00
|
|
|
int max_cpus = 0;
|
extend -smp parsing to include cores= and threads= options
For injecting multi-core and multi-threading CPU topology into guests
extend the -smp syntax to accommodate cores and threads specification.
Syntax: -smp smp_value[,cores=nr_cores][,threads=nr_threads]\
[,socket=nr_sockets][,maxcpus=max_cpus]
smp_value is the legacy value specifying the total number of vCPUs for
the guest. If you specify one of cores, threads or sockets this value
can be omitted. Missing values will be computed to fulfill:
smp_value = nr_cores * nr_threads * nr_sockets
where it will favour sockets over cores over threads (to mimic the
current behavior, which will only inject multiple sockets.)
So -smp 4,threads=2 will inject two sockets with 2 threads each,
-smp cores=4 is an abbreviation for -smp 4,cores=4,threads=1,sockets=1.
If max_cpus (the number of hotpluggable CPUs) is omitted, it will
be set to smp_value.
Signed-off-by: Andre Przywara <andre.przywara@amd.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-19 21:42:40 +08:00
|
|
|
int smp_cores = 1;
|
|
|
|
int smp_threads = 1;
|
2006-12-22 10:09:07 +08:00
|
|
|
const char *vnc_display;
|
2006-05-04 06:02:44 +08:00
|
|
|
int acpi_enabled = 1;
|
2008-12-18 07:28:44 +08:00
|
|
|
int no_hpet = 0;
|
2006-06-15 00:03:05 +08:00
|
|
|
int fd_bootchk = 1;
|
2006-10-03 03:44:22 +08:00
|
|
|
int no_reboot = 0;
|
2008-04-12 05:35:52 +08:00
|
|
|
int no_shutdown = 0;
|
2007-05-01 09:34:14 +08:00
|
|
|
int cursor_hide = 1;
|
2007-04-30 09:48:07 +08:00
|
|
|
int graphic_rotate = 0;
|
2009-08-06 22:25:50 +08:00
|
|
|
uint8_t irq0override = 1;
|
2009-08-21 16:31:34 +08:00
|
|
|
const char *watchdog;
|
2010-12-08 19:35:07 +08:00
|
|
|
QEMUOptionRom option_rom[MAX_OPTION_ROMS];
|
2007-01-06 01:39:04 +08:00
|
|
|
int nb_option_roms;
|
2007-01-21 01:12:09 +08:00
|
|
|
int semihosting_enabled = 0;
|
2007-07-28 06:08:46 +08:00
|
|
|
int old_param = 0;
|
2007-03-19 23:17:08 +08:00
|
|
|
const char *qemu_name;
|
2007-06-22 05:08:02 +08:00
|
|
|
int alt_grab = 0;
|
2009-09-18 04:48:04 +08:00
|
|
|
int ctrl_grab = 0;
|
2007-05-01 22:16:52 +08:00
|
|
|
unsigned int nb_prom_envs = 0;
|
|
|
|
const char *prom_envs[MAX_PROM_ENVS];
|
2009-07-02 06:19:02 +08:00
|
|
|
int boot_menu;
|
2003-06-24 21:42:40 +08:00
|
|
|
|
2010-12-08 19:35:05 +08:00
|
|
|
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);
|
|
|
|
|
2009-04-22 06:30:27 +08:00
|
|
|
int nb_numa_nodes;
|
|
|
|
uint64_t node_mem[MAX_NODES];
|
|
|
|
uint64_t node_cpumask[MAX_NODES];
|
|
|
|
|
2009-01-22 03:28:13 +08:00
|
|
|
static QEMUTimer *nographic_timer;
|
2007-12-03 11:01:40 +08:00
|
|
|
|
2008-09-19 02:29:08 +08:00
|
|
|
uint8_t qemu_uuid[16];
|
|
|
|
|
2009-07-02 06:19:02 +08:00
|
|
|
static QEMUBootSetHandler *boot_set_handler;
|
|
|
|
static void *boot_set_opaque;
|
|
|
|
|
2010-06-04 20:08:07 +08:00
|
|
|
static NotifierList exit_notifiers =
|
|
|
|
NOTIFIER_LIST_INITIALIZER(exit_notifiers);
|
|
|
|
|
2010-12-08 19:35:08 +08:00
|
|
|
static NotifierList machine_init_done_notifiers =
|
|
|
|
NOTIFIER_LIST_INITIALIZER(machine_init_done_notifiers);
|
|
|
|
|
2010-03-30 03:23:49 +08:00
|
|
|
int kvm_allowed = 0;
|
|
|
|
uint32_t xen_domid;
|
|
|
|
enum xen_mode xen_mode = XEN_EMULATE;
|
|
|
|
|
2009-12-08 20:11:41 +08:00
|
|
|
static int default_serial = 1;
|
2009-12-08 20:11:42 +08:00
|
|
|
static int default_parallel = 1;
|
2009-12-08 20:11:54 +08:00
|
|
|
static int default_virtcon = 1;
|
2009-12-08 20:11:43 +08:00
|
|
|
static int default_monitor = 1;
|
2009-12-08 20:11:45 +08:00
|
|
|
static int default_vga = 1;
|
2009-12-16 21:25:39 +08:00
|
|
|
static int default_floppy = 1;
|
|
|
|
static int default_cdrom = 1;
|
|
|
|
static int default_sdcard = 1;
|
2009-12-08 20:11:41 +08:00
|
|
|
|
|
|
|
static struct {
|
|
|
|
const char *driver;
|
|
|
|
int *flag;
|
|
|
|
} default_list[] = {
|
2009-12-08 20:11:42 +08:00
|
|
|
{ .driver = "isa-serial", .flag = &default_serial },
|
|
|
|
{ .driver = "isa-parallel", .flag = &default_parallel },
|
2009-12-16 21:25:40 +08:00
|
|
|
{ .driver = "isa-fdc", .flag = &default_floppy },
|
|
|
|
{ .driver = "ide-drive", .flag = &default_cdrom },
|
2010-01-21 18:49:23 +08:00
|
|
|
{ .driver = "virtio-serial-pci", .flag = &default_virtcon },
|
|
|
|
{ .driver = "virtio-serial-s390", .flag = &default_virtcon },
|
|
|
|
{ .driver = "virtio-serial", .flag = &default_virtcon },
|
2009-12-08 20:11:45 +08:00
|
|
|
{ .driver = "VGA", .flag = &default_vga },
|
2009-12-16 20:35:19 +08:00
|
|
|
{ .driver = "cirrus-vga", .flag = &default_vga },
|
|
|
|
{ .driver = "vmware-svga", .flag = &default_vga },
|
2009-12-08 20:11:41 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int default_driver_check(QemuOpts *opts, void *opaque)
|
|
|
|
{
|
|
|
|
const char *driver = qemu_opt_get(opts, "driver");
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!driver)
|
|
|
|
return 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(default_list); i++) {
|
|
|
|
if (strcmp(default_list[i].driver, driver) != 0)
|
|
|
|
continue;
|
|
|
|
*(default_list[i].flag) = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-01-13 21:05:34 +08:00
|
|
|
/***********************************************************/
|
|
|
|
/* real time host monotonic timer */
|
2006-04-13 05:09:08 +08:00
|
|
|
|
2008-02-17 19:42:19 +08:00
|
|
|
/***********************************************************/
|
|
|
|
/* host time/date access */
|
|
|
|
void qemu_get_timedate(struct tm *tm, int offset)
|
|
|
|
{
|
|
|
|
time_t ti;
|
|
|
|
struct tm *ret;
|
|
|
|
|
|
|
|
time(&ti);
|
|
|
|
ti += offset;
|
|
|
|
if (rtc_date_offset == -1) {
|
|
|
|
if (rtc_utc)
|
|
|
|
ret = gmtime(&ti);
|
|
|
|
else
|
|
|
|
ret = localtime(&ti);
|
|
|
|
} else {
|
|
|
|
ti -= rtc_date_offset;
|
|
|
|
ret = gmtime(&ti);
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(tm, ret, sizeof(struct tm));
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemu_timedate_diff(struct tm *tm)
|
|
|
|
{
|
|
|
|
time_t seconds;
|
|
|
|
|
|
|
|
if (rtc_date_offset == -1)
|
|
|
|
if (rtc_utc)
|
|
|
|
seconds = mktimegm(tm);
|
|
|
|
else
|
|
|
|
seconds = mktime(tm);
|
|
|
|
else
|
|
|
|
seconds = mktimegm(tm) + rtc_date_offset;
|
|
|
|
|
|
|
|
return seconds - time(NULL);
|
|
|
|
}
|
|
|
|
|
2010-02-25 23:11:44 +08:00
|
|
|
void rtc_change_mon_event(struct tm *tm)
|
|
|
|
{
|
|
|
|
QObject *data;
|
|
|
|
|
|
|
|
data = qobject_from_jsonf("{ 'offset': %d }", qemu_timedate_diff(tm));
|
|
|
|
monitor_protocol_event(QEVENT_RTC_CHANGE, data);
|
|
|
|
qobject_decref(data);
|
|
|
|
}
|
|
|
|
|
2009-09-15 19:36:04 +08:00
|
|
|
static void configure_rtc_date_offset(const char *startdate, int legacy)
|
|
|
|
{
|
|
|
|
time_t rtc_start_date;
|
|
|
|
struct tm tm;
|
|
|
|
|
|
|
|
if (!strcmp(startdate, "now") && legacy) {
|
|
|
|
rtc_date_offset = -1;
|
|
|
|
} else {
|
|
|
|
if (sscanf(startdate, "%d-%d-%dT%d:%d:%d",
|
|
|
|
&tm.tm_year,
|
|
|
|
&tm.tm_mon,
|
|
|
|
&tm.tm_mday,
|
|
|
|
&tm.tm_hour,
|
|
|
|
&tm.tm_min,
|
|
|
|
&tm.tm_sec) == 6) {
|
|
|
|
/* OK */
|
|
|
|
} else if (sscanf(startdate, "%d-%d-%d",
|
|
|
|
&tm.tm_year,
|
|
|
|
&tm.tm_mon,
|
|
|
|
&tm.tm_mday) == 3) {
|
|
|
|
tm.tm_hour = 0;
|
|
|
|
tm.tm_min = 0;
|
|
|
|
tm.tm_sec = 0;
|
|
|
|
} else {
|
|
|
|
goto date_fail;
|
|
|
|
}
|
|
|
|
tm.tm_year -= 1900;
|
|
|
|
tm.tm_mon--;
|
|
|
|
rtc_start_date = mktimegm(&tm);
|
|
|
|
if (rtc_start_date == -1) {
|
|
|
|
date_fail:
|
|
|
|
fprintf(stderr, "Invalid date format. Valid formats are:\n"
|
|
|
|
"'2006-06-17T16:01:21' or '2006-06-17'\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
rtc_date_offset = time(NULL) - rtc_start_date;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void configure_rtc(QemuOpts *opts)
|
|
|
|
{
|
|
|
|
const char *value;
|
|
|
|
|
|
|
|
value = qemu_opt_get(opts, "base");
|
|
|
|
if (value) {
|
|
|
|
if (!strcmp(value, "utc")) {
|
|
|
|
rtc_utc = 1;
|
|
|
|
} else if (!strcmp(value, "localtime")) {
|
|
|
|
rtc_utc = 0;
|
|
|
|
} else {
|
|
|
|
configure_rtc_date_offset(value, 0);
|
|
|
|
}
|
|
|
|
}
|
2009-09-15 19:36:04 +08:00
|
|
|
value = qemu_opt_get(opts, "clock");
|
|
|
|
if (value) {
|
|
|
|
if (!strcmp(value, "host")) {
|
|
|
|
rtc_clock = host_clock;
|
|
|
|
} else if (!strcmp(value, "vm")) {
|
|
|
|
rtc_clock = vm_clock;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "qemu: invalid option value '%s'\n", value);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
2009-09-15 19:36:04 +08:00
|
|
|
value = qemu_opt_get(opts, "driftfix");
|
|
|
|
if (value) {
|
2010-03-28 05:33:46 +08:00
|
|
|
if (!strcmp(value, "slew")) {
|
2009-09-15 19:36:04 +08:00
|
|
|
rtc_td_hack = 1;
|
2010-03-28 05:33:46 +08:00
|
|
|
} else if (!strcmp(value, "none")) {
|
2009-09-15 19:36:04 +08:00
|
|
|
rtc_td_hack = 0;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "qemu: invalid option value '%s'\n", value);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-29 07:19:47 +08:00
|
|
|
/***********************************************************/
|
|
|
|
/* Bluetooth support */
|
|
|
|
static int nb_hcis;
|
|
|
|
static int cur_hci;
|
|
|
|
static struct HCIInfo *hci_table[MAX_NICS];
|
2008-11-09 08:04:26 +08:00
|
|
|
|
2008-09-29 07:19:47 +08:00
|
|
|
static struct bt_vlan_s {
|
|
|
|
struct bt_scatternet_s net;
|
|
|
|
int id;
|
|
|
|
struct bt_vlan_s *next;
|
|
|
|
} *first_bt_vlan;
|
|
|
|
|
|
|
|
/* find or alloc a new bluetooth "VLAN" */
|
2008-10-01 02:18:27 +08:00
|
|
|
static struct bt_scatternet_s *qemu_find_bt_vlan(int id)
|
2008-09-29 07:19:47 +08:00
|
|
|
{
|
|
|
|
struct bt_vlan_s **pvlan, *vlan;
|
|
|
|
for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) {
|
|
|
|
if (vlan->id == id)
|
|
|
|
return &vlan->net;
|
|
|
|
}
|
|
|
|
vlan = qemu_mallocz(sizeof(struct bt_vlan_s));
|
|
|
|
vlan->id = id;
|
|
|
|
pvlan = &first_bt_vlan;
|
|
|
|
while (*pvlan != NULL)
|
|
|
|
pvlan = &(*pvlan)->next;
|
|
|
|
*pvlan = vlan;
|
|
|
|
return &vlan->net;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
|
|
|
|
{
|
|
|
|
return -ENOTSUP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct HCIInfo null_hci = {
|
|
|
|
.cmd_send = null_hci_send,
|
|
|
|
.sco_send = null_hci_send,
|
|
|
|
.acl_send = null_hci_send,
|
|
|
|
.bdaddr_set = null_hci_addr_set,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct HCIInfo *qemu_next_hci(void)
|
|
|
|
{
|
|
|
|
if (cur_hci == nb_hcis)
|
|
|
|
return &null_hci;
|
|
|
|
|
|
|
|
return hci_table[cur_hci++];
|
|
|
|
}
|
|
|
|
|
2008-11-09 08:04:26 +08:00
|
|
|
static struct HCIInfo *hci_init(const char *str)
|
|
|
|
{
|
|
|
|
char *endp;
|
|
|
|
struct bt_scatternet_s *vlan = 0;
|
|
|
|
|
|
|
|
if (!strcmp(str, "null"))
|
|
|
|
/* null */
|
|
|
|
return &null_hci;
|
|
|
|
else if (!strncmp(str, "host", 4) && (str[4] == '\0' || str[4] == ':'))
|
|
|
|
/* host[:hciN] */
|
|
|
|
return bt_host_hci(str[4] ? str + 5 : "hci0");
|
|
|
|
else if (!strncmp(str, "hci", 3)) {
|
|
|
|
/* hci[,vlan=n] */
|
|
|
|
if (str[3]) {
|
|
|
|
if (!strncmp(str + 3, ",vlan=", 6)) {
|
|
|
|
vlan = qemu_find_bt_vlan(strtol(str + 9, &endp, 0));
|
|
|
|
if (*endp)
|
|
|
|
vlan = 0;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
vlan = qemu_find_bt_vlan(0);
|
|
|
|
if (vlan)
|
|
|
|
return bt_new_hci(vlan);
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "qemu: Unknown bluetooth HCI `%s'.\n", str);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bt_hci_parse(const char *str)
|
|
|
|
{
|
|
|
|
struct HCIInfo *hci;
|
2009-10-02 05:12:16 +08:00
|
|
|
bdaddr_t bdaddr;
|
2008-11-09 08:04:26 +08:00
|
|
|
|
|
|
|
if (nb_hcis >= MAX_NICS) {
|
|
|
|
fprintf(stderr, "qemu: Too many bluetooth HCIs (max %i).\n", MAX_NICS);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
hci = hci_init(str);
|
|
|
|
if (!hci)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
bdaddr.b[0] = 0x52;
|
|
|
|
bdaddr.b[1] = 0x54;
|
|
|
|
bdaddr.b[2] = 0x00;
|
|
|
|
bdaddr.b[3] = 0x12;
|
|
|
|
bdaddr.b[4] = 0x34;
|
|
|
|
bdaddr.b[5] = 0x56 + nb_hcis;
|
|
|
|
hci->bdaddr_set(hci, bdaddr.b);
|
|
|
|
|
|
|
|
hci_table[nb_hcis++] = hci;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void bt_vhci_add(int vlan_id)
|
|
|
|
{
|
|
|
|
struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id);
|
|
|
|
|
|
|
|
if (!vlan->slave)
|
|
|
|
fprintf(stderr, "qemu: warning: adding a VHCI to "
|
|
|
|
"an empty scatternet %i\n", vlan_id);
|
|
|
|
|
|
|
|
bt_vhci_init(bt_new_hci(vlan));
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct bt_device_s *bt_device_add(const char *opt)
|
|
|
|
{
|
|
|
|
struct bt_scatternet_s *vlan;
|
|
|
|
int vlan_id = 0;
|
|
|
|
char *endp = strstr(opt, ",vlan=");
|
|
|
|
int len = (endp ? endp - opt : strlen(opt)) + 1;
|
|
|
|
char devname[10];
|
|
|
|
|
|
|
|
pstrcpy(devname, MIN(sizeof(devname), len), opt);
|
|
|
|
|
|
|
|
if (endp) {
|
|
|
|
vlan_id = strtol(endp + 6, &endp, 0);
|
|
|
|
if (*endp) {
|
|
|
|
fprintf(stderr, "qemu: unrecognised bluetooth vlan Id\n");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
vlan = qemu_find_bt_vlan(vlan_id);
|
|
|
|
|
|
|
|
if (!vlan->slave)
|
|
|
|
fprintf(stderr, "qemu: warning: adding a slave device to "
|
|
|
|
"an empty scatternet %i\n", vlan_id);
|
|
|
|
|
|
|
|
if (!strcmp(devname, "keyboard"))
|
|
|
|
return bt_keyboard_init(vlan);
|
|
|
|
|
|
|
|
fprintf(stderr, "qemu: unsupported bluetooth device `%s'\n", devname);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int bt_parse(const char *opt)
|
|
|
|
{
|
|
|
|
const char *endp, *p;
|
|
|
|
int vlan;
|
|
|
|
|
|
|
|
if (strstart(opt, "hci", &endp)) {
|
|
|
|
if (!*endp || *endp == ',') {
|
|
|
|
if (*endp)
|
|
|
|
if (!strstart(endp, ",vlan=", 0))
|
|
|
|
opt = endp + 1;
|
|
|
|
|
|
|
|
return bt_hci_parse(opt);
|
|
|
|
}
|
|
|
|
} else if (strstart(opt, "vhci", &endp)) {
|
|
|
|
if (!*endp || *endp == ',') {
|
|
|
|
if (*endp) {
|
|
|
|
if (strstart(endp, ",vlan=", &p)) {
|
|
|
|
vlan = strtol(p, (char **) &endp, 0);
|
|
|
|
if (*endp) {
|
|
|
|
fprintf(stderr, "qemu: bad scatternet '%s'\n", p);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "qemu: bad parameter '%s'\n", endp + 1);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
vlan = 0;
|
|
|
|
|
|
|
|
bt_vhci_add(vlan);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else if (strstart(opt, "device:", &endp))
|
|
|
|
return !bt_device_add(endp);
|
|
|
|
|
|
|
|
fprintf(stderr, "qemu: bad bluetooth parameter '%s'\n", opt);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-09-29 07:19:47 +08:00
|
|
|
/***********************************************************/
|
|
|
|
/* QEMU Block devices */
|
|
|
|
|
2011-01-28 18:21:41 +08:00
|
|
|
/* Any % in the following strings must be escaped as %% */
|
|
|
|
#define HD_OPTS "media=disk"
|
|
|
|
#define CDROM_OPTS "media=cdrom"
|
|
|
|
#define FD_OPTS ""
|
|
|
|
#define PFLASH_OPTS ""
|
|
|
|
#define MTD_OPTS ""
|
|
|
|
#define SD_OPTS ""
|
2007-12-02 12:51:10 +08:00
|
|
|
|
2009-07-22 22:43:04 +08:00
|
|
|
static int drive_init_func(QemuOpts *opts, void *opaque)
|
|
|
|
{
|
2010-06-02 19:31:55 +08:00
|
|
|
int *use_scsi = opaque;
|
2009-07-22 22:43:04 +08:00
|
|
|
int fatal_error = 0;
|
|
|
|
|
2010-06-02 19:31:55 +08:00
|
|
|
if (drive_init(opts, *use_scsi, &fatal_error) == NULL) {
|
2009-07-22 22:43:04 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
blockdev: Reject multiple definitions for the same drive
We silently ignore multiple definitions for the same drive:
$ qemu-system-x86_64 -nodefaults -vnc :1 -S -monitor stdio -drive if=ide,index=1,file=tmp.qcow2 -drive if=ide,index=1,file=nonexistant
QEMU 0.13.50 monitor - type 'help' for more information
(qemu) info block
ide0-hd1: type=hd removable=0 file=tmp.qcow2 backing_file=tmp.img ro=0 drv=qcow2 encrypted=0
With if=none, this can become quite confusing:
$ qemu-system-x86_64 -nodefaults -vnc :1 -S -monitor stdio -drive if=none,index=1,file=tmp.qcow2,id=eins -drive if=none,index=1,file=nonexistant,id=zwei -device ide-drive,drive=eins -device ide-drive,drive=zwei
qemu-system-x86_64: -device ide-drive,drive=zwei: Property 'ide-drive.drive' can't find value 'zwei'
The second -device fails, because it refers to drive zwei, which got
silently ignored.
Make multiple drive definitions fail cleanly.
Unfortunately, there's code that relies on multiple drive definitions
being silently ignored: main() merrily adds default drives even when
the user already defined these drives. Fix that up.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2011-01-28 18:21:45 +08:00
|
|
|
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_func(opts, &use_scsi)) {
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-02 06:19:02 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-04-07 06:22:08 +08:00
|
|
|
static void validate_bootdevices(char *devices)
|
2009-07-02 06:19:02 +08:00
|
|
|
{
|
|
|
|
/* 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');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-02 06:19:02 +08:00
|
|
|
static void restore_boot_devices(void *opaque)
|
|
|
|
{
|
|
|
|
char *standard_boot_devices = opaque;
|
2010-05-01 05:21:11 +08:00
|
|
|
static int first = 1;
|
|
|
|
|
|
|
|
/* Restore boot order and remove ourselves after the first boot */
|
|
|
|
if (first) {
|
|
|
|
first = 0;
|
|
|
|
return;
|
|
|
|
}
|
2009-07-02 06:19:02 +08:00
|
|
|
|
|
|
|
qemu_boot_set(standard_boot_devices);
|
|
|
|
|
|
|
|
qemu_unregister_reset(restore_boot_devices, standard_boot_devices);
|
|
|
|
qemu_free(standard_boot_devices);
|
|
|
|
}
|
|
|
|
|
2010-12-08 19:35:05 +08:00
|
|
|
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 = strdup(suffix);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-12-08 19:35:09 +08:00
|
|
|
/*
|
|
|
|
* 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) {
|
2010-12-19 22:05:43 +08:00
|
|
|
size_t bootpathlen = strlen(devpath) + strlen(i->suffix) + 1;
|
|
|
|
|
|
|
|
bootpath = qemu_malloc(bootpathlen);
|
|
|
|
snprintf(bootpath, bootpathlen, "%s%s", devpath, i->suffix);
|
2010-12-08 19:35:09 +08:00
|
|
|
qemu_free(devpath);
|
|
|
|
} else if (devpath) {
|
|
|
|
bootpath = devpath;
|
|
|
|
} else {
|
|
|
|
bootpath = 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;
|
|
|
|
}
|
|
|
|
|
2009-04-22 06:30:27 +08:00
|
|
|
static void numa_add(const char *optarg)
|
|
|
|
{
|
|
|
|
char option[128];
|
|
|
|
char *endptr;
|
|
|
|
unsigned long long value, endvalue;
|
|
|
|
int nodenr;
|
|
|
|
|
|
|
|
optarg = get_opt_name(option, 128, optarg, ',') + 1;
|
|
|
|
if (!strcmp(option, "node")) {
|
|
|
|
if (get_param_value(option, 128, "nodeid", optarg) == 0) {
|
|
|
|
nodenr = nb_numa_nodes;
|
|
|
|
} else {
|
|
|
|
nodenr = strtoull(option, NULL, 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (get_param_value(option, 128, "mem", optarg) == 0) {
|
|
|
|
node_mem[nodenr] = 0;
|
|
|
|
} else {
|
2011-01-05 18:41:02 +08:00
|
|
|
int64_t sval;
|
2010-10-21 23:15:46 +08:00
|
|
|
sval = strtosz(option, NULL);
|
|
|
|
if (sval < 0) {
|
|
|
|
fprintf(stderr, "qemu: invalid numa mem size: %s\n", optarg);
|
|
|
|
exit(1);
|
2009-04-22 06:30:27 +08:00
|
|
|
}
|
2010-10-21 23:15:46 +08:00
|
|
|
node_mem[nodenr] = sval;
|
2009-04-22 06:30:27 +08:00
|
|
|
}
|
|
|
|
if (get_param_value(option, 128, "cpus", optarg) == 0) {
|
|
|
|
node_cpumask[nodenr] = 0;
|
|
|
|
} else {
|
|
|
|
value = strtoull(option, &endptr, 10);
|
|
|
|
if (value >= 64) {
|
|
|
|
value = 63;
|
|
|
|
fprintf(stderr, "only 64 CPUs in NUMA mode supported.\n");
|
|
|
|
} else {
|
|
|
|
if (*endptr == '-') {
|
|
|
|
endvalue = strtoull(endptr+1, &endptr, 10);
|
|
|
|
if (endvalue >= 63) {
|
|
|
|
endvalue = 62;
|
|
|
|
fprintf(stderr,
|
|
|
|
"only 63 CPUs in NUMA mode supported.\n");
|
|
|
|
}
|
2010-02-04 21:31:50 +08:00
|
|
|
value = (2ULL << endvalue) - (1ULL << value);
|
2009-04-22 06:30:27 +08:00
|
|
|
} else {
|
2010-02-04 21:31:50 +08:00
|
|
|
value = 1ULL << value;
|
2009-04-22 06:30:27 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
node_cpumask[nodenr] = value;
|
|
|
|
}
|
|
|
|
nb_numa_nodes++;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
extend -smp parsing to include cores= and threads= options
For injecting multi-core and multi-threading CPU topology into guests
extend the -smp syntax to accommodate cores and threads specification.
Syntax: -smp smp_value[,cores=nr_cores][,threads=nr_threads]\
[,socket=nr_sockets][,maxcpus=max_cpus]
smp_value is the legacy value specifying the total number of vCPUs for
the guest. If you specify one of cores, threads or sockets this value
can be omitted. Missing values will be computed to fulfill:
smp_value = nr_cores * nr_threads * nr_sockets
where it will favour sockets over cores over threads (to mimic the
current behavior, which will only inject multiple sockets.)
So -smp 4,threads=2 will inject two sockets with 2 threads each,
-smp cores=4 is an abbreviation for -smp 4,cores=4,threads=1,sockets=1.
If max_cpus (the number of hotpluggable CPUs) is omitted, it will
be set to smp_value.
Signed-off-by: Andre Przywara <andre.przywara@amd.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-19 21:42:40 +08:00
|
|
|
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 {
|
|
|
|
if (cores == 0) {
|
|
|
|
threads = threads > 0 ? threads : 1;
|
|
|
|
cores = smp / (sockets * threads);
|
|
|
|
} else {
|
2010-07-22 04:05:17 +08:00
|
|
|
threads = smp / (cores * sockets);
|
extend -smp parsing to include cores= and threads= options
For injecting multi-core and multi-threading CPU topology into guests
extend the -smp syntax to accommodate cores and threads specification.
Syntax: -smp smp_value[,cores=nr_cores][,threads=nr_threads]\
[,socket=nr_sockets][,maxcpus=max_cpus]
smp_value is the legacy value specifying the total number of vCPUs for
the guest. If you specify one of cores, threads or sockets this value
can be omitted. Missing values will be computed to fulfill:
smp_value = nr_cores * nr_threads * nr_sockets
where it will favour sockets over cores over threads (to mimic the
current behavior, which will only inject multiple sockets.)
So -smp 4,threads=2 will inject two sockets with 2 threads each,
-smp cores=4 is an abbreviation for -smp 4,cores=4,threads=1,sockets=1.
If max_cpus (the number of hotpluggable CPUs) is omitted, it will
be set to smp_value.
Signed-off-by: Andre Przywara <andre.przywara@amd.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-19 21:42:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
smp_cpus = smp;
|
|
|
|
smp_cores = cores > 0 ? cores : 1;
|
|
|
|
smp_threads = threads > 0 ? threads : 1;
|
|
|
|
if (max_cpus == 0)
|
|
|
|
max_cpus = smp_cpus;
|
|
|
|
}
|
|
|
|
|
2005-11-07 00:13:29 +08:00
|
|
|
/***********************************************************/
|
|
|
|
/* USB devices */
|
|
|
|
|
2010-05-28 21:38:44 +08:00
|
|
|
static int usb_device_add(const char *devname)
|
2005-11-07 00:13:29 +08:00
|
|
|
{
|
|
|
|
const char *p;
|
2009-08-31 20:24:00 +08:00
|
|
|
USBDevice *dev = NULL;
|
2005-11-07 00:13:29 +08:00
|
|
|
|
2009-08-31 20:24:00 +08:00
|
|
|
if (!usb_enabled)
|
2005-11-07 00:13:29 +08:00
|
|
|
return -1;
|
|
|
|
|
2009-10-26 22:56:45 +08:00
|
|
|
/* drivers with .usbdevice_name entry in USBDeviceInfo */
|
|
|
|
dev = usbdevice_create(devname);
|
|
|
|
if (dev)
|
|
|
|
goto done;
|
|
|
|
|
2009-08-31 20:24:00 +08:00
|
|
|
/* the other ones */
|
2005-11-07 00:13:29 +08:00
|
|
|
if (strstart(devname, "host:", &p)) {
|
|
|
|
dev = usb_host_device_open(p);
|
2008-11-09 08:04:26 +08:00
|
|
|
} else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
|
|
|
|
dev = usb_bt_init(devname[2] ? hci_init(p) :
|
|
|
|
bt_new_hci(qemu_find_bt_vlan(0)));
|
2005-11-07 00:13:29 +08:00
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
2006-05-22 00:30:15 +08:00
|
|
|
if (!dev)
|
|
|
|
return -1;
|
|
|
|
|
2009-08-31 20:24:00 +08:00
|
|
|
done:
|
2005-11-07 00:13:29 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-08-22 03:27:48 +08:00
|
|
|
static int usb_device_del(const char *devname)
|
|
|
|
{
|
|
|
|
int bus_num, addr;
|
|
|
|
const char *p;
|
|
|
|
|
2008-09-14 09:07:41 +08:00
|
|
|
if (strstart(devname, "host:", &p))
|
|
|
|
return usb_host_device_close(p);
|
|
|
|
|
2009-08-31 20:24:00 +08:00
|
|
|
if (!usb_enabled)
|
2008-08-22 03:27:48 +08:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
p = strchr(devname, '.');
|
|
|
|
if (!p)
|
|
|
|
return -1;
|
|
|
|
bus_num = strtoul(devname, NULL, 0);
|
|
|
|
addr = strtoul(p + 1, NULL, 0);
|
|
|
|
|
2009-08-31 20:24:00 +08:00
|
|
|
return usb_device_delete_addr(bus_num, addr);
|
2008-08-22 03:27:48 +08:00
|
|
|
}
|
|
|
|
|
2009-07-15 19:59:26 +08:00
|
|
|
static int usb_parse(const char *cmdline)
|
|
|
|
{
|
2009-12-23 04:30:18 +08:00
|
|
|
int r;
|
2010-05-28 21:38:44 +08:00
|
|
|
r = usb_device_add(cmdline);
|
2009-12-23 04:30:18 +08:00
|
|
|
if (r < 0) {
|
|
|
|
fprintf(stderr, "qemu: could not add USB device '%s'\n", cmdline);
|
|
|
|
}
|
|
|
|
return r;
|
2009-07-15 19:59:26 +08:00
|
|
|
}
|
|
|
|
|
2009-08-29 02:27:13 +08:00
|
|
|
void do_usb_add(Monitor *mon, const QDict *qdict)
|
2005-11-07 00:13:29 +08:00
|
|
|
{
|
2009-12-23 04:30:18 +08:00
|
|
|
const char *devname = qdict_get_str(qdict, "devname");
|
2010-05-28 21:38:44 +08:00
|
|
|
if (usb_device_add(devname) < 0) {
|
2010-02-19 00:25:24 +08:00
|
|
|
error_report("could not add USB device '%s'", devname);
|
2009-12-23 04:30:18 +08:00
|
|
|
}
|
2005-11-07 00:13:29 +08:00
|
|
|
}
|
|
|
|
|
2009-08-29 02:27:13 +08:00
|
|
|
void do_usb_del(Monitor *mon, const QDict *qdict)
|
2005-11-07 00:13:29 +08:00
|
|
|
{
|
2009-12-23 04:30:18 +08:00
|
|
|
const char *devname = qdict_get_str(qdict, "devname");
|
|
|
|
if (usb_device_del(devname) < 0) {
|
2010-02-19 00:25:24 +08:00
|
|
|
error_report("could not delete USB device '%s'", devname);
|
2009-12-23 04:30:18 +08:00
|
|
|
}
|
2005-11-07 00:13:29 +08:00
|
|
|
}
|
|
|
|
|
2007-04-30 08:51:09 +08:00
|
|
|
/***********************************************************/
|
|
|
|
/* PCMCIA/Cardbus */
|
|
|
|
|
|
|
|
static struct pcmcia_socket_entry_s {
|
2009-05-10 08:44:56 +08:00
|
|
|
PCMCIASocket *socket;
|
2007-04-30 08:51:09 +08:00
|
|
|
struct pcmcia_socket_entry_s *next;
|
|
|
|
} *pcmcia_sockets = 0;
|
|
|
|
|
2009-05-10 08:44:56 +08:00
|
|
|
void pcmcia_socket_register(PCMCIASocket *socket)
|
2007-04-30 08:51:09 +08:00
|
|
|
{
|
|
|
|
struct pcmcia_socket_entry_s *entry;
|
|
|
|
|
|
|
|
entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s));
|
|
|
|
entry->socket = socket;
|
|
|
|
entry->next = pcmcia_sockets;
|
|
|
|
pcmcia_sockets = entry;
|
|
|
|
}
|
|
|
|
|
2009-05-10 08:44:56 +08:00
|
|
|
void pcmcia_socket_unregister(PCMCIASocket *socket)
|
2007-04-30 08:51:09 +08:00
|
|
|
{
|
|
|
|
struct pcmcia_socket_entry_s *entry, **ptr;
|
|
|
|
|
|
|
|
ptr = &pcmcia_sockets;
|
|
|
|
for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr)
|
|
|
|
if (entry->socket == socket) {
|
|
|
|
*ptr = entry->next;
|
|
|
|
qemu_free(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-06 07:01:23 +08:00
|
|
|
void pcmcia_info(Monitor *mon)
|
2007-04-30 08:51:09 +08:00
|
|
|
{
|
|
|
|
struct pcmcia_socket_entry_s *iter;
|
2009-03-06 07:01:23 +08:00
|
|
|
|
2007-04-30 08:51:09 +08:00
|
|
|
if (!pcmcia_sockets)
|
2009-03-06 07:01:23 +08:00
|
|
|
monitor_printf(mon, "No PCMCIA sockets\n");
|
2007-04-30 08:51:09 +08:00
|
|
|
|
|
|
|
for (iter = pcmcia_sockets; iter; iter = iter->next)
|
2009-03-06 07:01:23 +08:00
|
|
|
monitor_printf(mon, "%s: %s\n", iter->socket->slot_string,
|
|
|
|
iter->socket->attached ? iter->socket->card_string :
|
|
|
|
"Empty");
|
2007-04-30 08:51:09 +08:00
|
|
|
}
|
|
|
|
|
2007-06-22 07:34:19 +08:00
|
|
|
/***********************************************************/
|
2004-04-01 03:00:16 +08:00
|
|
|
/* I/O handling */
|
2003-06-24 21:42:40 +08:00
|
|
|
|
2004-03-15 05:44:30 +08:00
|
|
|
typedef struct IOHandlerRecord {
|
|
|
|
int fd;
|
2010-03-12 00:55:39 +08:00
|
|
|
IOCanReadHandler *fd_read_poll;
|
2005-11-16 06:16:05 +08:00
|
|
|
IOHandler *fd_read;
|
|
|
|
IOHandler *fd_write;
|
2007-03-01 05:59:44 +08:00
|
|
|
int deleted;
|
2004-03-15 05:44:30 +08:00
|
|
|
void *opaque;
|
|
|
|
/* temporary data */
|
|
|
|
struct pollfd *ufd;
|
2010-03-12 00:55:37 +08:00
|
|
|
QLIST_ENTRY(IOHandlerRecord) next;
|
2004-03-15 05:44:30 +08:00
|
|
|
} IOHandlerRecord;
|
|
|
|
|
2010-03-12 00:55:37 +08:00
|
|
|
static QLIST_HEAD(, IOHandlerRecord) io_handlers =
|
|
|
|
QLIST_HEAD_INITIALIZER(io_handlers);
|
|
|
|
|
2004-03-15 05:44:30 +08:00
|
|
|
|
2005-11-16 06:16:05 +08:00
|
|
|
/* XXX: fd_read_poll should be suppressed, but an API change is
|
|
|
|
necessary in the character devices to suppress fd_can_read(). */
|
2007-09-17 05:08:06 +08:00
|
|
|
int qemu_set_fd_handler2(int fd,
|
2010-03-12 00:55:39 +08:00
|
|
|
IOCanReadHandler *fd_read_poll,
|
2007-09-17 05:08:06 +08:00
|
|
|
IOHandler *fd_read,
|
|
|
|
IOHandler *fd_write,
|
2005-11-16 06:16:05 +08:00
|
|
|
void *opaque)
|
2004-03-15 05:44:30 +08:00
|
|
|
{
|
2010-03-12 00:55:37 +08:00
|
|
|
IOHandlerRecord *ioh;
|
2004-03-15 05:44:30 +08:00
|
|
|
|
2005-11-16 06:16:05 +08:00
|
|
|
if (!fd_read && !fd_write) {
|
2010-03-12 00:55:37 +08:00
|
|
|
QLIST_FOREACH(ioh, &io_handlers, next) {
|
2005-11-16 06:16:05 +08:00
|
|
|
if (ioh->fd == fd) {
|
2007-03-01 05:59:44 +08:00
|
|
|
ioh->deleted = 1;
|
2005-11-16 06:16:05 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2010-03-12 00:55:37 +08:00
|
|
|
QLIST_FOREACH(ioh, &io_handlers, next) {
|
2005-11-16 06:16:05 +08:00
|
|
|
if (ioh->fd == fd)
|
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
ioh = qemu_mallocz(sizeof(IOHandlerRecord));
|
2010-03-12 00:55:37 +08:00
|
|
|
QLIST_INSERT_HEAD(&io_handlers, ioh, next);
|
2005-11-16 06:16:05 +08:00
|
|
|
found:
|
|
|
|
ioh->fd = fd;
|
|
|
|
ioh->fd_read_poll = fd_read_poll;
|
|
|
|
ioh->fd_read = fd_read;
|
|
|
|
ioh->fd_write = fd_write;
|
|
|
|
ioh->opaque = opaque;
|
2007-03-01 05:59:44 +08:00
|
|
|
ioh->deleted = 0;
|
2005-11-16 06:16:05 +08:00
|
|
|
}
|
2004-03-15 05:44:30 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-09-17 05:08:06 +08:00
|
|
|
int qemu_set_fd_handler(int fd,
|
|
|
|
IOHandler *fd_read,
|
|
|
|
IOHandler *fd_write,
|
2005-11-16 06:16:05 +08:00
|
|
|
void *opaque)
|
2004-04-01 03:00:16 +08:00
|
|
|
{
|
2005-11-16 06:16:05 +08:00
|
|
|
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
|
2004-04-01 03:00:16 +08:00
|
|
|
}
|
|
|
|
|
2005-06-05 22:49:17 +08:00
|
|
|
/***********************************************************/
|
|
|
|
/* machine registration */
|
|
|
|
|
2008-10-04 15:24:27 +08:00
|
|
|
static QEMUMachine *first_machine = NULL;
|
2009-02-11 23:21:54 +08:00
|
|
|
QEMUMachine *current_machine = NULL;
|
2005-06-05 22:49:17 +08:00
|
|
|
|
|
|
|
int qemu_register_machine(QEMUMachine *m)
|
|
|
|
{
|
|
|
|
QEMUMachine **pm;
|
|
|
|
pm = &first_machine;
|
|
|
|
while (*pm != NULL)
|
|
|
|
pm = &(*pm)->next;
|
|
|
|
m->next = NULL;
|
|
|
|
*pm = m;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-11-18 09:44:38 +08:00
|
|
|
static QEMUMachine *find_machine(const char *name)
|
2005-06-05 22:49:17 +08:00
|
|
|
{
|
|
|
|
QEMUMachine *m;
|
|
|
|
|
|
|
|
for(m = first_machine; m != NULL; m = m->next) {
|
|
|
|
if (!strcmp(m->name, name))
|
|
|
|
return m;
|
2009-07-22 17:02:50 +08:00
|
|
|
if (m->alias && !strcmp(m->alias, name))
|
|
|
|
return m;
|
2005-06-05 22:49:17 +08:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-05-22 09:41:01 +08:00
|
|
|
static QEMUMachine *find_default_machine(void)
|
|
|
|
{
|
|
|
|
QEMUMachine *m;
|
|
|
|
|
|
|
|
for(m = first_machine; m != NULL; m = m->next) {
|
|
|
|
if (m->is_default) {
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2004-04-01 03:00:16 +08:00
|
|
|
/***********************************************************/
|
|
|
|
/* main execution loop */
|
|
|
|
|
2007-11-18 09:44:38 +08:00
|
|
|
static void gui_update(void *opaque)
|
2004-04-01 03:00:16 +08:00
|
|
|
{
|
2009-01-16 06:14:11 +08:00
|
|
|
uint64_t interval = GUI_REFRESH_INTERVAL;
|
2007-06-08 09:57:56 +08:00
|
|
|
DisplayState *ds = opaque;
|
2009-01-16 06:14:11 +08:00
|
|
|
DisplayChangeListener *dcl = ds->listeners;
|
|
|
|
|
2010-01-26 19:21:16 +08:00
|
|
|
qemu_flush_coalesced_mmio_buffer();
|
2009-01-16 06:14:11 +08:00
|
|
|
dpy_refresh(ds);
|
|
|
|
|
|
|
|
while (dcl != NULL) {
|
|
|
|
if (dcl->gui_timer_interval &&
|
|
|
|
dcl->gui_timer_interval < interval)
|
|
|
|
interval = dcl->gui_timer_interval;
|
|
|
|
dcl = dcl->next;
|
|
|
|
}
|
|
|
|
qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock(rt_clock));
|
2004-04-01 03:00:16 +08:00
|
|
|
}
|
|
|
|
|
2009-01-22 03:28:13 +08:00
|
|
|
static void nographic_update(void *opaque)
|
|
|
|
{
|
|
|
|
uint64_t interval = GUI_REFRESH_INTERVAL;
|
|
|
|
|
2010-01-26 19:21:16 +08:00
|
|
|
qemu_flush_coalesced_mmio_buffer();
|
2009-01-22 03:28:13 +08:00
|
|
|
qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock));
|
|
|
|
}
|
|
|
|
|
2005-11-11 08:00:47 +08:00
|
|
|
struct vm_change_state_entry {
|
|
|
|
VMChangeStateHandler *cb;
|
|
|
|
void *opaque;
|
2009-09-12 15:36:22 +08:00
|
|
|
QLIST_ENTRY (vm_change_state_entry) entries;
|
2005-11-11 08:00:47 +08:00
|
|
|
};
|
|
|
|
|
2009-09-12 15:36:22 +08:00
|
|
|
static QLIST_HEAD(vm_change_state_head, vm_change_state_entry) vm_change_state_head;
|
2005-11-11 08:00:47 +08:00
|
|
|
|
|
|
|
VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
VMChangeStateEntry *e;
|
|
|
|
|
|
|
|
e = qemu_mallocz(sizeof (*e));
|
|
|
|
|
|
|
|
e->cb = cb;
|
|
|
|
e->opaque = opaque;
|
2009-09-12 15:36:22 +08:00
|
|
|
QLIST_INSERT_HEAD(&vm_change_state_head, e, entries);
|
2005-11-11 08:00:47 +08:00
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_del_vm_change_state_handler(VMChangeStateEntry *e)
|
|
|
|
{
|
2009-09-12 15:36:22 +08:00
|
|
|
QLIST_REMOVE (e, entries);
|
2005-11-11 08:00:47 +08:00
|
|
|
qemu_free (e);
|
|
|
|
}
|
|
|
|
|
2010-03-30 03:23:50 +08:00
|
|
|
void vm_state_notify(int running, int reason)
|
2005-11-11 08:00:47 +08:00
|
|
|
{
|
|
|
|
VMChangeStateEntry *e;
|
|
|
|
|
2010-11-16 20:20:25 +08:00
|
|
|
trace_vm_state_notify(running, reason);
|
|
|
|
|
2005-11-11 08:00:47 +08:00
|
|
|
for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
|
2009-01-23 01:15:29 +08:00
|
|
|
e->cb(e->opaque, running, reason);
|
2005-11-11 08:00:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-04-01 03:00:16 +08:00
|
|
|
void vm_start(void)
|
|
|
|
{
|
|
|
|
if (!vm_running) {
|
|
|
|
cpu_enable_ticks();
|
|
|
|
vm_running = 1;
|
2009-01-23 01:15:29 +08:00
|
|
|
vm_state_notify(1, 0);
|
2009-04-25 02:04:07 +08:00
|
|
|
resume_all_vcpus();
|
2010-04-28 07:35:59 +08:00
|
|
|
monitor_protocol_event(QEVENT_RESUME, NULL);
|
2004-04-01 03:00:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-20 20:37:32 +08:00
|
|
|
/* reset/shutdown handler */
|
|
|
|
|
|
|
|
typedef struct QEMUResetEntry {
|
2009-09-12 15:36:22 +08:00
|
|
|
QTAILQ_ENTRY(QEMUResetEntry) entry;
|
2004-06-20 20:37:32 +08:00
|
|
|
QEMUResetHandler *func;
|
|
|
|
void *opaque;
|
|
|
|
} QEMUResetEntry;
|
|
|
|
|
2009-09-12 15:36:22 +08:00
|
|
|
static QTAILQ_HEAD(reset_handlers, QEMUResetEntry) reset_handlers =
|
|
|
|
QTAILQ_HEAD_INITIALIZER(reset_handlers);
|
2004-06-20 20:37:32 +08:00
|
|
|
static int reset_requested;
|
|
|
|
static int shutdown_requested;
|
2005-07-02 22:31:34 +08:00
|
|
|
static int powerdown_requested;
|
2010-03-30 03:23:50 +08:00
|
|
|
int debug_requested;
|
2010-04-13 01:19:06 +08:00
|
|
|
int vmstop_requested;
|
2004-06-20 20:37:32 +08:00
|
|
|
|
2008-03-18 14:53:05 +08:00
|
|
|
int qemu_shutdown_requested(void)
|
|
|
|
{
|
|
|
|
int r = shutdown_requested;
|
|
|
|
shutdown_requested = 0;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemu_reset_requested(void)
|
|
|
|
{
|
|
|
|
int r = reset_requested;
|
|
|
|
reset_requested = 0;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
int qemu_powerdown_requested(void)
|
|
|
|
{
|
|
|
|
int r = powerdown_requested;
|
|
|
|
powerdown_requested = 0;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2009-04-25 02:03:54 +08:00
|
|
|
static int qemu_debug_requested(void)
|
|
|
|
{
|
|
|
|
int r = debug_requested;
|
|
|
|
debug_requested = 0;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2009-04-25 02:04:02 +08:00
|
|
|
static int qemu_vmstop_requested(void)
|
|
|
|
{
|
|
|
|
int r = vmstop_requested;
|
|
|
|
vmstop_requested = 0;
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2009-06-27 15:25:07 +08:00
|
|
|
void qemu_register_reset(QEMUResetHandler *func, void *opaque)
|
2004-06-20 20:37:32 +08:00
|
|
|
{
|
2009-07-02 06:19:02 +08:00
|
|
|
QEMUResetEntry *re = qemu_mallocz(sizeof(QEMUResetEntry));
|
2004-06-20 20:37:32 +08:00
|
|
|
|
|
|
|
re->func = func;
|
|
|
|
re->opaque = opaque;
|
2009-09-12 15:36:22 +08:00
|
|
|
QTAILQ_INSERT_TAIL(&reset_handlers, re, entry);
|
2004-06-20 20:37:32 +08:00
|
|
|
}
|
|
|
|
|
2009-07-02 06:19:02 +08:00
|
|
|
void qemu_unregister_reset(QEMUResetHandler *func, void *opaque)
|
2004-06-20 20:37:32 +08:00
|
|
|
{
|
|
|
|
QEMUResetEntry *re;
|
|
|
|
|
2009-09-12 15:36:22 +08:00
|
|
|
QTAILQ_FOREACH(re, &reset_handlers, entry) {
|
2009-07-02 06:19:02 +08:00
|
|
|
if (re->func == func && re->opaque == opaque) {
|
2009-09-12 15:36:22 +08:00
|
|
|
QTAILQ_REMOVE(&reset_handlers, re, entry);
|
2009-07-02 06:19:02 +08:00
|
|
|
qemu_free(re);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_system_reset(void)
|
|
|
|
{
|
|
|
|
QEMUResetEntry *re, *nre;
|
|
|
|
|
|
|
|
/* reset all devices */
|
2009-09-12 15:36:22 +08:00
|
|
|
QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) {
|
2004-06-20 20:37:32 +08:00
|
|
|
re->func(re->opaque);
|
|
|
|
}
|
2010-03-10 23:06:34 +08:00
|
|
|
monitor_protocol_event(QEVENT_RESET, NULL);
|
2010-03-02 02:10:30 +08:00
|
|
|
cpu_synchronize_all_post_reset();
|
2004-06-20 20:37:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_system_reset_request(void)
|
|
|
|
{
|
2006-10-03 03:44:22 +08:00
|
|
|
if (no_reboot) {
|
|
|
|
shutdown_requested = 1;
|
|
|
|
} else {
|
|
|
|
reset_requested = 1;
|
|
|
|
}
|
2009-04-25 02:03:11 +08:00
|
|
|
qemu_notify_event();
|
2004-06-20 20:37:32 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_system_shutdown_request(void)
|
|
|
|
{
|
|
|
|
shutdown_requested = 1;
|
2009-04-25 02:03:11 +08:00
|
|
|
qemu_notify_event();
|
2004-06-20 20:37:32 +08:00
|
|
|
}
|
|
|
|
|
2005-07-02 22:31:34 +08:00
|
|
|
void qemu_system_powerdown_request(void)
|
|
|
|
{
|
|
|
|
powerdown_requested = 1;
|
2009-04-25 02:03:11 +08:00
|
|
|
qemu_notify_event();
|
|
|
|
}
|
|
|
|
|
2010-03-10 18:38:54 +08:00
|
|
|
void main_loop_wait(int nonblocking)
|
2008-11-01 02:07:17 +08:00
|
|
|
{
|
|
|
|
IOHandlerRecord *ioh;
|
|
|
|
fd_set rfds, wfds, xfds;
|
|
|
|
int ret, nfds;
|
|
|
|
struct timeval tv;
|
2010-03-10 18:38:54 +08:00
|
|
|
int timeout;
|
2008-11-01 02:07:17 +08:00
|
|
|
|
2010-03-10 18:38:54 +08:00
|
|
|
if (nonblocking)
|
|
|
|
timeout = 0;
|
|
|
|
else {
|
|
|
|
timeout = qemu_calculate_timeout();
|
|
|
|
qemu_bh_update_timeout(&timeout);
|
|
|
|
}
|
2008-11-01 02:07:17 +08:00
|
|
|
|
2010-06-10 17:42:18 +08:00
|
|
|
os_host_main_loop_wait(&timeout);
|
2008-11-01 02:07:17 +08:00
|
|
|
|
2006-02-02 05:29:26 +08:00
|
|
|
/* poll any events */
|
|
|
|
/* XXX: separate device handlers from system ones */
|
2008-11-06 04:49:37 +08:00
|
|
|
nfds = -1;
|
2006-02-02 05:29:26 +08:00
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_ZERO(&wfds);
|
2006-05-01 21:33:02 +08:00
|
|
|
FD_ZERO(&xfds);
|
2010-03-12 00:55:37 +08:00
|
|
|
QLIST_FOREACH(ioh, &io_handlers, next) {
|
2007-03-01 05:59:44 +08:00
|
|
|
if (ioh->deleted)
|
|
|
|
continue;
|
2006-02-02 05:29:26 +08:00
|
|
|
if (ioh->fd_read &&
|
|
|
|
(!ioh->fd_read_poll ||
|
|
|
|
ioh->fd_read_poll(ioh->opaque) != 0)) {
|
|
|
|
FD_SET(ioh->fd, &rfds);
|
|
|
|
if (ioh->fd > nfds)
|
|
|
|
nfds = ioh->fd;
|
|
|
|
}
|
|
|
|
if (ioh->fd_write) {
|
|
|
|
FD_SET(ioh->fd, &wfds);
|
|
|
|
if (ioh->fd > nfds)
|
|
|
|
nfds = ioh->fd;
|
|
|
|
}
|
|
|
|
}
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2008-11-01 02:07:17 +08:00
|
|
|
tv.tv_sec = timeout / 1000;
|
|
|
|
tv.tv_usec = (timeout % 1000) * 1000;
|
|
|
|
|
2009-06-24 20:42:30 +08:00
|
|
|
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
|
|
|
|
|
2009-04-25 02:03:49 +08:00
|
|
|
qemu_mutex_unlock_iothread();
|
2006-05-01 21:33:02 +08:00
|
|
|
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
|
2009-04-25 02:03:49 +08:00
|
|
|
qemu_mutex_lock_iothread();
|
2006-02-02 05:29:26 +08:00
|
|
|
if (ret > 0) {
|
2010-03-12 00:55:37 +08:00
|
|
|
IOHandlerRecord *pioh;
|
2007-03-01 05:59:44 +08:00
|
|
|
|
2010-03-12 00:55:37 +08:00
|
|
|
QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) {
|
2010-11-03 22:29:44 +08:00
|
|
|
if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
|
2010-03-12 00:55:41 +08:00
|
|
|
ioh->fd_read(ioh->opaque);
|
|
|
|
}
|
2010-11-03 22:29:44 +08:00
|
|
|
if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
|
2010-03-12 00:55:41 +08:00
|
|
|
ioh->fd_write(ioh->opaque);
|
2010-03-12 00:55:37 +08:00
|
|
|
}
|
2010-11-03 22:29:44 +08:00
|
|
|
|
|
|
|
/* Do this last in case read/write handlers marked it for deletion */
|
|
|
|
if (ioh->deleted) {
|
|
|
|
QLIST_REMOVE(ioh, next);
|
|
|
|
qemu_free(ioh);
|
|
|
|
}
|
2007-03-01 05:59:44 +08:00
|
|
|
}
|
2006-02-02 05:29:26 +08:00
|
|
|
}
|
2009-06-24 20:42:30 +08:00
|
|
|
|
|
|
|
slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0));
|
2003-06-28 01:34:32 +08:00
|
|
|
|
2010-03-10 18:38:45 +08:00
|
|
|
qemu_run_all_timers();
|
2009-09-15 19:36:04 +08:00
|
|
|
|
2007-05-23 08:06:54 +08:00
|
|
|
/* Check bottom-halves last in case any of the earlier events triggered
|
|
|
|
them. */
|
|
|
|
qemu_bh_poll();
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2004-08-02 05:53:26 +08:00
|
|
|
}
|
|
|
|
|
2009-04-25 02:03:33 +08:00
|
|
|
static int vm_can_run(void)
|
|
|
|
{
|
|
|
|
if (powerdown_requested)
|
|
|
|
return 0;
|
|
|
|
if (reset_requested)
|
|
|
|
return 0;
|
|
|
|
if (shutdown_requested)
|
|
|
|
return 0;
|
2009-04-25 02:03:54 +08:00
|
|
|
if (debug_requested)
|
|
|
|
return 0;
|
2009-04-25 02:03:33 +08:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2009-08-09 16:42:19 +08:00
|
|
|
qemu_irq qemu_system_powerdown;
|
|
|
|
|
2009-04-25 02:03:33 +08:00
|
|
|
static void main_loop(void)
|
|
|
|
{
|
2009-04-25 02:04:02 +08:00
|
|
|
int r;
|
2009-04-25 02:03:57 +08:00
|
|
|
|
2010-04-13 01:19:06 +08:00
|
|
|
qemu_main_loop_start();
|
2009-04-25 02:04:07 +08:00
|
|
|
|
2009-04-25 02:04:02 +08:00
|
|
|
for (;;) {
|
2009-04-25 02:03:33 +08:00
|
|
|
do {
|
2010-03-10 18:38:54 +08:00
|
|
|
bool nonblocking = false;
|
2009-04-25 02:03:57 +08:00
|
|
|
#ifdef CONFIG_PROFILER
|
|
|
|
int64_t ti;
|
|
|
|
#endif
|
2009-04-25 02:04:07 +08:00
|
|
|
#ifndef CONFIG_IOTHREAD
|
2010-06-25 22:56:55 +08:00
|
|
|
nonblocking = cpu_exec_all();
|
2009-04-25 02:04:07 +08:00
|
|
|
#endif
|
2006-02-09 06:46:31 +08:00
|
|
|
#ifdef CONFIG_PROFILER
|
2009-04-25 02:03:33 +08:00
|
|
|
ti = profile_getclock();
|
2006-02-09 06:46:31 +08:00
|
|
|
#endif
|
2010-03-10 18:38:54 +08:00
|
|
|
main_loop_wait(nonblocking);
|
2006-02-09 06:46:31 +08:00
|
|
|
#ifdef CONFIG_PROFILER
|
2009-04-25 02:03:33 +08:00
|
|
|
dev_time += profile_getclock() - ti;
|
2006-02-09 06:46:31 +08:00
|
|
|
#endif
|
2009-04-25 02:03:54 +08:00
|
|
|
} while (vm_can_run());
|
2009-04-25 02:03:33 +08:00
|
|
|
|
2010-03-30 03:23:46 +08:00
|
|
|
if ((r = qemu_debug_requested())) {
|
|
|
|
vm_stop(r);
|
2009-11-27 08:59:04 +08:00
|
|
|
}
|
2009-04-25 02:03:33 +08:00
|
|
|
if (qemu_shutdown_requested()) {
|
2009-12-05 02:05:45 +08:00
|
|
|
monitor_protocol_event(QEVENT_SHUTDOWN, NULL);
|
2009-04-25 02:03:33 +08:00
|
|
|
if (no_shutdown) {
|
|
|
|
vm_stop(0);
|
|
|
|
no_shutdown = 0;
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
}
|
2009-04-25 02:04:07 +08:00
|
|
|
if (qemu_reset_requested()) {
|
|
|
|
pause_all_vcpus();
|
2009-04-25 02:03:33 +08:00
|
|
|
qemu_system_reset();
|
2009-04-25 02:04:07 +08:00
|
|
|
resume_all_vcpus();
|
|
|
|
}
|
2009-08-09 16:42:19 +08:00
|
|
|
if (qemu_powerdown_requested()) {
|
2009-12-05 02:05:45 +08:00
|
|
|
monitor_protocol_event(QEVENT_POWERDOWN, NULL);
|
2009-08-09 16:42:19 +08:00
|
|
|
qemu_irq_raise(qemu_system_powerdown);
|
|
|
|
}
|
2009-11-27 08:59:04 +08:00
|
|
|
if ((r = qemu_vmstop_requested())) {
|
2009-04-25 02:04:02 +08:00
|
|
|
vm_stop(r);
|
2009-11-27 08:59:04 +08:00
|
|
|
}
|
2003-06-28 01:34:32 +08:00
|
|
|
}
|
2010-05-28 10:44:57 +08:00
|
|
|
bdrv_close_all();
|
2009-04-25 02:04:07 +08:00
|
|
|
pause_all_vcpus();
|
2003-06-28 01:34:32 +08:00
|
|
|
}
|
|
|
|
|
2009-04-08 06:58:45 +08:00
|
|
|
static void version(void)
|
|
|
|
{
|
2010-04-28 20:42:01 +08:00
|
|
|
printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n");
|
2009-04-08 06:58:45 +08:00
|
|
|
}
|
|
|
|
|
2007-06-30 07:26:08 +08:00
|
|
|
static void help(int exitcode)
|
2003-06-24 21:42:40 +08:00
|
|
|
{
|
2010-02-04 23:49:59 +08:00
|
|
|
const char *options_help =
|
2010-03-30 03:23:52 +08:00
|
|
|
#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
|
|
|
|
opt_help
|
2009-03-28 14:44:27 +08:00
|
|
|
#define DEFHEADING(text) stringify(text) "\n"
|
2010-06-10 17:42:24 +08:00
|
|
|
#include "qemu-options.def"
|
2009-03-28 14:44:27 +08:00
|
|
|
#undef DEF
|
|
|
|
#undef DEFHEADING
|
|
|
|
#undef GEN_DOCS
|
2010-02-04 23:49:59 +08:00
|
|
|
;
|
|
|
|
version();
|
|
|
|
printf("usage: %s [options] [disk_image]\n"
|
|
|
|
"\n"
|
2010-04-28 20:42:01 +08:00
|
|
|
"'disk_image' is a raw hard disk image for IDE hard disk 0\n"
|
2010-02-08 17:04:56 +08:00
|
|
|
"\n"
|
2010-02-04 23:49:59 +08:00
|
|
|
"%s\n"
|
2010-02-08 17:04:56 +08:00
|
|
|
"During emulation, the following keys are useful:\n"
|
|
|
|
"ctrl-alt-f toggle full screen\n"
|
|
|
|
"ctrl-alt-n switch to virtual console 'n'\n"
|
|
|
|
"ctrl-alt toggle mouse and keyboard grab\n"
|
|
|
|
"\n"
|
2010-02-04 23:49:59 +08:00
|
|
|
"When using -nographic, press 'ctrl-a h' to get some help.\n",
|
|
|
|
"qemu",
|
|
|
|
options_help);
|
2007-06-30 07:26:08 +08:00
|
|
|
exit(exitcode);
|
2003-06-24 21:42:40 +08:00
|
|
|
}
|
|
|
|
|
2004-05-14 06:02:20 +08:00
|
|
|
#define HAS_ARG 0x0001
|
|
|
|
|
|
|
|
typedef struct QEMUOption {
|
|
|
|
const char *name;
|
|
|
|
int flags;
|
|
|
|
int index;
|
2010-03-30 03:23:52 +08:00
|
|
|
uint32_t arch_mask;
|
2004-05-14 06:02:20 +08:00
|
|
|
} QEMUOption;
|
|
|
|
|
2008-10-02 03:38:09 +08:00
|
|
|
static const QEMUOption qemu_options[] = {
|
2010-03-30 03:23:52 +08:00
|
|
|
{ "h", 0, QEMU_OPTION_h, QEMU_ARCH_ALL },
|
|
|
|
#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \
|
|
|
|
{ option, opt_arg, opt_enum, arch_mask },
|
2009-03-28 14:44:27 +08:00
|
|
|
#define DEFHEADING(text)
|
2010-06-10 17:42:24 +08:00
|
|
|
#include "qemu-options.def"
|
2009-03-28 14:44:27 +08:00
|
|
|
#undef DEF
|
|
|
|
#undef DEFHEADING
|
|
|
|
#undef GEN_DOCS
|
2004-05-14 06:02:20 +08:00
|
|
|
{ NULL },
|
2003-06-30 18:03:06 +08:00
|
|
|
};
|
2008-09-28 08:42:05 +08:00
|
|
|
static void select_vgahw (const char *p)
|
|
|
|
{
|
|
|
|
const char *opts;
|
|
|
|
|
2009-12-08 20:11:45 +08:00
|
|
|
default_vga = 0;
|
2009-07-30 18:15:02 +08:00
|
|
|
vga_interface_type = VGA_NONE;
|
2008-09-28 08:42:05 +08:00
|
|
|
if (strstart(p, "std", &opts)) {
|
2009-07-30 18:15:02 +08:00
|
|
|
vga_interface_type = VGA_STD;
|
2008-09-28 08:42:05 +08:00
|
|
|
} else if (strstart(p, "cirrus", &opts)) {
|
2009-07-30 18:15:02 +08:00
|
|
|
vga_interface_type = VGA_CIRRUS;
|
2008-09-28 08:42:05 +08:00
|
|
|
} else if (strstart(p, "vmware", &opts)) {
|
2009-07-30 18:15:02 +08:00
|
|
|
vga_interface_type = VGA_VMWARE;
|
2009-04-22 23:19:53 +08:00
|
|
|
} else if (strstart(p, "xenfb", &opts)) {
|
2009-07-30 18:15:02 +08:00
|
|
|
vga_interface_type = VGA_XENFB;
|
2010-04-27 17:50:11 +08:00
|
|
|
} else if (strstart(p, "qxl", &opts)) {
|
|
|
|
vga_interface_type = VGA_QXL;
|
2009-04-22 23:19:48 +08:00
|
|
|
} else if (!strstart(p, "none", &opts)) {
|
2008-09-28 08:42:05 +08:00
|
|
|
invalid_vga:
|
|
|
|
fprintf(stderr, "Unknown vga type: %s\n", p);
|
|
|
|
exit(1);
|
|
|
|
}
|
2008-09-28 08:42:12 +08:00
|
|
|
while (*opts) {
|
|
|
|
const char *nextopt;
|
|
|
|
|
|
|
|
if (strstart(opts, ",retrace=", &nextopt)) {
|
|
|
|
opts = nextopt;
|
|
|
|
if (strstart(opts, "dumb", &nextopt))
|
|
|
|
vga_retrace_method = VGA_RETRACE_DUMB;
|
|
|
|
else if (strstart(opts, "precise", &nextopt))
|
|
|
|
vga_retrace_method = VGA_RETRACE_PRECISE;
|
|
|
|
else goto invalid_vga;
|
|
|
|
} else goto invalid_vga;
|
|
|
|
opts = nextopt;
|
|
|
|
}
|
2008-09-28 08:42:05 +08:00
|
|
|
}
|
|
|
|
|
2009-06-27 01:15:14 +08:00
|
|
|
static int balloon_parse(const char *arg)
|
|
|
|
{
|
2009-08-14 16:34:22 +08:00
|
|
|
QemuOpts *opts;
|
2009-06-27 01:15:14 +08:00
|
|
|
|
2009-08-14 16:34:22 +08:00
|
|
|
if (strcmp(arg, "none") == 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!strncmp(arg, "virtio", 6)) {
|
|
|
|
if (arg[6] == ',') {
|
|
|
|
/* have params -> parse them */
|
2010-08-20 19:52:01 +08:00
|
|
|
opts = qemu_opts_parse(qemu_find_opts("device"), arg+7, 0);
|
2009-08-14 16:34:22 +08:00
|
|
|
if (!opts)
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
/* create empty opts */
|
2010-08-20 19:52:01 +08:00
|
|
|
opts = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
|
2009-06-27 01:15:14 +08:00
|
|
|
}
|
2009-08-14 16:34:22 +08:00
|
|
|
qemu_opt_set(opts, "driver", "virtio-balloon-pci");
|
|
|
|
return 0;
|
2009-06-27 01:15:14 +08:00
|
|
|
}
|
2009-08-14 16:34:22 +08:00
|
|
|
|
|
|
|
return -1;
|
2009-06-27 01:15:14 +08:00
|
|
|
}
|
|
|
|
|
2009-05-30 07:52:44 +08:00
|
|
|
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) {
|
2009-09-03 05:59:06 +08:00
|
|
|
return qemu_strdup(name);
|
2009-05-30 07:52:44 +08:00
|
|
|
}
|
|
|
|
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);
|
2009-06-10 03:12:21 +08:00
|
|
|
snprintf(buf, len, "%s/%s%s", data_dir, subdir, name);
|
2009-05-30 07:52:44 +08:00
|
|
|
if (access(buf, R_OK)) {
|
|
|
|
qemu_free(buf);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2010-01-30 02:48:57 +08:00
|
|
|
static int device_help_func(QemuOpts *opts, void *opaque)
|
|
|
|
{
|
|
|
|
return qdev_device_help(opts);
|
|
|
|
}
|
|
|
|
|
2009-07-31 18:25:37 +08:00
|
|
|
static int device_init_func(QemuOpts *opts, void *opaque)
|
|
|
|
{
|
|
|
|
DeviceState *dev;
|
|
|
|
|
|
|
|
dev = qdev_device_add(opts);
|
|
|
|
if (!dev)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-08 20:11:36 +08:00
|
|
|
static int chardev_init_func(QemuOpts *opts, void *opaque)
|
|
|
|
{
|
|
|
|
CharDriverState *chr;
|
|
|
|
|
|
|
|
chr = qemu_chr_open_opts(opts, NULL);
|
|
|
|
if (!chr)
|
|
|
|
return -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-15 04:34:41 +08:00
|
|
|
#ifdef CONFIG_VIRTFS
|
2010-04-29 20:14:43 +08:00
|
|
|
static int fsdev_init_func(QemuOpts *opts, void *opaque)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
ret = qemu_fsdev_add(opts);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-12-08 20:11:50 +08:00
|
|
|
static int mon_init_func(QemuOpts *opts, void *opaque)
|
|
|
|
{
|
|
|
|
CharDriverState *chr;
|
|
|
|
const char *chardev;
|
|
|
|
const char *mode;
|
|
|
|
int flags;
|
|
|
|
|
|
|
|
mode = qemu_opt_get(opts, "mode");
|
|
|
|
if (mode == NULL) {
|
|
|
|
mode = "readline";
|
|
|
|
}
|
|
|
|
if (strcmp(mode, "readline") == 0) {
|
|
|
|
flags = MONITOR_USE_READLINE;
|
|
|
|
} else if (strcmp(mode, "control") == 0) {
|
|
|
|
flags = MONITOR_USE_CONTROL;
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "unknown monitor mode \"%s\"\n", mode);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2010-06-07 22:42:31 +08:00
|
|
|
if (qemu_opt_get_bool(opts, "pretty", 0))
|
|
|
|
flags |= MONITOR_USE_PRETTY;
|
|
|
|
|
2009-12-08 20:11:50 +08:00
|
|
|
if (qemu_opt_get_bool(opts, "default", 0))
|
|
|
|
flags |= MONITOR_IS_DEFAULT;
|
|
|
|
|
|
|
|
chardev = qemu_opt_get(opts, "chardev");
|
|
|
|
chr = qemu_chr_find(chardev);
|
|
|
|
if (chr == NULL) {
|
|
|
|
fprintf(stderr, "chardev \"%s\" not found\n", chardev);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
monitor_init(chr, flags);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-08 20:11:52 +08:00
|
|
|
static void monitor_parse(const char *optarg, const char *mode)
|
2009-12-08 20:11:50 +08:00
|
|
|
{
|
|
|
|
static int monitor_device_index = 0;
|
|
|
|
QemuOpts *opts;
|
|
|
|
const char *p;
|
|
|
|
char label[32];
|
|
|
|
int def = 0;
|
|
|
|
|
|
|
|
if (strstart(optarg, "chardev:", &p)) {
|
|
|
|
snprintf(label, sizeof(label), "%s", p);
|
|
|
|
} else {
|
2010-04-06 22:55:52 +08:00
|
|
|
snprintf(label, sizeof(label), "compat_monitor%d",
|
|
|
|
monitor_device_index);
|
|
|
|
if (monitor_device_index == 0) {
|
2009-12-08 20:11:50 +08:00
|
|
|
def = 1;
|
|
|
|
}
|
|
|
|
opts = qemu_chr_parse_compat(label, optarg);
|
|
|
|
if (!opts) {
|
|
|
|
fprintf(stderr, "parse error: %s\n", optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-20 19:52:01 +08:00
|
|
|
opts = qemu_opts_create(qemu_find_opts("mon"), label, 1);
|
2009-12-08 20:11:50 +08:00
|
|
|
if (!opts) {
|
|
|
|
fprintf(stderr, "duplicate chardev: %s\n", label);
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-12-08 20:11:52 +08:00
|
|
|
qemu_opt_set(opts, "mode", mode);
|
2009-12-08 20:11:50 +08:00
|
|
|
qemu_opt_set(opts, "chardev", label);
|
|
|
|
if (def)
|
|
|
|
qemu_opt_set(opts, "default", "on");
|
|
|
|
monitor_device_index++;
|
|
|
|
}
|
|
|
|
|
2009-07-15 19:59:26 +08:00
|
|
|
struct device_config {
|
|
|
|
enum {
|
2009-12-08 20:11:53 +08:00
|
|
|
DEV_USB, /* -usbdevice */
|
|
|
|
DEV_BT, /* -bt */
|
|
|
|
DEV_SERIAL, /* -serial */
|
|
|
|
DEV_PARALLEL, /* -parallel */
|
|
|
|
DEV_VIRTCON, /* -virtioconsole */
|
debugcon: support for debugging consoles (e.g. Bochs port 0xe9)
Add generic support for debugging consoles (simple I/O ports which
when written to cause debugging output to be written to a target.)
The current implementation matches Bochs' port 0xe9, allowing the same
debugging code to be used for both Bochs and Qemu.
There is no vm state associated with the debugging port, simply
because it has none -- the entire interface is a single, stateless,
write-only port.
Most of the code was cribbed from the serial port driver.
v2: removed non-ISA variants (they can be introduced when/if someone
wants them, using code from the serial port); added configurable
readback (Bochs returns 0xe9 on a read from this register, mimic that
by default) This retains the apparently somewhat controversial user
friendly option, however.
v3: reimplemented the user friendly option as a synthetic option
("-debugcon foo" basically ends up being a parser-level shorthand for
"-chardev stdio,id=debugcon -device isa-debugcon,chardev=debugcon") --
this dramatically reduced the complexity while keeping the same level
of user friendliness.
v4: spaces, not tabs.
v5: update to match current top of tree. Calling qemu_chr_open()
already during parsing no longer works; defer until we are parsing the
other console-like devices.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-12-30 05:51:36 +08:00
|
|
|
DEV_DEBUGCON, /* -debugcon */
|
2009-07-15 19:59:26 +08:00
|
|
|
} type;
|
|
|
|
const char *cmdline;
|
2009-09-12 15:36:22 +08:00
|
|
|
QTAILQ_ENTRY(device_config) next;
|
2009-07-15 19:59:26 +08:00
|
|
|
};
|
2009-09-12 15:36:22 +08:00
|
|
|
QTAILQ_HEAD(, device_config) device_configs = QTAILQ_HEAD_INITIALIZER(device_configs);
|
2009-07-15 19:59:26 +08:00
|
|
|
|
|
|
|
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;
|
2009-09-12 15:36:22 +08:00
|
|
|
QTAILQ_INSERT_TAIL(&device_configs, conf, next);
|
2009-07-15 19:59:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int foreach_device_config(int type, int (*func)(const char *cmdline))
|
|
|
|
{
|
|
|
|
struct device_config *conf;
|
|
|
|
int rc;
|
|
|
|
|
2009-09-12 15:36:22 +08:00
|
|
|
QTAILQ_FOREACH(conf, &device_configs, next) {
|
2009-07-15 19:59:26 +08:00
|
|
|
if (conf->type != type)
|
|
|
|
continue;
|
|
|
|
rc = func(conf->cmdline);
|
|
|
|
if (0 != rc)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-08 20:11:41 +08:00
|
|
|
static int serial_parse(const char *devname)
|
|
|
|
{
|
|
|
|
static int index = 0;
|
|
|
|
char label[32];
|
|
|
|
|
|
|
|
if (strcmp(devname, "none") == 0)
|
|
|
|
return 0;
|
|
|
|
if (index == MAX_SERIAL_PORTS) {
|
|
|
|
fprintf(stderr, "qemu: too many serial ports\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
snprintf(label, sizeof(label), "serial%d", index);
|
|
|
|
serial_hds[index] = qemu_chr_open(label, devname, NULL);
|
|
|
|
if (!serial_hds[index]) {
|
|
|
|
fprintf(stderr, "qemu: could not open serial device '%s': %s\n",
|
|
|
|
devname, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-08 20:11:42 +08:00
|
|
|
static int parallel_parse(const char *devname)
|
|
|
|
{
|
|
|
|
static int index = 0;
|
|
|
|
char label[32];
|
|
|
|
|
|
|
|
if (strcmp(devname, "none") == 0)
|
|
|
|
return 0;
|
|
|
|
if (index == MAX_PARALLEL_PORTS) {
|
|
|
|
fprintf(stderr, "qemu: too many parallel ports\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
snprintf(label, sizeof(label), "parallel%d", index);
|
|
|
|
parallel_hds[index] = qemu_chr_open(label, devname, NULL);
|
|
|
|
if (!parallel_hds[index]) {
|
|
|
|
fprintf(stderr, "qemu: could not open parallel device '%s': %s\n",
|
|
|
|
devname, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
index++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-12-08 20:11:53 +08:00
|
|
|
static int virtcon_parse(const char *devname)
|
|
|
|
{
|
2010-08-20 19:52:01 +08:00
|
|
|
QemuOptsList *device = qemu_find_opts("device");
|
2009-12-08 20:11:53 +08:00
|
|
|
static int index = 0;
|
|
|
|
char label[32];
|
2010-01-21 18:49:23 +08:00
|
|
|
QemuOpts *bus_opts, *dev_opts;
|
2009-12-08 20:11:53 +08:00
|
|
|
|
|
|
|
if (strcmp(devname, "none") == 0)
|
|
|
|
return 0;
|
|
|
|
if (index == MAX_VIRTIO_CONSOLES) {
|
|
|
|
fprintf(stderr, "qemu: too many virtio consoles\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2010-01-21 18:49:23 +08:00
|
|
|
|
2010-08-20 19:52:01 +08:00
|
|
|
bus_opts = qemu_opts_create(device, NULL, 0);
|
2010-01-21 18:49:23 +08:00
|
|
|
qemu_opt_set(bus_opts, "driver", "virtio-serial");
|
|
|
|
|
2010-08-20 19:52:01 +08:00
|
|
|
dev_opts = qemu_opts_create(device, NULL, 0);
|
2010-01-21 18:49:23 +08:00
|
|
|
qemu_opt_set(dev_opts, "driver", "virtconsole");
|
|
|
|
|
2009-12-08 20:11:53 +08:00
|
|
|
snprintf(label, sizeof(label), "virtcon%d", index);
|
|
|
|
virtcon_hds[index] = qemu_chr_open(label, devname, NULL);
|
|
|
|
if (!virtcon_hds[index]) {
|
|
|
|
fprintf(stderr, "qemu: could not open virtio console '%s': %s\n",
|
|
|
|
devname, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
2010-01-21 18:49:23 +08:00
|
|
|
qemu_opt_set(dev_opts, "chardev", label);
|
|
|
|
|
2009-12-08 20:11:53 +08:00
|
|
|
index++;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
debugcon: support for debugging consoles (e.g. Bochs port 0xe9)
Add generic support for debugging consoles (simple I/O ports which
when written to cause debugging output to be written to a target.)
The current implementation matches Bochs' port 0xe9, allowing the same
debugging code to be used for both Bochs and Qemu.
There is no vm state associated with the debugging port, simply
because it has none -- the entire interface is a single, stateless,
write-only port.
Most of the code was cribbed from the serial port driver.
v2: removed non-ISA variants (they can be introduced when/if someone
wants them, using code from the serial port); added configurable
readback (Bochs returns 0xe9 on a read from this register, mimic that
by default) This retains the apparently somewhat controversial user
friendly option, however.
v3: reimplemented the user friendly option as a synthetic option
("-debugcon foo" basically ends up being a parser-level shorthand for
"-chardev stdio,id=debugcon -device isa-debugcon,chardev=debugcon") --
this dramatically reduced the complexity while keeping the same level
of user friendliness.
v4: spaces, not tabs.
v5: update to match current top of tree. Calling qemu_chr_open()
already during parsing no longer works; defer until we are parsing the
other console-like devices.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-12-30 05:51:36 +08:00
|
|
|
static int debugcon_parse(const char *devname)
|
|
|
|
{
|
|
|
|
QemuOpts *opts;
|
|
|
|
|
|
|
|
if (!qemu_chr_open("debugcon", devname, NULL)) {
|
|
|
|
exit(1);
|
|
|
|
}
|
2010-08-20 19:52:01 +08:00
|
|
|
opts = qemu_opts_create(qemu_find_opts("device"), "debugcon", 1);
|
debugcon: support for debugging consoles (e.g. Bochs port 0xe9)
Add generic support for debugging consoles (simple I/O ports which
when written to cause debugging output to be written to a target.)
The current implementation matches Bochs' port 0xe9, allowing the same
debugging code to be used for both Bochs and Qemu.
There is no vm state associated with the debugging port, simply
because it has none -- the entire interface is a single, stateless,
write-only port.
Most of the code was cribbed from the serial port driver.
v2: removed non-ISA variants (they can be introduced when/if someone
wants them, using code from the serial port); added configurable
readback (Bochs returns 0xe9 on a read from this register, mimic that
by default) This retains the apparently somewhat controversial user
friendly option, however.
v3: reimplemented the user friendly option as a synthetic option
("-debugcon foo" basically ends up being a parser-level shorthand for
"-chardev stdio,id=debugcon -device isa-debugcon,chardev=debugcon") --
this dramatically reduced the complexity while keeping the same level
of user friendliness.
v4: spaces, not tabs.
v5: update to match current top of tree. Calling qemu_chr_open()
already during parsing no longer works; defer until we are parsing the
other console-like devices.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-12-30 05:51:36 +08:00
|
|
|
if (!opts) {
|
|
|
|
fprintf(stderr, "qemu: already have a debugcon device\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
qemu_opt_set(opts, "driver", "isa-debugcon");
|
|
|
|
qemu_opt_set(opts, "chardev", "debugcon");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-06-04 20:08:07 +08:00
|
|
|
void qemu_add_exit_notifier(Notifier *notify)
|
|
|
|
{
|
|
|
|
notifier_list_add(&exit_notifiers, notify);
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_remove_exit_notifier(Notifier *notify)
|
|
|
|
{
|
|
|
|
notifier_list_remove(&exit_notifiers, notify);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qemu_run_exit_notifiers(void)
|
|
|
|
{
|
|
|
|
notifier_list_notify(&exit_notifiers);
|
|
|
|
}
|
|
|
|
|
2010-12-08 19:35:08 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2010-01-22 23:18:06 +08:00
|
|
|
static const QEMUOption *lookup_opt(int argc, char **argv,
|
|
|
|
const char **poptarg, int *poptind)
|
|
|
|
{
|
|
|
|
const QEMUOption *popt;
|
|
|
|
int optind = *poptind;
|
|
|
|
char *r = argv[optind];
|
|
|
|
const char *optarg;
|
|
|
|
|
2010-02-19 03:13:51 +08:00
|
|
|
loc_set_cmdline(argv, optind, 1);
|
2010-01-22 23:18:06 +08:00
|
|
|
optind++;
|
|
|
|
/* Treat --foo the same as -foo. */
|
|
|
|
if (r[1] == '-')
|
|
|
|
r++;
|
|
|
|
popt = qemu_options;
|
|
|
|
for(;;) {
|
|
|
|
if (!popt->name) {
|
2010-02-19 03:13:51 +08:00
|
|
|
error_report("invalid option");
|
2010-01-22 23:18:06 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (!strcmp(popt->name, r + 1))
|
|
|
|
break;
|
|
|
|
popt++;
|
|
|
|
}
|
|
|
|
if (popt->flags & HAS_ARG) {
|
|
|
|
if (optind >= argc) {
|
2010-02-19 03:13:51 +08:00
|
|
|
error_report("requires an argument");
|
2010-01-22 23:18:06 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
optarg = argv[optind++];
|
2010-02-19 03:13:51 +08:00
|
|
|
loc_set_cmdline(argv, optind - 2, 2);
|
2010-01-22 23:18:06 +08:00
|
|
|
} else {
|
|
|
|
optarg = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*poptarg = optarg;
|
|
|
|
*poptind = optind;
|
|
|
|
|
|
|
|
return popt;
|
|
|
|
}
|
|
|
|
|
2008-12-11 03:18:40 +08:00
|
|
|
int main(int argc, char **argv, char **envp)
|
2003-06-24 21:42:40 +08:00
|
|
|
{
|
2009-04-06 02:43:41 +08:00
|
|
|
const char *gdbstub_dev = NULL;
|
2007-12-02 12:51:10 +08:00
|
|
|
int i;
|
net: remove broken net_set_boot_mask() boot device validation
There are many problems with net_set_boot_mask():
1) It is broken when using the device model instead of "-net nic". Example:
$ qemu-system-x86_64 -device rtl8139,vlan=0,id=net0,mac=52:54:00:82:41:fd,bus=pci.0,addr=0x4 -net user,vlan=0,name=hostnet0 -vnc 0.0.0.0:0 -boot n
Cannot boot from non-existent NIC
$
2) The mask was previously used to set which boot ROMs were supposed to be
loaded, but this was changed long time ago. Now all ROM images are loaded,
and SeaBIOS takes care of jumping to the right boot entry point depending on
the boot settings.
3) Interpretation and validation of the boot parameter letters is done on
the machine type code. Examples: PC accepts only a,b,c,d,n as valid boot
device letters. mac99 accepts only a,b,c,d,e,f.
As a side-effect of this change, qemu-kvm won't abort anymore if using "-boot n"
on a machine with no network devices. Checking if the requested boot device is
valid is now a task for the BIOS or the machine-type code.
Signed-off-by: Eduardo Habkost <ehabkost@redhat.com>
Acked-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
2010-04-07 06:22:07 +08:00
|
|
|
int snapshot, linux_boot;
|
2010-03-10 18:38:48 +08:00
|
|
|
const char *icount_option = NULL;
|
2003-10-30 09:11:23 +08:00
|
|
|
const char *initrd_filename;
|
2003-10-01 05:07:02 +08:00
|
|
|
const char *kernel_filename, *kernel_cmdline;
|
2009-10-31 01:42:29 +08:00
|
|
|
char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */
|
2009-01-17 03:04:14 +08:00
|
|
|
DisplayState *ds;
|
2009-01-16 06:14:11 +08:00
|
|
|
DisplayChangeListener *dcl;
|
2004-11-16 09:45:27 +08:00
|
|
|
int cyls, heads, secs, translation;
|
2009-07-31 18:25:37 +08:00
|
|
|
QemuOpts *hda_opts = NULL, *opts;
|
2010-08-20 19:52:02 +08:00
|
|
|
QemuOptsList *olist;
|
2004-05-14 06:02:20 +08:00
|
|
|
int optind;
|
2010-01-22 23:18:06 +08:00
|
|
|
const char *optarg;
|
2004-10-03 21:29:03 +08:00
|
|
|
const char *loadvm = NULL;
|
2005-06-05 22:49:17 +08:00
|
|
|
QEMUMachine *machine;
|
2007-03-06 03:44:02 +08:00
|
|
|
const char *cpu_model;
|
2008-05-28 20:30:31 +08:00
|
|
|
int tb_size;
|
2007-03-19 23:58:31 +08:00
|
|
|
const char *pid_file = NULL;
|
2008-10-13 11:12:02 +08:00
|
|
|
const char *incoming = NULL;
|
2009-05-22 05:54:00 +08:00
|
|
|
int show_vnc_port = 0;
|
2010-01-22 00:57:58 +08:00
|
|
|
int defconfig = 1;
|
2005-11-11 08:00:47 +08:00
|
|
|
|
2010-08-09 18:48:32 +08:00
|
|
|
#ifdef CONFIG_SIMPLE_TRACE
|
|
|
|
const char *trace_file = NULL;
|
|
|
|
#endif
|
2010-06-04 20:08:07 +08:00
|
|
|
atexit(qemu_run_exit_notifiers);
|
2010-02-24 21:37:14 +08:00
|
|
|
error_set_progname(argv[0]);
|
|
|
|
|
2009-09-15 19:36:04 +08:00
|
|
|
init_clocks();
|
|
|
|
|
2008-12-11 03:18:40 +08:00
|
|
|
qemu_cache_utils_init(envp);
|
|
|
|
|
2009-09-12 15:36:22 +08:00
|
|
|
QLIST_INIT (&vm_change_state_head);
|
2010-06-10 17:42:21 +08:00
|
|
|
os_setup_early_signal_handling();
|
2006-06-26 00:25:21 +08:00
|
|
|
|
2009-05-21 07:38:09 +08:00
|
|
|
module_call_init(MODULE_INIT_MACHINE);
|
2009-05-22 09:41:01 +08:00
|
|
|
machine = find_default_machine();
|
2007-03-06 03:44:02 +08:00
|
|
|
cpu_model = NULL;
|
2003-06-30 18:03:06 +08:00
|
|
|
initrd_filename = NULL;
|
2008-04-28 05:39:40 +08:00
|
|
|
ram_size = 0;
|
2003-07-07 01:15:21 +08:00
|
|
|
snapshot = 0;
|
2003-10-01 05:07:02 +08:00
|
|
|
kernel_filename = NULL;
|
|
|
|
kernel_cmdline = "";
|
2004-03-15 05:44:30 +08:00
|
|
|
cyls = heads = secs = 0;
|
2004-11-16 09:45:27 +08:00
|
|
|
translation = BIOS_ATA_TRANSLATION_AUTO;
|
2004-03-15 05:44:30 +08:00
|
|
|
|
2009-04-22 06:30:27 +08:00
|
|
|
for (i = 0; i < MAX_NODES; i++) {
|
|
|
|
node_mem[i] = 0;
|
|
|
|
node_cpumask[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
nb_numa_nodes = 0;
|
2005-11-16 06:16:05 +08:00
|
|
|
nb_nics = 0;
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2008-05-28 20:30:31 +08:00
|
|
|
tb_size = 0;
|
2008-10-05 17:56:21 +08:00
|
|
|
autostart= 1;
|
|
|
|
|
2010-01-22 00:57:58 +08:00
|
|
|
/* first pass of option parsing */
|
|
|
|
optind = 1;
|
|
|
|
while (optind < argc) {
|
|
|
|
if (argv[optind][0] != '-') {
|
|
|
|
/* disk image */
|
2010-01-28 00:46:00 +08:00
|
|
|
optind++;
|
2010-01-22 00:57:58 +08:00
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
const QEMUOption *popt;
|
|
|
|
|
|
|
|
popt = lookup_opt(argc, argv, &optarg, &optind);
|
|
|
|
switch (popt->index) {
|
|
|
|
case QEMU_OPTION_nodefconfig:
|
|
|
|
defconfig=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (defconfig) {
|
2010-03-06 00:25:55 +08:00
|
|
|
int ret;
|
2010-02-19 02:48:33 +08:00
|
|
|
|
2010-03-06 00:25:55 +08:00
|
|
|
ret = qemu_read_config_file(CONFIG_QEMU_CONFDIR "/qemu.conf");
|
2010-05-17 16:36:47 +08:00
|
|
|
if (ret < 0 && ret != -ENOENT) {
|
2010-03-06 00:25:55 +08:00
|
|
|
exit(1);
|
2010-01-22 00:57:58 +08:00
|
|
|
}
|
|
|
|
|
2010-03-06 00:25:55 +08:00
|
|
|
ret = qemu_read_config_file(arch_config_name);
|
2010-05-17 16:36:47 +08:00
|
|
|
if (ret < 0 && ret != -ENOENT) {
|
2010-03-06 00:25:55 +08:00
|
|
|
exit(1);
|
2010-01-22 00:57:58 +08:00
|
|
|
}
|
|
|
|
}
|
2010-03-30 03:23:50 +08:00
|
|
|
cpudef_init();
|
2010-01-22 00:57:58 +08:00
|
|
|
|
|
|
|
/* second pass of option parsing */
|
2004-05-14 06:02:20 +08:00
|
|
|
optind = 1;
|
2003-06-24 21:42:40 +08:00
|
|
|
for(;;) {
|
2004-05-14 06:02:20 +08:00
|
|
|
if (optind >= argc)
|
2003-06-24 21:42:40 +08:00
|
|
|
break;
|
2010-01-22 23:18:06 +08:00
|
|
|
if (argv[optind][0] != '-') {
|
2011-01-28 18:21:41 +08:00
|
|
|
hda_opts = drive_add(IF_DEFAULT, 0, argv[optind++], HD_OPTS);
|
2004-05-14 06:02:20 +08:00
|
|
|
} else {
|
|
|
|
const QEMUOption *popt;
|
|
|
|
|
2010-01-22 23:18:06 +08:00
|
|
|
popt = lookup_opt(argc, argv, &optarg, &optind);
|
2010-03-30 03:23:52 +08:00
|
|
|
if (!(popt->arch_mask & arch_type)) {
|
|
|
|
printf("Option %s not supported for this target\n", popt->name);
|
|
|
|
exit(1);
|
|
|
|
}
|
2004-05-14 06:02:20 +08:00
|
|
|
switch(popt->index) {
|
2005-06-05 22:49:17 +08:00
|
|
|
case QEMU_OPTION_M:
|
|
|
|
machine = find_machine(optarg);
|
|
|
|
if (!machine) {
|
|
|
|
QEMUMachine *m;
|
|
|
|
printf("Supported machines are:\n");
|
|
|
|
for(m = first_machine; m != NULL; m = m->next) {
|
2009-07-22 17:02:50 +08:00
|
|
|
if (m->alias)
|
|
|
|
printf("%-10s %s (alias of %s)\n",
|
|
|
|
m->alias, m->desc, m->name);
|
2005-06-05 22:49:17 +08:00
|
|
|
printf("%-10s %s%s\n",
|
2007-09-17 05:08:06 +08:00
|
|
|
m->name, m->desc,
|
2009-05-22 09:41:01 +08:00
|
|
|
m->is_default ? " (default)" : "");
|
2005-06-05 22:49:17 +08:00
|
|
|
}
|
2007-06-30 07:26:08 +08:00
|
|
|
exit(*optarg != '?');
|
2005-06-05 22:49:17 +08:00
|
|
|
}
|
|
|
|
break;
|
2007-03-06 03:44:02 +08:00
|
|
|
case QEMU_OPTION_cpu:
|
|
|
|
/* hw initialization will check this */
|
2007-06-30 07:26:08 +08:00
|
|
|
if (*optarg == '?') {
|
2010-05-05 03:55:35 +08:00
|
|
|
list_cpus(stdout, &fprintf, optarg);
|
2007-06-30 07:26:08 +08:00
|
|
|
exit(0);
|
2007-03-06 03:44:02 +08:00
|
|
|
} else {
|
|
|
|
cpu_model = optarg;
|
|
|
|
}
|
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_initrd:
|
2003-06-30 18:03:06 +08:00
|
|
|
initrd_filename = optarg;
|
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_hda:
|
2007-12-02 12:51:10 +08:00
|
|
|
if (cyls == 0)
|
2011-01-28 18:21:41 +08:00
|
|
|
hda_opts = drive_add(IF_DEFAULT, 0, optarg, HD_OPTS);
|
2007-12-02 12:51:10 +08:00
|
|
|
else
|
2011-01-28 18:21:41 +08:00
|
|
|
hda_opts = drive_add(IF_DEFAULT, 0, optarg, HD_OPTS
|
2007-12-02 12:51:10 +08:00
|
|
|
",cyls=%d,heads=%d,secs=%d%s",
|
2011-01-28 18:21:41 +08:00
|
|
|
cyls, heads, secs,
|
2007-12-02 12:51:10 +08:00
|
|
|
translation == BIOS_ATA_TRANSLATION_LBA ?
|
|
|
|
",trans=lba" :
|
|
|
|
translation == BIOS_ATA_TRANSLATION_NONE ?
|
|
|
|
",trans=none" : "");
|
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_hdb:
|
2005-06-05 22:49:17 +08:00
|
|
|
case QEMU_OPTION_hdc:
|
|
|
|
case QEMU_OPTION_hdd:
|
2011-01-28 18:21:41 +08:00
|
|
|
drive_add(IF_DEFAULT, popt->index - QEMU_OPTION_hda, optarg,
|
|
|
|
HD_OPTS);
|
2003-06-30 18:03:06 +08:00
|
|
|
break;
|
2007-12-02 12:51:10 +08:00
|
|
|
case QEMU_OPTION_drive:
|
2011-01-28 18:21:41 +08:00
|
|
|
drive_def(optarg);
|
2007-12-02 12:51:10 +08:00
|
|
|
break;
|
2009-07-31 18:25:36 +08:00
|
|
|
case QEMU_OPTION_set:
|
|
|
|
if (qemu_set_option(optarg) != 0)
|
|
|
|
exit(1);
|
|
|
|
break;
|
2009-12-08 20:11:34 +08:00
|
|
|
case QEMU_OPTION_global:
|
|
|
|
if (qemu_global_option(optarg) != 0)
|
|
|
|
exit(1);
|
|
|
|
break;
|
2007-04-30 10:09:25 +08:00
|
|
|
case QEMU_OPTION_mtdblock:
|
2011-01-28 18:21:41 +08:00
|
|
|
drive_add(IF_MTD, -1, optarg, MTD_OPTS);
|
2007-04-30 10:09:25 +08:00
|
|
|
break;
|
2007-04-07 00:49:48 +08:00
|
|
|
case QEMU_OPTION_sd:
|
2011-01-28 18:21:41 +08:00
|
|
|
drive_add(IF_SD, 0, optarg, SD_OPTS);
|
2007-04-07 00:49:48 +08:00
|
|
|
break;
|
2007-04-24 14:52:59 +08:00
|
|
|
case QEMU_OPTION_pflash:
|
2011-01-28 18:21:41 +08:00
|
|
|
drive_add(IF_PFLASH, -1, optarg, PFLASH_OPTS);
|
2007-04-24 14:52:59 +08:00
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_snapshot:
|
2003-07-07 01:15:21 +08:00
|
|
|
snapshot = 1;
|
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_hdachs:
|
2003-07-27 02:11:40 +08:00
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
p = optarg;
|
|
|
|
cyls = strtol(p, (char **)&p, 0);
|
2004-11-16 09:45:27 +08:00
|
|
|
if (cyls < 1 || cyls > 16383)
|
|
|
|
goto chs_fail;
|
2003-07-27 02:11:40 +08:00
|
|
|
if (*p != ',')
|
|
|
|
goto chs_fail;
|
|
|
|
p++;
|
|
|
|
heads = strtol(p, (char **)&p, 0);
|
2004-11-16 09:45:27 +08:00
|
|
|
if (heads < 1 || heads > 16)
|
|
|
|
goto chs_fail;
|
2003-07-27 02:11:40 +08:00
|
|
|
if (*p != ',')
|
|
|
|
goto chs_fail;
|
|
|
|
p++;
|
|
|
|
secs = strtol(p, (char **)&p, 0);
|
2004-11-16 09:45:27 +08:00
|
|
|
if (secs < 1 || secs > 63)
|
|
|
|
goto chs_fail;
|
|
|
|
if (*p == ',') {
|
|
|
|
p++;
|
|
|
|
if (!strcmp(p, "none"))
|
|
|
|
translation = BIOS_ATA_TRANSLATION_NONE;
|
|
|
|
else if (!strcmp(p, "lba"))
|
|
|
|
translation = BIOS_ATA_TRANSLATION_LBA;
|
|
|
|
else if (!strcmp(p, "auto"))
|
|
|
|
translation = BIOS_ATA_TRANSLATION_AUTO;
|
|
|
|
else
|
|
|
|
goto chs_fail;
|
|
|
|
} else if (*p != '\0') {
|
2004-03-15 05:44:30 +08:00
|
|
|
chs_fail:
|
2004-11-16 09:45:27 +08:00
|
|
|
fprintf(stderr, "qemu: invalid physical CHS format\n");
|
|
|
|
exit(1);
|
2004-03-15 05:44:30 +08:00
|
|
|
}
|
2009-07-22 22:43:04 +08:00
|
|
|
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");
|
|
|
|
}
|
2003-07-27 02:11:40 +08:00
|
|
|
}
|
|
|
|
break;
|
2009-04-22 06:30:27 +08:00
|
|
|
case QEMU_OPTION_numa:
|
|
|
|
if (nb_numa_nodes >= MAX_NODES) {
|
|
|
|
fprintf(stderr, "qemu: too many NUMA nodes\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
numa_add(optarg);
|
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_nographic:
|
2009-05-22 05:54:00 +08:00
|
|
|
display_type = DT_NOGRAPHIC;
|
2003-10-01 05:07:02 +08:00
|
|
|
break;
|
2008-02-11 00:33:14 +08:00
|
|
|
#ifdef CONFIG_CURSES
|
|
|
|
case QEMU_OPTION_curses:
|
2009-05-22 05:54:00 +08:00
|
|
|
display_type = DT_CURSES;
|
2008-02-11 00:33:14 +08:00
|
|
|
break;
|
|
|
|
#endif
|
2007-04-30 09:48:07 +08:00
|
|
|
case QEMU_OPTION_portrait:
|
|
|
|
graphic_rotate = 1;
|
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_kernel:
|
2003-10-01 05:07:02 +08:00
|
|
|
kernel_filename = optarg;
|
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_append:
|
2003-10-01 05:07:02 +08:00
|
|
|
kernel_cmdline = optarg;
|
2003-08-11 05:52:11 +08:00
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_cdrom:
|
2011-01-28 18:21:41 +08:00
|
|
|
drive_add(IF_DEFAULT, 2, optarg, CDROM_OPTS);
|
2003-11-11 21:36:08 +08:00
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_boot:
|
2007-11-11 09:50:45 +08:00
|
|
|
{
|
2009-07-02 06:19:02 +08:00
|
|
|
static const char * const params[] = {
|
2009-07-02 06:19:02 +08:00
|
|
|
"order", "once", "menu", NULL
|
2009-07-02 06:19:02 +08:00
|
|
|
};
|
|
|
|
char buf[sizeof(boot_devices)];
|
2009-07-02 06:19:02 +08:00
|
|
|
char *standard_boot_devices;
|
2009-07-02 06:19:02 +08:00
|
|
|
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)) {
|
2010-04-07 06:22:08 +08:00
|
|
|
validate_bootdevices(buf);
|
2009-07-02 06:19:02 +08:00
|
|
|
pstrcpy(boot_devices, sizeof(boot_devices), buf);
|
2007-11-11 09:50:45 +08:00
|
|
|
}
|
2009-07-02 06:19:02 +08:00
|
|
|
if (!legacy) {
|
|
|
|
if (get_param_value(buf, sizeof(buf),
|
|
|
|
"once", optarg)) {
|
2010-04-07 06:22:08 +08:00
|
|
|
validate_bootdevices(buf);
|
2009-07-02 06:19:02 +08:00
|
|
|
standard_boot_devices = qemu_strdup(boot_devices);
|
|
|
|
pstrcpy(boot_devices, sizeof(boot_devices), buf);
|
|
|
|
qemu_register_reset(restore_boot_devices,
|
|
|
|
standard_boot_devices);
|
|
|
|
}
|
2009-07-02 06:19:02 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2009-07-02 06:19:02 +08:00
|
|
|
}
|
2003-11-11 21:36:08 +08:00
|
|
|
}
|
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_fda:
|
|
|
|
case QEMU_OPTION_fdb:
|
2011-01-28 18:21:41 +08:00
|
|
|
drive_add(IF_FLOPPY, popt->index - QEMU_OPTION_fda,
|
|
|
|
optarg, FD_OPTS);
|
2004-01-05 08:02:06 +08:00
|
|
|
break;
|
2006-06-15 00:03:05 +08:00
|
|
|
case QEMU_OPTION_no_fd_bootchk:
|
|
|
|
fd_bootchk = 0;
|
|
|
|
break;
|
2009-10-09 02:58:26 +08:00
|
|
|
case QEMU_OPTION_netdev:
|
2010-08-20 19:52:01 +08:00
|
|
|
if (net_client_parse(qemu_find_opts("netdev"), optarg) == -1) {
|
2009-10-09 02:58:26 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
2005-11-16 06:16:05 +08:00
|
|
|
case QEMU_OPTION_net:
|
2010-08-20 19:52:01 +08:00
|
|
|
if (net_client_parse(qemu_find_opts("net"), optarg) == -1) {
|
2004-03-15 05:44:30 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
2004-04-03 05:21:32 +08:00
|
|
|
break;
|
2004-08-25 05:57:12 +08:00
|
|
|
#ifdef CONFIG_SLIRP
|
|
|
|
case QEMU_OPTION_tftp:
|
2009-06-24 20:42:28 +08:00
|
|
|
legacy_tftp_prefix = optarg;
|
2004-08-26 06:12:49 +08:00
|
|
|
break;
|
2007-02-20 08:05:08 +08:00
|
|
|
case QEMU_OPTION_bootp:
|
2009-06-24 20:42:28 +08:00
|
|
|
legacy_bootp_filename = optarg;
|
2007-02-20 08:05:08 +08:00
|
|
|
break;
|
2004-08-26 06:12:49 +08:00
|
|
|
case QEMU_OPTION_redir:
|
Don't exit() in config_error()
Propagating errors up the call chain is tedious. In startup code, we
can take a shortcut: terminate the program. This is wrong elsewhere,
the monitor in particular.
config_error() tries to cater for both customers: it terminates the
program unless its mon parameter tells it it's working for the
monitor.
Its users need to return status anyway (unless passing a null mon
argument, which none do), which their users need to check. So this
automatic exit buys us exactly nothing useful. Only the dangerous
delusion that we can get away without returning status. Some of its
users fell for that. Their callers continue executing after failure
when working for the monitor.
This bites monitor command host_net_add in two places:
* net_slirp_init() continues after slirp_hostfwd(), slirp_guestfwd(),
or slirp_smb() failed, and may end up reporting success. This
happens for "host_net_add user guestfwd=foo": it complains about the
invalid guest forwarding rule, then happily creates the user network
without guest forwarding.
* net_client_init() can't detect slirp_guestfwd() failure, and gets
fooled by net_slirp_init() lying about success. Suppresses its
"Could not initialize device" message.
Add the missing error reporting, make sure errors are checked, and
drop the exit() from config_error().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-10-06 19:16:57 +08:00
|
|
|
if (net_slirp_redir(optarg) < 0)
|
|
|
|
exit(1);
|
2004-08-26 06:12:49 +08:00
|
|
|
break;
|
2004-08-25 05:57:12 +08:00
|
|
|
#endif
|
2008-11-09 08:04:26 +08:00
|
|
|
case QEMU_OPTION_bt:
|
2009-07-15 19:59:26 +08:00
|
|
|
add_device_config(DEV_BT, optarg);
|
2008-11-09 08:04:26 +08:00
|
|
|
break;
|
2005-10-31 02:58:22 +08:00
|
|
|
case QEMU_OPTION_audio_help:
|
2010-03-30 03:23:52 +08:00
|
|
|
if (!(audio_available())) {
|
|
|
|
printf("Option %s not supported for this target\n", popt->name);
|
|
|
|
exit(1);
|
|
|
|
}
|
2005-10-31 02:58:22 +08:00
|
|
|
AUD_help ();
|
|
|
|
exit (0);
|
|
|
|
break;
|
|
|
|
case QEMU_OPTION_soundhw:
|
2010-03-30 03:23:52 +08:00
|
|
|
if (!(audio_available())) {
|
|
|
|
printf("Option %s not supported for this target\n", popt->name);
|
|
|
|
exit(1);
|
|
|
|
}
|
2005-10-31 02:58:22 +08:00
|
|
|
select_soundhw (optarg);
|
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_h:
|
2007-06-30 07:26:08 +08:00
|
|
|
help(0);
|
2004-05-14 06:02:20 +08:00
|
|
|
break;
|
2009-04-08 06:58:45 +08:00
|
|
|
case QEMU_OPTION_version:
|
|
|
|
version();
|
|
|
|
exit(0);
|
|
|
|
break;
|
2008-04-28 05:12:55 +08:00
|
|
|
case QEMU_OPTION_m: {
|
2011-01-05 18:41:02 +08:00
|
|
|
int64_t value;
|
2010-10-21 23:15:46 +08:00
|
|
|
|
|
|
|
value = strtosz(optarg, NULL);
|
|
|
|
if (value < 0) {
|
2008-04-28 05:12:55 +08:00
|
|
|
fprintf(stderr, "qemu: invalid ram size: %s\n", optarg);
|
2004-05-14 06:02:20 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
2008-04-28 05:12:55 +08:00
|
|
|
|
|
|
|
/* On 32-bit hosts, QEMU is limited by virtual address space */
|
2009-08-11 06:07:24 +08:00
|
|
|
if (value > (2047 << 20) && HOST_LONG_BITS == 32) {
|
2008-04-28 05:12:55 +08:00
|
|
|
fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-10-02 05:12:16 +08:00
|
|
|
if (value != (uint64_t)(ram_addr_t)value) {
|
2008-04-28 05:12:55 +08:00
|
|
|
fprintf(stderr, "qemu: ram size too large\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
ram_size = value;
|
2004-05-14 06:02:20 +08:00
|
|
|
break;
|
2008-04-28 05:12:55 +08:00
|
|
|
}
|
2010-03-02 07:25:08 +08:00
|
|
|
case QEMU_OPTION_mempath:
|
|
|
|
mem_path = optarg;
|
|
|
|
break;
|
|
|
|
#ifdef MAP_POPULATE
|
|
|
|
case QEMU_OPTION_mem_prealloc:
|
|
|
|
mem_prealloc = 1;
|
|
|
|
break;
|
|
|
|
#endif
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_d:
|
2010-03-30 03:23:50 +08:00
|
|
|
set_cpu_log(optarg);
|
2004-05-14 06:02:20 +08:00
|
|
|
break;
|
|
|
|
case QEMU_OPTION_s:
|
2009-04-06 02:43:41 +08:00
|
|
|
gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT;
|
2004-05-14 06:02:20 +08:00
|
|
|
break;
|
2009-04-06 02:43:41 +08:00
|
|
|
case QEMU_OPTION_gdb:
|
|
|
|
gdbstub_dev = optarg;
|
2004-05-14 06:02:20 +08:00
|
|
|
break;
|
|
|
|
case QEMU_OPTION_L:
|
2009-05-30 07:52:44 +08:00
|
|
|
data_dir = optarg;
|
2004-05-14 06:02:20 +08:00
|
|
|
break;
|
2007-10-05 21:08:35 +08:00
|
|
|
case QEMU_OPTION_bios:
|
|
|
|
bios_name = optarg;
|
|
|
|
break;
|
2009-04-06 04:08:59 +08:00
|
|
|
case QEMU_OPTION_singlestep:
|
|
|
|
singlestep = 1;
|
|
|
|
break;
|
2004-05-14 06:02:20 +08:00
|
|
|
case QEMU_OPTION_S:
|
2007-01-22 00:47:01 +08:00
|
|
|
autostart = 0;
|
2004-05-14 06:02:20 +08:00
|
|
|
break;
|
2004-12-13 00:56:30 +08:00
|
|
|
case QEMU_OPTION_k:
|
|
|
|
keyboard_layout = optarg;
|
|
|
|
break;
|
2004-06-03 20:49:50 +08:00
|
|
|
case QEMU_OPTION_localtime:
|
|
|
|
rtc_utc = 0;
|
|
|
|
break;
|
2008-09-28 08:42:05 +08:00
|
|
|
case QEMU_OPTION_vga:
|
|
|
|
select_vgahw (optarg);
|
2004-07-09 05:17:50 +08:00
|
|
|
break;
|
2004-06-22 00:46:10 +08:00
|
|
|
case QEMU_OPTION_g:
|
|
|
|
{
|
|
|
|
const char *p;
|
|
|
|
int w, h, depth;
|
|
|
|
p = optarg;
|
|
|
|
w = strtol(p, (char **)&p, 10);
|
|
|
|
if (w <= 0) {
|
|
|
|
graphic_error:
|
|
|
|
fprintf(stderr, "qemu: invalid resolution or depth\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (*p != 'x')
|
|
|
|
goto graphic_error;
|
|
|
|
p++;
|
|
|
|
h = strtol(p, (char **)&p, 10);
|
|
|
|
if (h <= 0)
|
|
|
|
goto graphic_error;
|
|
|
|
if (*p == 'x') {
|
|
|
|
p++;
|
|
|
|
depth = strtol(p, (char **)&p, 10);
|
2007-09-17 05:08:06 +08:00
|
|
|
if (depth != 8 && depth != 15 && depth != 16 &&
|
2004-06-22 00:46:10 +08:00
|
|
|
depth != 24 && depth != 32)
|
|
|
|
goto graphic_error;
|
|
|
|
} else if (*p == '\0') {
|
|
|
|
depth = graphic_depth;
|
|
|
|
} else {
|
|
|
|
goto graphic_error;
|
|
|
|
}
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2004-06-22 00:46:10 +08:00
|
|
|
graphic_width = w;
|
|
|
|
graphic_height = h;
|
|
|
|
graphic_depth = depth;
|
|
|
|
}
|
|
|
|
break;
|
2007-02-19 01:04:49 +08:00
|
|
|
case QEMU_OPTION_echr:
|
|
|
|
{
|
|
|
|
char *r;
|
|
|
|
term_escape_char = strtol(optarg, &r, 0);
|
|
|
|
if (r == optarg)
|
|
|
|
printf("Bad argument to echr\n");
|
|
|
|
break;
|
|
|
|
}
|
2004-07-15 01:28:13 +08:00
|
|
|
case QEMU_OPTION_monitor:
|
2009-12-08 20:11:52 +08:00
|
|
|
monitor_parse(optarg, "readline");
|
|
|
|
default_monitor = 0;
|
|
|
|
break;
|
|
|
|
case QEMU_OPTION_qmp:
|
|
|
|
monitor_parse(optarg, "control");
|
2010-03-22 03:14:38 +08:00
|
|
|
default_monitor = 0;
|
2004-07-15 01:28:13 +08:00
|
|
|
break;
|
2009-12-08 20:11:51 +08:00
|
|
|
case QEMU_OPTION_mon:
|
2010-08-20 19:52:01 +08:00
|
|
|
opts = qemu_opts_parse(qemu_find_opts("mon"), optarg, 1);
|
2009-12-08 20:11:51 +08:00
|
|
|
if (!opts) {
|
|
|
|
exit(1);
|
|
|
|
}
|
2010-03-22 03:14:38 +08:00
|
|
|
default_monitor = 0;
|
2009-12-08 20:11:51 +08:00
|
|
|
break;
|
2009-09-10 16:58:35 +08:00
|
|
|
case QEMU_OPTION_chardev:
|
2010-08-20 19:52:01 +08:00
|
|
|
opts = qemu_opts_parse(qemu_find_opts("chardev"), optarg, 1);
|
2009-09-10 16:58:35 +08:00
|
|
|
if (!opts) {
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
2010-04-29 20:14:43 +08:00
|
|
|
case QEMU_OPTION_fsdev:
|
2010-08-20 19:52:02 +08:00
|
|
|
olist = qemu_find_opts("fsdev");
|
|
|
|
if (!olist) {
|
|
|
|
fprintf(stderr, "fsdev is not supported by this qemu build.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
opts = qemu_opts_parse(olist, optarg, 1);
|
2010-04-29 20:14:43 +08:00
|
|
|
if (!opts) {
|
|
|
|
fprintf(stderr, "parse error: %s\n", optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
virtio-9p: Create a syntactic shortcut for the file-system pass-thru
Currently the commandline to create a virtual-filesystem pass-through between
the guest and the host is as follows:
#qemu -fsdev fstype,id=ID,path=path/to/share \
-device virtio-9p-pci,fsdev=ID,mount_tag=tag \
This patch provides a syntactic short-cut to achieve the same as follows:
#qemu -virtfs fstype,path=path/to/share,mount_tag=tag
This will be internally expanded as:
#qemu -fsdev fstype,id=tag,path=path/to/share, \
-device virtio-9p-pci,fsdev=tag,mount_tag=tag \
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-04-29 20:15:03 +08:00
|
|
|
case QEMU_OPTION_virtfs: {
|
|
|
|
char *arg_fsdev = NULL;
|
|
|
|
char *arg_9p = NULL;
|
|
|
|
int len = 0;
|
|
|
|
|
2010-08-20 19:52:02 +08:00
|
|
|
olist = qemu_find_opts("virtfs");
|
|
|
|
if (!olist) {
|
|
|
|
fprintf(stderr, "virtfs is not supported by this qemu build.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
opts = qemu_opts_parse(olist, optarg, 1);
|
virtio-9p: Create a syntactic shortcut for the file-system pass-thru
Currently the commandline to create a virtual-filesystem pass-through between
the guest and the host is as follows:
#qemu -fsdev fstype,id=ID,path=path/to/share \
-device virtio-9p-pci,fsdev=ID,mount_tag=tag \
This patch provides a syntactic short-cut to achieve the same as follows:
#qemu -virtfs fstype,path=path/to/share,mount_tag=tag
This will be internally expanded as:
#qemu -fsdev fstype,id=tag,path=path/to/share, \
-device virtio-9p-pci,fsdev=tag,mount_tag=tag \
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-04-29 20:15:03 +08:00
|
|
|
if (!opts) {
|
|
|
|
fprintf(stderr, "parse error: %s\n", optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2010-06-15 04:34:40 +08:00
|
|
|
if (qemu_opt_get(opts, "fstype") == NULL ||
|
|
|
|
qemu_opt_get(opts, "mount_tag") == NULL ||
|
|
|
|
qemu_opt_get(opts, "path") == NULL ||
|
|
|
|
qemu_opt_get(opts, "security_model") == NULL) {
|
|
|
|
fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/,"
|
2010-09-02 13:39:07 +08:00
|
|
|
"security_model=[mapped|passthrough|none],"
|
2010-06-15 04:34:40 +08:00
|
|
|
"mnt_tag=tag.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
len = strlen(",id=,path=,security_model=");
|
virtio-9p: Create a syntactic shortcut for the file-system pass-thru
Currently the commandline to create a virtual-filesystem pass-through between
the guest and the host is as follows:
#qemu -fsdev fstype,id=ID,path=path/to/share \
-device virtio-9p-pci,fsdev=ID,mount_tag=tag \
This patch provides a syntactic short-cut to achieve the same as follows:
#qemu -virtfs fstype,path=path/to/share,mount_tag=tag
This will be internally expanded as:
#qemu -fsdev fstype,id=tag,path=path/to/share, \
-device virtio-9p-pci,fsdev=tag,mount_tag=tag \
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-04-29 20:15:03 +08:00
|
|
|
len += strlen(qemu_opt_get(opts, "fstype"));
|
|
|
|
len += strlen(qemu_opt_get(opts, "mount_tag"));
|
|
|
|
len += strlen(qemu_opt_get(opts, "path"));
|
2010-06-15 04:34:40 +08:00
|
|
|
len += strlen(qemu_opt_get(opts, "security_model"));
|
virtio-9p: Create a syntactic shortcut for the file-system pass-thru
Currently the commandline to create a virtual-filesystem pass-through between
the guest and the host is as follows:
#qemu -fsdev fstype,id=ID,path=path/to/share \
-device virtio-9p-pci,fsdev=ID,mount_tag=tag \
This patch provides a syntactic short-cut to achieve the same as follows:
#qemu -virtfs fstype,path=path/to/share,mount_tag=tag
This will be internally expanded as:
#qemu -fsdev fstype,id=tag,path=path/to/share, \
-device virtio-9p-pci,fsdev=tag,mount_tag=tag \
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-04-29 20:15:03 +08:00
|
|
|
arg_fsdev = qemu_malloc((len + 1) * sizeof(*arg_fsdev));
|
|
|
|
|
2010-09-03 00:17:59 +08:00
|
|
|
snprintf(arg_fsdev, (len + 1) * sizeof(*arg_fsdev),
|
2010-09-01 04:16:59 +08:00
|
|
|
"%s,id=%s,path=%s,security_model=%s",
|
|
|
|
qemu_opt_get(opts, "fstype"),
|
|
|
|
qemu_opt_get(opts, "mount_tag"),
|
|
|
|
qemu_opt_get(opts, "path"),
|
|
|
|
qemu_opt_get(opts, "security_model"));
|
virtio-9p: Create a syntactic shortcut for the file-system pass-thru
Currently the commandline to create a virtual-filesystem pass-through between
the guest and the host is as follows:
#qemu -fsdev fstype,id=ID,path=path/to/share \
-device virtio-9p-pci,fsdev=ID,mount_tag=tag \
This patch provides a syntactic short-cut to achieve the same as follows:
#qemu -virtfs fstype,path=path/to/share,mount_tag=tag
This will be internally expanded as:
#qemu -fsdev fstype,id=tag,path=path/to/share, \
-device virtio-9p-pci,fsdev=tag,mount_tag=tag \
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-04-29 20:15:03 +08:00
|
|
|
|
|
|
|
len = strlen("virtio-9p-pci,fsdev=,mount_tag=");
|
|
|
|
len += 2*strlen(qemu_opt_get(opts, "mount_tag"));
|
|
|
|
arg_9p = qemu_malloc((len + 1) * sizeof(*arg_9p));
|
|
|
|
|
2010-09-03 00:17:59 +08:00
|
|
|
snprintf(arg_9p, (len + 1) * sizeof(*arg_9p),
|
2010-09-01 04:16:59 +08:00
|
|
|
"virtio-9p-pci,fsdev=%s,mount_tag=%s",
|
|
|
|
qemu_opt_get(opts, "mount_tag"),
|
|
|
|
qemu_opt_get(opts, "mount_tag"));
|
virtio-9p: Create a syntactic shortcut for the file-system pass-thru
Currently the commandline to create a virtual-filesystem pass-through between
the guest and the host is as follows:
#qemu -fsdev fstype,id=ID,path=path/to/share \
-device virtio-9p-pci,fsdev=ID,mount_tag=tag \
This patch provides a syntactic short-cut to achieve the same as follows:
#qemu -virtfs fstype,path=path/to/share,mount_tag=tag
This will be internally expanded as:
#qemu -fsdev fstype,id=tag,path=path/to/share, \
-device virtio-9p-pci,fsdev=tag,mount_tag=tag \
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-04-29 20:15:03 +08:00
|
|
|
|
2010-08-20 19:52:01 +08:00
|
|
|
if (!qemu_opts_parse(qemu_find_opts("fsdev"), arg_fsdev, 1)) {
|
virtio-9p: Create a syntactic shortcut for the file-system pass-thru
Currently the commandline to create a virtual-filesystem pass-through between
the guest and the host is as follows:
#qemu -fsdev fstype,id=ID,path=path/to/share \
-device virtio-9p-pci,fsdev=ID,mount_tag=tag \
This patch provides a syntactic short-cut to achieve the same as follows:
#qemu -virtfs fstype,path=path/to/share,mount_tag=tag
This will be internally expanded as:
#qemu -fsdev fstype,id=tag,path=path/to/share, \
-device virtio-9p-pci,fsdev=tag,mount_tag=tag \
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-04-29 20:15:03 +08:00
|
|
|
fprintf(stderr, "parse error [fsdev]: %s\n", optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2010-08-20 19:52:01 +08:00
|
|
|
if (!qemu_opts_parse(qemu_find_opts("device"), arg_9p, 1)) {
|
virtio-9p: Create a syntactic shortcut for the file-system pass-thru
Currently the commandline to create a virtual-filesystem pass-through between
the guest and the host is as follows:
#qemu -fsdev fstype,id=ID,path=path/to/share \
-device virtio-9p-pci,fsdev=ID,mount_tag=tag \
This patch provides a syntactic short-cut to achieve the same as follows:
#qemu -virtfs fstype,path=path/to/share,mount_tag=tag
This will be internally expanded as:
#qemu -fsdev fstype,id=tag,path=path/to/share, \
-device virtio-9p-pci,fsdev=tag,mount_tag=tag \
Signed-off-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2010-04-29 20:15:03 +08:00
|
|
|
fprintf(stderr, "parse error [device]: %s\n", optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
qemu_free(arg_fsdev);
|
|
|
|
qemu_free(arg_9p);
|
|
|
|
break;
|
|
|
|
}
|
2004-07-15 01:28:13 +08:00
|
|
|
case QEMU_OPTION_serial:
|
2009-12-08 20:11:41 +08:00
|
|
|
add_device_config(DEV_SERIAL, optarg);
|
|
|
|
default_serial = 0;
|
2010-03-07 18:28:40 +08:00
|
|
|
if (strncmp(optarg, "mon:", 4) == 0) {
|
|
|
|
default_monitor = 0;
|
|
|
|
}
|
2004-07-15 01:28:13 +08:00
|
|
|
break;
|
2009-04-25 20:56:19 +08:00
|
|
|
case QEMU_OPTION_watchdog:
|
2009-08-21 16:31:34 +08:00
|
|
|
if (watchdog) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"qemu: only one watchdog option may be given\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
watchdog = optarg;
|
2009-04-25 20:56:19 +08:00
|
|
|
break;
|
|
|
|
case QEMU_OPTION_watchdog_action:
|
|
|
|
if (select_watchdog_action(optarg) == -1) {
|
|
|
|
fprintf(stderr, "Unknown -watchdog-action parameter\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
2009-01-16 04:06:40 +08:00
|
|
|
case QEMU_OPTION_virtiocon:
|
2009-12-08 20:11:53 +08:00
|
|
|
add_device_config(DEV_VIRTCON, optarg);
|
|
|
|
default_virtcon = 0;
|
2010-03-07 18:28:40 +08:00
|
|
|
if (strncmp(optarg, "mon:", 4) == 0) {
|
|
|
|
default_monitor = 0;
|
|
|
|
}
|
2009-01-16 04:06:40 +08:00
|
|
|
break;
|
2005-01-15 20:02:56 +08:00
|
|
|
case QEMU_OPTION_parallel:
|
2009-12-08 20:11:42 +08:00
|
|
|
add_device_config(DEV_PARALLEL, optarg);
|
|
|
|
default_parallel = 0;
|
2010-03-07 18:28:40 +08:00
|
|
|
if (strncmp(optarg, "mon:", 4) == 0) {
|
|
|
|
default_monitor = 0;
|
|
|
|
}
|
2005-01-15 20:02:56 +08:00
|
|
|
break;
|
debugcon: support for debugging consoles (e.g. Bochs port 0xe9)
Add generic support for debugging consoles (simple I/O ports which
when written to cause debugging output to be written to a target.)
The current implementation matches Bochs' port 0xe9, allowing the same
debugging code to be used for both Bochs and Qemu.
There is no vm state associated with the debugging port, simply
because it has none -- the entire interface is a single, stateless,
write-only port.
Most of the code was cribbed from the serial port driver.
v2: removed non-ISA variants (they can be introduced when/if someone
wants them, using code from the serial port); added configurable
readback (Bochs returns 0xe9 on a read from this register, mimic that
by default) This retains the apparently somewhat controversial user
friendly option, however.
v3: reimplemented the user friendly option as a synthetic option
("-debugcon foo" basically ends up being a parser-level shorthand for
"-chardev stdio,id=debugcon -device isa-debugcon,chardev=debugcon") --
this dramatically reduced the complexity while keeping the same level
of user friendliness.
v4: spaces, not tabs.
v5: update to match current top of tree. Calling qemu_chr_open()
already during parsing no longer works; defer until we are parsing the
other console-like devices.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-12-30 05:51:36 +08:00
|
|
|
case QEMU_OPTION_debugcon:
|
|
|
|
add_device_config(DEV_DEBUGCON, optarg);
|
|
|
|
break;
|
2004-10-03 21:29:03 +08:00
|
|
|
case QEMU_OPTION_loadvm:
|
|
|
|
loadvm = optarg;
|
|
|
|
break;
|
|
|
|
case QEMU_OPTION_full_screen:
|
|
|
|
full_screen = 1;
|
|
|
|
break;
|
2006-12-11 10:08:05 +08:00
|
|
|
#ifdef CONFIG_SDL
|
2007-02-19 02:19:32 +08:00
|
|
|
case QEMU_OPTION_no_frame:
|
|
|
|
no_frame = 1;
|
|
|
|
break;
|
2007-06-22 05:08:02 +08:00
|
|
|
case QEMU_OPTION_alt_grab:
|
|
|
|
alt_grab = 1;
|
|
|
|
break;
|
2009-09-18 04:48:04 +08:00
|
|
|
case QEMU_OPTION_ctrl_grab:
|
|
|
|
ctrl_grab = 1;
|
|
|
|
break;
|
2006-12-11 10:08:05 +08:00
|
|
|
case QEMU_OPTION_no_quit:
|
|
|
|
no_quit = 1;
|
|
|
|
break;
|
2009-01-16 06:14:11 +08:00
|
|
|
case QEMU_OPTION_sdl:
|
2009-05-22 05:54:00 +08:00
|
|
|
display_type = DT_SDL;
|
2009-01-16 06:14:11 +08:00
|
|
|
break;
|
2006-12-11 10:08:05 +08:00
|
|
|
#endif
|
2004-12-09 06:21:25 +08:00
|
|
|
case QEMU_OPTION_pidfile:
|
2007-03-19 23:58:31 +08:00
|
|
|
pid_file = optarg;
|
2004-12-09 06:21:25 +08:00
|
|
|
break;
|
2005-05-01 00:10:35 +08:00
|
|
|
case QEMU_OPTION_win2k_hack:
|
|
|
|
win2k_install_hack = 1;
|
|
|
|
break;
|
2009-01-16 04:11:34 +08:00
|
|
|
case QEMU_OPTION_rtc_td_hack:
|
|
|
|
rtc_td_hack = 1;
|
|
|
|
break;
|
2009-02-28 04:12:36 +08:00
|
|
|
case QEMU_OPTION_acpitable:
|
2010-03-30 03:23:50 +08:00
|
|
|
do_acpitable_option(optarg);
|
2009-02-28 04:12:36 +08:00
|
|
|
break;
|
qemu: Add support for SMBIOS command line otions (Alex Williamson)
Create a new -smbios option (x86-only) to allow binary SMBIOS entries
to be passed through to the BIOS or modify the default values of
individual fields of type 0 and 1 entries on the command line.
Binary SMBIOS entries can be generated as follows:
dmidecode -t 1 -u | grep $'^\t\t[^"]' | xargs -n1 | \
perl -lne 'printf "%c", hex($_)' > smbios_type_1.bin
These can then be passed to the BIOS using this switch:
-smbios file=smbios_type_1.bin
Command line generation supports the following syntax:
-smbios type=0[,vendor=str][,version=str][,date=str][,release=%d.%d]
-smbios type=1[,manufacturer=str][,product=str][,version=str][,serial=str]
[,uuid=$(uuidgen)][,sku=str][,family=str]
For instance, to add a serial number to the type 1 table:
-smbios type=1,serial=0123456789
Interface is extensible to support more fields/tables as needed.
aliguori: remove texi formatting from help output
Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7163 c046a42c-6fe2-441c-8c8c-71466251a162
2009-04-18 02:59:56 +08:00
|
|
|
case QEMU_OPTION_smbios:
|
2010-03-30 03:23:50 +08:00
|
|
|
do_smbios_option(optarg);
|
qemu: Add support for SMBIOS command line otions (Alex Williamson)
Create a new -smbios option (x86-only) to allow binary SMBIOS entries
to be passed through to the BIOS or modify the default values of
individual fields of type 0 and 1 entries on the command line.
Binary SMBIOS entries can be generated as follows:
dmidecode -t 1 -u | grep $'^\t\t[^"]' | xargs -n1 | \
perl -lne 'printf "%c", hex($_)' > smbios_type_1.bin
These can then be passed to the BIOS using this switch:
-smbios file=smbios_type_1.bin
Command line generation supports the following syntax:
-smbios type=0[,vendor=str][,version=str][,date=str][,release=%d.%d]
-smbios type=1[,manufacturer=str][,product=str][,version=str][,serial=str]
[,uuid=$(uuidgen)][,sku=str][,family=str]
For instance, to add a serial number to the type 1 table:
-smbios type=1,serial=0123456789
Interface is extensible to support more fields/tables as needed.
aliguori: remove texi formatting from help output
Signed-off-by: Alex Williamson <alex.williamson@hp.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@7163 c046a42c-6fe2-441c-8c8c-71466251a162
2009-04-18 02:59:56 +08:00
|
|
|
break;
|
2008-11-06 00:04:33 +08:00
|
|
|
case QEMU_OPTION_enable_kvm:
|
|
|
|
kvm_allowed = 1;
|
|
|
|
break;
|
2005-11-05 22:22:28 +08:00
|
|
|
case QEMU_OPTION_usb:
|
|
|
|
usb_enabled = 1;
|
|
|
|
break;
|
2005-11-07 00:13:29 +08:00
|
|
|
case QEMU_OPTION_usbdevice:
|
|
|
|
usb_enabled = 1;
|
2009-07-15 19:59:26 +08:00
|
|
|
add_device_config(DEV_USB, optarg);
|
|
|
|
break;
|
|
|
|
case QEMU_OPTION_device:
|
2010-08-20 19:52:01 +08:00
|
|
|
if (!qemu_opts_parse(qemu_find_opts("device"), optarg, 1)) {
|
2009-07-31 18:25:37 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
2005-11-07 00:13:29 +08:00
|
|
|
break;
|
2005-11-22 07:25:50 +08:00
|
|
|
case QEMU_OPTION_smp:
|
extend -smp parsing to include cores= and threads= options
For injecting multi-core and multi-threading CPU topology into guests
extend the -smp syntax to accommodate cores and threads specification.
Syntax: -smp smp_value[,cores=nr_cores][,threads=nr_threads]\
[,socket=nr_sockets][,maxcpus=max_cpus]
smp_value is the legacy value specifying the total number of vCPUs for
the guest. If you specify one of cores, threads or sockets this value
can be omitted. Missing values will be computed to fulfill:
smp_value = nr_cores * nr_threads * nr_sockets
where it will favour sockets over cores over threads (to mimic the
current behavior, which will only inject multiple sockets.)
So -smp 4,threads=2 will inject two sockets with 2 threads each,
-smp cores=4 is an abbreviation for -smp 4,cores=4,threads=1,sockets=1.
If max_cpus (the number of hotpluggable CPUs) is omitted, it will
be set to smp_value.
Signed-off-by: Andre Przywara <andre.przywara@amd.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-08-19 21:42:40 +08:00
|
|
|
smp_parse(optarg);
|
2008-10-08 04:39:39 +08:00
|
|
|
if (smp_cpus < 1) {
|
2005-11-22 07:25:50 +08:00
|
|
|
fprintf(stderr, "Invalid number of CPUs\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-07-23 23:03:42 +08:00
|
|
|
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);
|
|
|
|
}
|
2005-11-22 07:25:50 +08:00
|
|
|
break;
|
2006-05-01 05:28:36 +08:00
|
|
|
case QEMU_OPTION_vnc:
|
2010-08-25 16:51:06 +08:00
|
|
|
display_remote++;
|
2006-12-22 10:09:07 +08:00
|
|
|
vnc_display = optarg;
|
2006-05-01 05:28:36 +08:00
|
|
|
break;
|
2006-05-04 06:02:44 +08:00
|
|
|
case QEMU_OPTION_no_acpi:
|
|
|
|
acpi_enabled = 0;
|
|
|
|
break;
|
2008-12-18 07:28:44 +08:00
|
|
|
case QEMU_OPTION_no_hpet:
|
|
|
|
no_hpet = 1;
|
|
|
|
break;
|
2009-06-27 01:15:14 +08:00
|
|
|
case QEMU_OPTION_balloon:
|
|
|
|
if (balloon_parse(optarg) < 0) {
|
|
|
|
fprintf(stderr, "Unknown -balloon argument %s\n", optarg);
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-06-11 03:34:08 +08:00
|
|
|
break;
|
2006-10-03 03:44:22 +08:00
|
|
|
case QEMU_OPTION_no_reboot:
|
|
|
|
no_reboot = 1;
|
|
|
|
break;
|
2008-04-12 05:35:52 +08:00
|
|
|
case QEMU_OPTION_no_shutdown:
|
|
|
|
no_shutdown = 1;
|
|
|
|
break;
|
2007-05-01 09:34:14 +08:00
|
|
|
case QEMU_OPTION_show_cursor:
|
|
|
|
cursor_hide = 0;
|
|
|
|
break;
|
2008-09-19 02:29:08 +08:00
|
|
|
case QEMU_OPTION_uuid:
|
|
|
|
if(qemu_uuid_parse(optarg, qemu_uuid) < 0) {
|
|
|
|
fprintf(stderr, "Fail to parse UUID string."
|
|
|
|
" Wrong format.\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
2007-01-06 01:39:04 +08:00
|
|
|
case QEMU_OPTION_option_rom:
|
|
|
|
if (nb_option_roms >= MAX_OPTION_ROMS) {
|
|
|
|
fprintf(stderr, "Too many option ROMs\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2010-12-08 19:35:07 +08:00
|
|
|
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);
|
|
|
|
}
|
2007-01-06 01:39:04 +08:00
|
|
|
nb_option_roms++;
|
|
|
|
break;
|
2007-01-21 01:12:09 +08:00
|
|
|
case QEMU_OPTION_semihosting:
|
|
|
|
semihosting_enabled = 1;
|
|
|
|
break;
|
2007-03-19 23:17:08 +08:00
|
|
|
case QEMU_OPTION_name:
|
2009-07-02 15:34:17 +08:00
|
|
|
qemu_name = qemu_strdup(optarg);
|
|
|
|
{
|
|
|
|
char *p = strchr(qemu_name, ',');
|
|
|
|
if (p != NULL) {
|
|
|
|
*p++ = 0;
|
|
|
|
if (strncmp(p, "process=", 8)) {
|
2010-12-28 01:29:20 +08:00
|
|
|
fprintf(stderr, "Unknown subargument %s to -name\n", p);
|
2009-07-02 15:34:17 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
p += 8;
|
2010-06-10 17:42:31 +08:00
|
|
|
os_set_proc_name(p);
|
2009-07-02 15:34:17 +08:00
|
|
|
}
|
|
|
|
}
|
2007-03-19 23:17:08 +08:00
|
|
|
break;
|
2007-05-01 22:16:52 +08:00
|
|
|
case QEMU_OPTION_prom_env:
|
|
|
|
if (nb_prom_envs >= MAX_PROM_ENVS) {
|
|
|
|
fprintf(stderr, "Too many prom variables\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
prom_envs[nb_prom_envs] = optarg;
|
|
|
|
nb_prom_envs++;
|
|
|
|
break;
|
2007-07-28 06:08:46 +08:00
|
|
|
case QEMU_OPTION_old_param:
|
|
|
|
old_param = 1;
|
2008-01-09 03:32:16 +08:00
|
|
|
break;
|
2007-08-24 09:26:02 +08:00
|
|
|
case QEMU_OPTION_clock:
|
|
|
|
configure_alarms(optarg);
|
|
|
|
break;
|
2007-11-08 00:24:33 +08:00
|
|
|
case QEMU_OPTION_startdate:
|
2009-09-15 19:36:04 +08:00
|
|
|
configure_rtc_date_offset(optarg, 1);
|
|
|
|
break;
|
|
|
|
case QEMU_OPTION_rtc:
|
2010-08-20 19:52:01 +08:00
|
|
|
opts = qemu_opts_parse(qemu_find_opts("rtc"), optarg, 0);
|
2009-09-15 19:36:04 +08:00
|
|
|
if (!opts) {
|
|
|
|
exit(1);
|
2007-11-08 00:24:33 +08:00
|
|
|
}
|
2009-09-15 19:36:04 +08:00
|
|
|
configure_rtc(opts);
|
2007-11-08 00:24:33 +08:00
|
|
|
break;
|
2008-05-28 20:30:31 +08:00
|
|
|
case QEMU_OPTION_tb_size:
|
|
|
|
tb_size = strtol(optarg, NULL, 0);
|
|
|
|
if (tb_size < 0)
|
|
|
|
tb_size = 0;
|
|
|
|
break;
|
2008-06-29 09:03:05 +08:00
|
|
|
case QEMU_OPTION_icount:
|
2010-03-10 18:38:48 +08:00
|
|
|
icount_option = optarg;
|
2008-06-29 09:03:05 +08:00
|
|
|
break;
|
2008-10-13 11:12:02 +08:00
|
|
|
case QEMU_OPTION_incoming:
|
|
|
|
incoming = optarg;
|
2010-07-27 18:19:19 +08:00
|
|
|
incoming_expected = true;
|
2008-10-13 11:12:02 +08:00
|
|
|
break;
|
2009-12-08 20:11:46 +08:00
|
|
|
case QEMU_OPTION_nodefaults:
|
|
|
|
default_serial = 0;
|
|
|
|
default_parallel = 0;
|
2009-12-08 20:11:53 +08:00
|
|
|
default_virtcon = 0;
|
2009-12-08 20:11:46 +08:00
|
|
|
default_monitor = 0;
|
|
|
|
default_vga = 0;
|
2009-12-08 20:11:47 +08:00
|
|
|
default_net = 0;
|
2009-12-16 21:25:39 +08:00
|
|
|
default_floppy = 0;
|
|
|
|
default_cdrom = 0;
|
|
|
|
default_sdcard = 0;
|
2009-12-08 20:11:46 +08:00
|
|
|
break;
|
2009-04-22 23:19:10 +08:00
|
|
|
case QEMU_OPTION_xen_domid:
|
2010-03-30 03:23:52 +08:00
|
|
|
if (!(xen_available())) {
|
|
|
|
printf("Option %s not supported for this target\n", popt->name);
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-04-22 23:19:10 +08:00
|
|
|
xen_domid = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case QEMU_OPTION_xen_create:
|
2010-03-30 03:23:52 +08:00
|
|
|
if (!(xen_available())) {
|
|
|
|
printf("Option %s not supported for this target\n", popt->name);
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-04-22 23:19:10 +08:00
|
|
|
xen_mode = XEN_CREATE;
|
|
|
|
break;
|
|
|
|
case QEMU_OPTION_xen_attach:
|
2010-03-30 03:23:52 +08:00
|
|
|
if (!(xen_available())) {
|
|
|
|
printf("Option %s not supported for this target\n", popt->name);
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-04-22 23:19:10 +08:00
|
|
|
xen_mode = XEN_ATTACH;
|
|
|
|
break;
|
2010-08-09 18:48:32 +08:00
|
|
|
#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
|
2009-10-14 16:39:28 +08:00
|
|
|
case QEMU_OPTION_readconfig:
|
|
|
|
{
|
2010-03-06 00:25:55 +08:00
|
|
|
int ret = qemu_read_config_file(optarg);
|
|
|
|
if (ret < 0) {
|
|
|
|
fprintf(stderr, "read config %s: %s\n", optarg,
|
|
|
|
strerror(-ret));
|
2009-10-14 16:39:28 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2010-03-11 22:13:27 +08:00
|
|
|
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;
|
2009-10-14 16:39:28 +08:00
|
|
|
case QEMU_OPTION_writeconfig:
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
if (strcmp(optarg, "-") == 0) {
|
|
|
|
fp = stdout;
|
|
|
|
} else {
|
|
|
|
fp = fopen(optarg, "w");
|
|
|
|
if (fp == NULL) {
|
|
|
|
fprintf(stderr, "open %s: %s\n", optarg, strerror(errno));
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qemu_config_write(fp);
|
|
|
|
fclose(fp);
|
|
|
|
break;
|
|
|
|
}
|
2010-06-10 17:42:25 +08:00
|
|
|
default:
|
|
|
|
os_parse_cmd_args(popt->index, optarg);
|
2004-05-14 06:02:20 +08:00
|
|
|
}
|
2003-06-24 21:42:40 +08:00
|
|
|
}
|
|
|
|
}
|
2010-02-19 03:13:51 +08:00
|
|
|
loc_set_none();
|
2003-07-27 02:11:40 +08:00
|
|
|
|
2009-05-30 07:52:44 +08:00
|
|
|
/* If no data_dir is specified then try to find it relative to the
|
|
|
|
executable path. */
|
|
|
|
if (!data_dir) {
|
2010-06-10 17:42:23 +08:00
|
|
|
data_dir = os_find_datadir(argv[0]);
|
2009-05-30 07:52:44 +08:00
|
|
|
}
|
|
|
|
/* If all else fails use the install patch specified when building. */
|
|
|
|
if (!data_dir) {
|
2010-05-26 22:08:25 +08:00
|
|
|
data_dir = CONFIG_QEMU_DATADIR;
|
2009-05-30 07:52:44 +08:00
|
|
|
}
|
|
|
|
|
2010-08-09 18:48:32 +08:00
|
|
|
#ifdef CONFIG_SIMPLE_TRACE
|
|
|
|
/*
|
|
|
|
* Set the trace file name, if specified.
|
|
|
|
*/
|
|
|
|
st_set_trace_file(trace_file);
|
|
|
|
#endif
|
2009-07-23 23:03:42 +08:00
|
|
|
/*
|
|
|
|
* Default to max_cpus = smp_cpus, in case the user doesn't
|
|
|
|
* specify a max_cpus value.
|
|
|
|
*/
|
|
|
|
if (!max_cpus)
|
|
|
|
max_cpus = smp_cpus;
|
|
|
|
|
2008-10-28 18:59:59 +08:00
|
|
|
machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */
|
2008-10-08 04:39:39 +08:00
|
|
|
if (smp_cpus > machine->max_cpus) {
|
|
|
|
fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus "
|
|
|
|
"supported by machine `%s' (%d)\n", smp_cpus, machine->name,
|
|
|
|
machine->max_cpus);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2010-08-20 19:52:01 +08:00
|
|
|
qemu_opts_foreach(qemu_find_opts("device"), default_driver_check, NULL, 0);
|
|
|
|
qemu_opts_foreach(qemu_find_opts("global"), default_driver_check, NULL, 0);
|
2009-12-08 20:11:41 +08:00
|
|
|
|
2009-12-08 20:11:54 +08:00
|
|
|
if (machine->no_serial) {
|
|
|
|
default_serial = 0;
|
|
|
|
}
|
|
|
|
if (machine->no_parallel) {
|
|
|
|
default_parallel = 0;
|
|
|
|
}
|
|
|
|
if (!machine->use_virtcon) {
|
|
|
|
default_virtcon = 0;
|
|
|
|
}
|
|
|
|
if (machine->no_vga) {
|
|
|
|
default_vga = 0;
|
|
|
|
}
|
2009-12-16 21:25:39 +08:00
|
|
|
if (machine->no_floppy) {
|
|
|
|
default_floppy = 0;
|
|
|
|
}
|
|
|
|
if (machine->no_cdrom) {
|
|
|
|
default_cdrom = 0;
|
|
|
|
}
|
|
|
|
if (machine->no_sdcard) {
|
|
|
|
default_sdcard = 0;
|
|
|
|
}
|
2009-12-08 20:11:54 +08:00
|
|
|
|
2009-05-22 05:54:00 +08:00
|
|
|
if (display_type == DT_NOGRAPHIC) {
|
2009-12-08 20:11:42 +08:00
|
|
|
if (default_parallel)
|
|
|
|
add_device_config(DEV_PARALLEL, "null");
|
2009-12-08 20:11:44 +08:00
|
|
|
if (default_serial && default_monitor) {
|
|
|
|
add_device_config(DEV_SERIAL, "mon:stdio");
|
2009-12-08 20:11:54 +08:00
|
|
|
} else if (default_virtcon && default_monitor) {
|
|
|
|
add_device_config(DEV_VIRTCON, "mon:stdio");
|
2009-12-08 20:11:44 +08:00
|
|
|
} else {
|
|
|
|
if (default_serial)
|
|
|
|
add_device_config(DEV_SERIAL, "stdio");
|
2009-12-08 20:11:54 +08:00
|
|
|
if (default_virtcon)
|
|
|
|
add_device_config(DEV_VIRTCON, "stdio");
|
2009-12-08 20:11:44 +08:00
|
|
|
if (default_monitor)
|
2009-12-08 20:11:52 +08:00
|
|
|
monitor_parse("stdio", "readline");
|
2009-12-08 20:11:44 +08:00
|
|
|
}
|
2009-12-08 20:11:41 +08:00
|
|
|
} else {
|
|
|
|
if (default_serial)
|
|
|
|
add_device_config(DEV_SERIAL, "vc:80Cx24C");
|
2009-12-08 20:11:42 +08:00
|
|
|
if (default_parallel)
|
|
|
|
add_device_config(DEV_PARALLEL, "vc:80Cx24C");
|
2009-12-08 20:11:43 +08:00
|
|
|
if (default_monitor)
|
2009-12-08 20:11:52 +08:00
|
|
|
monitor_parse("vc:80Cx24C", "readline");
|
2009-12-17 20:06:08 +08:00
|
|
|
if (default_virtcon)
|
|
|
|
add_device_config(DEV_VIRTCON, "vc:80Cx24C");
|
2008-08-01 23:12:34 +08:00
|
|
|
}
|
2009-12-08 20:11:45 +08:00
|
|
|
if (default_vga)
|
|
|
|
vga_interface_type = VGA_CIRRUS;
|
2008-08-01 23:12:34 +08:00
|
|
|
|
2010-04-15 12:37:55 +08:00
|
|
|
socket_init();
|
|
|
|
|
2010-08-20 19:52:01 +08:00
|
|
|
if (qemu_opts_foreach(qemu_find_opts("chardev"), chardev_init_func, NULL, 1) != 0)
|
2009-12-08 20:11:36 +08:00
|
|
|
exit(1);
|
2010-06-15 04:34:41 +08:00
|
|
|
#ifdef CONFIG_VIRTFS
|
2010-08-20 19:52:01 +08:00
|
|
|
if (qemu_opts_foreach(qemu_find_opts("fsdev"), fsdev_init_func, NULL, 1) != 0) {
|
2010-04-29 20:14:43 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
#endif
|
2009-12-08 20:11:36 +08:00
|
|
|
|
2010-06-10 17:42:28 +08:00
|
|
|
os_daemonize();
|
2006-12-22 10:11:31 +08:00
|
|
|
|
2007-03-26 05:33:06 +08:00
|
|
|
if (pid_file && qemu_create_pidfile(pid_file) != 0) {
|
2010-06-10 17:42:28 +08:00
|
|
|
os_pidfile_error();
|
2007-03-19 23:58:31 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2010-04-20 02:59:30 +08:00
|
|
|
if (kvm_allowed) {
|
|
|
|
int ret = kvm_init(smp_cpus);
|
2009-09-18 13:41:23 +08:00
|
|
|
if (ret < 0) {
|
2010-04-20 02:59:30 +08:00
|
|
|
if (!kvm_available()) {
|
|
|
|
printf("KVM not supported for this target\n");
|
|
|
|
} else {
|
|
|
|
fprintf(stderr, "failed to initialize KVM: %s\n", strerror(-ret));
|
|
|
|
}
|
2009-09-18 13:41:23 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-25 02:03:25 +08:00
|
|
|
if (qemu_init_main_loop()) {
|
|
|
|
fprintf(stderr, "qemu_init_main_loop failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2003-10-01 05:07:02 +08:00
|
|
|
linux_boot = (kernel_filename != NULL);
|
2007-11-17 20:12:29 +08:00
|
|
|
|
2008-07-03 18:01:15 +08:00
|
|
|
if (!linux_boot && *kernel_cmdline != '\0') {
|
|
|
|
fprintf(stderr, "-append only allowed with -kernel option\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!linux_boot && initrd_filename != NULL) {
|
|
|
|
fprintf(stderr, "-initrd only allowed with -kernel option\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2010-06-10 17:42:30 +08:00
|
|
|
os_set_line_buffering();
|
2007-09-17 16:09:54 +08:00
|
|
|
|
2008-11-06 04:40:18 +08:00
|
|
|
if (init_timer_alarm() < 0) {
|
|
|
|
fprintf(stderr, "could not initialize alarm timer\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2010-03-10 18:38:48 +08:00
|
|
|
configure_icount(icount_option);
|
2006-07-16 01:40:09 +08:00
|
|
|
|
2009-10-06 19:17:16 +08:00
|
|
|
if (net_init_clients() < 0) {
|
|
|
|
exit(1);
|
2004-04-03 05:21:32 +08:00
|
|
|
}
|
2003-06-25 08:07:40 +08:00
|
|
|
|
2008-11-09 08:04:26 +08:00
|
|
|
/* init the bluetooth world */
|
2009-07-15 19:59:26 +08:00
|
|
|
if (foreach_device_config(DEV_BT, bt_parse))
|
|
|
|
exit(1);
|
2008-11-09 08:04:26 +08:00
|
|
|
|
2003-06-24 21:42:40 +08:00
|
|
|
/* init the memory */
|
2009-04-12 01:15:54 +08:00
|
|
|
if (ram_size == 0)
|
|
|
|
ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
|
2007-01-06 01:39:04 +08:00
|
|
|
|
2008-05-28 20:30:31 +08:00
|
|
|
/* init the dynamic translator */
|
|
|
|
cpu_exec_init_all(tb_size * 1024 * 1024);
|
|
|
|
|
2009-10-28 01:41:44 +08:00
|
|
|
bdrv_init_with_whitelist();
|
2004-03-15 05:44:30 +08:00
|
|
|
|
2009-11-02 21:40:58 +08:00
|
|
|
blk_mig_init();
|
|
|
|
|
2007-12-02 12:51:10 +08:00
|
|
|
/* open the virtual block devices */
|
2009-07-22 22:43:04 +08:00
|
|
|
if (snapshot)
|
2010-08-20 19:52:01 +08:00
|
|
|
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)
|
2009-07-22 22:43:04 +08:00
|
|
|
exit(1);
|
2007-04-30 10:09:25 +08:00
|
|
|
|
blockdev: Reject multiple definitions for the same drive
We silently ignore multiple definitions for the same drive:
$ qemu-system-x86_64 -nodefaults -vnc :1 -S -monitor stdio -drive if=ide,index=1,file=tmp.qcow2 -drive if=ide,index=1,file=nonexistant
QEMU 0.13.50 monitor - type 'help' for more information
(qemu) info block
ide0-hd1: type=hd removable=0 file=tmp.qcow2 backing_file=tmp.img ro=0 drv=qcow2 encrypted=0
With if=none, this can become quite confusing:
$ qemu-system-x86_64 -nodefaults -vnc :1 -S -monitor stdio -drive if=none,index=1,file=tmp.qcow2,id=eins -drive if=none,index=1,file=nonexistant,id=zwei -device ide-drive,drive=eins -device ide-drive,drive=zwei
qemu-system-x86_64: -device ide-drive,drive=zwei: Property 'ide-drive.drive' can't find value 'zwei'
The second -device fails, because it refers to drive zwei, which got
silently ignored.
Make multiple drive definitions fail cleanly.
Unfortunately, there's code that relies on multiple drive definitions
being silently ignored: main() merrily adds default drives even when
the user already defined these drives. Fix that up.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2011-01-28 18:21:45 +08:00
|
|
|
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);
|
|
|
|
|
2010-06-26 01:09:50 +08:00
|
|
|
register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL,
|
2009-11-02 21:40:58 +08:00
|
|
|
ram_load, NULL);
|
2004-04-01 03:00:16 +08:00
|
|
|
|
2009-04-22 06:30:27 +08:00
|
|
|
if (nb_numa_nodes > 0) {
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (nb_numa_nodes > smp_cpus) {
|
|
|
|
nb_numa_nodes = smp_cpus;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If no memory size if given for any node, assume the default case
|
|
|
|
* and distribute the available memory equally across all nodes
|
|
|
|
*/
|
|
|
|
for (i = 0; i < nb_numa_nodes; i++) {
|
|
|
|
if (node_mem[i] != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i == nb_numa_nodes) {
|
|
|
|
uint64_t usedmem = 0;
|
|
|
|
|
|
|
|
/* On Linux, the each node's border has to be 8MB aligned,
|
|
|
|
* the final node gets the rest.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < nb_numa_nodes - 1; i++) {
|
|
|
|
node_mem[i] = (ram_size / nb_numa_nodes) & ~((1 << 23UL) - 1);
|
|
|
|
usedmem += node_mem[i];
|
|
|
|
}
|
|
|
|
node_mem[i] = ram_size - usedmem;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nb_numa_nodes; i++) {
|
|
|
|
if (node_cpumask[i] != 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* assigning the VCPUs round-robin is easier to implement, guest OSes
|
|
|
|
* must cope with this anyway, because there are BIOSes out there in
|
|
|
|
* real machines which also use this scheme.
|
|
|
|
*/
|
|
|
|
if (i == nb_numa_nodes) {
|
|
|
|
for (i = 0; i < smp_cpus; i++) {
|
|
|
|
node_cpumask[i % nb_numa_nodes] |= 1 << i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-20 19:52:01 +08:00
|
|
|
if (qemu_opts_foreach(qemu_find_opts("mon"), mon_init_func, NULL, 1) != 0) {
|
2010-04-06 22:55:53 +08:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2009-12-08 20:11:41 +08:00
|
|
|
if (foreach_device_config(DEV_SERIAL, serial_parse) < 0)
|
|
|
|
exit(1);
|
2009-12-08 20:11:42 +08:00
|
|
|
if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0)
|
|
|
|
exit(1);
|
2009-12-08 20:11:53 +08:00
|
|
|
if (foreach_device_config(DEV_VIRTCON, virtcon_parse) < 0)
|
|
|
|
exit(1);
|
debugcon: support for debugging consoles (e.g. Bochs port 0xe9)
Add generic support for debugging consoles (simple I/O ports which
when written to cause debugging output to be written to a target.)
The current implementation matches Bochs' port 0xe9, allowing the same
debugging code to be used for both Bochs and Qemu.
There is no vm state associated with the debugging port, simply
because it has none -- the entire interface is a single, stateless,
write-only port.
Most of the code was cribbed from the serial port driver.
v2: removed non-ISA variants (they can be introduced when/if someone
wants them, using code from the serial port); added configurable
readback (Bochs returns 0xe9 on a read from this register, mimic that
by default) This retains the apparently somewhat controversial user
friendly option, however.
v3: reimplemented the user friendly option as a synthetic option
("-debugcon foo" basically ends up being a parser-level shorthand for
"-chardev stdio,id=debugcon -device isa-debugcon,chardev=debugcon") --
this dramatically reduced the complexity while keeping the same level
of user friendliness.
v4: spaces, not tabs.
v5: update to match current top of tree. Calling qemu_chr_open()
already during parsing no longer works; defer until we are parsing the
other console-like devices.
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-12-30 05:51:36 +08:00
|
|
|
if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0)
|
|
|
|
exit(1);
|
2009-01-17 04:23:27 +08:00
|
|
|
|
2009-05-15 05:35:06 +08:00
|
|
|
module_call_init(MODULE_INIT_DEVICE);
|
|
|
|
|
2010-08-20 19:52:01 +08:00
|
|
|
if (qemu_opts_foreach(qemu_find_opts("device"), device_help_func, NULL, 0) != 0)
|
2010-01-30 02:48:57 +08:00
|
|
|
exit(0);
|
|
|
|
|
2009-08-21 16:31:34 +08:00
|
|
|
if (watchdog) {
|
|
|
|
i = select_watchdog(watchdog);
|
|
|
|
if (i > 0)
|
|
|
|
exit (i == 1 ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
2009-07-15 19:48:21 +08:00
|
|
|
if (machine->compat_props) {
|
2009-12-08 20:11:33 +08:00
|
|
|
qdev_prop_register_global_list(machine->compat_props);
|
2009-07-15 19:48:21 +08:00
|
|
|
}
|
2009-12-08 20:11:34 +08:00
|
|
|
qemu_add_globals();
|
|
|
|
|
2009-05-14 00:56:25 +08:00
|
|
|
machine->init(ram_size, boot_devices,
|
2009-01-17 03:04:14 +08:00
|
|
|
kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
|
|
|
|
|
2010-03-02 02:10:30 +08:00
|
|
|
cpu_synchronize_all_post_init();
|
2009-04-22 06:30:27 +08:00
|
|
|
|
2009-08-29 01:25:15 +08:00
|
|
|
/* must be after terminal init, SDL library changes signal handlers */
|
2010-06-10 17:42:22 +08:00
|
|
|
os_setup_signal_handling();
|
2009-08-29 01:25:15 +08:00
|
|
|
|
2010-03-28 02:24:45 +08:00
|
|
|
set_numa_modes();
|
2009-04-22 06:30:27 +08:00
|
|
|
|
2009-02-11 23:21:54 +08:00
|
|
|
current_machine = machine;
|
|
|
|
|
2009-01-17 03:04:14 +08:00
|
|
|
/* init USB devices */
|
|
|
|
if (usb_enabled) {
|
Don't exit() in config_error()
Propagating errors up the call chain is tedious. In startup code, we
can take a shortcut: terminate the program. This is wrong elsewhere,
the monitor in particular.
config_error() tries to cater for both customers: it terminates the
program unless its mon parameter tells it it's working for the
monitor.
Its users need to return status anyway (unless passing a null mon
argument, which none do), which their users need to check. So this
automatic exit buys us exactly nothing useful. Only the dangerous
delusion that we can get away without returning status. Some of its
users fell for that. Their callers continue executing after failure
when working for the monitor.
This bites monitor command host_net_add in two places:
* net_slirp_init() continues after slirp_hostfwd(), slirp_guestfwd(),
or slirp_smb() failed, and may end up reporting success. This
happens for "host_net_add user guestfwd=foo": it complains about the
invalid guest forwarding rule, then happily creates the user network
without guest forwarding.
* net_client_init() can't detect slirp_guestfwd() failure, and gets
fooled by net_slirp_init() lying about success. Suppresses its
"Could not initialize device" message.
Add the missing error reporting, make sure errors are checked, and
drop the exit() from config_error().
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
2009-10-06 19:16:57 +08:00
|
|
|
if (foreach_device_config(DEV_USB, usb_parse) < 0)
|
|
|
|
exit(1);
|
2009-01-17 03:04:14 +08:00
|
|
|
}
|
|
|
|
|
2009-07-15 19:59:26 +08:00
|
|
|
/* init generic devices */
|
2010-08-20 19:52:01 +08:00
|
|
|
if (qemu_opts_foreach(qemu_find_opts("device"), device_init_func, NULL, 1) != 0)
|
2009-07-15 19:59:26 +08:00
|
|
|
exit(1);
|
|
|
|
|
2010-02-11 21:44:58 +08:00
|
|
|
net_check_clients();
|
|
|
|
|
2009-01-17 03:04:14 +08:00
|
|
|
/* just use the first displaystate for the moment */
|
2010-02-11 07:29:55 +08:00
|
|
|
ds = get_displaystate();
|
2009-05-22 05:54:00 +08:00
|
|
|
|
2010-08-25 21:32:06 +08:00
|
|
|
if (using_spice)
|
|
|
|
display_remote++;
|
2010-08-25 16:51:06 +08:00
|
|
|
if (display_type == DT_DEFAULT && !display_remote) {
|
2009-05-22 05:54:00 +08:00
|
|
|
#if defined(CONFIG_SDL) || defined(CONFIG_COCOA)
|
|
|
|
display_type = DT_SDL;
|
|
|
|
#else
|
|
|
|
vnc_display = "localhost:0,to=99";
|
|
|
|
show_vnc_port = 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-08-25 16:51:06 +08:00
|
|
|
/* init local displays */
|
2009-05-22 05:54:00 +08:00
|
|
|
switch (display_type) {
|
|
|
|
case DT_NOGRAPHIC:
|
|
|
|
break;
|
2008-02-11 00:33:14 +08:00
|
|
|
#if defined(CONFIG_CURSES)
|
2009-05-22 05:54:00 +08:00
|
|
|
case DT_CURSES:
|
|
|
|
curses_display_init(ds, full_screen);
|
|
|
|
break;
|
2008-02-11 00:33:14 +08:00
|
|
|
#endif
|
2005-03-02 05:37:28 +08:00
|
|
|
#if defined(CONFIG_SDL)
|
2009-05-22 05:54:00 +08:00
|
|
|
case DT_SDL:
|
|
|
|
sdl_display_init(ds, full_screen, no_frame);
|
|
|
|
break;
|
2005-03-02 05:37:28 +08:00
|
|
|
#elif defined(CONFIG_COCOA)
|
2009-05-22 05:54:00 +08:00
|
|
|
case DT_SDL:
|
|
|
|
cocoa_display_init(ds, full_screen);
|
|
|
|
break;
|
2003-08-11 05:52:11 +08:00
|
|
|
#endif
|
2010-08-25 16:51:06 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* init remote displays */
|
|
|
|
if (vnc_display) {
|
2009-05-22 05:54:00 +08:00
|
|
|
vnc_display_init(ds);
|
|
|
|
if (vnc_display_open(ds, vnc_display) < 0)
|
|
|
|
exit(1);
|
2009-05-21 02:01:02 +08:00
|
|
|
|
2009-05-22 05:54:00 +08:00
|
|
|
if (show_vnc_port) {
|
|
|
|
printf("VNC server running on `%s'\n", vnc_display_local_addr(ds));
|
2009-05-21 02:01:02 +08:00
|
|
|
}
|
2003-08-11 05:52:11 +08:00
|
|
|
}
|
2010-08-25 21:32:06 +08:00
|
|
|
#ifdef CONFIG_SPICE
|
2010-04-27 17:50:11 +08:00
|
|
|
if (using_spice && !qxl_enabled) {
|
2010-08-25 21:32:06 +08:00
|
|
|
qemu_spice_display_init(ds);
|
|
|
|
}
|
|
|
|
#endif
|
2008-08-22 04:08:03 +08:00
|
|
|
|
2010-08-25 16:51:06 +08:00
|
|
|
/* display setup */
|
|
|
|
dpy_resize(ds);
|
2009-01-17 03:04:14 +08:00
|
|
|
dcl = ds->listeners;
|
|
|
|
while (dcl != NULL) {
|
|
|
|
if (dcl->dpy_refresh != NULL) {
|
|
|
|
ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds);
|
|
|
|
qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock));
|
2010-05-27 13:38:47 +08:00
|
|
|
break;
|
2007-02-19 01:04:49 +08:00
|
|
|
}
|
2009-01-17 03:04:14 +08:00
|
|
|
dcl = dcl->next;
|
2007-02-19 01:04:49 +08:00
|
|
|
}
|
2010-08-25 16:51:06 +08:00
|
|
|
if (ds->gui_timer == NULL) {
|
2009-01-22 03:28:13 +08:00
|
|
|
nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL);
|
|
|
|
qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock));
|
|
|
|
}
|
2010-02-11 07:29:55 +08:00
|
|
|
text_consoles_set_display(ds);
|
2009-01-17 04:23:27 +08:00
|
|
|
|
2009-04-06 02:43:41 +08:00
|
|
|
if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) {
|
|
|
|
fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n",
|
|
|
|
gdbstub_dev);
|
|
|
|
exit(1);
|
2007-07-02 21:20:17 +08:00
|
|
|
}
|
|
|
|
|
2009-09-26 03:42:41 +08:00
|
|
|
qdev_machine_creation_done();
|
|
|
|
|
2009-12-14 23:07:35 +08:00
|
|
|
if (rom_load_all() != 0) {
|
|
|
|
fprintf(stderr, "rom loading failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2009-10-01 22:42:33 +08:00
|
|
|
|
2010-12-20 13:33:35 +08:00
|
|
|
/* 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());
|
2010-12-08 19:35:08 +08:00
|
|
|
qemu_run_machine_init_done_notifiers();
|
|
|
|
|
2009-11-12 07:39:13 +08:00
|
|
|
qemu_system_reset();
|
2009-08-21 01:42:22 +08:00
|
|
|
if (loadvm) {
|
2010-02-17 23:24:10 +08:00
|
|
|
if (load_vmstate(loadvm) < 0) {
|
2009-08-21 01:42:22 +08:00
|
|
|
autostart = 0;
|
|
|
|
}
|
|
|
|
}
|
2004-10-03 21:29:03 +08:00
|
|
|
|
2009-07-25 04:20:23 +08:00
|
|
|
if (incoming) {
|
2010-06-09 20:10:54 +08:00
|
|
|
int ret = qemu_start_incoming_migration(incoming);
|
|
|
|
if (ret < 0) {
|
|
|
|
fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n",
|
|
|
|
incoming, ret);
|
|
|
|
exit(ret);
|
|
|
|
}
|
2009-08-09 19:39:20 +08:00
|
|
|
} else if (autostart) {
|
2009-03-06 07:01:01 +08:00
|
|
|
vm_start();
|
2009-08-09 19:39:20 +08:00
|
|
|
}
|
2006-12-22 03:46:43 +08:00
|
|
|
|
2010-06-10 17:42:28 +08:00
|
|
|
os_setup_post();
|
2006-12-22 10:11:31 +08:00
|
|
|
|
2004-04-01 03:00:16 +08:00
|
|
|
main_loop();
|
2004-04-04 20:56:28 +08:00
|
|
|
quit_timers();
|
2008-11-01 03:10:00 +08:00
|
|
|
net_cleanup();
|
2007-10-22 07:20:45 +08:00
|
|
|
|
2003-06-24 21:42:40 +08:00
|
|
|
return 0;
|
|
|
|
}
|