]> Git Repo - qemu.git/blobdiff - vl.c
Drop an unused variable (Samuel Thibault).
[qemu.git] / vl.c
diff --git a/vl.c b/vl.c
index 91b1c5a5b3d51e5c9df05812f60576541e77741a..1a7f4a34ce385d83b4c32147566a863173cb4c66 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -1,8 +1,8 @@
 /*
  * 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>
@@ -73,6 +97,9 @@
 #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];
@@ -148,13 +176,13 @@ static DisplayState display_state;
 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];
 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
@@ -195,6 +223,9 @@ const char *option_rom[MAX_OPTION_ROMS];
 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
@@ -202,13 +233,15 @@ 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);
@@ -216,7 +249,7 @@ uint32_t default_ioport_readb(void *opaque, uint32_t 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);
@@ -224,7 +257,7 @@ void default_ioport_writeb(void *opaque, uint32_t address, uint32_t 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);
@@ -233,14 +266,14 @@ uint32_t default_ioport_readw(void *opaque, uint32_t 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);
@@ -248,14 +281,14 @@ uint32_t default_ioport_readl(void *opaque, uint32_t 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;
 
@@ -270,7 +303,7 @@ void init_ioports(void)
 }
 
 /* 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;
@@ -295,7 +328,7 @@ int register_ioport_read(int start, int length, int size,
 }
 
 /* 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;
@@ -341,7 +374,7 @@ void cpu_outb(CPUState *env, int addr, int val)
 #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)
@@ -354,7 +387,7 @@ void cpu_outw(CPUState *env, int addr, int val)
 #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)
@@ -617,7 +650,7 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
             uint32_t high, low;
 #else
             uint32_t low, high;
-#endif            
+#endif
         } l;
     } u, res;
     uint64_t rl, rh;
@@ -683,7 +716,7 @@ static int64_t get_clock(void)
         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
@@ -757,7 +790,7 @@ void cpu_disable_ticks(void)
 
 /***********************************************************/
 /* timers */
+
 #define QEMU_TIMER_REALTIME 0
 #define QEMU_TIMER_VIRTUAL  1
 
@@ -774,20 +807,160 @@ struct QEMUTimer {
     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));
@@ -849,7 +1022,7 @@ void qemu_mod_timer(QEMUTimer *ts, int64_t expire_time)
         t = *pt;
         if (!t)
             break;
-        if (t->expire_time > expire_time) 
+        if (t->expire_time > expire_time)
             break;
         pt = &t->next;
     }
@@ -878,7 +1051,7 @@ static inline int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time
 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)
@@ -886,10 +1059,11 @@ static void qemu_run_timers(QEMUTimer **ptimer_head, int64_t 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)
@@ -962,7 +1136,7 @@ static int timer_load(QEMUFile *f, void *opaque, int version_id)
 }
 
 #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)
@@ -997,12 +1171,14 @@ 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) {
@@ -1017,17 +1193,104 @@ static void host_alarm_handler(int host_signum)
     }
 }
 
+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;
 
-static int start_rtc_timer(void)
+    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)
 {
-    rtc_fd = open("/dev/rtc", O_RDONLY);
+    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 rtc_start_timer(struct qemu_alarm_timer *t)
+{
+    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) {
@@ -1041,117 +1304,244 @@ static int start_rtc_timer(void)
         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;
 }
 
 /***********************************************************/
@@ -1221,8 +1611,8 @@ void qemu_chr_send_event(CharDriverState *s, int event)
         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)
@@ -1234,7 +1624,7 @@ void qemu_chr_add_handlers(CharDriverState *s,
     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;
@@ -1441,7 +1831,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr)
     d->mux_cnt++;
 }
 
-CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
 {
     CharDriverState *chr;
     MuxDriver *d;
@@ -1489,7 +1879,7 @@ static int socket_init(void)
 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);
@@ -1579,7 +1969,7 @@ static void fd_chr_read(void *opaque)
     FDCharDriver *s = chr->opaque;
     int size, len;
     uint8_t buf[1024];
