/*
* QEMU System Emulator
- *
+ *
* Copyright (c) 2003-2007 Fabrice Bellard
- *
+ *
* 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
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include "vl.h"
+#include "hw/hw.h"
+#include "hw/boards.h"
+#include "hw/usb.h"
+#include "hw/pcmcia.h"
+#include "hw/pc.h"
+#include "hw/fdc.h"
+#include "hw/audiodev.h"
+#include "hw/isa.h"
+#include "net.h"
+#include "console.h"
+#include "sysemu.h"
+#include "gdbstub.h"
+#include "qemu-timer.h"
+#include "qemu-char.h"
+#include "block.h"
+#include "audio/audio.h"
#include <unistd.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <dirent.h>
#include <netdb.h>
+#include <sys/select.h>
+#include <arpa/inet.h>
#ifdef _BSD
#include <sys/stat.h>
#ifndef __APPLE__
#include <libutil.h>
#endif
+#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
+#include <freebsd/stdlib.h>
#else
#ifndef __sun__
#include <linux/if.h>
#include <pty.h>
#include <malloc.h>
#include <linux/rtc.h>
+
+/* For the benefit of older linux systems which don't supply it,
+ we use a local copy of hpet.h. */
+/* #include <linux/hpet.h> */
+#include "hpet.h"
+
#include <linux/ppdev.h>
#include <linux/parport.h>
#else
#include <sys/stat.h>
#include <sys/ethernet.h>
#include <sys/sockio.h>
-#include <arpa/inet.h>
#include <netinet/arp.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <stropts.h>
#endif
#endif
+#else
+#include <winsock2.h>
+int inet_aton(const char *cp, struct in_addr *ia);
#endif
#if defined(CONFIG_SLIRP)
#include "exec-all.h"
#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"
+#define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown"
#ifdef __sun__
#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
#else
#define MAX_IOPORTS 65536
const char *bios_dir = CONFIG_QEMU_SHAREDIR;
-char phys_ram_file[1024];
+const char *bios_name = NULL;
void *ioport_opaque[MAX_IOPORTS];
IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
int nographic;
const char* keyboard_layout = NULL;
int64_t ticks_per_sec;
-int boot_device = 'c';
int ram_size;
int pit_min_timer_count = 0;
int nb_nics;
NICInfo nd_table[MAX_NICS];
-QEMUTimer *gui_timer;
int vm_running;
int rtc_utc = 1;
+int rtc_start_date = -1; /* -1 means now */
int cirrus_vga_enabled = 1;
int vmsvga_enabled = 0;
#ifdef TARGET_SPARC
int nb_option_roms;
int semihosting_enabled = 0;
int autostart = 1;
+#ifdef TARGET_ARM
+int old_param = 0;
+#endif
const char *qemu_name;
+int alt_grab = 0;
#ifdef TARGET_SPARC
unsigned int nb_prom_envs = 0;
const char *prom_envs[MAX_PROM_ENVS];
#endif
+#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)
+
/***********************************************************/
/* x86 ISA bus support */
target_phys_addr_t isa_mem_base = 0;
PicState2 *isa_pic;
-uint32_t default_ioport_readb(void *opaque, uint32_t address)
+static uint32_t default_ioport_readb(void *opaque, uint32_t address)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "unused inb: port=0x%04x\n", address);
return 0xff;
}
-void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
+static void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "unused outb: port=0x%04x data=0x%02x\n", address, data);
}
/* default is to make two byte accesses */
-uint32_t default_ioport_readw(void *opaque, uint32_t address)
+static uint32_t default_ioport_readw(void *opaque, uint32_t address)
{
uint32_t data;
data = ioport_read_table[0][address](ioport_opaque[address], address);
return data;
}
-void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
+static void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
{
ioport_write_table[0][address](ioport_opaque[address], address, data & 0xff);
address = (address + 1) & (MAX_IOPORTS - 1);
ioport_write_table[0][address](ioport_opaque[address], address, (data >> 8) & 0xff);
}
-uint32_t default_ioport_readl(void *opaque, uint32_t address)
+static uint32_t default_ioport_readl(void *opaque, uint32_t address)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "unused inl: port=0x%04x\n", address);
return 0xffffffff;
}
-void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
+static void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
{
#ifdef DEBUG_UNUSED_IOPORT
fprintf(stderr, "unused outl: port=0x%04x data=0x%02x\n", address, data);
#endif
}
-void init_ioports(void)
+static void init_ioports(void)
{
int i;
}
/* size is the word size in byte */
-int register_ioport_read(int start, int length, int size,
+int register_ioport_read(int start, int length, int size,
IOPortReadFunc *func, void *opaque)
{
int i, bsize;
}
/* size is the word size in byte */
-int register_ioport_write(int start, int length, int size,
+int register_ioport_write(int start, int length, int size,
IOPortWriteFunc *func, void *opaque)
{
int i, bsize;
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "outb: %04x %02x\n", addr, val);
-#endif
+#endif
ioport_write_table[0][addr](ioport_opaque[addr], addr, val);
#ifdef USE_KQEMU
if (env)
#ifdef DEBUG_IOPORT
if (loglevel & CPU_LOG_IOPORT)
fprintf(logfile, "outw: %04x %04x\n", addr, val);
-#endif
+#endif
ioport_write_table[1][addr](ioport_opaque[addr], addr, val);
#ifdef USE_KQEMU
if (env)
uint32_t high, low;
#else
uint32_t low, high;
-#endif
+#endif
} l;
} u, res;
uint64_t rl, rh;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000000000LL + ts.tv_nsec;
- } else
+ } else
#endif
{
/* XXX: using gettimeofday leads to problems if the date
/***********************************************************/
/* timers */
-
+
#define QEMU_TIMER_REALTIME 0
#define QEMU_TIMER_VIRTUAL 1
struct QEMUTimer *next;
};
-QEMUClock *rt_clock;
-QEMUClock *vm_clock;
+struct qemu_alarm_timer {
+ char const *name;
+ unsigned int flags;
+
+ int (*start)(struct qemu_alarm_timer *t);
+ void (*stop)(struct qemu_alarm_timer *t);
+ void (*rearm)(struct qemu_alarm_timer *t);
+ void *priv;
+};
+
+#define ALARM_FLAG_DYNTICKS 0x1
+
+static inline int alarm_has_dynticks(struct qemu_alarm_timer *t)
+{
+ return t->flags & ALARM_FLAG_DYNTICKS;
+}
+
+static void qemu_rearm_alarm_timer(struct qemu_alarm_timer *t)
+{
+ if (!alarm_has_dynticks(t))
+ return;
+
+ t->rearm(t);
+}
+
+/* TODO: MIN_TIMER_REARM_US should be optimized */
+#define MIN_TIMER_REARM_US 250
+
+static struct qemu_alarm_timer *alarm_timer;
-static QEMUTimer *active_timers[2];
#ifdef _WIN32
-static MMRESULT timerID;
-static HANDLE host_alarm = NULL;
-static unsigned int period = 1;
+
+struct qemu_alarm_win32 {
+ MMRESULT timerId;
+ HANDLE host_alarm;
+ unsigned int period;
+} alarm_win32_data = {0, NULL, -1};
+
+static int win32_start_timer(struct qemu_alarm_timer *t);
+static void win32_stop_timer(struct qemu_alarm_timer *t);
+static void win32_rearm_timer(struct qemu_alarm_timer *t);
+
+#else
+
+static int unix_start_timer(struct qemu_alarm_timer *t);
+static void unix_stop_timer(struct qemu_alarm_timer *t);
+
+#ifdef __linux__
+
+static int dynticks_start_timer(struct qemu_alarm_timer *t);
+static void dynticks_stop_timer(struct qemu_alarm_timer *t);
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t);
+
+static int hpet_start_timer(struct qemu_alarm_timer *t);
+static void hpet_stop_timer(struct qemu_alarm_timer *t);
+
+static int rtc_start_timer(struct qemu_alarm_timer *t);
+static void rtc_stop_timer(struct qemu_alarm_timer *t);
+
+#endif /* __linux__ */
+
+#endif /* _WIN32 */
+
+static struct qemu_alarm_timer alarm_timers[] = {
+#ifndef _WIN32
+#ifdef __linux__
+ {"dynticks", ALARM_FLAG_DYNTICKS, dynticks_start_timer,
+ dynticks_stop_timer, dynticks_rearm_timer, NULL},
+ /* HPET - if available - is preferred */
+ {"hpet", 0, hpet_start_timer, hpet_stop_timer, NULL, NULL},
+ /* ...otherwise try RTC */
+ {"rtc", 0, rtc_start_timer, rtc_stop_timer, NULL, NULL},
+#endif
+ {"unix", 0, unix_start_timer, unix_stop_timer, NULL, NULL},
#else
-/* frequency of the times() clock tick */
-static int timer_freq;
+ {"dynticks", ALARM_FLAG_DYNTICKS, win32_start_timer,
+ win32_stop_timer, win32_rearm_timer, &alarm_win32_data},
+ {"win32", 0, win32_start_timer,
+ win32_stop_timer, NULL, &alarm_win32_data},
#endif
+ {NULL, }
+};
+
+static void show_available_alarms()
+{
+ int i;
+
+ printf("Available alarm timers, in order of precedence:\n");
+ for (i = 0; alarm_timers[i].name; i++)
+ printf("%s\n", alarm_timers[i].name);
+}
-QEMUClock *qemu_new_clock(int type)
+static void configure_alarms(char const *opt)
+{
+ int i;
+ int cur = 0;
+ int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1;
+ char *arg;
+ char *name;
+
+ if (!strcmp(opt, "help")) {
+ show_available_alarms();
+ exit(0);
+ }
+
+ arg = strdup(opt);
+
+ /* Reorder the array */
+ name = strtok(arg, ",");
+ while (name) {
+ struct qemu_alarm_timer tmp;
+
+ for (i = 0; i < count && alarm_timers[i].name; i++) {
+ if (!strcmp(alarm_timers[i].name, name))
+ break;
+ }
+
+ if (i == count) {
+ fprintf(stderr, "Unknown clock %s\n", name);
+ goto next;
+ }
+
+ if (i < cur)
+ /* Ignore */
+ goto next;
+
+ /* Swap */
+ tmp = alarm_timers[i];
+ alarm_timers[i] = alarm_timers[cur];
+ alarm_timers[cur] = tmp;
+
+ cur++;
+next:
+ name = strtok(NULL, ",");
+ }
+
+ free(arg);
+
+ if (cur) {
+ /* Disable remaining timers */
+ for (i = cur; i < count; i++)
+ alarm_timers[i].name = NULL;
+ }
+
+ /* debug */
+ show_available_alarms();
+}
+
+QEMUClock *rt_clock;
+QEMUClock *vm_clock;
+
+static QEMUTimer *active_timers[2];
+
+static QEMUClock *qemu_new_clock(int type)
{
QEMUClock *clock;
clock = qemu_mallocz(sizeof(QEMUClock));
t = *pt;
if (!t)
break;
- if (t->expire_time > expire_time)
+ if (t->expire_time > expire_time)
break;
pt = &t->next;
}
static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t current_time)
{
QEMUTimer *ts;
-
+
for(;;) {
ts = *ptimer_head;
if (!ts || ts->expire_time > current_time)
/* remove timer from the list before calling the callback */
*ptimer_head = ts->next;
ts->next = NULL;
-
+
/* run the callback (the timer list can be modified) */
ts->cb(ts->opaque);
}
+ qemu_rearm_alarm_timer(alarm_timer);
}
int64_t qemu_get_clock(QEMUClock *clock)
}
#ifdef _WIN32
-void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
+void CALLBACK host_alarm_handler(UINT uTimerID, UINT uMsg,
DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
#else
static void host_alarm_handler(int host_signum)
last_clock = ti;
}
#endif
- if (qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
+ if (alarm_has_dynticks(alarm_timer) ||
+ qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
qemu_get_clock(vm_clock)) ||
qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock))) {
#ifdef _WIN32
- SetEvent(host_alarm);
+ struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;
+ SetEvent(data->host_alarm);
#endif
CPUState *env = cpu_single_env;
if (env) {
}
}
+static uint64_t qemu_next_deadline(void)
+{
+ int64_t nearest_delta_us = INT64_MAX;
+ int64_t vmdelta_us;
+
+ if (active_timers[QEMU_TIMER_REALTIME])
+ nearest_delta_us = (active_timers[QEMU_TIMER_REALTIME]->expire_time -
+ qemu_get_clock(rt_clock))*1000;
+
+ if (active_timers[QEMU_TIMER_VIRTUAL]) {
+ /* round up */
+ vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time -
+ qemu_get_clock(vm_clock)+999)/1000;
+ if (vmdelta_us < nearest_delta_us)
+ nearest_delta_us = vmdelta_us;
+ }
+
+ /* Avoid arming the timer to negative, zero, or too low values */
+ if (nearest_delta_us <= MIN_TIMER_REARM_US)
+ nearest_delta_us = MIN_TIMER_REARM_US;
+
+ return nearest_delta_us;
+}
+
#ifndef _WIN32
#if defined(__linux__)
#define RTC_FREQ 1024
-static int rtc_fd;
+static void enable_sigio_timer(int fd)
+{
+ struct sigaction act;
+
+ /* timer signal */
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = host_alarm_handler;
+
+ sigaction(SIGIO, &act, NULL);
+ fcntl(fd, F_SETFL, O_ASYNC);
+ fcntl(fd, F_SETOWN, getpid());
+}
+
+static int hpet_start_timer(struct qemu_alarm_timer *t)
+{
+ struct hpet_info info;
+ int r, fd;
+
+ fd = open("/dev/hpet", O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ /* Set frequency */
+ r = ioctl(fd, HPET_IRQFREQ, RTC_FREQ);
+ if (r < 0) {
+ fprintf(stderr, "Could not configure '/dev/hpet' to have a 1024Hz timer. This is not a fatal\n"
+ "error, but for better emulation accuracy type:\n"
+ "'echo 1024 > /proc/sys/dev/hpet/max-user-freq' as root.\n");
+ goto fail;
+ }
+
+ /* Check capabilities */
+ r = ioctl(fd, HPET_INFO, &info);
+ if (r < 0)
+ goto fail;
+
+ /* Enable periodic mode */
+ r = ioctl(fd, HPET_EPI, 0);
+ if (info.hi_flags && (r < 0))
+ goto fail;
+
+ /* Enable interrupt */
+ r = ioctl(fd, HPET_IE_ON, 0);
+ if (r < 0)
+ goto fail;
+
+ enable_sigio_timer(fd);
+ t->priv = (void *)(long)fd;
+
+ return 0;
+fail:
+ close(fd);
+ return -1;
+}
+
+static void hpet_stop_timer(struct qemu_alarm_timer *t)
+{
+ int fd = (long)t->priv;
+
+ close(fd);
+}
-static int start_rtc_timer(void)
+static int rtc_start_timer(struct qemu_alarm_timer *t)
{
- rtc_fd = open("/dev/rtc", O_RDONLY);
+ int rtc_fd;
+
+ TFR(rtc_fd = open("/dev/rtc", O_RDONLY));
if (rtc_fd < 0)
return -1;
if (ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
close(rtc_fd);
return -1;
}
- pit_min_timer_count = PIT_FREQ / RTC_FREQ;
+
+ enable_sigio_timer(rtc_fd);
+
+ t->priv = (void *)(long)rtc_fd;
+
return 0;
}
-#else
+static void rtc_stop_timer(struct qemu_alarm_timer *t)
+{
+ int rtc_fd = (long)t->priv;
-static int start_rtc_timer(void)
+ close(rtc_fd);
+}
+
+static int dynticks_start_timer(struct qemu_alarm_timer *t)
{
- return -1;
+ struct sigevent ev;
+ timer_t host_timer;
+ struct sigaction act;
+
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = host_alarm_handler;
+
+ sigaction(SIGALRM, &act, NULL);
+
+ ev.sigev_value.sival_int = 0;
+ ev.sigev_notify = SIGEV_SIGNAL;
+ ev.sigev_signo = SIGALRM;
+
+ if (timer_create(CLOCK_REALTIME, &ev, &host_timer)) {
+ perror("timer_create");
+
+ /* disable dynticks */
+ fprintf(stderr, "Dynamic Ticks disabled\n");
+
+ return -1;
+ }
+
+ t->priv = (void *)host_timer;
+
+ return 0;
}
-#endif /* !defined(__linux__) */
+static void dynticks_stop_timer(struct qemu_alarm_timer *t)
+{
+ timer_t host_timer = (timer_t)t->priv;
-#endif /* !defined(_WIN32) */
+ timer_delete(host_timer);
+}
-static void init_timer_alarm(void)
+static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
{
-#ifdef _WIN32
- {
- int count=0;
- TIMECAPS tc;
-
- ZeroMemory(&tc, sizeof(TIMECAPS));
- timeGetDevCaps(&tc, sizeof(TIMECAPS));
- if (period < tc.wPeriodMin)
- period = tc.wPeriodMin;
- timeBeginPeriod(period);
- timerID = timeSetEvent(1, // interval (ms)
- period, // resolution
- host_alarm_handler, // function
- (DWORD)&count, // user parameter
- TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
- if( !timerID ) {
- perror("failed timer alarm");
- exit(1);
- }
- host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
- if (!host_alarm) {
- perror("failed CreateEvent");
- exit(1);
- }
- qemu_add_wait_object(host_alarm, NULL, NULL);
+ timer_t host_timer = (timer_t)t->priv;
+ struct itimerspec timeout;
+ int64_t nearest_delta_us = INT64_MAX;
+ int64_t current_us;
+
+ if (!active_timers[QEMU_TIMER_REALTIME] &&
+ !active_timers[QEMU_TIMER_VIRTUAL])
+ return;
+
+ nearest_delta_us = qemu_next_deadline();
+
+ /* check whether a timer is already running */
+ if (timer_gettime(host_timer, &timeout)) {
+ perror("gettime");
+ fprintf(stderr, "Internal timer error: aborting\n");
+ exit(1);
}
- pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000;
-#else
- {
- struct sigaction act;
- struct itimerval itv;
-
- /* get times() syscall frequency */
- timer_freq = sysconf(_SC_CLK_TCK);
-
- /* timer signal */
- sigfillset(&act.sa_mask);
- act.sa_flags = 0;
-#if defined (TARGET_I386) && defined(USE_CODE_COPY)
- act.sa_flags |= SA_ONSTACK;
-#endif
- act.sa_handler = host_alarm_handler;
- sigaction(SIGALRM, &act, NULL);
-
- itv.it_interval.tv_sec = 0;
- itv.it_interval.tv_usec = 999; /* for i386 kernel 2.6 to get 1 ms */
- itv.it_value.tv_sec = 0;
- itv.it_value.tv_usec = 10 * 1000;
- setitimer(ITIMER_REAL, &itv, NULL);
- /* we probe the tick duration of the kernel to inform the user if
- the emulated kernel requested a too high timer frequency */
- getitimer(ITIMER_REAL, &itv);
+ current_us = timeout.it_value.tv_sec * 1000000 + timeout.it_value.tv_nsec/1000;
+ if (current_us && current_us <= nearest_delta_us)
+ return;
-#if defined(__linux__)
- /* XXX: force /dev/rtc usage because even 2.6 kernels may not
- have timers with 1 ms resolution. The correct solution will
- be to use the POSIX real time timers available in recent
- 2.6 kernels */
- if (itv.it_interval.tv_usec > 1000 || 1) {
- /* try to use /dev/rtc to have a faster timer */
- if (start_rtc_timer() < 0)
- goto use_itimer;
- /* disable itimer */
- itv.it_interval.tv_sec = 0;
- itv.it_interval.tv_usec = 0;
- itv.it_value.tv_sec = 0;
- itv.it_value.tv_usec = 0;
- setitimer(ITIMER_REAL, &itv, NULL);
-
- /* use the RTC */
- sigaction(SIGIO, &act, NULL);
- fcntl(rtc_fd, F_SETFL, O_ASYNC);
- fcntl(rtc_fd, F_SETOWN, getpid());
- } else
-#endif /* defined(__linux__) */
- {
- use_itimer:
- pit_min_timer_count = ((uint64_t)itv.it_interval.tv_usec *
- PIT_FREQ) / 1000000;
- }
+ timeout.it_interval.tv_sec = 0;
+ timeout.it_interval.tv_nsec = 0; /* 0 for one-shot timer */
+ timeout.it_value.tv_sec = nearest_delta_us / 1000000;
+ timeout.it_value.tv_nsec = (nearest_delta_us % 1000000) * 1000;
+ if (timer_settime(host_timer, 0 /* RELATIVE */, &timeout, NULL)) {
+ perror("settime");
+ fprintf(stderr, "Internal timer error: aborting\n");
+ exit(1);
}
-#endif
}
-void quit_timers(void)
+#endif /* defined(__linux__) */
+
+static int unix_start_timer(struct qemu_alarm_timer *t)
{
+ struct sigaction act;
+ struct itimerval itv;
+ int err;
+
+ /* timer signal */
+ sigfillset(&act.sa_mask);
+ act.sa_flags = 0;
+ act.sa_handler = host_alarm_handler;
+
+ sigaction(SIGALRM, &act, NULL);
+
+ itv.it_interval.tv_sec = 0;
+ /* for i386 kernel 2.6 to get 1 ms */
+ itv.it_interval.tv_usec = 999;
+ itv.it_value.tv_sec = 0;
+ itv.it_value.tv_usec = 10 * 1000;
+
+ err = setitimer(ITIMER_REAL, &itv, NULL);
+ if (err)
+ return -1;
+
+ return 0;
+}
+
+static void unix_stop_timer(struct qemu_alarm_timer *t)
+{
+ struct itimerval itv;
+
+ memset(&itv, 0, sizeof(itv));
+ setitimer(ITIMER_REAL, &itv, NULL);
+}
+
+#endif /* !defined(_WIN32) */
+
#ifdef _WIN32
- timeKillEvent(timerID);
- timeEndPeriod(period);
- if (host_alarm) {
- CloseHandle(host_alarm);
- host_alarm = NULL;
+
+static int win32_start_timer(struct qemu_alarm_timer *t)
+{
+ TIMECAPS tc;
+ struct qemu_alarm_win32 *data = t->priv;
+ UINT flags;
+
+ data->host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!data->host_alarm) {
+ perror("Failed CreateEvent");
+ return -1;
}
-#endif
+
+ memset(&tc, 0, sizeof(tc));
+ timeGetDevCaps(&tc, sizeof(tc));
+
+ if (data->period < tc.wPeriodMin)
+ data->period = tc.wPeriodMin;
+
+ timeBeginPeriod(data->period);
+
+ flags = TIME_CALLBACK_FUNCTION;
+ if (alarm_has_dynticks(t))
+ flags |= TIME_ONESHOT;
+ else
+ flags |= TIME_PERIODIC;
+
+ data->timerId = timeSetEvent(1, // interval (ms)
+ data->period, // resolution
+ host_alarm_handler, // function
+ (DWORD)t, // parameter
+ flags);
+
+ if (!data->timerId) {
+ perror("Failed to initialize win32 alarm timer");
+
+ timeEndPeriod(data->period);
+ CloseHandle(data->host_alarm);
+ return -1;
+ }
+
+ qemu_add_wait_object(data->host_alarm, NULL, NULL);
+
+ return 0;
+}
+
+static void win32_stop_timer(struct qemu_alarm_timer *t)
+{
+ struct qemu_alarm_win32 *data = t->priv;
+
+ timeKillEvent(data->timerId);
+ timeEndPeriod(data->period);
+
+ CloseHandle(data->host_alarm);
+}
+
+static void win32_rearm_timer(struct qemu_alarm_timer *t)
+{
+ struct qemu_alarm_win32 *data = t->priv;
+ uint64_t nearest_delta_us;
+
+ if (!active_timers[QEMU_TIMER_REALTIME] &&
+ !active_timers[QEMU_TIMER_VIRTUAL])
+ return;
+
+ nearest_delta_us = qemu_next_deadline();
+ nearest_delta_us /= 1000;
+
+ timeKillEvent(data->timerId);
+
+ data->timerId = timeSetEvent(1,
+ data->period,
+ host_alarm_handler,
+ (DWORD)t,
+ TIME_ONESHOT | TIME_PERIODIC);
+
+ if (!data->timerId) {
+ perror("Failed to re-arm win32 alarm timer");
+
+ timeEndPeriod(data->period);
+ CloseHandle(data->host_alarm);
+ exit(1);
+ }
+}
+
+#endif /* _WIN32 */
+
+static void init_timer_alarm(void)
+{
+ struct qemu_alarm_timer *t;
+ int i, err = -1;
+
+ for (i = 0; alarm_timers[i].name; i++) {
+ t = &alarm_timers[i];
+
+ err = t->start(t);
+ if (!err)
+ break;
+ }
+
+ if (err) {
+ fprintf(stderr, "Unable to find any suitable alarm timer.\n");
+ fprintf(stderr, "Terminating\n");
+ exit(1);
+ }
+
+ alarm_timer = t;
+}
+
+static void quit_timers(void)
+{
+ alarm_timer->stop(alarm_timer);
+ alarm_timer = NULL;
}
/***********************************************************/
s->chr_send_event(s, event);
}
-void qemu_chr_add_handlers(CharDriverState *s,
- IOCanRWHandler *fd_can_read,
+void qemu_chr_add_handlers(CharDriverState *s,
+ IOCanRWHandler *fd_can_read,
IOReadHandler *fd_read,
IOEventHandler *fd_event,
void *opaque)
if (s->chr_update_read_handler)
s->chr_update_read_handler(s);
}
-
+
static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
return len;
d->mux_cnt++;
}
-CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
{
CharDriverState *chr;
MuxDriver *d;
static int send_all(int fd, const uint8_t *buf, int len1)
{
int ret, len;
-
+
len = len1;
while (len > 0) {
ret = send(fd, buf, len, 0);
FDCharDriver *s = chr->opaque;
int size, len;
uint8_t buf[1024];
-
+
len = sizeof(buf);
if (len > s->max_size)
len = s->max_size;
if (s->fd_in >= 0) {
if (nographic && s->fd_in == 0) {
} else {
- qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
+ qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
fd_chr_read, NULL, chr);
}
}
{
int fd_out;
- fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666);
+ TFR(fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
if (fd_out < 0)
return NULL;
return qemu_chr_open_fd(-1, fd_out);
snprintf(filename_in, 256, "%s.in", filename);
snprintf(filename_out, 256, "%s.out", filename);
- fd_in = open(filename_in, O_RDWR | O_BINARY);
- fd_out = open(filename_out, O_RDWR | O_BINARY);
+ TFR(fd_in = open(filename_in, O_RDWR | O_BINARY));
+ TFR(fd_out = open(filename_out, O_RDWR | O_BINARY));
if (fd_in < 0 || fd_out < 0) {
if (fd_in >= 0)
close(fd_in);
if (fd_out >= 0)
close(fd_out);
- fd_in = fd_out = open(filename, O_RDWR | O_BINARY);
+ TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY));
if (fd_in < 0)
return NULL;
}
tty.c_cflag |= CS8;
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 0;
-
+
tcsetattr (0, TCSANOW, &tty);
atexit(term_exit);
return chr;
}
-#if defined(__linux__)
+#if defined(__linux__) || defined(__sun__)
static CharDriverState *qemu_chr_open_pty(void)
{
struct termios tty;
char slave_name[1024];
int master_fd, slave_fd;
-
+
+#if defined(__linux__)
/* Not satisfying */
if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) {
return NULL;
}
-
+#endif
+
/* Disabling local echo and line-buffered output */
tcgetattr (master_fd, &tty);
tty.c_lflag &= ~(ECHO|ICANON|ISIG);
return qemu_chr_open_fd(master_fd, master_fd);
}
-static void tty_serial_init(int fd, int speed,
+static void tty_serial_init(int fd, int speed,
int parity, int data_bits, int stop_bits)
{
struct termios tty;
speed_t spd;
#if 0
- printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
+ printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
speed, parity, data_bits, stop_bits);
#endif
tcgetattr (fd, &tty);
}
if (stop_bits == 2)
tty.c_cflag |= CSTOPB;
-
+
tcsetattr (fd, TCSANOW, &tty);
}
static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
{
FDCharDriver *s = chr->opaque;
-
+
switch(cmd) {
case CHR_IOCTL_SERIAL_SET_PARAMS:
{
QEMUSerialSetParams *ssp = arg;
- tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
+ tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
ssp->data_bits, ssp->stop_bits);
}
break;
CharDriverState *chr;
int fd;
- fd = open(filename, O_RDWR | O_NONBLOCK);
- if (fd < 0)
- return NULL;
+ TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
fcntl(fd, F_SETFL, O_NONBLOCK);
tty_serial_init(fd, 115200, 'N', 8, 1);
chr = qemu_chr_open_fd(fd, fd);
- if (!chr)
+ if (!chr) {
+ close(fd);
return NULL;
+ }
chr->chr_ioctl = tty_serial_ioctl;
qemu_chr_reset(chr);
return chr;
}
+#else /* ! __linux__ && ! __sun__ */
+static CharDriverState *qemu_chr_open_pty(void)
+{
+ return NULL;
+}
+#endif /* __linux__ || __sun__ */
+#if defined(__linux__)
typedef struct {
int fd;
int mode;
ParallelCharDriver *drv;
int fd;
- fd = open(filename, O_RDWR);
+ TFR(fd = open(filename, O_RDWR));
if (fd < 0)
return NULL;
return chr;
}
+#endif /* __linux__ */
-#else
-static CharDriverState *qemu_chr_open_pty(void)
-{
- return NULL;
-}
-#endif
-
-#endif /* !defined(_WIN32) */
+#else /* _WIN32 */
-#ifdef _WIN32
typedef struct {
int max_size;
HANDLE hcom, hrecv, hsend;
COMSTAT comstat;
DWORD size;
DWORD err;
-
+
s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!s->hsend) {
fprintf(stderr, "Failed CreateEvent\n");
s->hcom = NULL;
goto fail;
}
-
+
if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
fprintf(stderr, "Failed SetupComm\n");
goto fail;
}
-
+
ZeroMemory(&comcfg, sizeof(COMMCONFIG));
size = sizeof(COMMCONFIG);
GetDefaultCommConfig(filename, &comcfg, &size);
fprintf(stderr, "Failed SetCommTimeouts\n");
goto fail;
}
-
+
if (!ClearCommError(s->hcom, &err, &comstat)) {
fprintf(stderr, "Failed ClearCommError\n");
goto fail;
int ret, err;
uint8_t buf[1024];
DWORD size;
-
+
ZeroMemory(&s->orecv, sizeof(s->orecv));
s->orecv.hEvent = s->hrecv;
ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
s->len = s->max_size;
if (s->len == 0)
return;
-
+
win_chr_readfile(chr);
}
WinCharState *s = chr->opaque;
COMSTAT status;
DWORD comerr;
-
+
ClearCommError(s->hcom, &comerr, &status);
if (status.cbInQue > 0) {
s->len = status.cbInQue;
{
CharDriverState *chr;
WinCharState *s;
-
+
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
int ret;
DWORD size;
char openname[256];
-
+
s->fpipe = TRUE;
s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
fprintf(stderr, "Failed CreateEvent\n");
goto fail;
}
-
+
snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename);
s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
chr->opaque = s;
chr->chr_write = win_chr_write;
chr->chr_close = win_chr_close;
-
+
if (win_chr_pipe_init(chr, filename) < 0) {
free(s);
free(chr);
static CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
{
HANDLE fd_out;
-
+
fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (fd_out == INVALID_HANDLE_VALUE)
return qemu_chr_open_win_file(fd_out);
}
-#endif
+#endif /* !_WIN32 */
/***********************************************************/
/* UDP Net console */
qemu_free(s);
}
-static CharDriverState *qemu_chr_open_tcp(const char *host_str,
+static CharDriverState *qemu_chr_open_tcp(const char *host_str,
int is_telnet,
int is_unix)
{
else
#endif
fd = socket(PF_INET, SOCK_STREAM, 0);
-
- if (fd < 0)
+
+ if (fd < 0)
goto fail;
if (!is_waitconnect)
val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
}
-
+
ret = bind(fd, addr, addrlen);
if (ret < 0)
goto fail;
else
qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr);
}
-
+
if (is_listen && is_waitconnect) {
printf("QEMU waiting for connection on: %s\n", host_str);
tcp_chr_accept(chr);
const char *p;
if (!strcmp(filename, "vc")) {
- return text_console_init(&display_state);
+ return text_console_init(&display_state, 0);
+ } else if (strstart(filename, "vc:", &p)) {
+ return text_console_init(&display_state, p);
} else if (!strcmp(filename, "null")) {
return qemu_chr_open_null();
- } else
+ } else
if (strstart(filename, "tcp:", &p)) {
return qemu_chr_open_tcp(p, 0, 0);
} else
return qemu_chr_open_pty();
} else if (!strcmp(filename, "stdio")) {
return qemu_chr_open_stdio();
- } else
-#endif
+ } else
#if defined(__linux__)
if (strstart(filename, "/dev/parport", NULL)) {
return qemu_chr_open_pp(filename);
- } else
+ } else
+#endif
+#if defined(__linux__) || defined(__sun__)
if (strstart(filename, "/dev/", NULL)) {
return qemu_chr_open_tty(filename);
- } else
+ } else
#endif
-#ifdef _WIN32
+#else /* !_WIN32 */
if (strstart(filename, "COM", NULL)) {
return qemu_chr_open_win(filename);
} else
/***********************************************************/
/* network device redirectors */
-void hex_dump(FILE *f, const uint8_t *buf, int size)
+__attribute__ (( unused ))
+static void hex_dump(FILE *f, const uint8_t *buf, int size)
{
int len, i, j, c;
for(i = 0; i < 6; i++) {
macaddr[i] = strtol(p, (char **)&p, 16);
if (i == 5) {
- if (*p != '\0')
+ if (*p != '\0')
return -1;
} else {
- if (*p != ':')
+ if (*p != ':')
return -1;
p++;
}
for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
if (vc != vc1) {
- if (vc->fd_can_read && !vc->fd_can_read(vc->opaque))
- return 0;
+ if (vc->fd_can_read && vc->fd_can_read(vc->opaque))
+ return 1;
}
}
- return 1;
+ return 0;
}
void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)
slirp_inited = 1;
slirp_init();
}
- slirp_vc = qemu_new_vlan_client(vlan,
+ slirp_vc = qemu_new_vlan_client(vlan,
slirp_receive, NULL, NULL);
snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector");
return 0;
const char *p;
struct in_addr guest_addr;
int host_port, guest_port;
-
+
if (!slirp_inited) {
slirp_inited = 1;
slirp_init();
}
if (!inet_aton(buf, &guest_addr))
goto fail;
-
+
guest_port = strtol(p, &r, 0);
if (r == p)
goto fail;
-
+
if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) {
fprintf(stderr, "qemu: could not set up redirection\n");
exit(1);
fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n");
exit(1);
}
-
+
#ifndef _WIN32
char smb_dir[1024];
break;
if (strcmp(de->d_name, ".") != 0 &&
strcmp(de->d_name, "..") != 0) {
- snprintf(filename, sizeof(filename), "%s/%s",
+ snprintf(filename, sizeof(filename), "%s/%s",
smb_dir, de->d_name);
unlink(filename);
}
}
/* automatic user mode samba server configuration */
-void net_slirp_smb(const char *exported_dir)
+static void net_slirp_smb(const char *exported_dir)
{
char smb_conf[1024];
char smb_cmdline[1024];
exit(1);
}
snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf");
-
+
f = fopen(smb_conf, "w");
if (!f) {
fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf);
exit(1);
}
- fprintf(f,
+ fprintf(f,
"[global]\n"
"private dir=%s\n"
"smb ports=0\n"
snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
SMBD_COMMAND, smb_conf);
-
+
slirp_add_exec(0, smb_cmdline, 4, 139);
}
#endif /* !defined(_WIN32) */
+void do_info_slirp(void)
+{
+ slirp_stats();
+}
#endif /* CONFIG_SLIRP */
typedef struct TAPState {
VLANClientState *vc;
int fd;
+ char down_script[1024];
} TAPState;
static void tap_receive(void *opaque, const uint8_t *buf, int size)
return s;
}
-#ifdef _BSD
+#if defined (_BSD) || defined (__FreeBSD_kernel__)
static int tap_open(char *ifname, int ifname_size)
{
int fd;
char *dev;
struct stat s;
- fd = open("/dev/tap", O_RDWR);
+ TFR(fd = open("/dev/tap", O_RDWR));
if (fd < 0) {
fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
return -1;
}
#elif defined(__sun__)
#define TUNNEWPPA (('T'<<16) | 0x0001)
-/*
- * Allocate TAP device, returns opened fd.
+/*
+ * Allocate TAP device, returns opened fd.
* Stores dev name in the first arg(must be large enough).
- */
+ */
int tap_alloc(char *dev)
{
int tap_fd, if_fd, ppa = -1;
memset(&ifr, 0x0, sizeof(ifr));
if( *dev ){
- ptr = dev;
- while( *ptr && !isdigit((int)*ptr) ) ptr++;
+ ptr = dev;
+ while( *ptr && !isdigit((int)*ptr) ) ptr++;
ppa = atoi(ptr);
}
if( ip_fd )
close(ip_fd);
- if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
+ TFR(ip_fd = open("/dev/udp", O_RDWR, 0));
+ if (ip_fd < 0) {
syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");
return -1;
}
- if( (tap_fd = open("/dev/tap", O_RDWR, 0)) < 0){
+ TFR(tap_fd = open("/dev/tap", O_RDWR, 0));
+ if (tap_fd < 0) {
syslog(LOG_ERR, "Can't open /dev/tap");
return -1;
}
if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
syslog (LOG_ERR, "Can't assign new interface");
- if( (if_fd = open("/dev/tap", O_RDWR, 0)) < 0){
+ TFR(if_fd = open("/dev/tap", O_RDWR, 0));
+ if (if_fd < 0) {
syslog(LOG_ERR, "Can't open /dev/tap (2)");
return -1;
}
if (ioctl (ip_fd, I_PUSH, "arp") < 0)
syslog (LOG_ERR, "Can't push ARP module (3)\n");
/* Open arp_fd */
- if ((arp_fd = open ("/dev/tap", O_RDWR, 0)) < 0)
+ TFR(arp_fd = open ("/dev/tap", O_RDWR, 0));
+ if (arp_fd < 0)
syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");
/* Set ifname to arp */
{
struct ifreq ifr;
int fd, ret;
-
- fd = open("/dev/net/tun", O_RDWR);
+
+ TFR(fd = open("/dev/net/tun", O_RDWR));
if (fd < 0) {
fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
return -1;
}
#endif
-static int net_tap_init(VLANState *vlan, const char *ifname1,
- const char *setup_script)
+static int launch_script(const char *setup_script, const char *ifname, int fd)
{
- TAPState *s;
- int pid, status, fd;
+ int pid, status;
char *args[3];
char **parg;
- char ifname[128];
- if (ifname1 != NULL)
- pstrcpy(ifname, sizeof(ifname), ifname1);
- else
- ifname[0] = '\0';
- fd = tap_open(ifname, sizeof(ifname));
- if (fd < 0)
- return -1;
-
- if (!setup_script || !strcmp(setup_script, "no"))
- setup_script = "";
- if (setup_script[0] != '\0') {
- /* try to launch network init script */
+ /* try to launch network script */
pid = fork();
if (pid >= 0) {
if (pid == 0) {
parg = args;
*parg++ = (char *)setup_script;
- *parg++ = ifname;
+ *parg++ = (char *)ifname;
*parg++ = NULL;
execv(setup_script, args);
_exit(1);
return -1;
}
}
+ return 0;
+}
+
+static int net_tap_init(VLANState *vlan, const char *ifname1,
+ const char *setup_script, const char *down_script)
+{
+ TAPState *s;
+ int fd;
+ char ifname[128];
+
+ if (ifname1 != NULL)
+ pstrcpy(ifname, sizeof(ifname), ifname1);
+ else
+ ifname[0] = '\0';
+ TFR(fd = tap_open(ifname, sizeof(ifname)));
+ if (fd < 0)
+ return -1;
+
+ if (!setup_script || !strcmp(setup_script, "no"))
+ setup_script = "";
+ if (setup_script[0] != '\0') {
+ if (launch_script(setup_script, ifname, fd))
+ return -1;
}
s = net_tap_fd_init(vlan, fd);
if (!s)
return -1;
- snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+ snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"tap: ifname=%s setup_script=%s", ifname, setup_script);
+ if (down_script && strcmp(down_script, "no"))
+ snprintf(s->down_script, sizeof(s->down_script), "%s", down_script);
return 0;
}
static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size)
{
NetSocketState *s = opaque;
- sendto(s->fd, buf, size, 0,
+ sendto(s->fd, buf, size, 0,
(struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
}
size = recv(s->fd, buf1, sizeof(buf1), 0);
if (size < 0) {
err = socket_error();
- if (err != EWOULDBLOCK)
+ if (err != EWOULDBLOCK)
goto eoc;
} else if (size == 0) {
/* end of connection */
int size;
size = recv(s->fd, s->buf, sizeof(s->buf), 0);
- if (size < 0)
+ if (size < 0)
return;
if (size == 0) {
/* end of connection */
int val, ret;
if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
- inet_ntoa(mcastaddr->sin_addr),
+ inet_ntoa(mcastaddr->sin_addr),
(int)ntohl(mcastaddr->sin_addr.s_addr));
return -1;
}
val = 1;
- ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(const char *)&val, sizeof(val));
if (ret < 0) {
perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
perror("bind");
goto fail;
}
-
+
/* Add host to multicast group */
imr.imr_multiaddr = mcastaddr->sin_addr;
imr.imr_interface.s_addr = htonl(INADDR_ANY);
- ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const char *)&imr, sizeof(struct ip_mreq));
if (ret < 0) {
perror("setsockopt(IP_ADD_MEMBERSHIP)");
/* Force mcast msgs to loopback (eg. several QEMUs in same host */
val = 1;
- ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
+ ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
(const char *)&val, sizeof(val));
if (ret < 0) {
perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
socket_set_nonblock(fd);
return fd;
fail:
- if (fd >= 0)
+ if (fd >= 0)
closesocket(fd);
return -1;
}
-static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
+static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
int is_connected)
{
struct sockaddr_in saddr;
NetSocketState *s;
/* fd passed: multicast: "learn" dgram_dst address from bound address and save it
- * Because this may be "shared" socket from a "master" process, datagrams would be recv()
+ * Because this may be "shared" socket from a "master" process, datagrams would be recv()
* by ONLY ONE process: we must "clone" this dgram socket --jjo
*/
/* clone newfd to fd, close newfd */
dup2(newfd, fd);
close(newfd);
-
+
} else {
fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
fd, strerror(errno));
if (is_connected) s->dgram_dst=saddr;
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "socket: fd=%d (%s mcast=%s:%d)",
+ "socket: fd=%d (%s mcast=%s:%d)",
fd, is_connected? "cloned" : "",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
return s;
qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
}
-static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,
+static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,
int is_connected)
{
NetSocketState *s;
if (!s)
return NULL;
s->fd = fd;
- s->vc = qemu_new_vlan_client(vlan,
+ s->vc = qemu_new_vlan_client(vlan,
net_socket_receive, NULL, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
"socket: fd=%d", fd);
return s;
}
-static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
+static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
int is_connected)
{
int so_type=-1, optlen=sizeof(so_type);
static void net_socket_accept(void *opaque)
{
- NetSocketListenState *s = opaque;
+ NetSocketListenState *s = opaque;
NetSocketState *s1;
struct sockaddr_in saddr;
socklen_t len;
break;
}
}
- s1 = net_socket_fd_init(s->vlan, fd, 1);
+ s1 = net_socket_fd_init(s->vlan, fd, 1);
if (!s1) {
closesocket(fd);
} else {
snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
- "socket: connection from %s:%d",
+ "socket: connection from %s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
}
}
if (parse_host_port(&saddr, host_str) < 0)
return -1;
-
+
s = qemu_mallocz(sizeof(NetSocketListenState));
if (!s)
return -1;
/* allow fast reuse */
val = 1;
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
-
+
ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
if (ret < 0) {
perror("bind");
if (!s)
return -1;
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "socket: connect to %s:%d",
+ "socket: connect to %s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
return 0;
}
return -1;
s->dgram_dst = saddr;
-
+
snprintf(s->vc->info_str, sizeof(s->vc->info_str),
- "socket: mcast=%s:%d",
+ "socket: mcast=%s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
return 0;
#else
if (!strcmp(device, "tap")) {
char ifname[64];
- char setup_script[1024];
+ char setup_script[1024], down_script[1024];
int fd;
vlan->nb_host_devs++;
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) {
pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT);
}
- ret = net_tap_init(vlan, ifname, setup_script);
+ if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) {
+ pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT);
+ }
+ ret = net_tap_init(vlan, ifname, setup_script, down_script);
}
} else
#endif
if (ret < 0) {
fprintf(stderr, "Could not initialize device '%s'\n", device);
}
-
+
return ret;
}
} else if (!strcmp(devname, "mouse")) {
dev = usb_mouse_init();
} else if (!strcmp(devname, "tablet")) {
- dev = usb_tablet_init();
+ dev = usb_tablet_init();
+ } else if (!strcmp(devname, "keyboard")) {
+ dev = usb_keyboard_init();
} else if (strstart(devname, "disk:", &p)) {
dev = usb_msd_init(p);
+ } else if (!strcmp(devname, "wacom-tablet")) {
+ dev = usb_wacom_init();
} else {
return -1;
}
return -1;
p = strchr(devname, '.');
- if (!p)
+ if (!p)
return -1;
bus_num = strtoul(devname, NULL, 0);
addr = strtoul(p + 1, NULL, 0);
{
int ret;
ret = usb_device_add(devname);
- if (ret < 0)
+ if (ret < 0)
term_printf("Could not add USB device '%s'\n", devname);
}
{
int ret;
ret = usb_device_del(devname);
- if (ret < 0)
+ if (ret < 0)
term_printf("Could not remove USB device '%s'\n", devname);
}
if (!dev)
continue;
switch(dev->speed) {
- case USB_SPEED_LOW:
- speed_str = "1.5";
+ case USB_SPEED_LOW:
+ speed_str = "1.5";
break;
- case USB_SPEED_FULL:
- speed_str = "12";
+ case USB_SPEED_FULL:
+ speed_str = "12";
break;
- case USB_SPEED_HIGH:
- speed_str = "480";
+ case USB_SPEED_HIGH:
+ speed_str = "480";
break;
default:
- speed_str = "?";
+ speed_str = "?";
break;
}
- term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n",
+ term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n",
0, dev->addr, speed_str, dev->devname);
}
}
static void dumb_refresh(DisplayState *ds)
{
+#if defined(CONFIG_SDL)
vga_hw_update();
+#endif
}
-void dumb_display_init(DisplayState *ds)
+static void dumb_display_init(DisplayState *ds)
{
ds->data = NULL;
ds->linesize = 0;
/* XXX: fd_read_poll should be suppressed, but an API change is
necessary in the character devices to suppress fd_can_read(). */
-int qemu_set_fd_handler2(int fd,
- IOCanRWHandler *fd_read_poll,
- IOHandler *fd_read,
- IOHandler *fd_write,
+int qemu_set_fd_handler2(int fd,
+ IOCanRWHandler *fd_read_poll,
+ IOHandler *fd_read,
+ IOHandler *fd_write,
void *opaque)
{
IOHandlerRecord **pioh, *ioh;
return 0;
}
-int qemu_set_fd_handler(int fd,
- IOHandler *fd_read,
- IOHandler *fd_write,
+int qemu_set_fd_handler(int fd,
+ IOHandler *fd_read,
+ IOHandler *fd_write,
void *opaque)
{
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
} WaitObjects;
static WaitObjects wait_objects = {0};
-
+
int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
{
WaitObjects *w = &wait_objects;
w->events[i] = w->events[i + 1];
w->func[i] = w->func[i + 1];
w->opaque[i] = w->opaque[i + 1];
- }
+ }
}
if (found)
w->num--;
return NULL;
}
-QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable)
+static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable)
{
QEMUFile *f;
fseek(f->outfile, f->buf_offset, SEEK_SET);
fwrite(f->buf, 1, f->buf_index, f->outfile);
} else {
- bdrv_pwrite(f->bs, f->base_offset + f->buf_offset,
+ bdrv_pwrite(f->bs, f->base_offset + f->buf_offset,
f->buf, f->buf_index);
}
f->buf_offset += f->buf_index;
if (len < 0)
len = 0;
} else {
- len = bdrv_pread(f->bs, f->base_offset + f->buf_offset,
+ len = bdrv_pread(f->bs, f->base_offset + f->buf_offset,
f->buf, IO_BUF_SIZE);
if (len < 0)
len = 0;
static SaveStateEntry *first_se;
-int register_savevm(const char *idstr,
- int instance_id,
+int register_savevm(const char *idstr,
+ int instance_id,
int version_id,
SaveStateHandler *save_state,
LoadStateHandler *load_state,
#define QEMU_VM_FILE_MAGIC 0x5145564d
#define QEMU_VM_FILE_VERSION 0x00000002
-int qemu_savevm_state(QEMUFile *f)
+static int qemu_savevm_state(QEMUFile *f)
{
SaveStateEntry *se;
int len, ret;
/* record size: filled later */
len_pos = qemu_ftell(f);
qemu_put_be32(f, 0);
-
se->save_state(f, se->opaque);
/* fill record size */
SaveStateEntry *se;
for(se = first_se; se != NULL; se = se->next) {
- if (!strcmp(se->idstr, idstr) &&
+ if (!strcmp(se->idstr, idstr) &&
instance_id == se->instance_id)
return se;
}
return NULL;
}
-int qemu_loadvm_state(QEMUFile *f)
+static int qemu_loadvm_state(QEMUFile *f)
{
SaveStateEntry *se;
int len, ret, instance_id, record_len, version_id;
int64_t total_len, end_pos, cur_pos;
unsigned int v;
char idstr[256];
-
+
v = qemu_get_be32(f);
if (v != QEMU_VM_FILE_MAGIC)
goto fail;
version_id = qemu_get_be32(f);
record_len = qemu_get_be32(f);
#if 0
- printf("idstr=%s instance=0x%x version=%d len=%d\n",
+ printf("idstr=%s instance=0x%x version=%d len=%d\n",
idstr, instance_id, version_id, record_len);
#endif
cur_pos = qemu_ftell(f);
se = find_se(idstr, instance_id);
if (!se) {
- fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
+ fprintf(stderr, "qemu: warning: instance 0x%x of device '%s' not present in current VM\n",
instance_id, idstr);
} else {
ret = se->load_state(f, se->opaque, version_id);
if (ret < 0) {
- fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
+ fprintf(stderr, "qemu: warning: error while loading state for instance 0x%x of device '%s'\n",
instance_id, idstr);
}
}
{
QEMUSnapshotInfo *sn_tab, *sn;
int nb_sns, i, ret;
-
+
ret = -ENOENT;
nb_sns = bdrv_snapshot_list(bs, &sn_tab);
if (nb_sns < 0)
saved_vm_running = vm_running;
vm_stop(0);
-
+
must_delete = 0;
if (name) {
ret = bdrv_snapshot_find(bs, old_sn, name);
sn->date_nsec = tv.tv_usec * 1000;
#endif
sn->vm_clock_nsec = qemu_get_clock(vm_clock);
-
+
if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {
term_printf("Device %s does not support VM state snapshots\n",
bdrv_get_device_name(bs));
goto the_end;
}
-
+
/* save the VM state */
f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1);
if (!f) {
term_printf("Error %d while writing VM\n", ret);
goto the_end;
}
-
+
/* create the snapshots */
for(i = 0; i < MAX_DISKS; i++) {
term_printf("No block device supports snapshots\n");
return;
}
-
+
/* Flush all IO requests so they don't interfere with the new state. */
qemu_aio_flush();
bdrv_get_device_name(bs));
return;
}
-
+
/* restore the VM state */
f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0);
if (!f) {
term_printf("No block device supports snapshots\n");
return;
}
-
+
for(i = 0; i <= MAX_DISKS; i++) {
bs1 = bs_table[i];
if (bdrv_has_snapshot(bs1)) {
uint16_t fptag, fpus, fpuc, fpregs_format;
uint32_t hflags;
int i;
-
+
for(i = 0; i < CPU_NB_REGS; i++)
qemu_put_betls(f, &env->regs[i]);
qemu_put_betls(f, &env->eip);
qemu_put_betls(f, &env->eflags);
hflags = env->hflags; /* XXX: suppress most of the redundant hflags */
qemu_put_be32s(f, &hflags);
-
+
/* FPU */
fpuc = env->fpuc;
fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
for(i = 0; i < 8; i++) {
fptag |= ((!env->fptags[i]) << i);
}
-
+
qemu_put_be16s(f, &fpuc);
qemu_put_be16s(f, &fpus);
qemu_put_be16s(f, &fptag);
fpregs_format = 1;
#endif
qemu_put_be16s(f, &fpregs_format);
-
+
for(i = 0; i < 8; i++) {
#ifdef USE_X86LDOUBLE
{
cpu_put_seg(f, &env->tr);
cpu_put_seg(f, &env->gdt);
cpu_put_seg(f, &env->idt);
-
+
qemu_put_be32s(f, &env->sysenter_cs);
qemu_put_be32s(f, &env->sysenter_esp);
qemu_put_be32s(f, &env->sysenter_eip);
-
+
qemu_put_betls(f, &env->cr[0]);
qemu_put_betls(f, &env->cr[2]);
qemu_put_betls(f, &env->cr[3]);
qemu_put_betls(f, &env->cr[4]);
-
+
for(i = 0; i < 8; i++)
qemu_put_betls(f, &env->dr[i]);
qemu_get_be16s(f, &fpus);
qemu_get_be16s(f, &fptag);
qemu_get_be16s(f, &fpregs_format);
-
+
/* NOTE: we cannot always restore the FPU state if the image come
from a host with a different 'USE_X86LDOUBLE' define. We guess
if we are in an MMX state to restore correctly in that case. */
for(i = 0; i < 8; i++) {
uint64_t mant;
uint16_t exp;
-
+
switch(fpregs_format) {
case 0:
mant = qemu_get_be64(f);
}
#else
env->fpregs[i].mmx.MMX_Q(0) = mant;
-#endif
+#endif
break;
default:
return -EINVAL;
for(i = 0; i < 8; i++) {
env->fptags[i] = (fptag >> i) & 1;
}
-
+
for(i = 0; i < 6; i++)
cpu_get_seg(f, &env->segs[i]);
cpu_get_seg(f, &env->ldt);
cpu_get_seg(f, &env->tr);
cpu_get_seg(f, &env->gdt);
cpu_get_seg(f, &env->idt);
-
+
qemu_get_be32s(f, &env->sysenter_cs);
qemu_get_be32s(f, &env->sysenter_esp);
qemu_get_be32s(f, &env->sysenter_eip);
-
+
qemu_get_betls(f, &env->cr[0]);
qemu_get_betls(f, &env->cr[2]);
qemu_get_betls(f, &env->cr[3]);
qemu_get_betls(f, &env->cr[4]);
-
+
for(i = 0; i < 8; i++)
qemu_get_betls(f, &env->dr[i]);
qemu_get_be64s(f, &env->fmask);
qemu_get_be64s(f, &env->kernelgsbase);
#endif
- if (version_id >= 4)
+ if (version_id >= 4)
qemu_get_be32s(f, &env->smbase);
/* XXX: compute hflags from scratch, except for CPL and IIF */
qemu_put_be32(f, env->cp15.c0_cachetype);
qemu_put_be32(f, env->cp15.c1_sys);
qemu_put_be32(f, env->cp15.c1_coproc);
- qemu_put_be32(f, env->cp15.c2_base);
+ qemu_put_be32(f, env->cp15.c1_xscaleauxcr);
+ qemu_put_be32(f, env->cp15.c2_base0);
+ qemu_put_be32(f, env->cp15.c2_base1);
+ qemu_put_be32(f, env->cp15.c2_mask);
qemu_put_be32(f, env->cp15.c2_data);
qemu_put_be32(f, env->cp15.c2_insn);
qemu_put_be32(f, env->cp15.c3);
qemu_put_be32(f, env->cp15.c9_data);
qemu_put_be32(f, env->cp15.c13_fcse);
qemu_put_be32(f, env->cp15.c13_context);
+ qemu_put_be32(f, env->cp15.c13_tls1);
+ qemu_put_be32(f, env->cp15.c13_tls2);
+ qemu_put_be32(f, env->cp15.c13_tls3);
qemu_put_be32(f, env->cp15.c15_cpar);
qemu_put_be32(f, env->features);
/* TODO: Should use proper FPSCR access functions. */
qemu_put_be32(f, env->vfp.vec_len);
qemu_put_be32(f, env->vfp.vec_stride);
+
+ if (arm_feature(env, ARM_FEATURE_VFP3)) {
+ for (i = 16; i < 32; i++) {
+ CPU_DoubleU u;
+ u.d = env->vfp.regs[i];
+ qemu_put_be32(f, u.l.upper);
+ qemu_put_be32(f, u.l.lower);
+ }
+ }
}
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
qemu_put_be32(f, env->iwmmxt.cregs[i]);
}
}
+
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ qemu_put_be32(f, env->v7m.other_sp);
+ qemu_put_be32(f, env->v7m.vecbase);
+ qemu_put_be32(f, env->v7m.basepri);
+ qemu_put_be32(f, env->v7m.control);
+ qemu_put_be32(f, env->v7m.current_sp);
+ qemu_put_be32(f, env->v7m.exception);
+ }
}
int cpu_load(QEMUFile *f, void *opaque, int version_id)
CPUARMState *env = (CPUARMState *)opaque;
int i;
- if (version_id != 0)
+ if (version_id != ARM_CPU_SAVE_VERSION)
return -EINVAL;
for (i = 0; i < 16; i++) {
env->cp15.c0_cachetype = qemu_get_be32(f);
env->cp15.c1_sys = qemu_get_be32(f);
env->cp15.c1_coproc = qemu_get_be32(f);
- env->cp15.c2_base = qemu_get_be32(f);
+ env->cp15.c1_xscaleauxcr = qemu_get_be32(f);
+ env->cp15.c2_base0 = qemu_get_be32(f);
+ env->cp15.c2_base1 = qemu_get_be32(f);
+ env->cp15.c2_mask = qemu_get_be32(f);
env->cp15.c2_data = qemu_get_be32(f);
env->cp15.c2_insn = qemu_get_be32(f);
env->cp15.c3 = qemu_get_be32(f);
env->cp15.c9_data = qemu_get_be32(f);
env->cp15.c13_fcse = qemu_get_be32(f);
env->cp15.c13_context = qemu_get_be32(f);
+ env->cp15.c13_tls1 = qemu_get_be32(f);
+ env->cp15.c13_tls2 = qemu_get_be32(f);
+ env->cp15.c13_tls3 = qemu_get_be32(f);
env->cp15.c15_cpar = qemu_get_be32(f);
env->features = qemu_get_be32(f);
/* TODO: Should use proper FPSCR access functions. */
env->vfp.vec_len = qemu_get_be32(f);
env->vfp.vec_stride = qemu_get_be32(f);
+
+ if (arm_feature(env, ARM_FEATURE_VFP3)) {
+ for (i = 0; i < 16; i++) {
+ CPU_DoubleU u;
+ u.l.upper = qemu_get_be32(f);
+ u.l.lower = qemu_get_be32(f);
+ env->vfp.regs[i] = u.d;
+ }
+ }
}
if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
}
}
+ if (arm_feature(env, ARM_FEATURE_M)) {
+ env->v7m.other_sp = qemu_get_be32(f);
+ env->v7m.vecbase = qemu_get_be32(f);
+ env->v7m.basepri = qemu_get_be32(f);
+ env->v7m.control = qemu_get_be32(f);
+ env->v7m.current_sp = qemu_get_be32(f);
+ env->v7m.exception = qemu_get_be32(f);
+ }
+
return 0;
}
#else
-#warning No CPU save/restore functions
+//#warning No CPU save/restore functions
#endif
memset(s, 0, sizeof(*s));
s->f = f;
ret = deflateInit2(&s->zstream, 1,
- Z_DEFLATED, 15,
+ Z_DEFLATED, 15,
9, Z_DEFAULT_STRATEGY);
if (ret != Z_OK)
return -1;
int i;
RamCompressState s1, *s = &s1;
uint8_t buf[10];
-
+
qemu_put_be32(f, phys_ram_size);
if (ram_compress_open(s, f) < 0)
return;
sector_num = -1;
for(j = 0; j < MAX_DISKS; j++) {
if (bs_table[j]) {
- sector_num = bdrv_hash_find(bs_table[j],
+ sector_num = bdrv_hash_find(bs_table[j],
phys_ram_base + i, BDRV_HASH_BLOCK_SIZE);
if (sector_num >= 0)
break;
buf[1] = j;
cpu_to_be64wu((uint64_t *)(buf + 2), sector_num);
ram_compress_buf(s, buf, 10);
- } else
+ } else
#endif
{
// normal_compress:
fprintf(stderr, "Error while reading ram block address=0x%08x", i);
goto error;
}
- } else
+ } else
#if 0
if (buf[0] == 1) {
int bs_index;
fprintf(stderr, "Invalid block device index %d\n", bs_index);
goto error;
}
- if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i,
+ if (bdrv_read(bs_table[bs_index], sector_num, phys_ram_base + i,
BDRV_HASH_BLOCK_SIZE / 512) < 0) {
- fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n",
+ fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n",
bs_index, sector_num);
goto error;
}
- } else
+ } else
#endif
{
error:
return 0;
}
-QEMUMachine *find_machine(const char *name)
+static QEMUMachine *find_machine(const char *name)
{
QEMUMachine *m;
/***********************************************************/
/* main execution loop */
-void gui_update(void *opaque)
+static void gui_update(void *opaque)
{
- display_state.dpy_refresh(&display_state);
- qemu_mod_timer(gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock));
+ DisplayState *ds = opaque;
+ ds->dpy_refresh(ds);
+ qemu_mod_timer(ds->gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock));
}
struct vm_change_state_entry {
cpu_enable_ticks();
vm_running = 1;
vm_state_notify(1);
+ qemu_rearm_alarm_timer(alarm_timer);
}
}
-void vm_stop(int reason)
+void vm_stop(int reason)
{
if (vm_running) {
cpu_disable_ticks();
if (ret == 0) {
int err;
WaitObjects *w = &wait_objects;
-
+
ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout);
if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
if (w->func[ret - WAIT_OBJECT_0])
w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
-
- /* Check for additional signaled events */
+
+ /* Check for additional signaled events */
for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
-
+
/* Check if event is signaled */
ret2 = WaitForSingleObject(w->events[i], 0);
if(ret2 == WAIT_OBJECT_0) {
} else {
err = GetLastError();
fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
- }
- }
+ }
+ }
} else if (ret == WAIT_TIMEOUT) {
} else {
err = GetLastError();
nfds = ioh->fd;
}
}
-
+
tv.tv_sec = 0;
#ifdef _WIN32
tv.tv_usec = 0;
IOHandlerRecord **pioh;
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
- if (ioh->deleted)
- continue;
- if (FD_ISSET(ioh->fd, &rfds)) {
+ if (!ioh->deleted && ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) {
ioh->fd_read(ioh->opaque);
}
- if (FD_ISSET(ioh->fd, &wfds)) {
+ if (!ioh->deleted && ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) {
ioh->fd_write(ioh->opaque);
}
}
if (ioh->deleted) {
*pioh = ioh->next;
qemu_free(ioh);
- } else
+ } else
pioh = &ioh->next;
}
}
qemu_aio_poll();
if (vm_running) {
- qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
+ qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
qemu_get_clock(vm_clock));
/* run dma transfers, if any */
DMA_run();
}
/* real time timers */
- qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
+ qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME],
qemu_get_clock(rt_clock));
/* Check bottom-halves last in case any of the earlier events triggered
them. */
qemu_bh_poll();
-
+
}
static CPUState *cur_cpu;
-int main_loop(void)
+static int main_loop(void)
{
int ret, timeout;
#ifdef CONFIG_PROFILER
return ret;
}
-void help(void)
+static void help(int exitcode)
{
printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
"usage: %s [options] [disk_image]\n"
"-snapshot write to temporary files instead of disk image files\n"
#ifdef CONFIG_SDL
"-no-frame open SDL window without a frame and window decorations\n"
+ "-alt-grab use Ctrl-Alt-Shift to grab mouse (instead of Ctrl-Alt)\n"
"-no-quit disable SDL window close capability\n"
#endif
#ifdef TARGET_I386
"-net tap[,vlan=n],ifname=name\n"
" connect the host TAP network interface to VLAN 'n'\n"
#else
- "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\n"
- " connect the host TAP network interface to VLAN 'n' and use\n"
- " the network script 'file' (default=%s);\n"
- " use 'script=no' to disable script execution;\n"
+ "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file][,downscript=dfile]\n"
+ " connect the host TAP network interface to VLAN 'n' and use the\n"
+ " network scripts 'file' (default=%s)\n"
+ " and 'dfile' (default=%s);\n"
+ " use '[down]script=no' to disable script execution;\n"
" use 'fd=h' to connect to an already opened TAP interface\n"
#endif
"-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n"
"-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n"
"-no-kqemu disable KQEMU kernel module usage\n"
#endif
-#ifdef USE_CODE_COPY
- "-no-code-copy disable code copy acceleration\n"
-#endif
#ifdef TARGET_I386
"-std-vga simulate a standard VGA card with VESA Bochs Extensions\n"
" (default is CL-GD5446 PCI VGA)\n"
#ifdef TARGET_SPARC
"-prom-env variable=value set OpenBIOS nvram variables\n"
#endif
+ "-clock force the use of the given methods for timer alarm.\n"
+ " To see what timers are available use -clock help\n"
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
DEFAULT_RAM_SIZE,
#ifndef _WIN32
DEFAULT_NETWORK_SCRIPT,
+ DEFAULT_NETWORK_DOWN_SCRIPT,
#endif
DEFAULT_GDBSTUB_PORT,
"/tmp/qemu.log");
- exit(1);
+ exit(exitcode);
}
#define HAS_ARG 0x0001
QEMU_OPTION_d,
QEMU_OPTION_hdachs,
QEMU_OPTION_L,
+ QEMU_OPTION_bios,
QEMU_OPTION_no_code_copy,
QEMU_OPTION_k,
QEMU_OPTION_localtime,
QEMU_OPTION_loadvm,
QEMU_OPTION_full_screen,
QEMU_OPTION_no_frame,
+ QEMU_OPTION_alt_grab,
QEMU_OPTION_no_quit,
QEMU_OPTION_pidfile,
QEMU_OPTION_no_kqemu,
QEMU_OPTION_semihosting,
QEMU_OPTION_name,
QEMU_OPTION_prom_env,
+ QEMU_OPTION_old_param,
+ QEMU_OPTION_clock,
+ QEMU_OPTION_startdate,
};
typedef struct QEMUOption {
{ "d", HAS_ARG, QEMU_OPTION_d },
{ "hdachs", HAS_ARG, QEMU_OPTION_hdachs },
{ "L", HAS_ARG, QEMU_OPTION_L },
+ { "bios", HAS_ARG, QEMU_OPTION_bios },
{ "no-code-copy", 0, QEMU_OPTION_no_code_copy },
#ifdef USE_KQEMU
{ "no-kqemu", 0, QEMU_OPTION_no_kqemu },
#endif
{ "localtime", 0, QEMU_OPTION_localtime },
{ "std-vga", 0, QEMU_OPTION_std_vga },
- { "echr", 1, QEMU_OPTION_echr },
- { "monitor", 1, QEMU_OPTION_monitor },
- { "serial", 1, QEMU_OPTION_serial },
- { "parallel", 1, QEMU_OPTION_parallel },
+ { "echr", HAS_ARG, QEMU_OPTION_echr },
+ { "monitor", HAS_ARG, QEMU_OPTION_monitor },
+ { "serial", HAS_ARG, QEMU_OPTION_serial },
+ { "parallel", HAS_ARG, QEMU_OPTION_parallel },
{ "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
{ "full-screen", 0, QEMU_OPTION_full_screen },
#ifdef CONFIG_SDL
{ "no-frame", 0, QEMU_OPTION_no_frame },
+ { "alt-grab", 0, QEMU_OPTION_alt_grab },
{ "no-quit", 0, QEMU_OPTION_no_quit },
#endif
{ "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
#if defined(TARGET_SPARC)
{ "prom-env", HAS_ARG, QEMU_OPTION_prom_env },
#endif
+#if defined(TARGET_ARM)
+ { "old-param", 0, QEMU_OPTION_old_param },
+#endif
+ { "clock", HAS_ARG, QEMU_OPTION_clock },
+ { "startdate", HAS_ARG, QEMU_OPTION_startdate },
{ NULL },
};
-#if defined (TARGET_I386) && defined(USE_CODE_COPY)
-
-/* this stack is only used during signal handling */
-#define SIGNAL_STACK_SIZE 32768
-
-static uint8_t *signal_stack;
-
-#endif
-
/* password input */
int qemu_key_check(BlockDriverState *bs, const char *name)
}
/* XXX: currently we cannot use simultaneously different CPUs */
-void register_machines(void)
+static void register_machines(void)
{
#if defined(TARGET_I386)
qemu_register_machine(&pc_machine);
qemu_register_machine(&mips_machine);
qemu_register_machine(&mips_malta_machine);
qemu_register_machine(&mips_pica61_machine);
+ qemu_register_machine(&mips_mipssim_machine);
#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
qemu_register_machine(&sun4u_machine);
#else
qemu_register_machine(&ss5_machine);
qemu_register_machine(&ss10_machine);
+ qemu_register_machine(&ss600mp_machine);
#endif
#elif defined(TARGET_ARM)
qemu_register_machine(&integratorcp_machine);
qemu_register_machine(&spitzpda_machine);
qemu_register_machine(&borzoipda_machine);
qemu_register_machine(&terrierpda_machine);
+ qemu_register_machine(&palmte_machine);
+ qemu_register_machine(&lm3s811evb_machine);
+ qemu_register_machine(&lm3s6965evb_machine);
+ qemu_register_machine(&connex_machine);
#elif defined(TARGET_SH4)
qemu_register_machine(&shix_machine);
+ qemu_register_machine(&r2d_machine);
#elif defined(TARGET_ALPHA)
/* XXX: TODO */
#elif defined(TARGET_M68K)
+ qemu_register_machine(&mcf5208evb_machine);
qemu_register_machine(&an5206_machine);
+ qemu_register_machine(&dummy_m68k_machine);
+#elif defined(TARGET_CRIS)
+ qemu_register_machine(&bareetraxfs_machine);
#else
#error unsupported CPU
#endif
int use_gdbstub;
const char *gdbstub_port;
#endif
+ uint32_t boot_devices_bitmap = 0;
int i, cdrom_index, pflash_index;
- int snapshot, linux_boot;
+ int snapshot, linux_boot, net_boot;
const char *initrd_filename;
const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
const char *pflash_filename[MAX_PFLASH];
const char *sd_filename;
const char *mtd_filename;
const char *kernel_filename, *kernel_cmdline;
+ const char *boot_devices = "";
DisplayState *ds = &display_state;
int cyls, heads, secs, translation;
char net_clients[MAX_NET_CLIENTS][256];
for(i = 1; i < MAX_SERIAL_PORTS; i++)
serial_devices[i][0] = '\0';
serial_device_index = 0;
-
+
pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc");
for(i = 1; i < MAX_PARALLEL_PORTS; i++)
parallel_devices[i][0] = '\0';
parallel_device_index = 0;
-
+
usb_devices_index = 0;
-
+
nb_net_clients = 0;
nb_nics = 0;
/* default mac address of the first network interface */
-
+
optind = 1;
for(;;) {
if (optind >= argc)
popt = qemu_options;
for(;;) {
if (!popt->name) {
- fprintf(stderr, "%s: invalid option -- '%s'\n",
+ fprintf(stderr, "%s: invalid option -- '%s'\n",
argv[0], r);
exit(1);
}
printf("Supported machines are:\n");
for(m = first_machine; m != NULL; m = m->next) {
printf("%-10s %s%s\n",
- m->name, m->desc,
+ m->name, m->desc,
m == first_machine ? " (default)" : "");
}
- exit(1);
+ exit(*optarg != '?');
}
break;
case QEMU_OPTION_cpu:
/* hw initialization will check this */
- if (optarg[0] == '?') {
-#if defined(TARGET_PPC)
- ppc_cpu_list(stdout, &fprintf);
-#elif defined(TARGET_ARM)
- arm_cpu_list();
-#elif defined(TARGET_MIPS)
- mips_cpu_list(stdout, &fprintf);
-#elif defined(TARGET_SPARC)
- sparc_cpu_list(stdout, &fprintf);
+ if (*optarg == '?') {
+/* XXX: implement xxx_cpu_list for targets that still miss it */
+#if defined(cpu_list)
+ cpu_list(stdout, &fprintf);
#endif
- exit(1);
+ exit(0);
} else {
cpu_model = optarg;
}
}
break;
case QEMU_OPTION_boot:
- boot_device = optarg[0];
- if (boot_device != 'a' &&
-#if defined(TARGET_SPARC) || defined(TARGET_I386)
- // Network boot
- boot_device != 'n' &&
-#endif
- boot_device != 'c' && boot_device != 'd') {
- fprintf(stderr, "qemu: invalid boot device '%c'\n", boot_device);
- exit(1);
+ boot_devices = optarg;
+ /* We just do some generic consistency checks */
+ {
+ /* Could easily be extended to 64 devices if needed */
+ const unsigned char *p;
+
+ boot_devices_bitmap = 0;
+ for (p = boot_devices; *p != '\0'; p++) {
+ /* Allowed boot devices are:
+ * a b : floppy disk drives
+ * c ... f : IDE disk drives
+ * g ... m : machine implementation dependant drives
+ * n ... p : network devices
+ * It's up to each machine implementation to check
+ * if the given boot devices match the actual hardware
+ * implementation and firmware features.
+ */
+ if (*p < 'a' || *p > 'q') {
+ fprintf(stderr, "Invalid boot device '%c'\n", *p);
+ exit(1);
+ }
+ if (boot_devices_bitmap & (1 << (*p - 'a'))) {
+ fprintf(stderr,
+ "Boot device '%c' was given twice\n",*p);
+ exit(1);
+ }
+ boot_devices_bitmap |= 1 << (*p - 'a');
+ }
}
break;
case QEMU_OPTION_fda:
break;
#endif
case QEMU_OPTION_redir:
- net_slirp_redir(optarg);
+ net_slirp_redir(optarg);
break;
#endif
#ifdef HAS_AUDIO
break;
#endif
case QEMU_OPTION_h:
- help();
+ help(0);
break;
case QEMU_OPTION_m:
ram_size = atoi(optarg) * 1024 * 1024;
if (ram_size <= 0)
- help();
+ help(1);
if (ram_size > PHYS_RAM_MAX_SIZE) {
fprintf(stderr, "qemu: at most %d MB RAM can be simulated\n",
PHYS_RAM_MAX_SIZE / (1024 * 1024));
{
int mask;
CPULogItem *item;
-
+
mask = cpu_str_to_log_mask(optarg);
if (!mask) {
printf("Log items (comma separated):\n");
case QEMU_OPTION_L:
bios_dir = optarg;
break;
+ case QEMU_OPTION_bios:
+ bios_name = optarg;
+ break;
case QEMU_OPTION_S:
autostart = 0;
break;
if (*p == 'x') {
p++;
depth = strtol(p, (char **)&p, 10);
- if (depth != 8 && depth != 15 && depth != 16 &&
+ if (depth != 8 && depth != 15 && depth != 16 &&
depth != 24 && depth != 32)
goto graphic_error;
} else if (*p == '\0') {
} else {
goto graphic_error;
}
-
+
graphic_width = w;
graphic_height = h;
graphic_depth = depth;
fprintf(stderr, "qemu: too many serial ports\n");
exit(1);
}
- pstrcpy(serial_devices[serial_device_index],
+ pstrcpy(serial_devices[serial_device_index],
sizeof(serial_devices[0]), optarg);
serial_device_index++;
break;
fprintf(stderr, "qemu: too many parallel ports\n");
exit(1);
}
- pstrcpy(parallel_devices[parallel_device_index],
+ pstrcpy(parallel_devices[parallel_device_index],
sizeof(parallel_devices[0]), optarg);
parallel_device_index++;
break;
case QEMU_OPTION_no_frame:
no_frame = 1;
break;
+ case QEMU_OPTION_alt_grab:
+ alt_grab = 1;
+ break;
case QEMU_OPTION_no_quit:
no_quit = 1;
break;
nb_prom_envs++;
break;
#endif
+#ifdef TARGET_ARM
+ case QEMU_OPTION_old_param:
+ old_param = 1;
+#endif
+ case QEMU_OPTION_clock:
+ configure_alarms(optarg);
+ break;
+ case QEMU_OPTION_startdate:
+ {
+ struct tm tm;
+ if (!strcmp(optarg, "now")) {
+ rtc_start_date = -1;
+ } else {
+ if (sscanf(optarg, "%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(optarg, "%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 format are:\n"
+ "'now' or '2006-06-17T16:01:21' or '2006-06-17'\n");
+ exit(1);
+ }
+ }
+ }
+ break;
}
}
}
kqemu_allowed = 0;
#endif
linux_boot = (kernel_filename != NULL);
+ net_boot = (boot_devices_bitmap >> ('n' - 'a')) & 0xF;
- if (!linux_boot &&
- boot_device != 'n' &&
- hd_filename[0] == '\0' &&
- (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') &&
- fd_filename[0] == '\0')
- help();
+ /* XXX: this should not be: some embedded targets just have flash */
+ if (!linux_boot && net_boot == 0 &&
+ hd_filename[0] == NULL &&
+ (cdrom_index >= 0 && hd_filename[cdrom_index] == NULL) &&
+ fd_filename[0] == NULL &&
+ pflash_filename[0] == NULL)
+ help(1);
/* boot to floppy or the default cd if no hard disk defined yet */
- if (hd_filename[0] == '\0' && boot_device == 'c') {
- if (fd_filename[0] != '\0')
- boot_device = 'a';
+ if (!boot_devices[0]) {
+ if (hd_filename[0] != NULL)
+ boot_devices = "c";
+ else if (fd_filename[0] != NULL)
+ boot_devices = "a";
else
- boot_device = 'd';
+ boot_devices = "d";
}
-
setvbuf(stdout, NULL, _IOLBF, 0);
-
+
init_timers();
init_timer_alarm();
qemu_aio_init();
}
#ifdef TARGET_I386
- if (boot_device == 'n') {
- for (i = 0; i < nb_nics; i++) {
+ /* XXX: this should be moved in the PC machine instanciation code */
+ if (net_boot != 0) {
+ int netroms = 0;
+ for (i = 0; i < nb_nics && i < 4; i++) {
const char *model = nd_table[i].model;
char buf[1024];
- if (model == NULL)
- model = "ne2k_pci";
- snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model);
- if (get_image_size(buf) > 0) {
- option_rom[nb_option_roms] = strdup(buf);
- nb_option_roms++;
- break;
- }
+ if (net_boot & (1 << i)) {
+ if (model == NULL)
+ model = "ne2k_pci";
+ snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model);
+ if (get_image_size(buf) > 0) {
+ if (nb_option_roms >= MAX_OPTION_ROMS) {
+ fprintf(stderr, "Too many option ROMs\n");
+ exit(1);
+ }
+ option_rom[nb_option_roms] = strdup(buf);
+ nb_option_roms++;
+ netroms++;
+ }
+ }
}
- if (i == nb_nics) {
+ if (netroms == 0) {
fprintf(stderr, "No valid PXE rom found for network device\n");
exit(1);
}
- boot_device = 'c'; /* to prevent confusion by the BIOS */
}
#endif
init_ioports();
/* terminal init */
+ memset(&display_state, 0, sizeof(display_state));
if (nographic) {
+ /* nearly nothing to do */
dumb_display_init(ds);
} else if (vnc_display != NULL) {
- vnc_display_init(ds, vnc_display);
+ vnc_display_init(ds);
+ if (vnc_display_open(ds, vnc_display) < 0)
+ exit(1);
} else {
#if defined(CONFIG_SDL)
sdl_display_init(ds, full_screen, no_frame);
if (devname[0] != '\0' && strcmp(devname, "none")) {
serial_hds[i] = qemu_chr_open(devname);
if (!serial_hds[i]) {
- fprintf(stderr, "qemu: could not open serial device '%s'\n",
+ fprintf(stderr, "qemu: could not open serial device '%s'\n",
devname);
exit(1);
}
- if (!strcmp(devname, "vc"))
+ if (strstart(devname, "vc", 0))
qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i);
}
}
if (devname[0] != '\0' && strcmp(devname, "none")) {
parallel_hds[i] = qemu_chr_open(devname);
if (!parallel_hds[i]) {
- fprintf(stderr, "qemu: could not open parallel device '%s'\n",
+ fprintf(stderr, "qemu: could not open parallel device '%s'\n",
devname);
exit(1);
}
- if (!strcmp(devname, "vc"))
+ if (strstart(devname, "vc", 0))
qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i);
}
}
- machine->init(ram_size, vga_ram_size, boot_device,
- ds, fd_filename, snapshot,
+ machine->init(ram_size, vga_ram_size, boot_devices, ds,
kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
/* init USB devices */
}
}
- gui_timer = qemu_new_timer(rt_clock, gui_update, NULL);
- qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock));
+ if (display_state.dpy_refresh) {
+ display_state.gui_timer = qemu_new_timer(rt_clock, gui_update, &display_state);
+ qemu_mod_timer(display_state.gui_timer, qemu_get_clock(rt_clock));
+ }
#ifdef CONFIG_GDBSTUB
if (use_gdbstub) {
gdbstub_port);
exit(1);
}
- } else
+ }
#endif
+
if (loadvm)
do_loadvm(loadvm);
if (len != 1)
exit(1);
- fd = open("/dev/null", O_RDWR);
+ TFR(fd = open("/dev/null", O_RDWR));
if (fd == -1)
exit(1);
main_loop();
quit_timers();
+
+#if !defined(_WIN32)
+ /* close network clients */
+ for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
+ VLANClientState *vc;
+
+ for(vc = vlan->first_client; vc != NULL; vc = vc->next) {
+ if (vc->fd_read == tap_receive) {
+ char ifname[64];
+ TAPState *s = vc->opaque;
+
+ if (sscanf(vc->info_str, "tap: ifname=%63s ", ifname) == 1 &&
+ s->down_script[0])
+ launch_script(s->down_script, ifname, s->fd);
+ }
+ }
+ }
+#endif
return 0;
}