-    
+
     len = sizeof(buf);
     if (len > s->max_size)
         len = s->max_size;
@@ -1603,7 +1993,7 @@ static void fd_chr_update_read_handler(CharDriverState *chr)
     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);
         }
     }
@@ -1638,7 +2028,7 @@ static CharDriverState *qemu_chr_open_file_out(const char *file_out)
 {
     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);
@@ -1651,14 +2041,14 @@ static CharDriverState *qemu_chr_open_pipe(const char *filename)
 
     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;
     }
@@ -1740,7 +2130,7 @@ static void term_init(void)
     tty.c_cflag |= CS8;
     tty.c_cc[VMIN] = 1;
     tty.c_cc[VTIME] = 0;
-    
+
     tcsetattr (0, TCSANOW, &tty);
 
     atexit(term_exit);
@@ -1762,18 +2152,20 @@ static CharDriverState *qemu_chr_open_stdio(void)
     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);
@@ -1785,14 +2177,14 @@ static CharDriverState *qemu_chr_open_pty(void)
     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);
@@ -1873,19 +2265,19 @@ static void tty_serial_init(int fd, int speed,
     }
     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;
@@ -1907,19 +2299,26 @@ static CharDriverState *qemu_chr_open_tty(const char *filename)
     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;
@@ -2030,7 +2429,7 @@ static CharDriverState *qemu_chr_open_pp(const char *filename)
     ParallelCharDriver *drv;
     int fd;
 
-    fd = open(filename, O_RDWR);
+    TFR(fd = open(filename, O_RDWR));
     if (fd < 0)
         return NULL;
 
@@ -2062,17 +2461,10 @@ static CharDriverState *qemu_chr_open_pp(const char *filename)
 
     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;
@@ -2119,7 +2511,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename)
     COMSTAT comstat;
     DWORD size;
     DWORD err;
-    
+
     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
     if (!s->hsend) {
         fprintf(stderr, "Failed CreateEvent\n");
@@ -2138,12 +2530,12 @@ static int win_chr_init(CharDriverState *chr, const char *filename)
         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);
@@ -2165,7 +2557,7 @@ static int win_chr_init(CharDriverState *chr, const char *filename)
         fprintf(stderr, "Failed SetCommTimeouts\n");
         goto fail;
     }
-    
+
     if (!ClearCommError(s->hcom, &err, &comstat)) {
         fprintf(stderr, "Failed ClearCommError\n");
         goto fail;
@@ -2226,7 +2618,7 @@ static void win_chr_readfile(CharDriverState *chr)
     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);
@@ -2250,7 +2642,7 @@ static void win_chr_read(CharDriverState *chr)
         s->len = s->max_size;
     if (s->len == 0)
         return;
-    
+
     win_chr_readfile(chr);
 }
 
@@ -2260,7 +2652,7 @@ static int win_chr_poll(void *opaque)
     WinCharState *s = chr->opaque;
     COMSTAT status;
     DWORD comerr;
-    
+
     ClearCommError(s->hcom, &comerr, &status);
     if (status.cbInQue > 0) {
         s->len = status.cbInQue;
@@ -2275,7 +2667,7 @@ static CharDriverState *qemu_chr_open_win(const char *filename)
 {
     CharDriverState *chr;
     WinCharState *s;
-    
+
     chr = qemu_mallocz(sizeof(CharDriverState));
     if (!chr)
         return NULL;
@@ -2320,7 +2712,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
     int ret;
     DWORD size;
     char openname[256];
-    
+
     s->fpipe = TRUE;
 
     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
@@ -2333,7 +2725,7 @@ static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
         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 |
@@ -2392,7 +2784,7 @@ static CharDriverState *qemu_chr_open_win_pipe(const char *filename)
     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);
@@ -2430,7 +2822,7 @@ static CharDriverState *qemu_chr_open_win_con(const char *filename)
 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)
@@ -2438,7 +2830,7 @@ static CharDriverState *qemu_chr_open_win_file_out(const char *file_out)
 
     return qemu_chr_open_win_file(fd_out);
 }
-#endif
+#endif /* !_WIN32 */
 
 /***********************************************************/
 /* UDP Net console */
@@ -2762,7 +3154,7 @@ static void tcp_chr_close(CharDriverState *chr)
     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)
 {
@@ -2825,8 +3217,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
     else
 #endif
        fd = socket(PF_INET, SOCK_STREAM, 0);
-       
-    if (fd < 0) 
+
+    if (fd < 0)
         goto fail;
 
     if (!is_waitconnect)
@@ -2856,7 +3248,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
            val = 1;
            setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
        }
-        
+
         ret = bind(fd, addr, addrlen);
         if (ret < 0)
             goto fail;
@@ -2896,7 +3288,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str,
         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);
@@ -2917,10 +3309,12 @@ CharDriverState *qemu_chr_open(const char *filename)
     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
@@ -2951,17 +3345,18 @@ CharDriverState *qemu_chr_open(const char *filename)
         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
@@ -2989,7 +3384,8 @@ void qemu_chr_close(CharDriverState *chr)
 /***********************************************************/
 /* 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;
 
@@ -3021,10 +3417,10 @@ static int parse_macaddr(uint8_t *macaddr, const char *p)
     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++;
         }
@@ -3190,11 +3586,11 @@ int qemu_can_send_packet(VLANClientState *vc1)
 
     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)
@@ -3251,7 +3647,7 @@ static int net_slirp_init(VLANState *vlan)
         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;
@@ -3264,7 +3660,7 @@ static void net_slirp_redir(const char *redir_str)
     const char *p;
     struct in_addr guest_addr;
     int host_port, guest_port;
-    
+
     if (!slirp_inited) {
         slirp_inited = 1;
         slirp_init();
@@ -3294,11 +3690,11 @@ static void net_slirp_redir(const char *redir_str)
     }
     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);
@@ -3308,7 +3704,7 @@ static void net_slirp_redir(const char *redir_str)
     fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n");
     exit(1);
 }
-    
+
 #ifndef _WIN32
 
 char smb_dir[1024];
@@ -3327,7 +3723,7 @@ static void smb_exit(void)
             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);
         }
@@ -3337,7 +3733,7 @@ static void smb_exit(void)
 }
 
 /* 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];
@@ -3355,13 +3751,13 @@ void net_slirp_smb(const char *exported_dir)
         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"
@@ -3387,11 +3783,15 @@ void net_slirp_smb(const char *exported_dir)
 
     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 */
 
@@ -3400,6 +3800,7 @@ void net_slirp_smb(const char *exported_dir)
 typedef struct TAPState {
     VLANClientState *vc;
     int fd;
+    char down_script[1024];
 } TAPState;
 
 static void tap_receive(void *opaque, const uint8_t *buf, int size)
@@ -3451,14 +3852,14 @@ static TAPState *net_tap_fd_init(VLANState *vlan, int fd)
     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;
@@ -3473,10 +3874,10 @@ static int tap_open(char *ifname, int ifname_size)
 }
 #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;
@@ -3493,8 +3894,8 @@ int tap_alloc(char *dev)
     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);
     }
 
@@ -3502,12 +3903,14 @@ int tap_alloc(char *dev)
     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;
     }
@@ -3520,7 +3923,8 @@ int tap_alloc(char *dev)
     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;
     }
@@ -3552,7 +3956,8 @@ int tap_alloc(char *dev)
     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 */
@@ -3607,8 +4012,8 @@ static int tap_open(char *ifname, int ifname_size)
 {
     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;
@@ -3631,27 +4036,13 @@ static int tap_open(char *ifname, int ifname_size)
 }
 #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) {
@@ -3665,7 +4056,7 @@ static int net_tap_init(VLANState *vlan, const char *ifname1,
 
                 parg = args;
                 *parg++ = (char *)setup_script;
-                *parg++ = ifname;
+                *parg++ = (char *)ifname;
                 *parg++ = NULL;
                 execv(setup_script, args);
                 _exit(1);
@@ -3678,12 +4069,37 @@ static int net_tap_init(VLANState *vlan, const char *ifname1,
                 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;
 }
 
@@ -3719,7 +4135,7 @@ static void net_socket_receive(void *opaque, const uint8_t *buf, int size)
 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));
 }
 
@@ -3733,7 +4149,7 @@ static void net_socket_send(void *opaque)
     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 */
@@ -3785,7 +4201,7 @@ static void net_socket_send_dgram(void *opaque)
     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 */
@@ -3802,7 +4218,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
     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;
 
@@ -3814,7 +4230,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
     }
 
     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)");
@@ -3826,12 +4242,12 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
         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)");
@@ -3840,7 +4256,7 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
 
     /* 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)");
@@ -3850,12 +4266,12 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
     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;
@@ -3864,7 +4280,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
     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
      */
 
@@ -3886,7 +4302,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
            /* 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));
@@ -3906,7 +4322,7 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,
     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;
@@ -3918,7 +4334,7 @@ static void net_socket_connect(void *opaque)
     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;
@@ -3926,7 +4342,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,
     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);
@@ -3938,7 +4354,7 @@ static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int 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);
@@ -3962,7 +4378,7 @@ static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,
 
 static void net_socket_accept(void *opaque)
 {
-    NetSocketListenState *s = opaque;    
+    NetSocketListenState *s = opaque;
     NetSocketState *s1;
     struct sockaddr_in saddr;
     socklen_t len;
@@ -3977,12 +4393,12 @@ static void net_socket_accept(void *opaque)
             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));
     }
 }
@@ -3995,7 +4411,7 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str)
 
     if (parse_host_port(&saddr, host_str) < 0)
         return -1;
-    
+
     s = qemu_mallocz(sizeof(NetSocketListenState));
     if (!s)
         return -1;
@@ -4010,7 +4426,7 @@ static int net_socket_listen_init(VLANState *vlan, const char *host_str)
     /* 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");
@@ -4069,7 +4485,7 @@ static int net_socket_connect_init(VLANState *vlan, const char *host_str)
     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;
 }
@@ -4093,9 +4509,9 @@ static int net_socket_mcast_init(VLANState *vlan, const char *host_str)
         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;
 
@@ -4227,7 +4643,7 @@ static int net_client_init(const char *str)
 #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) {
@@ -4242,7 +4658,10 @@ static int net_client_init(const char *str)
             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
@@ -4272,7 +4691,7 @@ static int net_client_init(const char *str)
     if (ret < 0) {
         fprintf(stderr, "Could not initialize device '%s'\n", device);
     }
-    
+
     return ret;
 }
 
@@ -4366,7 +4785,7 @@ static int usb_device_del(const char *devname)
         return -1;
 
     p = strchr(devname, '.');
-    if (!p) 
+    if (!p)
         return -1;
     bus_num = strtoul(devname, NULL, 0);
     addr = strtoul(p + 1, NULL, 0);
@@ -4396,7 +4815,7 @@ void do_usb_add(const char *devname)
 {
     int ret;
     ret = usb_device_add(devname);
-    if (ret < 0) 
+    if (ret < 0)
         term_printf("Could not add USB device '%s'\n", devname);
 }
 
@@ -4404,7 +4823,7 @@ void do_usb_del(const char *devname)
 {
     int ret;
     ret = usb_device_del(devname);
-    if (ret < 0) 
+    if (ret < 0)
         term_printf("Could not remove USB device '%s'\n", devname);
 }
 
@@ -4424,20 +4843,20 @@ void usb_info(void)
         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);
     }
 }
@@ -4533,10 +4952,10 @@ static IOHandlerRecord *first_io_handler;
 
 /* 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;
@@ -4574,9 +4993,9 @@ int qemu_set_fd_handler2(int fd,
     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);
@@ -4630,7 +5049,7 @@ typedef struct WaitObjects {
 } WaitObjects;
 
 static WaitObjects wait_objects = {0};
-    
+
 int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
 {
     WaitObjects *w = &wait_objects;
@@ -4657,7 +5076,7 @@ void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
             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--;
@@ -4708,7 +5127,7 @@ QEMUFile *qemu_fopen(const char *filename, const char *mode)
     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;
 
@@ -4731,7 +5150,7 @@ void qemu_fflush(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;
@@ -4751,7 +5170,7 @@ static void qemu_fill_buffer(QEMUFile *f)
         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;
@@ -4911,8 +5330,8 @@ typedef struct SaveStateEntry {
 
 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,
@@ -4942,7 +5361,7 @@ int register_savevm(const char *idstr,
 #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;
@@ -4965,7 +5384,6 @@ int qemu_savevm_state(QEMUFile *f)
         /* record size: filled later */
         len_pos = qemu_ftell(f);
         qemu_put_be32(f, 0);
-        
         se->save_state(f, se->opaque);
 
         /* fill record size */
@@ -4989,21 +5407,21 @@ static SaveStateEntry *find_se(const char *idstr, int instance_id)
     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;
@@ -5025,18 +5443,18 @@ int qemu_loadvm_state(QEMUFile *f)
         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);
             }
         }
@@ -5087,7 +5505,7 @@ static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,
 {
     QEMUSnapshotInfo *sn_tab, *sn;
     int nb_sns, i, ret;
-    
+
     ret = -ENOENT;
     nb_sns = bdrv_snapshot_list(bs, &sn_tab);
     if (nb_sns < 0)
@@ -5129,7 +5547,7 @@ void do_savevm(const char *name)
 
     saved_vm_running = vm_running;
     vm_stop(0);
-    
+
     must_delete = 0;
     if (name) {
         ret = bdrv_snapshot_find(bs, old_sn, name);
@@ -5157,13 +5575,13 @@ void do_savevm(const char *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) {
@@ -5177,7 +5595,7 @@ void do_savevm(const char *name)
         term_printf("Error %d while writing VM\n", ret);
         goto the_end;
     }
-    
+
     /* create the snapshots */
 
     for(i = 0; i < MAX_DISKS; i++) {
@@ -5216,7 +5634,7 @@ void do_loadvm(const char *name)
         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();
 
@@ -5256,7 +5674,7 @@ void do_loadvm(const char *name)
                     bdrv_get_device_name(bs));
         return;
     }
-    
+
     /* restore the VM state */
     f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0);
     if (!f) {
@@ -5283,7 +5701,7 @@ void do_delvm(const char *name)
         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)) {
@@ -5363,14 +5781,14 @@ void cpu_save(QEMUFile *f, void *opaque)
     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;
@@ -5378,7 +5796,7 @@ void cpu_save(QEMUFile *f, void *opaque)
     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);
@@ -5389,7 +5807,7 @@ void cpu_save(QEMUFile *f, void *opaque)
     fpregs_format = 1;
 #endif
     qemu_put_be16s(f, &fpregs_format);
-    
+
     for(i = 0; i < 8; i++) {
 #ifdef USE_X86LDOUBLE
         {
@@ -5416,16 +5834,16 @@ void cpu_save(QEMUFile *f, void *opaque)
     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]);
 
@@ -5493,7 +5911,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     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. */
@@ -5501,7 +5919,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     for(i = 0; i < 8; i++) {
         uint64_t mant;
         uint16_t exp;
-        
+
         switch(fpregs_format) {
         case 0:
             mant = qemu_get_be64(f);
@@ -5532,7 +5950,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
             }
 #else
             env->fpregs[i].mmx.MMX_Q(0) = mant;
-#endif            
+#endif
             break;
         default:
             return -EINVAL;
@@ -5547,23 +5965,23 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     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]);
 
@@ -5584,7 +6002,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     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 */
@@ -5715,7 +6133,10 @@ void cpu_save(QEMUFile *f, void *opaque)
     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);
@@ -5730,6 +6151,9 @@ void cpu_save(QEMUFile *f, void *opaque)
     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);
@@ -5748,6 +6172,15 @@ void cpu_save(QEMUFile *f, void *opaque)
         /* 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)) {
@@ -5758,6 +6191,15 @@ void cpu_save(QEMUFile *f, void *opaque)
             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)
@@ -5765,7 +6207,7 @@ 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++) {
@@ -5786,7 +6228,10 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     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);
@@ -5801,6 +6246,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     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);
@@ -5819,6 +6267,15 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
         /* 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)) {
@@ -5830,12 +6287,21 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
         }
     }
 
+    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
 
@@ -5892,7 +6358,7 @@ static int ram_compress_open(RamCompressState *s, QEMUFile *f)
     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;
@@ -6003,7 +6469,7 @@ static void ram_save(QEMUFile *f, void *opaque)
     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;
@@ -6018,7 +6484,7 @@ static void ram_save(QEMUFile *f, void *opaque)
             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;
@@ -6030,7 +6496,7 @@ static void ram_save(QEMUFile *f, void *opaque)
             buf[1] = j;
             cpu_to_be64wu((uint64_t *)(buf + 2), sector_num);
             ram_compress_buf(s, buf, 10);
-        } else 
+        } else
 #endif
         {
             //        normal_compress:
@@ -6066,7 +6532,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
                 fprintf(stderr, "Error while reading ram block address=0x%08x", i);
                 goto error;
             }
-        } else 
+        } else
 #if 0
         if (buf[0] == 1) {
             int bs_index;
@@ -6079,13 +6545,13 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
                 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:
@@ -6188,7 +6654,7 @@ int qemu_register_machine(QEMUMachine *m)
     return 0;
 }
 
-QEMUMachine *find_machine(const char *name)
+static QEMUMachine *find_machine(const char *name)
 {
     QEMUMachine *m;
 
@@ -6202,7 +6668,7 @@ QEMUMachine *find_machine(const char *name)
 /***********************************************************/
 /* main execution loop */
 
-void gui_update(void *opaque)
+static void gui_update(void *opaque)
 {
     DisplayState *ds = opaque;
     ds->dpy_refresh(ds);
@@ -6269,10 +6735,11 @@ void vm_start(void)
         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();
@@ -6369,15 +6836,15 @@ void main_loop_wait(int timeout)
     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) {
@@ -6387,8 +6854,8 @@ void main_loop_wait(int timeout)
                 } else {
                     err = GetLastError();
                     fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
-                }                
-            }                 
+                }
+            }
         } else if (ret == WAIT_TIMEOUT) {
         } else {
             err = GetLastError();
@@ -6418,7 +6885,7 @@ void main_loop_wait(int timeout)
                 nfds = ioh->fd;
         }
     }
-    
+
     tv.tv_sec = 0;
 #ifdef _WIN32
     tv.tv_usec = 0;
@@ -6435,12 +6902,10 @@ void main_loop_wait(int timeout)
         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);
             }
         }
@@ -6452,7 +6917,7 @@ void main_loop_wait(int timeout)
             if (ioh->deleted) {
                 *pioh = ioh->next;
                 qemu_free(ioh);
-            } else 
+            } else
                 pioh = &ioh->next;
         }
     }
@@ -6469,25 +6934,25 @@ void main_loop_wait(int timeout)
     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
@@ -6563,7 +7028,7 @@ int main_loop(void)
     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"
@@ -6628,10 +7093,11 @@ void help(void)
            "-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"
@@ -6672,9 +7138,6 @@ void help(void)
            "-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"
@@ -6690,6 +7153,8 @@ void help(void)
 #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"
@@ -6702,10 +7167,11 @@ void help(void)
            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
@@ -6754,6 +7220,7 @@ enum {
     QEMU_OPTION_d,
     QEMU_OPTION_hdachs,
     QEMU_OPTION_L,
+    QEMU_OPTION_bios,
     QEMU_OPTION_no_code_copy,
     QEMU_OPTION_k,
     QEMU_OPTION_localtime,
@@ -6786,6 +7253,9 @@ enum {
     QEMU_OPTION_semihosting,
     QEMU_OPTION_name,
     QEMU_OPTION_prom_env,
+    QEMU_OPTION_old_param,
+    QEMU_OPTION_clock,
+    QEMU_OPTION_startdate,
 };
 
 typedef struct QEMUOption {
@@ -6844,6 +7314,7 @@ const QEMUOption qemu_options[] = {
     { "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 },
@@ -6854,10 +7325,10 @@ const QEMUOption qemu_options[] = {
 #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
@@ -6887,18 +7358,14 @@ const QEMUOption qemu_options[] = {
 #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)
@@ -6946,7 +7413,7 @@ static void read_passwords(void)
 }
 
 /* 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);
@@ -6961,12 +7428,14 @@ void register_machines(void)
     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);
@@ -6977,13 +7446,21 @@ void register_machines(void)
     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
@@ -7120,14 +7597,16 @@ int main(int argc, char **argv)
     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];
@@ -7216,19 +7695,19 @@ int main(int argc, char **argv)
     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)
@@ -7246,7 +7725,7 @@ int main(int argc, char **argv)
             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);
                 }
@@ -7273,25 +7752,20 @@ int main(int argc, char **argv)
                     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;
                 }
@@ -7384,15 +7858,34 @@ int main(int argc, char **argv)
                 }
                 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:
@@ -7432,7 +7925,7 @@ int main(int argc, char **argv)
                 break;
 #endif
             case QEMU_OPTION_redir:
-                net_slirp_redir(optarg);                
+                net_slirp_redir(optarg);
                 break;
 #endif
 #ifdef HAS_AUDIO
@@ -7445,12 +7938,12 @@ int main(int argc, char **argv)
                 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));
@@ -7461,7 +7954,7 @@ int main(int argc, char **argv)
                 {
                     int mask;
                     CPULogItem *item;
-                    
+
                     mask = cpu_str_to_log_mask(optarg);
                     if (!mask) {
                         printf("Log items (comma separated):\n");
@@ -7484,6 +7977,9 @@ int main(int argc, char **argv)
             case QEMU_OPTION_L:
                 bios_dir = optarg;
                 break;
+            case QEMU_OPTION_bios:
+                bios_name = optarg;
+                break;
             case QEMU_OPTION_S:
                 autostart = 0;
                 break;
@@ -7525,7 +8021,7 @@ int main(int argc, char **argv)
                     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') {
@@ -7533,7 +8029,7 @@ int main(int argc, char **argv)
                     } else {
                         goto graphic_error;
                     }
-                    
+
                     graphic_width = w;
                     graphic_height = h;
                     graphic_depth = depth;
@@ -7555,7 +8051,7 @@ int main(int argc, char **argv)
                     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;
@@ -7564,7 +8060,7 @@ int main(int argc, char **argv)
                     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;
@@ -7661,6 +8157,49 @@ int main(int argc, char **argv)
                 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;
             }
         }
     }
@@ -7730,24 +8269,27 @@ int main(int argc, char **argv)
         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();
@@ -7784,24 +8326,31 @@ int main(int argc, char **argv)
     }
 
 #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
 
@@ -7917,12 +8466,16 @@ int main(int argc, char **argv)
         /* 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);
 #elif defined(CONFIG_COCOA)
         cocoa_display_init(ds, full_screen);
+#else
+        dumb_display_init(ds);
 #endif
     }
 
@@ -7953,11 +8506,11 @@ int main(int argc, char **argv)
         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);
         }
     }
@@ -7967,17 +8520,16 @@ int main(int argc, char **argv)
         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 */
@@ -8004,8 +8556,9 @@ int main(int argc, char **argv)
                     gdbstub_port);
             exit(1);
         }
-    } else 
+    }
 #endif
+
     if (loadvm)
         do_loadvm(loadvm);
 
@@ -8030,7 +8583,7 @@ int main(int argc, char **argv)
        if (len != 1)
            exit(1);
 
-       fd = open("/dev/null", O_RDWR);
+       TFR(fd = open("/dev/null", O_RDWR));
        if (fd == -1)
            exit(1);
 
@@ -8043,5 +8596,23 @@ int main(int argc, char **argv)
 
     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;
 }
This page took 0.124386 seconds and 4 git commands to generate.