Diff for /qemu/vl.c between versions 1.1.1.6 and 1.1.1.7

version 1.1.1.6, 2018/04/24 16:47:02 version 1.1.1.7, 2018/04/24 16:50:15
Line 26 Line 26
 #include "hw/usb.h"  #include "hw/usb.h"
 #include "hw/pcmcia.h"  #include "hw/pcmcia.h"
 #include "hw/pc.h"  #include "hw/pc.h"
 #include "hw/fdc.h"  
 #include "hw/audiodev.h"  #include "hw/audiodev.h"
 #include "hw/isa.h"  #include "hw/isa.h"
   #include "hw/baum.h"
   #include "hw/bt.h"
 #include "net.h"  #include "net.h"
 #include "console.h"  #include "console.h"
 #include "sysemu.h"  #include "sysemu.h"
 #include "gdbstub.h"  #include "gdbstub.h"
 #include "qemu-timer.h"  #include "qemu-timer.h"
 #include "qemu-char.h"  #include "qemu-char.h"
   #include "cache-utils.h"
 #include "block.h"  #include "block.h"
 #include "audio/audio.h"  #include "audio/audio.h"
   #include "migration.h"
   #include "kvm.h"
   #include "balloon.h"
   
 #include <unistd.h>  #include <unistd.h>
 #include <fcntl.h>  #include <fcntl.h>
Line 47 Line 52
 #include <zlib.h>  #include <zlib.h>
   
 #ifndef _WIN32  #ifndef _WIN32
   #include <pwd.h>
 #include <sys/times.h>  #include <sys/times.h>
 #include <sys/wait.h>  #include <sys/wait.h>
 #include <termios.h>  #include <termios.h>
 #include <sys/poll.h>  
 #include <sys/mman.h>  #include <sys/mman.h>
 #include <sys/ioctl.h>  #include <sys/ioctl.h>
   #include <sys/resource.h>
 #include <sys/socket.h>  #include <sys/socket.h>
 #include <netinet/in.h>  #include <netinet/in.h>
   #include <net/if.h>
   #if defined(__NetBSD__)
   #include <net/if_tap.h>
   #endif
   #ifdef __linux__
   #include <linux/if_tun.h>
   #endif
   #include <arpa/inet.h>
 #include <dirent.h>  #include <dirent.h>
 #include <netdb.h>  #include <netdb.h>
 #include <sys/select.h>  #include <sys/select.h>
 #include <arpa/inet.h>  
 #ifdef _BSD  #ifdef _BSD
 #include <sys/stat.h>  #include <sys/stat.h>
 #ifndef __APPLE__  #ifdef __FreeBSD__
 #include <libutil.h>  #include <libutil.h>
   #else
   #include <util.h>
 #endif  #endif
 #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)  #elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
 #include <freebsd/stdlib.h>  #include <freebsd/stdlib.h>
 #else  #else
 #ifndef __sun__  #ifdef __linux__
 #include <linux/if.h>  
 #include <linux/if_tun.h>  
 #include <pty.h>  #include <pty.h>
 #include <malloc.h>  #include <malloc.h>
 #include <linux/rtc.h>  #include <linux/rtc.h>
Line 81 Line 94
   
 #include <linux/ppdev.h>  #include <linux/ppdev.h>
 #include <linux/parport.h>  #include <linux/parport.h>
 #else  #endif
   #ifdef __sun__
 #include <sys/stat.h>  #include <sys/stat.h>
 #include <sys/ethernet.h>  #include <sys/ethernet.h>
 #include <sys/sockio.h>  #include <sys/sockio.h>
Line 97 Line 111
 #include <stropts.h>  #include <stropts.h>
 #endif  #endif
 #endif  #endif
 #else  
 #include <winsock2.h>  
 int inet_aton(const char *cp, struct in_addr *ia);  
 #endif  #endif
   
   #include "qemu_socket.h"
   
 #if defined(CONFIG_SLIRP)  #if defined(CONFIG_SLIRP)
 #include "libslirp.h"  #include "libslirp.h"
 #endif  #endif
   
   #if defined(__OpenBSD__)
   #include <util.h>
   #endif
   
   #if defined(CONFIG_VDE)
   #include <libvdeplug.h>
   #endif
   
 #ifdef _WIN32  #ifdef _WIN32
 #include <malloc.h>  #include <malloc.h>
 #include <sys/timeb.h>  #include <sys/timeb.h>
Line 114  int inet_aton(const char *cp, struct in_ Line 135  int inet_aton(const char *cp, struct in_
 #define memalign(align, size) malloc(size)  #define memalign(align, size) malloc(size)
 #endif  #endif
   
 #include "qemu_socket.h"  
   
 #ifdef CONFIG_SDL  #ifdef CONFIG_SDL
 #ifdef __APPLE__  #ifdef __APPLE__
 #include <SDL/SDL.h>  #include <SDL/SDL.h>
   int qemu_main(int argc, char **argv, char **envp);
   int main(int argc, char **argv)
   {
       qemu_main(argc, argv, NULL);
   }
   #undef main
   #define main qemu_main
 #endif  #endif
 #endif /* CONFIG_SDL */  #endif /* CONFIG_SDL */
   
Line 131  int inet_aton(const char *cp, struct in_ Line 157  int inet_aton(const char *cp, struct in_
   
 #include "exec-all.h"  #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 SMBD_COMMAND "/usr/sbin/smbd"  
 #endif  
   
 //#define DEBUG_UNUSED_IOPORT  //#define DEBUG_UNUSED_IOPORT
 //#define DEBUG_IOPORT  //#define DEBUG_IOPORT
   //#define DEBUG_NET
   //#define DEBUG_SLIRP
   
 #define PHYS_RAM_MAX_SIZE (2047 * 1024 * 1024)  
   
 #ifdef TARGET_PPC  #ifdef DEBUG_IOPORT
 #define DEFAULT_RAM_SIZE 144  #  define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__)
 #else  #else
 #define DEFAULT_RAM_SIZE 128  #  define LOG_IOPORT(...) do { } while (0)
 #endif  #endif
 /* in ms */  
 #define GUI_REFRESH_INTERVAL 30  #define DEFAULT_RAM_SIZE 128
   
 /* Max number of USB devices that can be specified on the commandline.  */  /* Max number of USB devices that can be specified on the commandline.  */
 #define MAX_USB_CMDLINE 8  #define MAX_USB_CMDLINE 8
   
   /* Max number of bluetooth switches on the commandline.  */
   #define MAX_BT_CMDLINE 10
   
 /* XXX: use a two level table to limit memory usage */  /* XXX: use a two level table to limit memory usage */
 #define MAX_IOPORTS 65536  #define MAX_IOPORTS 65536
   
 const char *bios_dir = CONFIG_QEMU_SHAREDIR;  const char *bios_dir = CONFIG_QEMU_SHAREDIR;
 const char *bios_name = NULL;  const char *bios_name = NULL;
 void *ioport_opaque[MAX_IOPORTS];  static void *ioport_opaque[MAX_IOPORTS];
 IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];  static IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
 IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];  static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
 /* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available  /* Note: drives_table[MAX_DRIVES] is a dummy block driver if none available
    to store the VM snapshots */     to store the VM snapshots */
 DriveInfo drives_table[MAX_DRIVES+1];  DriveInfo drives_table[MAX_DRIVES+1];
 int nb_drives;  int nb_drives;
 /* point to the block driver where the snapshots are managed */  static int vga_ram_size;
 BlockDriverState *bs_snapshots;  enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB;
 int vga_ram_size;  static DisplayState *display_state;
 static DisplayState display_state;  
 int nographic;  int nographic;
   static int curses;
   static int sdl;
 const char* keyboard_layout = NULL;  const char* keyboard_layout = NULL;
 int64_t ticks_per_sec;  int64_t ticks_per_sec;
 int ram_size;  ram_addr_t ram_size;
 int pit_min_timer_count = 0;  
 int nb_nics;  int nb_nics;
 NICInfo nd_table[MAX_NICS];  NICInfo nd_table[MAX_NICS];
 int vm_running;  int vm_running;
 int rtc_utc = 1;  static int rtc_utc = 1;
 int rtc_start_date = -1; /* -1 means now */  static int rtc_date_offset = -1; /* -1 means no change */
 int cirrus_vga_enabled = 1;  int cirrus_vga_enabled = 1;
   int std_vga_enabled = 0;
 int vmsvga_enabled = 0;  int vmsvga_enabled = 0;
 #ifdef TARGET_SPARC  #ifdef TARGET_SPARC
 int graphic_width = 1024;  int graphic_width = 1024;
Line 192  int graphic_width = 800; Line 215  int graphic_width = 800;
 int graphic_height = 600;  int graphic_height = 600;
 int graphic_depth = 15;  int graphic_depth = 15;
 #endif  #endif
 int full_screen = 0;  static int full_screen = 0;
 int no_frame = 0;  #ifdef CONFIG_SDL
   static int no_frame = 0;
   #endif
 int no_quit = 0;  int no_quit = 0;
 CharDriverState *serial_hds[MAX_SERIAL_PORTS];  CharDriverState *serial_hds[MAX_SERIAL_PORTS];
 CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];  CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
   CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES];
 #ifdef TARGET_I386  #ifdef TARGET_I386
 int win2k_install_hack = 0;  int win2k_install_hack = 0;
   int rtc_td_hack = 0;
 #endif  #endif
 int usb_enabled = 0;  int usb_enabled = 0;
 static VLANState *first_vlan;  
 int smp_cpus = 1;  int smp_cpus = 1;
 const char *vnc_display;  const char *vnc_display;
 #if defined(TARGET_SPARC)  
 #define MAX_CPUS 16  
 #elif defined(TARGET_I386)  
 #define MAX_CPUS 255  
 #else  
 #define MAX_CPUS 1  
 #endif  
 int acpi_enabled = 1;  int acpi_enabled = 1;
   int no_hpet = 0;
 int fd_bootchk = 1;  int fd_bootchk = 1;
 int no_reboot = 0;  int no_reboot = 0;
   int no_shutdown = 0;
 int cursor_hide = 1;  int cursor_hide = 1;
 int graphic_rotate = 0;  int graphic_rotate = 0;
 int daemonize = 0;  int daemonize = 0;
 const char *option_rom[MAX_OPTION_ROMS];  const char *option_rom[MAX_OPTION_ROMS];
 int nb_option_roms;  int nb_option_roms;
 int semihosting_enabled = 0;  int semihosting_enabled = 0;
 int autostart = 1;  
 #ifdef TARGET_ARM  #ifdef TARGET_ARM
 int old_param = 0;  int old_param = 0;
 #endif  #endif
 const char *qemu_name;  const char *qemu_name;
 int alt_grab = 0;  int alt_grab = 0;
 #ifdef TARGET_SPARC  #if defined(TARGET_SPARC) || defined(TARGET_PPC)
 unsigned int nb_prom_envs = 0;  unsigned int nb_prom_envs = 0;
 const char *prom_envs[MAX_PROM_ENVS];  const char *prom_envs[MAX_PROM_ENVS];
 #endif  #endif
 int nb_drives_opt;  int nb_drives_opt;
 char drives_opt[MAX_DRIVES][1024];  struct drive_opt drives_opt[MAX_DRIVES];
   
 static CPUState *cur_cpu;  static CPUState *cur_cpu;
 static CPUState *next_cpu;  static CPUState *next_cpu;
 static int event_pending = 1;  static int event_pending = 1;
   /* Conversion factor from emulated instructions to virtual clock ticks.  */
   static int icount_time_shift;
   /* Arbitrarily pick 1MIPS as the minimum allowable speed.  */
   #define MAX_ICOUNT_SHIFT 10
   /* Compensate for varying guest execution speed.  */
   static int64_t qemu_icount_bias;
   static QEMUTimer *icount_rt_timer;
   static QEMUTimer *icount_vm_timer;
   static QEMUTimer *nographic_timer;
   
 #define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR)  uint8_t qemu_uuid[16];
   
 /***********************************************************/  /***********************************************************/
 /* x86 ISA bus support */  /* x86 ISA bus support */
Line 245  static int event_pending = 1; Line 274  static int event_pending = 1;
 target_phys_addr_t isa_mem_base = 0;  target_phys_addr_t isa_mem_base = 0;
 PicState2 *isa_pic;  PicState2 *isa_pic;
   
   static IOPortReadFunc default_ioport_readb, default_ioport_readw, default_ioport_readl;
   static IOPortWriteFunc default_ioport_writeb, default_ioport_writew, default_ioport_writel;
   
   static uint32_t ioport_read(int index, uint32_t address)
   {
       static IOPortReadFunc *default_func[3] = {
           default_ioport_readb,
           default_ioport_readw,
           default_ioport_readl
       };
       IOPortReadFunc *func = ioport_read_table[index][address];
       if (!func)
           func = default_func[index];
       return func(ioport_opaque[address], address);
   }
   
   static void ioport_write(int index, uint32_t address, uint32_t data)
   {
       static IOPortWriteFunc *default_func[3] = {
           default_ioport_writeb,
           default_ioport_writew,
           default_ioport_writel
       };
       IOPortWriteFunc *func = ioport_write_table[index][address];
       if (!func)
           func = default_func[index];
       func(ioport_opaque[address], address, data);
   }
   
 static uint32_t default_ioport_readb(void *opaque, uint32_t address)  static uint32_t default_ioport_readb(void *opaque, uint32_t address)
 {  {
 #ifdef DEBUG_UNUSED_IOPORT  #ifdef DEBUG_UNUSED_IOPORT
Line 264  static void default_ioport_writeb(void * Line 322  static void default_ioport_writeb(void *
 static uint32_t default_ioport_readw(void *opaque, uint32_t address)  static uint32_t default_ioport_readw(void *opaque, uint32_t address)
 {  {
     uint32_t data;      uint32_t data;
     data = ioport_read_table[0][address](ioport_opaque[address], address);      data = ioport_read(0, address);
     address = (address + 1) & (MAX_IOPORTS - 1);      address = (address + 1) & (MAX_IOPORTS - 1);
     data |= ioport_read_table[0][address](ioport_opaque[address], address) << 8;      data |= ioport_read(0, address) << 8;
     return data;      return data;
 }  }
   
 static 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);      ioport_write(0, address, data & 0xff);
     address = (address + 1) & (MAX_IOPORTS - 1);      address = (address + 1) & (MAX_IOPORTS - 1);
     ioport_write_table[0][address](ioport_opaque[address], address, (data >> 8) & 0xff);      ioport_write(0, address, (data >> 8) & 0xff);
 }  }
   
 static uint32_t default_ioport_readl(void *opaque, uint32_t address)  static uint32_t default_ioport_readl(void *opaque, uint32_t address)
Line 292  static void default_ioport_writel(void * Line 350  static void default_ioport_writel(void *
 #endif  #endif
 }  }
   
 static void init_ioports(void)  
 {  
     int i;  
   
     for(i = 0; i < MAX_IOPORTS; i++) {  
         ioport_read_table[0][i] = default_ioport_readb;  
         ioport_write_table[0][i] = default_ioport_writeb;  
         ioport_read_table[1][i] = default_ioport_readw;  
         ioport_write_table[1][i] = default_ioport_writew;  
         ioport_read_table[2][i] = default_ioport_readl;  
         ioport_write_table[2][i] = default_ioport_writel;  
     }  
 }  
   
 /* size is the word size in byte */  /* 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)                           IOPortReadFunc *func, void *opaque)
Line 368  void isa_unassign_ioport(int start, int  Line 412  void isa_unassign_ioport(int start, int 
         ioport_write_table[0][i] = default_ioport_writeb;          ioport_write_table[0][i] = default_ioport_writeb;
         ioport_write_table[1][i] = default_ioport_writew;          ioport_write_table[1][i] = default_ioport_writew;
         ioport_write_table[2][i] = default_ioport_writel;          ioport_write_table[2][i] = default_ioport_writel;
   
           ioport_opaque[i] = NULL;
     }      }
 }  }
   
Line 375  void isa_unassign_ioport(int start, int  Line 421  void isa_unassign_ioport(int start, int 
   
 void cpu_outb(CPUState *env, int addr, int val)  void cpu_outb(CPUState *env, int addr, int val)
 {  {
 #ifdef DEBUG_IOPORT      LOG_IOPORT("outb: %04x %02x\n", addr, val);
     if (loglevel & CPU_LOG_IOPORT)      ioport_write(0, addr, val);
         fprintf(logfile, "outb: %04x %02x\n", addr, val);  
 #endif  
     ioport_write_table[0][addr](ioport_opaque[addr], addr, val);  
 #ifdef USE_KQEMU  #ifdef USE_KQEMU
     if (env)      if (env)
         env->last_io_time = cpu_get_time_fast();          env->last_io_time = cpu_get_time_fast();
Line 388  void cpu_outb(CPUState *env, int addr, i Line 431  void cpu_outb(CPUState *env, int addr, i
   
 void cpu_outw(CPUState *env, int addr, int val)  void cpu_outw(CPUState *env, int addr, int val)
 {  {
 #ifdef DEBUG_IOPORT      LOG_IOPORT("outw: %04x %04x\n", addr, val);
     if (loglevel & CPU_LOG_IOPORT)      ioport_write(1, addr, val);
         fprintf(logfile, "outw: %04x %04x\n", addr, val);  
 #endif  
     ioport_write_table[1][addr](ioport_opaque[addr], addr, val);  
 #ifdef USE_KQEMU  #ifdef USE_KQEMU
     if (env)      if (env)
         env->last_io_time = cpu_get_time_fast();          env->last_io_time = cpu_get_time_fast();
Line 401  void cpu_outw(CPUState *env, int addr, i Line 441  void cpu_outw(CPUState *env, int addr, i
   
 void cpu_outl(CPUState *env, int addr, int val)  void cpu_outl(CPUState *env, int addr, int val)
 {  {
 #ifdef DEBUG_IOPORT      LOG_IOPORT("outl: %04x %08x\n", addr, val);
     if (loglevel & CPU_LOG_IOPORT)      ioport_write(2, addr, val);
         fprintf(logfile, "outl: %04x %08x\n", addr, val);  
 #endif  
     ioport_write_table[2][addr](ioport_opaque[addr], addr, val);  
 #ifdef USE_KQEMU  #ifdef USE_KQEMU
     if (env)      if (env)
         env->last_io_time = cpu_get_time_fast();          env->last_io_time = cpu_get_time_fast();
Line 415  void cpu_outl(CPUState *env, int addr, i Line 452  void cpu_outl(CPUState *env, int addr, i
 int cpu_inb(CPUState *env, int addr)  int cpu_inb(CPUState *env, int addr)
 {  {
     int val;      int val;
     val = ioport_read_table[0][addr](ioport_opaque[addr], addr);      val = ioport_read(0, addr);
 #ifdef DEBUG_IOPORT      LOG_IOPORT("inb : %04x %02x\n", addr, val);
     if (loglevel & CPU_LOG_IOPORT)  
         fprintf(logfile, "inb : %04x %02x\n", addr, val);  
 #endif  
 #ifdef USE_KQEMU  #ifdef USE_KQEMU
     if (env)      if (env)
         env->last_io_time = cpu_get_time_fast();          env->last_io_time = cpu_get_time_fast();
Line 430  int cpu_inb(CPUState *env, int addr) Line 464  int cpu_inb(CPUState *env, int addr)
 int cpu_inw(CPUState *env, int addr)  int cpu_inw(CPUState *env, int addr)
 {  {
     int val;      int val;
     val = ioport_read_table[1][addr](ioport_opaque[addr], addr);      val = ioport_read(1, addr);
 #ifdef DEBUG_IOPORT      LOG_IOPORT("inw : %04x %04x\n", addr, val);
     if (loglevel & CPU_LOG_IOPORT)  
         fprintf(logfile, "inw : %04x %04x\n", addr, val);  
 #endif  
 #ifdef USE_KQEMU  #ifdef USE_KQEMU
     if (env)      if (env)
         env->last_io_time = cpu_get_time_fast();          env->last_io_time = cpu_get_time_fast();
Line 445  int cpu_inw(CPUState *env, int addr) Line 476  int cpu_inw(CPUState *env, int addr)
 int cpu_inl(CPUState *env, int addr)  int cpu_inl(CPUState *env, int addr)
 {  {
     int val;      int val;
     val = ioport_read_table[2][addr](ioport_opaque[addr], addr);      val = ioport_read(2, addr);
 #ifdef DEBUG_IOPORT      LOG_IOPORT("inl : %04x %08x\n", addr, val);
     if (loglevel & CPU_LOG_IOPORT)  
         fprintf(logfile, "inl : %04x %08x\n", addr, val);  
 #endif  
 #ifdef USE_KQEMU  #ifdef USE_KQEMU
     if (env)      if (env)
         env->last_io_time = cpu_get_time_fast();          env->last_io_time = cpu_get_time_fast();
Line 478  void hw_error(const char *fmt, ...) Line 506  void hw_error(const char *fmt, ...)
     va_end(ap);      va_end(ap);
     abort();      abort();
 }  }
    
   /***************/
   /* ballooning */
   
   static QEMUBalloonEvent *qemu_balloon_event;
   void *qemu_balloon_event_opaque;
   
   void qemu_add_balloon_handler(QEMUBalloonEvent *func, void *opaque)
   {
       qemu_balloon_event = func;
       qemu_balloon_event_opaque = opaque;
   }
   
   void qemu_balloon(ram_addr_t target)
   {
       if (qemu_balloon_event)
           qemu_balloon_event(qemu_balloon_event_opaque, target);
   }
   
   ram_addr_t qemu_balloon_status(void)
   {
       if (qemu_balloon_event)
           return qemu_balloon_event(qemu_balloon_event_opaque, 0);
       return 0;
   }
   
 /***********************************************************/  /***********************************************************/
 /* keyboard/mouse */  /* keyboard/mouse */
Line 500  QEMUPutMouseEntry *qemu_add_mouse_event_ Line 553  QEMUPutMouseEntry *qemu_add_mouse_event_
     QEMUPutMouseEntry *s, *cursor;      QEMUPutMouseEntry *s, *cursor;
   
     s = qemu_mallocz(sizeof(QEMUPutMouseEntry));      s = qemu_mallocz(sizeof(QEMUPutMouseEntry));
     if (!s)  
         return NULL;  
   
     s->qemu_put_mouse_event = func;      s->qemu_put_mouse_event = func;
     s->qemu_put_mouse_event_opaque = opaque;      s->qemu_put_mouse_event_opaque = opaque;
Line 584  void kbd_mouse_event(int dx, int dy, int Line 635  void kbd_mouse_event(int dx, int dy, int
             if (qemu_put_mouse_event_current->qemu_put_mouse_event_absolute)              if (qemu_put_mouse_event_current->qemu_put_mouse_event_absolute)
                 width = 0x7fff;                  width = 0x7fff;
             else              else
                 width = graphic_width;                  width = graphic_width - 1;
             mouse_event(mouse_event_opaque,              mouse_event(mouse_event_opaque,
                                  width - dy, dx, dz, buttons_state);                                   width - dy, dx, dz, buttons_state);
         } else          } else
Line 703  static int use_rt_clock; Line 754  static int use_rt_clock;
 static void init_get_clock(void)  static void init_get_clock(void)
 {  {
     use_rt_clock = 0;      use_rt_clock = 0;
 #if defined(__linux__)  #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000)
     {      {
         struct timespec ts;          struct timespec ts;
         if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {          if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
Line 715  static void init_get_clock(void) Line 766  static void init_get_clock(void)
   
 static int64_t get_clock(void)  static int64_t get_clock(void)
 {  {
 #if defined(__linux__)  #if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000)
     if (use_rt_clock) {      if (use_rt_clock) {
         struct timespec ts;          struct timespec ts;
         clock_gettime(CLOCK_MONOTONIC, &ts);          clock_gettime(CLOCK_MONOTONIC, &ts);
Line 730  static int64_t get_clock(void) Line 781  static int64_t get_clock(void)
         return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);          return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
     }      }
 }  }
   
 #endif  #endif
   
   /* Return the virtual CPU time, based on the instruction counter.  */
   static int64_t cpu_get_icount(void)
   {
       int64_t icount;
       CPUState *env = cpu_single_env;;
       icount = qemu_icount;
       if (env) {
           if (!can_do_io(env))
               fprintf(stderr, "Bad clock read\n");
           icount -= (env->icount_decr.u16.low + env->icount_extra);
       }
       return qemu_icount_bias + (icount << icount_time_shift);
   }
   
 /***********************************************************/  /***********************************************************/
 /* guest cycle counter */  /* guest cycle counter */
   
Line 744  static int cpu_ticks_enabled; Line 808  static int cpu_ticks_enabled;
 /* return the host CPU cycle counter and handle stop/restart */  /* return the host CPU cycle counter and handle stop/restart */
 int64_t cpu_get_ticks(void)  int64_t cpu_get_ticks(void)
 {  {
       if (use_icount) {
           return cpu_get_icount();
       }
     if (!cpu_ticks_enabled) {      if (!cpu_ticks_enabled) {
         return cpu_ticks_offset;          return cpu_ticks_offset;
     } else {      } else {
Line 841  static void qemu_rearm_alarm_timer(struc Line 908  static void qemu_rearm_alarm_timer(struc
 #define MIN_TIMER_REARM_US 250  #define MIN_TIMER_REARM_US 250
   
 static struct qemu_alarm_timer *alarm_timer;  static struct qemu_alarm_timer *alarm_timer;
   #ifndef _WIN32
   static int alarm_timer_rfd, alarm_timer_wfd;
   #endif
   
 #ifdef _WIN32  #ifdef _WIN32
   
Line 875  static void rtc_stop_timer(struct qemu_a Line 945  static void rtc_stop_timer(struct qemu_a
   
 #endif /* _WIN32 */  #endif /* _WIN32 */
   
   /* Correlation between real and virtual time is always going to be
      fairly approximate, so ignore small variation.
      When the guest is idle real and virtual time will be aligned in
      the IO wait loop.  */
   #define ICOUNT_WOBBLE (QEMU_TIMER_BASE / 10)
   
   static void icount_adjust(void)
   {
       int64_t cur_time;
       int64_t cur_icount;
       int64_t delta;
       static int64_t last_delta;
       /* If the VM is not running, then do nothing.  */
       if (!vm_running)
           return;
   
       cur_time = cpu_get_clock();
       cur_icount = qemu_get_clock(vm_clock);
       delta = cur_icount - cur_time;
       /* FIXME: This is a very crude algorithm, somewhat prone to oscillation.  */
       if (delta > 0
           && last_delta + ICOUNT_WOBBLE < delta * 2
           && icount_time_shift > 0) {
           /* The guest is getting too far ahead.  Slow time down.  */
           icount_time_shift--;
       }
       if (delta < 0
           && last_delta - ICOUNT_WOBBLE > delta * 2
           && icount_time_shift < MAX_ICOUNT_SHIFT) {
           /* The guest is getting too far behind.  Speed time up.  */
           icount_time_shift++;
       }
       last_delta = delta;
       qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
   }
   
   static void icount_adjust_rt(void * opaque)
   {
       qemu_mod_timer(icount_rt_timer,
                      qemu_get_clock(rt_clock) + 1000);
       icount_adjust();
   }
   
   static void icount_adjust_vm(void * opaque)
   {
       qemu_mod_timer(icount_vm_timer,
                      qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10);
       icount_adjust();
   }
   
   static void init_icount_adjust(void)
   {
       /* Have both realtime and virtual time triggers for speed adjustment.
          The realtime trigger catches emulated time passing too slowly,
          the virtual time trigger catches emulated time passing too fast.
          Realtime triggers occur even when idle, so use them less frequently
          than VM triggers.  */
       icount_rt_timer = qemu_new_timer(rt_clock, icount_adjust_rt, NULL);
       qemu_mod_timer(icount_rt_timer,
                      qemu_get_clock(rt_clock) + 1000);
       icount_vm_timer = qemu_new_timer(vm_clock, icount_adjust_vm, NULL);
       qemu_mod_timer(icount_vm_timer,
                      qemu_get_clock(vm_clock) + QEMU_TIMER_BASE / 10);
   }
   
 static struct qemu_alarm_timer alarm_timers[] = {  static struct qemu_alarm_timer alarm_timers[] = {
 #ifndef _WIN32  #ifndef _WIN32
 #ifdef __linux__  #ifdef __linux__
Line 895  static struct qemu_alarm_timer alarm_tim Line 1030  static struct qemu_alarm_timer alarm_tim
     {NULL, }      {NULL, }
 };  };
   
 static void show_available_alarms()  static void show_available_alarms(void)
 {  {
     int i;      int i;
   
Line 908  static void configure_alarms(char const  Line 1043  static void configure_alarms(char const 
 {  {
     int i;      int i;
     int cur = 0;      int cur = 0;
     int count = (sizeof(alarm_timers) / sizeof(*alarm_timers)) - 1;      int count = ARRAY_SIZE(alarm_timers) - 1;
     char *arg;      char *arg;
     char *name;      char *name;
       struct qemu_alarm_timer tmp;
   
     if (!strcmp(opt, "help")) {      if (!strcmp(opt, "?")) {
         show_available_alarms();          show_available_alarms();
         exit(0);          exit(0);
     }      }
Line 922  static void configure_alarms(char const  Line 1058  static void configure_alarms(char const 
     /* Reorder the array */      /* Reorder the array */
     name = strtok(arg, ",");      name = strtok(arg, ",");
     while (name) {      while (name) {
         struct qemu_alarm_timer tmp;  
   
         for (i = 0; i < count && alarm_timers[i].name; i++) {          for (i = 0; i < count && alarm_timers[i].name; i++) {
             if (!strcmp(alarm_timers[i].name, name))              if (!strcmp(alarm_timers[i].name, name))
                 break;                  break;
Line 951  next: Line 1085  next:
     free(arg);      free(arg);
   
     if (cur) {      if (cur) {
         /* Disable remaining timers */          /* Disable remaining timers */
         for (i = cur; i < count; i++)          for (i = cur; i < count; i++)
             alarm_timers[i].name = NULL;              alarm_timers[i].name = NULL;
       } else {
           show_available_alarms();
           exit(1);
     }      }
   
     /* debug */  
     show_available_alarms();  
 }  }
   
 QEMUClock *rt_clock;  QEMUClock *rt_clock;
Line 969  static QEMUClock *qemu_new_clock(int typ Line 1103  static QEMUClock *qemu_new_clock(int typ
 {  {
     QEMUClock *clock;      QEMUClock *clock;
     clock = qemu_mallocz(sizeof(QEMUClock));      clock = qemu_mallocz(sizeof(QEMUClock));
     if (!clock)  
         return NULL;  
     clock->type = type;      clock->type = type;
     return clock;      return clock;
 }  }
Line 1036  void qemu_mod_timer(QEMUTimer *ts, int64 Line 1168  void qemu_mod_timer(QEMUTimer *ts, int64
     *pt = ts;      *pt = ts;
   
     /* Rearm if necessary  */      /* Rearm if necessary  */
     if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0 &&      if (pt == &active_timers[ts->clock->type]) {
         pt == &active_timers[ts->clock->type])          if ((alarm_timer->flags & ALARM_FLAG_EXPIRED) == 0) {
         qemu_rearm_alarm_timer(alarm_timer);              qemu_rearm_alarm_timer(alarm_timer);
           }
           /* Interrupt execution to force deadline recalculation.  */
           if (use_icount && cpu_single_env) {
               cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
           }
       }
 }  }
   
 int qemu_timer_pending(QEMUTimer *ts)  int qemu_timer_pending(QEMUTimer *ts)
Line 1082  int64_t qemu_get_clock(QEMUClock *clock) Line 1220  int64_t qemu_get_clock(QEMUClock *clock)
         return get_clock() / 1000000;          return get_clock() / 1000000;
     default:      default:
     case QEMU_TIMER_VIRTUAL:      case QEMU_TIMER_VIRTUAL:
         return cpu_get_clock();          if (use_icount) {
               return cpu_get_icount();
           } else {
               return cpu_get_clock();
           }
     }      }
 }  }
   
Line 1181  static void host_alarm_handler(int host_ Line 1323  static void host_alarm_handler(int host_
     }      }
 #endif  #endif
     if (alarm_has_dynticks(alarm_timer) ||      if (alarm_has_dynticks(alarm_timer) ||
         qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],          (!use_icount &&
                            qemu_get_clock(vm_clock)) ||              qemu_timer_expired(active_timers[QEMU_TIMER_VIRTUAL],
                                  qemu_get_clock(vm_clock))) ||
         qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],          qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME],
                            qemu_get_clock(rt_clock))) {                             qemu_get_clock(rt_clock))) {
           CPUState *env = next_cpu;
   
 #ifdef _WIN32  #ifdef _WIN32
         struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;          struct qemu_alarm_win32 *data = ((struct qemu_alarm_timer*)dwUser)->priv;
         SetEvent(data->host_alarm);          SetEvent(data->host_alarm);
   #else
           static const char byte = 0;
           write(alarm_timer_wfd, &byte, sizeof(byte));
 #endif  #endif
         CPUState *env = next_cpu;  
   
         alarm_timer->flags |= ALARM_FLAG_EXPIRED;          alarm_timer->flags |= ALARM_FLAG_EXPIRED;
   
         if (env) {          if (env) {
Line 1206  static void host_alarm_handler(int host_ Line 1352  static void host_alarm_handler(int host_
     }      }
 }  }
   
 static uint64_t qemu_next_deadline(void)  static int64_t qemu_next_deadline(void)
 {  {
     int64_t nearest_delta_us = INT64_MAX;      int64_t delta;
     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]) {      if (active_timers[QEMU_TIMER_VIRTUAL]) {
         /* round up */          delta = active_timers[QEMU_TIMER_VIRTUAL]->expire_time -
         vmdelta_us = (active_timers[QEMU_TIMER_VIRTUAL]->expire_time -                       qemu_get_clock(vm_clock);
                       qemu_get_clock(vm_clock)+999)/1000;      } else {
         if (vmdelta_us < nearest_delta_us)          /* To avoid problems with overflow limit this to 2^32.  */
             nearest_delta_us = vmdelta_us;          delta = INT32_MAX;
       }
   
       if (delta < 0)
           delta = 0;
   
       return delta;
   }
   
   #if defined(__linux__) || defined(_WIN32)
   static uint64_t qemu_next_deadline_dyntick(void)
   {
       int64_t delta;
       int64_t rtdelta;
   
       if (use_icount)
           delta = INT32_MAX;
       else
           delta = (qemu_next_deadline() + 999) / 1000;
   
       if (active_timers[QEMU_TIMER_REALTIME]) {
           rtdelta = (active_timers[QEMU_TIMER_REALTIME]->expire_time -
                    qemu_get_clock(rt_clock))*1000;
           if (rtdelta < delta)
               delta = rtdelta;
     }      }
   
     /* Avoid arming the timer to negative, zero, or too low values */      if (delta < MIN_TIMER_REARM_US)
     if (nearest_delta_us <= MIN_TIMER_REARM_US)          delta = MIN_TIMER_REARM_US;
         nearest_delta_us = MIN_TIMER_REARM_US;  
   
     return nearest_delta_us;      return delta;
 }  }
   #endif
   
 #ifndef _WIN32  #ifndef _WIN32
   
   /* Sets a specific flag */
   static int fcntl_setfl(int fd, int flag)
   {
       int flags;
   
       flags = fcntl(fd, F_GETFL);
       if (flags == -1)
           return -errno;
   
       if (fcntl(fd, F_SETFL, flags | flag) == -1)
           return -errno;
   
       return 0;
   }
   
 #if defined(__linux__)  #if defined(__linux__)
   
 #define RTC_FREQ 1024  #define RTC_FREQ 1024
Line 1246  static void enable_sigio_timer(int fd) Line 1426  static void enable_sigio_timer(int fd)
     act.sa_handler = host_alarm_handler;      act.sa_handler = host_alarm_handler;
   
     sigaction(SIGIO, &act, NULL);      sigaction(SIGIO, &act, NULL);
     fcntl(fd, F_SETFL, O_ASYNC);      fcntl_setfl(fd, O_ASYNC);
     fcntl(fd, F_SETOWN, getpid());      fcntl(fd, F_SETOWN, getpid());
 }  }
   
Line 1302  static void hpet_stop_timer(struct qemu_ Line 1482  static void hpet_stop_timer(struct qemu_
 static int rtc_start_timer(struct qemu_alarm_timer *t)  static int rtc_start_timer(struct qemu_alarm_timer *t)
 {  {
     int rtc_fd;      int rtc_fd;
       unsigned long current_rtc_freq = 0;
   
     TFR(rtc_fd = open("/dev/rtc", O_RDONLY));      TFR(rtc_fd = open("/dev/rtc", O_RDONLY));
     if (rtc_fd < 0)      if (rtc_fd < 0)
         return -1;          return -1;
     if (ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {      ioctl(rtc_fd, RTC_IRQP_READ, &current_rtc_freq);
       if (current_rtc_freq != RTC_FREQ &&
           ioctl(rtc_fd, RTC_IRQP_SET, RTC_FREQ) < 0) {
         fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"          fprintf(stderr, "Could not configure '/dev/rtc' to have a 1024 Hz timer. This is not a fatal\n"
                 "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"                  "error, but for better emulation accuracy either use a 2.6 host Linux kernel or\n"
                 "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");                  "type 'echo 1024 > /proc/sys/dev/rtc/max-user-freq' as root.\n");
Line 1357  static int dynticks_start_timer(struct q Line 1540  static int dynticks_start_timer(struct q
         return -1;          return -1;
     }      }
   
     t->priv = (void *)host_timer;      t->priv = (void *)(long)host_timer;
   
     return 0;      return 0;
 }  }
   
 static void dynticks_stop_timer(struct qemu_alarm_timer *t)  static void dynticks_stop_timer(struct qemu_alarm_timer *t)
 {  {
     timer_t host_timer = (timer_t)t->priv;      timer_t host_timer = (timer_t)(long)t->priv;
   
     timer_delete(host_timer);      timer_delete(host_timer);
 }  }
   
 static void dynticks_rearm_timer(struct qemu_alarm_timer *t)  static void dynticks_rearm_timer(struct qemu_alarm_timer *t)
 {  {
     timer_t host_timer = (timer_t)t->priv;      timer_t host_timer = (timer_t)(long)t->priv;
     struct itimerspec timeout;      struct itimerspec timeout;
     int64_t nearest_delta_us = INT64_MAX;      int64_t nearest_delta_us = INT64_MAX;
     int64_t current_us;      int64_t current_us;
Line 1380  static void dynticks_rearm_timer(struct  Line 1563  static void dynticks_rearm_timer(struct 
                 !active_timers[QEMU_TIMER_VIRTUAL])                  !active_timers[QEMU_TIMER_VIRTUAL])
         return;          return;
   
     nearest_delta_us = qemu_next_deadline();      nearest_delta_us = qemu_next_deadline_dyntick();
   
     /* check whether a timer is already running */      /* check whether a timer is already running */
     if (timer_gettime(host_timer, &timeout)) {      if (timer_gettime(host_timer, &timeout)) {
Line 1441  static void unix_stop_timer(struct qemu_ Line 1624  static void unix_stop_timer(struct qemu_
   
 #endif /* !defined(_WIN32) */  #endif /* !defined(_WIN32) */
   
   static void try_to_rearm_timer(void *opaque)
   {
       struct qemu_alarm_timer *t = opaque;
   #ifndef _WIN32
       ssize_t len;
   
       /* Drain the notify pipe */
       do {
           char buffer[512];
           len = read(alarm_timer_rfd, buffer, sizeof(buffer));
       } while ((len == -1 && errno == EINTR) || len > 0);
   #endif
   
       if (t->flags & ALARM_FLAG_EXPIRED) {
           alarm_timer->flags &= ~ALARM_FLAG_EXPIRED;
           qemu_rearm_alarm_timer(alarm_timer);
       }
   }
   
 #ifdef _WIN32  #ifdef _WIN32
   
 static int win32_start_timer(struct qemu_alarm_timer *t)  static int win32_start_timer(struct qemu_alarm_timer *t)
Line 1483  static int win32_start_timer(struct qemu Line 1685  static int win32_start_timer(struct qemu
         return -1;          return -1;
     }      }
   
     qemu_add_wait_object(data->host_alarm, NULL, NULL);      qemu_add_wait_object(data->host_alarm, try_to_rearm_timer, t);
   
     return 0;      return 0;
 }  }
Line 1507  static void win32_rearm_timer(struct qem Line 1709  static void win32_rearm_timer(struct qem
                 !active_timers[QEMU_TIMER_VIRTUAL])                  !active_timers[QEMU_TIMER_VIRTUAL])
         return;          return;
   
     nearest_delta_us = qemu_next_deadline();      nearest_delta_us = qemu_next_deadline_dyntick();
     nearest_delta_us /= 1000;      nearest_delta_us /= 1000;
   
     timeKillEvent(data->timerId);      timeKillEvent(data->timerId);
Line 1529  static void win32_rearm_timer(struct qem Line 1731  static void win32_rearm_timer(struct qem
   
 #endif /* _WIN32 */  #endif /* _WIN32 */
   
 static void init_timer_alarm(void)  static int init_timer_alarm(void)
 {  {
     struct qemu_alarm_timer *t;      struct qemu_alarm_timer *t = NULL;
     int i, err = -1;      int i, err = -1;
   
   #ifndef _WIN32
       int fds[2];
   
       err = pipe(fds);
       if (err == -1)
           return -errno;
   
       err = fcntl_setfl(fds[0], O_NONBLOCK);
       if (err < 0)
           goto fail;
   
       err = fcntl_setfl(fds[1], O_NONBLOCK);
       if (err < 0)
           goto fail;
   
       alarm_timer_rfd = fds[0];
       alarm_timer_wfd = fds[1];
   #endif
   
     for (i = 0; alarm_timers[i].name; i++) {      for (i = 0; alarm_timers[i].name; i++) {
         t = &alarm_timers[i];          t = &alarm_timers[i];
   
Line 1543  static void init_timer_alarm(void) Line 1764  static void init_timer_alarm(void)
     }      }
   
     if (err) {      if (err) {
         fprintf(stderr, "Unable to find any suitable alarm timer.\n");          err = -ENOENT;
         fprintf(stderr, "Terminating\n");          goto fail;
         exit(1);  
     }      }
   
   #ifndef _WIN32
       qemu_set_fd_handler2(alarm_timer_rfd, NULL,
                            try_to_rearm_timer, NULL, t);
   #endif
   
     alarm_timer = t;      alarm_timer = t;
   
       return 0;
   
   fail:
   #ifndef _WIN32
       close(fds[0]);
       close(fds[1]);
   #endif
       return err;
 }  }
   
 static void quit_timers(void)  static void quit_timers(void)
Line 1558  static void quit_timers(void) Line 1792  static void quit_timers(void)
 }  }
   
 /***********************************************************/  /***********************************************************/
 /* character device */  /* host time/date access */
   void qemu_get_timedate(struct tm *tm, int offset)
 static void qemu_chr_event(CharDriverState *s, int event)  
 {  
     if (!s->chr_event)  
         return;  
     s->chr_event(s->handler_opaque, event);  
 }  
   
 static void qemu_chr_reset_bh(void *opaque)  
 {  {
     CharDriverState *s = opaque;      time_t ti;
     qemu_chr_event(s, CHR_EVENT_RESET);      struct tm *ret;
     qemu_bh_delete(s->bh);  
     s->bh = NULL;  
 }  
   
 void qemu_chr_reset(CharDriverState *s)      time(&ti);
 {      ti += offset;
     if (s->bh == NULL) {      if (rtc_date_offset == -1) {
         s->bh = qemu_bh_new(qemu_chr_reset_bh, s);          if (rtc_utc)
         qemu_bh_schedule(s->bh);              ret = gmtime(&ti);
           else
               ret = localtime(&ti);
       } else {
           ti -= rtc_date_offset;
           ret = gmtime(&ti);
     }      }
 }  
   
 int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)      memcpy(tm, ret, sizeof(struct tm));
 {  
     return s->chr_write(s, buf, len);  
 }  }
   
 int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)  int qemu_timedate_diff(struct tm *tm)
 {  {
     if (!s->chr_ioctl)      time_t seconds;
         return -ENOTSUP;  
     return s->chr_ioctl(s, cmd, arg);  
 }  
   
 int qemu_chr_can_read(CharDriverState *s)      if (rtc_date_offset == -1)
 {          if (rtc_utc)
     if (!s->chr_can_read)              seconds = mktimegm(tm);
         return 0;          else
     return s->chr_can_read(s->handler_opaque);              seconds = mktime(tm);
 }      else
           seconds = mktimegm(tm) + rtc_date_offset;
   
 void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)      return seconds - time(NULL);
 {  
     s->chr_read(s->handler_opaque, buf, len);  
 }  }
   
 void qemu_chr_accept_input(CharDriverState *s)  #ifdef _WIN32
   static void socket_cleanup(void)
 {  {
     if (s->chr_accept_input)      WSACleanup();
         s->chr_accept_input(s);  
 }  }
   
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)  static int socket_init(void)
 {  {
     char buf[4096];      WSADATA Data;
     va_list ap;      int ret, err;
     va_start(ap, fmt);  
     vsnprintf(buf, sizeof(buf), fmt, ap);  
     qemu_chr_write(s, (uint8_t *)buf, strlen(buf));  
     va_end(ap);  
 }  
   
 void qemu_chr_send_event(CharDriverState *s, int event)      ret = WSAStartup(MAKEWORD(2,2), &Data);
 {      if (ret != 0) {
     if (s->chr_send_event)          err = WSAGetLastError();
         s->chr_send_event(s, event);          fprintf(stderr, "WSAStartup: %d\n", err);
           return -1;
       }
       atexit(socket_cleanup);
       return 0;
 }  }
   #endif
   
 void qemu_chr_add_handlers(CharDriverState *s,  const char *get_opt_name(char *buf, int buf_size, const char *p)
                            IOCanRWHandler *fd_can_read,  
                            IOReadHandler *fd_read,  
                            IOEventHandler *fd_event,  
                            void *opaque)  
 {  {
     s->chr_can_read = fd_can_read;      char *q;
     s->chr_read = fd_read;  
     s->chr_event = fd_event;  
     s->handler_opaque = opaque;  
     if (s->chr_update_read_handler)  
         s->chr_update_read_handler(s);  
 }  
   
 static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)      q = buf;
 {      while (*p != '\0' && *p != '=') {
     return len;          if (q && (q - buf) < buf_size - 1)
               *q++ = *p;
           p++;
       }
       if (q)
           *q = '\0';
   
       return p;
 }  }
   
 static CharDriverState *qemu_chr_open_null(void)  const char *get_opt_value(char *buf, int buf_size, const char *p)
 {  {
     CharDriverState *chr;      char *q;
   
     chr = qemu_mallocz(sizeof(CharDriverState));  
     if (!chr)  
         return NULL;  
     chr->chr_write = null_chr_write;  
     return chr;  
 }  
   
 /* MUX driver for serial I/O splitting */      q = buf;
 static int term_timestamps;      while (*p != '\0') {
 static int64_t term_timestamps_start;          if (*p == ',') {
 #define MAX_MUX 4              if (*(p + 1) != ',')
 #define MUX_BUFFER_SIZE 32      /* Must be a power of 2.  */                  break;
 #define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)              p++;
 typedef struct {          }
     IOCanRWHandler *chr_can_read[MAX_MUX];          if (q && (q - buf) < buf_size - 1)
     IOReadHandler *chr_read[MAX_MUX];              *q++ = *p;
     IOEventHandler *chr_event[MAX_MUX];          p++;
     void *ext_opaque[MAX_MUX];      }
     CharDriverState *drv;      if (q)
     unsigned char buffer[MUX_BUFFER_SIZE];          *q = '\0';
     int prod;  
     int cons;  
     int mux_cnt;  
     int term_got_escape;  
     int max_size;  
 } MuxDriver;  
   
       return p;
   }
   
 static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)  int get_param_value(char *buf, int buf_size,
                       const char *tag, const char *str)
 {  {
     MuxDriver *d = chr->opaque;      const char *p;
     int ret;      char option[128];
     if (!term_timestamps) {  
         ret = d->drv->chr_write(d->drv, buf, len);  
     } else {  
         int i;  
   
         ret = 0;      p = str;
         for(i = 0; i < len; i++) {      for(;;) {
             ret += d->drv->chr_write(d->drv, buf+i, 1);          p = get_opt_name(option, sizeof(option), p);
             if (buf[i] == '\n') {          if (*p != '=')
                 char buf1[64];              break;
                 int64_t ti;          p++;
                 int secs;          if (!strcmp(tag, option)) {
               (void)get_opt_value(buf, buf_size, p);
                 ti = get_clock();              return strlen(buf);
                 if (term_timestamps_start == -1)          } else {
                     term_timestamps_start = ti;              p = get_opt_value(NULL, 0, p);
                 ti -= term_timestamps_start;  
                 secs = ti / 1000000000;  
                 snprintf(buf1, sizeof(buf1),  
                          "[%02d:%02d:%02d.%03d] ",  
                          secs / 3600,  
                          (secs / 60) % 60,  
                          secs % 60,  
                          (int)((ti / 1000000) % 1000));  
                 d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));  
             }  
         }          }
           if (*p != ',')
               break;
           p++;
     }      }
     return ret;      return 0;
 }  }
   
 static char *mux_help[] = {  int check_params(char *buf, int buf_size,
     "% h    print this help\n\r",                   const char * const *params, const char *str)
     "% x    exit emulator\n\r",  
     "% s    save disk data back to file (if -snapshot)\n\r",  
     "% t    toggle console timestamps\n\r"  
     "% b    send break (magic sysrq)\n\r",  
     "% c    switch between console and monitor\n\r",  
     "% %  sends %\n\r",  
     NULL  
 };  
   
 static int term_escape_char = 0x01; /* ctrl-a is used for escape */  
 static void mux_print_help(CharDriverState *chr)  
 {  {
     int i, j;      const char *p;
     char ebuf[15] = "Escape-Char";      int i;
     char cbuf[50] = "\n\r";  
   
     if (term_escape_char > 0 && term_escape_char < 26) {  
         sprintf(cbuf,"\n\r");  
         sprintf(ebuf,"C-%c", term_escape_char - 1 + 'a');  
     } else {  
         sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",  
             term_escape_char);  
     }  
     chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf));  
     for (i = 0; mux_help[i] != NULL; i++) {  
         for (j=0; mux_help[i][j] != '\0'; j++) {  
             if (mux_help[i][j] == '%')  
                 chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf));  
             else  
                 chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1);  
         }  
     }  
 }  
   
 static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)      p = str;
 {      for(;;) {
     if (d->term_got_escape) {          p = get_opt_name(buf, buf_size, p);
         d->term_got_escape = 0;          if (*p != '=')
         if (ch == term_escape_char)              return -1;
             goto send_char;          p++;
         switch(ch) {          for(i = 0; params[i] != NULL; i++)
         case '?':              if (!strcmp(params[i], buf))
         case 'h':                  break;
             mux_print_help(chr);          if (params[i] == NULL)
             break;              return -1;
         case 'x':          p = get_opt_value(NULL, 0, p);
             {          if (*p != ',')
                  char *term =  "QEMU: Terminated\n\r";  
                  chr->chr_write(chr,(uint8_t *)term,strlen(term));  
                  exit(0);  
                  break;  
             }  
         case 's':  
             {  
                 int i;  
                 for (i = 0; i < nb_drives; i++) {  
                         bdrv_commit(drives_table[i].bdrv);  
                 }  
             }  
             break;  
         case 'b':  
             qemu_chr_event(chr, CHR_EVENT_BREAK);  
             break;  
         case 'c':  
             /* Switch to the next registered device */  
             chr->focus++;  
             if (chr->focus >= d->mux_cnt)  
                 chr->focus = 0;  
             break;              break;
        case 't':          p++;
            term_timestamps = !term_timestamps;  
            term_timestamps_start = -1;  
            break;  
         }  
     } else if (ch == term_escape_char) {  
         d->term_got_escape = 1;  
     } else {  
     send_char:  
         return 1;  
     }      }
     return 0;      return 0;
 }  }
   
 static void mux_chr_accept_input(CharDriverState *chr)  /***********************************************************/
 {  /* Bluetooth support */
     int m = chr->focus;  static int nb_hcis;
     MuxDriver *d = chr->opaque;  static int cur_hci;
   static struct HCIInfo *hci_table[MAX_NICS];
   
   static struct bt_vlan_s {
       struct bt_scatternet_s net;
       int id;
       struct bt_vlan_s *next;
   } *first_bt_vlan;
   
     while (d->prod != d->cons &&  /* find or alloc a new bluetooth "VLAN" */
            d->chr_can_read[m] &&  static struct bt_scatternet_s *qemu_find_bt_vlan(int id)
            d->chr_can_read[m](d->ext_opaque[m])) {  {
         d->chr_read[m](d->ext_opaque[m],      struct bt_vlan_s **pvlan, *vlan;
                        &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1);      for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) {
           if (vlan->id == id)
               return &vlan->net;
     }      }
       vlan = qemu_mallocz(sizeof(struct bt_vlan_s));
       vlan->id = id;
       pvlan = &first_bt_vlan;
       while (*pvlan != NULL)
           pvlan = &(*pvlan)->next;
       *pvlan = vlan;
       return &vlan->net;
 }  }
   
 static int mux_chr_can_read(void *opaque)  static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len)
 {  {
     CharDriverState *chr = opaque;  
     MuxDriver *d = chr->opaque;  
   
     if ((d->prod - d->cons) < MUX_BUFFER_SIZE)  
         return 1;  
     if (d->chr_can_read[chr->focus])  
         return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);  
     return 0;  
 }  }
   
 static void mux_chr_read(void *opaque, const uint8_t *buf, int size)  static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
 {  {
     CharDriverState *chr = opaque;      return -ENOTSUP;
     MuxDriver *d = chr->opaque;  
     int m = chr->focus;  
     int i;  
   
     mux_chr_accept_input (opaque);  
   
     for(i = 0; i < size; i++)  
         if (mux_proc_byte(chr, d, buf[i])) {  
             if (d->prod == d->cons &&  
                 d->chr_can_read[m] &&  
                 d->chr_can_read[m](d->ext_opaque[m]))  
                 d->chr_read[m](d->ext_opaque[m], &buf[i], 1);  
             else  
                 d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i];  
         }  
 }  }
   
 static void mux_chr_event(void *opaque, int event)  static struct HCIInfo null_hci = {
       .cmd_send = null_hci_send,
       .sco_send = null_hci_send,
       .acl_send = null_hci_send,
       .bdaddr_set = null_hci_addr_set,
   };
   
   struct HCIInfo *qemu_next_hci(void)
 {  {
     CharDriverState *chr = opaque;      if (cur_hci == nb_hcis)
     MuxDriver *d = chr->opaque;          return &null_hci;
     int i;  
   
     /* Send the event to all registered listeners */      return hci_table[cur_hci++];
     for (i = 0; i < d->mux_cnt; i++)  
         if (d->chr_event[i])  
             d->chr_event[i](d->ext_opaque[i], event);  
 }  }
   
 static void mux_chr_update_read_handler(CharDriverState *chr)  static struct HCIInfo *hci_init(const char *str)
 {  {
     MuxDriver *d = chr->opaque;      char *endp;
       struct bt_scatternet_s *vlan = 0;
     if (d->mux_cnt >= MAX_MUX) {  
         fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");      if (!strcmp(str, "null"))
         return;          /* null */
           return &null_hci;
       else if (!strncmp(str, "host", 4) && (str[4] == '\0' || str[4] == ':'))
           /* host[:hciN] */
           return bt_host_hci(str[4] ? str + 5 : "hci0");
       else if (!strncmp(str, "hci", 3)) {
           /* hci[,vlan=n] */
           if (str[3]) {
               if (!strncmp(str + 3, ",vlan=", 6)) {
                   vlan = qemu_find_bt_vlan(strtol(str + 9, &endp, 0));
                   if (*endp)
                       vlan = 0;
               }
           } else
               vlan = qemu_find_bt_vlan(0);
           if (vlan)
              return bt_new_hci(vlan);
     }      }
     d->ext_opaque[d->mux_cnt] = chr->handler_opaque;  
     d->chr_can_read[d->mux_cnt] = chr->chr_can_read;      fprintf(stderr, "qemu: Unknown bluetooth HCI `%s'.\n", str);
     d->chr_read[d->mux_cnt] = chr->chr_read;  
     d->chr_event[d->mux_cnt] = chr->chr_event;      return 0;
     /* Fix up the real driver with mux routines */  
     if (d->mux_cnt == 0) {  
         qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,  
                               mux_chr_event, chr);  
     }  
     chr->focus = d->mux_cnt;  
     d->mux_cnt++;  
 }  }
   
 static CharDriverState *qemu_chr_open_mux(CharDriverState *drv)  static int bt_hci_parse(const char *str)
 {  {
     CharDriverState *chr;      struct HCIInfo *hci;
     MuxDriver *d;      bdaddr_t bdaddr;
   
     chr = qemu_mallocz(sizeof(CharDriverState));      if (nb_hcis >= MAX_NICS) {
     if (!chr)          fprintf(stderr, "qemu: Too many bluetooth HCIs (max %i).\n", MAX_NICS);
         return NULL;          return -1;
     d = qemu_mallocz(sizeof(MuxDriver));  
     if (!d) {  
         free(chr);  
         return NULL;  
     }      }
   
     chr->opaque = d;      hci = hci_init(str);
     d->drv = drv;      if (!hci)
     chr->focus = -1;          return -1;
     chr->chr_write = mux_chr_write;  
     chr->chr_update_read_handler = mux_chr_update_read_handler;  
     chr->chr_accept_input = mux_chr_accept_input;  
     return chr;  
 }  
   
       bdaddr.b[0] = 0x52;
       bdaddr.b[1] = 0x54;
       bdaddr.b[2] = 0x00;
       bdaddr.b[3] = 0x12;
       bdaddr.b[4] = 0x34;
       bdaddr.b[5] = 0x56 + nb_hcis;
       hci->bdaddr_set(hci, bdaddr.b);
   
 #ifdef _WIN32      hci_table[nb_hcis++] = hci;
   
 static void socket_cleanup(void)      return 0;
 {  
     WSACleanup();  
 }  }
   
 static int socket_init(void)  static void bt_vhci_add(int vlan_id)
 {  {
     WSADATA Data;      struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id);
     int ret, err;  
   
     ret = WSAStartup(MAKEWORD(2,2), &Data);      if (!vlan->slave)
     if (ret != 0) {          fprintf(stderr, "qemu: warning: adding a VHCI to "
         err = WSAGetLastError();                          "an empty scatternet %i\n", vlan_id);
         fprintf(stderr, "WSAStartup: %d\n", err);  
         return -1;      bt_vhci_init(bt_new_hci(vlan));
     }  
     atexit(socket_cleanup);  
     return 0;  
 }  }
   
 static int send_all(int fd, const uint8_t *buf, int len1)  static struct bt_device_s *bt_device_add(const char *opt)
 {  {
     int ret, len;      struct bt_scatternet_s *vlan;
       int vlan_id = 0;
       char *endp = strstr(opt, ",vlan=");
       int len = (endp ? endp - opt : strlen(opt)) + 1;
       char devname[10];
   
     len = len1;      pstrcpy(devname, MIN(sizeof(devname), len), opt);
     while (len > 0) {  
         ret = send(fd, buf, len, 0);      if (endp) {
         if (ret < 0) {          vlan_id = strtol(endp + 6, &endp, 0);
             int errno;          if (*endp) {
             errno = WSAGetLastError();              fprintf(stderr, "qemu: unrecognised bluetooth vlan Id\n");
             if (errno != WSAEWOULDBLOCK) {              return 0;
                 return -1;  
             }  
         } else if (ret == 0) {  
             break;  
         } else {  
             buf += ret;  
             len -= ret;  
         }          }
     }      }
     return len1 - len;  
 }  
   
 void socket_set_nonblock(int fd)  
 {  
     unsigned long opt = 1;  
     ioctlsocket(fd, FIONBIO, &opt);  
 }  
   
 #else      vlan = qemu_find_bt_vlan(vlan_id);
   
 static int unix_write(int fd, const uint8_t *buf, int len1)      if (!vlan->slave)
 {          fprintf(stderr, "qemu: warning: adding a slave device to "
     int ret, len;                          "an empty scatternet %i\n", vlan_id);
   
     len = len1;      if (!strcmp(devname, "keyboard"))
     while (len > 0) {          return bt_keyboard_init(vlan);
         ret = write(fd, buf, len);  
         if (ret < 0) {  
             if (errno != EINTR && errno != EAGAIN)  
                 return -1;  
         } else if (ret == 0) {  
             break;  
         } else {  
             buf += ret;  
             len -= ret;  
         }  
     }  
     return len1 - len;  
 }  
   
 static inline int send_all(int fd, const uint8_t *buf, int len1)      fprintf(stderr, "qemu: unsupported bluetooth device `%s'\n", devname);
 {      return 0;
     return unix_write(fd, buf, len1);  
 }  }
   
 void socket_set_nonblock(int fd)  static int bt_parse(const char *opt)
 {  {
     fcntl(fd, F_SETFL, O_NONBLOCK);      const char *endp, *p;
 }      int vlan;
 #endif /* !_WIN32 */  
   
 #ifndef _WIN32      if (strstart(opt, "hci", &endp)) {
           if (!*endp || *endp == ',') {
               if (*endp)
                   if (!strstart(endp, ",vlan=", 0))
                       opt = endp + 1;
   
 typedef struct {              return bt_hci_parse(opt);
     int fd_in, fd_out;         }
     int max_size;      } else if (strstart(opt, "vhci", &endp)) {
 } FDCharDriver;          if (!*endp || *endp == ',') {
               if (*endp) {
                   if (strstart(endp, ",vlan=", &p)) {
                       vlan = strtol(p, (char **) &endp, 0);
                       if (*endp) {
                           fprintf(stderr, "qemu: bad scatternet '%s'\n", p);
                           return 1;
                       }
                   } else {
                       fprintf(stderr, "qemu: bad parameter '%s'\n", endp + 1);
                       return 1;
                   }
               } else
                   vlan = 0;
   
 #define STDIO_MAX_CLIENTS 1              bt_vhci_add(vlan);
 static int stdio_nb_clients = 0;              return 0;
           }
       } else if (strstart(opt, "device:", &endp))
           return !bt_device_add(endp);
   
 static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)      fprintf(stderr, "qemu: bad bluetooth parameter '%s'\n", opt);
 {      return 1;
     FDCharDriver *s = chr->opaque;  
     return unix_write(s->fd_out, buf, len);  
 }  }
   
 static int fd_chr_read_poll(void *opaque)  /***********************************************************/
 {  /* QEMU Block devices */
     CharDriverState *chr = opaque;  
     FDCharDriver *s = chr->opaque;  
   
     s->max_size = qemu_chr_can_read(chr);  #define HD_ALIAS "index=%d,media=disk"
     return s->max_size;  #ifdef TARGET_PPC
 }  #define CDROM_ALIAS "index=1,media=cdrom"
   #else
   #define CDROM_ALIAS "index=2,media=cdrom"
   #endif
   #define FD_ALIAS "index=%d,if=floppy"
   #define PFLASH_ALIAS "if=pflash"
   #define MTD_ALIAS "if=mtd"
   #define SD_ALIAS "index=0,if=sd"
   
 static void fd_chr_read(void *opaque)  static int drive_opt_get_free_idx(void)
 {  {
     CharDriverState *chr = opaque;      int index;
     FDCharDriver *s = chr->opaque;  
     int size, len;  
     uint8_t buf[1024];  
   
     len = sizeof(buf);      for (index = 0; index < MAX_DRIVES; index++)
     if (len > s->max_size)          if (!drives_opt[index].used) {
         len = s->max_size;              drives_opt[index].used = 1;
     if (len == 0)              return index;
         return;          }
     size = read(s->fd_in, buf, len);  
     if (size == 0) {      return -1;
         /* FD has been closed. Remove it from the active list.  */  
         qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);  
         return;  
     }  
     if (size > 0) {  
         qemu_chr_read(chr, buf, size);  
     }  
 }  }
   
 static void fd_chr_update_read_handler(CharDriverState *chr)  static int drive_get_free_idx(void)
 {  {
     FDCharDriver *s = chr->opaque;      int index;
   
     if (s->fd_in >= 0) {      for (index = 0; index < MAX_DRIVES; index++)
         if (nographic && s->fd_in == 0) {          if (!drives_table[index].used) {
         } else {              drives_table[index].used = 1;
             qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,              return index;
                                  fd_chr_read, NULL, chr);  
         }          }
     }  
       return -1;
 }  }
   
 /* open a character device to a unix fd */  int drive_add(const char *file, const char *fmt, ...)
 static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)  
 {  {
     CharDriverState *chr;      va_list ap;
     FDCharDriver *s;      int index = drive_opt_get_free_idx();
   
     chr = qemu_mallocz(sizeof(CharDriverState));      if (nb_drives_opt >= MAX_DRIVES || index == -1) {
     if (!chr)          fprintf(stderr, "qemu: too many drives\n");
         return NULL;          return -1;
     s = qemu_mallocz(sizeof(FDCharDriver));  
     if (!s) {  
         free(chr);  
         return NULL;  
     }      }
     s->fd_in = fd_in;  
     s->fd_out = fd_out;  
     chr->opaque = s;  
     chr->chr_write = fd_chr_write;  
     chr->chr_update_read_handler = fd_chr_update_read_handler;  
   
     qemu_chr_reset(chr);      drives_opt[index].file = file;
       va_start(ap, fmt);
       vsnprintf(drives_opt[index].opt,
                 sizeof(drives_opt[0].opt), fmt, ap);
       va_end(ap);
   
     return chr;      nb_drives_opt++;
       return index;
 }  }
   
 static CharDriverState *qemu_chr_open_file_out(const char *file_out)  void drive_remove(int index)
 {  {
     int fd_out;      drives_opt[index].used = 0;
       nb_drives_opt--;
     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);  
 }  }
   
 static CharDriverState *qemu_chr_open_pipe(const char *filename)  int drive_get_index(BlockInterfaceType type, int bus, int unit)
 {  {
     int fd_in, fd_out;      int index;
     char filename_in[256], filename_out[256];  
   
     snprintf(filename_in, 256, "%s.in", filename);  
     snprintf(filename_out, 256, "%s.out", filename);  
     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);  
         TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY));  
         if (fd_in < 0)  
             return NULL;  
     }  
     return qemu_chr_open_fd(fd_in, fd_out);  
 }  
   
   
 /* for STDIO, we handle the case where several clients use it      /* seek interface, bus and unit */
    (nographic mode) */  
   
 #define TERM_FIFO_MAX_SIZE 1      for (index = 0; index < MAX_DRIVES; index++)
           if (drives_table[index].type == type &&
               drives_table[index].bus == bus &&
               drives_table[index].unit == unit &&
               drives_table[index].used)
           return index;
   
 static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];      return -1;
 static int term_fifo_size;  }
   
 static int stdio_read_poll(void *opaque)  int drive_get_max_bus(BlockInterfaceType type)
 {  {
     CharDriverState *chr = opaque;      int max_bus;
       int index;
   
     /* try to flush the queue if needed */      max_bus = -1;
     if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {      for (index = 0; index < nb_drives; index++) {
         qemu_chr_read(chr, term_fifo, 1);          if(drives_table[index].type == type &&
         term_fifo_size = 0;             drives_table[index].bus > max_bus)
               max_bus = drives_table[index].bus;
     }      }
     /* see if we can absorb more chars */      return max_bus;
     if (term_fifo_size == 0)  
         return 1;  
     else  
         return 0;  
 }  }
   
 static void stdio_read(void *opaque)  const char *drive_get_serial(BlockDriverState *bdrv)
 {  {
     int size;      int index;
     uint8_t buf[1];  
     CharDriverState *chr = opaque;  
   
     size = read(0, buf, 1);  
     if (size == 0) {  
         /* stdin has been closed. Remove it from the active list.  */  
         qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);  
         return;  
     }  
     if (size > 0) {  
         if (qemu_chr_can_read(chr) > 0) {  
             qemu_chr_read(chr, buf, 1);  
         } else if (term_fifo_size == 0) {  
             term_fifo[term_fifo_size++] = buf[0];  
         }  
     }  
 }  
   
 /* init terminal so that we can grab keys */      for (index = 0; index < nb_drives; index++)
 static struct termios oldtty;          if (drives_table[index].bdrv == bdrv)
 static int old_fd0_flags;              return drives_table[index].serial;
   
 static void term_exit(void)      return "\0";
 {  
     tcsetattr (0, TCSANOW, &oldtty);  
     fcntl(0, F_SETFL, old_fd0_flags);  
 }  }
   
 static void term_init(void)  BlockInterfaceErrorAction drive_get_onerror(BlockDriverState *bdrv)
 {  {
     struct termios tty;      int index;
   
     tcgetattr (0, &tty);  
     oldtty = tty;  
     old_fd0_flags = fcntl(0, F_GETFL);  
   
     tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP  
                           |INLCR|IGNCR|ICRNL|IXON);  
     tty.c_oflag |= OPOST;  
     tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);  
     /* if graphical mode, we allow Ctrl-C handling */  
     if (nographic)  
         tty.c_lflag &= ~ISIG;  
     tty.c_cflag &= ~(CSIZE|PARENB);  
     tty.c_cflag |= CS8;  
     tty.c_cc[VMIN] = 1;  
     tty.c_cc[VTIME] = 0;  
   
     tcsetattr (0, TCSANOW, &tty);  
   
     atexit(term_exit);      for (index = 0; index < nb_drives; index++)
           if (drives_table[index].bdrv == bdrv)
               return drives_table[index].onerror;
   
     fcntl(0, F_SETFL, O_NONBLOCK);      return BLOCK_ERR_STOP_ENOSPC;
 }  }
   
 static CharDriverState *qemu_chr_open_stdio(void)  static void bdrv_format_print(void *opaque, const char *name)
 {  {
     CharDriverState *chr;      fprintf(stderr, " %s", name);
   
     if (stdio_nb_clients >= STDIO_MAX_CLIENTS)  
         return NULL;  
     chr = qemu_chr_open_fd(0, 1);  
     qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);  
     stdio_nb_clients++;  
     term_init();  
   
     return chr;  
 }  }
   
 #if defined(__linux__) || defined(__sun__)  void drive_uninit(BlockDriverState *bdrv)
 static CharDriverState *qemu_chr_open_pty(void)  
 {  {
     struct termios tty;      int i;
     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 */      for (i = 0; i < MAX_DRIVES; i++)
     tcgetattr (master_fd, &tty);          if (drives_table[i].bdrv == bdrv) {
     tty.c_lflag &= ~(ECHO|ICANON|ISIG);              drives_table[i].bdrv = NULL;
     tty.c_cc[VMIN] = 1;              drives_table[i].used = 0;
     tty.c_cc[VTIME] = 0;              drive_remove(drives_table[i].drive_opt_idx);
     tcsetattr (master_fd, TCSAFLUSH, &tty);              nb_drives--;
               break;
     fprintf(stderr, "char device redirected to %s\n", slave_name);          }
     return qemu_chr_open_fd(master_fd, master_fd);  
 }  }
   
 static void tty_serial_init(int fd, int speed,  int drive_init(struct drive_opt *arg, int snapshot, void *opaque)
                             int parity, int data_bits, int stop_bits)  
 {  {
     struct termios tty;      char buf[128];
     speed_t spd;      char file[1024];
       char devname[128];
 #if 0      char serial[21];
     printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",      const char *mediastr = "";
            speed, parity, data_bits, stop_bits);      BlockInterfaceType type;
 #endif      enum { MEDIA_DISK, MEDIA_CDROM } media;
     tcgetattr (fd, &tty);      int bus_id, unit_id;
       int cyls, heads, secs, translation;
       BlockDriverState *bdrv;
       BlockDriver *drv = NULL;
       QEMUMachine *machine = opaque;
       int max_devs;
       int index;
       int cache;
       int bdrv_flags, onerror;
       int drives_table_idx;
       char *str = arg->opt;
       static const char * const params[] = { "bus", "unit", "if", "index",
                                              "cyls", "heads", "secs", "trans",
                                              "media", "snapshot", "file",
                                              "cache", "format", "serial", "werror",
                                              NULL };
   
     switch(speed) {      if (check_params(buf, sizeof(buf), params, str) < 0) {
     case 50:           fprintf(stderr, "qemu: unknown parameter '%s' in '%s'\n",
         spd = B50;                           buf, str);
         break;           return -1;
     case 75:  
         spd = B75;  
         break;  
     case 300:  
         spd = B300;  
         break;  
     case 600:  
         spd = B600;  
         break;  
     case 1200:  
         spd = B1200;  
         break;  
     case 2400:  
         spd = B2400;  
         break;  
     case 4800:  
         spd = B4800;  
         break;  
     case 9600:  
         spd = B9600;  
         break;  
     case 19200:  
         spd = B19200;  
         break;  
     case 38400:  
         spd = B38400;  
         break;  
     case 57600:  
         spd = B57600;  
         break;  
     default:  
     case 115200:  
         spd = B115200;  
         break;  
     }      }
   
     cfsetispeed(&tty, spd);      file[0] = 0;
     cfsetospeed(&tty, spd);      cyls = heads = secs = 0;
       bus_id = 0;
       unit_id = -1;
       translation = BIOS_ATA_TRANSLATION_AUTO;
       index = -1;
       cache = 3;
   
     tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP      if (machine->use_scsi) {
                           |INLCR|IGNCR|ICRNL|IXON);          type = IF_SCSI;
     tty.c_oflag |= OPOST;          max_devs = MAX_SCSI_DEVS;
     tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);          pstrcpy(devname, sizeof(devname), "scsi");
     tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB);      } else {
     switch(data_bits) {          type = IF_IDE;
     default:          max_devs = MAX_IDE_DEVS;
     case 8:          pstrcpy(devname, sizeof(devname), "ide");
         tty.c_cflag |= CS8;  
         break;  
     case 7:  
         tty.c_cflag |= CS7;  
         break;  
     case 6:  
         tty.c_cflag |= CS6;  
         break;  
     case 5:  
         tty.c_cflag |= CS5;  
         break;  
     }  
     switch(parity) {  
     default:  
     case 'N':  
         break;  
     case 'E':  
         tty.c_cflag |= PARENB;  
         break;  
     case 'O':  
         tty.c_cflag |= PARENB | PARODD;  
         break;  
     }      }
     if (stop_bits == 2)      media = MEDIA_DISK;
         tty.c_cflag |= CSTOPB;  
   
     tcsetattr (fd, TCSANOW, &tty);      /* extract parameters */
 }  
   
 static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)      if (get_param_value(buf, sizeof(buf), "bus", str)) {
 {          bus_id = strtol(buf, NULL, 0);
     FDCharDriver *s = chr->opaque;          if (bus_id < 0) {
               fprintf(stderr, "qemu: '%s' invalid bus id\n", str);
               return -1;
           }
       }
   
     switch(cmd) {      if (get_param_value(buf, sizeof(buf), "unit", str)) {
     case CHR_IOCTL_SERIAL_SET_PARAMS:          unit_id = strtol(buf, NULL, 0);
         {          if (unit_id < 0) {
             QEMUSerialSetParams *ssp = arg;              fprintf(stderr, "qemu: '%s' invalid unit id\n", str);
             tty_serial_init(s->fd_in, ssp->speed, ssp->parity,              return -1;
                             ssp->data_bits, ssp->stop_bits);  
         }  
         break;  
     case CHR_IOCTL_SERIAL_SET_BREAK:  
         {  
             int enable = *(int *)arg;  
             if (enable)  
                 tcsendbreak(s->fd_in, 1);  
         }  
         break;  
     default:  
         return -ENOTSUP;  
     }  
     return 0;  
 }  
   
 static CharDriverState *qemu_chr_open_tty(const char *filename)  
 {  
     CharDriverState *chr;  
     int fd;  
   
     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) {  
         close(fd);  
         return NULL;  
     }  
     chr->chr_ioctl = tty_serial_ioctl;  
     qemu_chr_reset(chr);  
     return chr;  
 }  
 #else  /* ! __linux__ && ! __sun__ */  
 static CharDriverState *qemu_chr_open_pty(void)  
 {  
     return NULL;  
 }  
 #endif /* __linux__ || __sun__ */  
   
 #if defined(__linux__)  
 typedef struct {  
     int fd;  
     int mode;  
 } ParallelCharDriver;  
   
 static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)  
 {  
     if (s->mode != mode) {  
         int m = mode;  
         if (ioctl(s->fd, PPSETMODE, &m) < 0)  
             return 0;  
         s->mode = mode;  
     }  
     return 1;  
 }  
   
 static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)  
 {  
     ParallelCharDriver *drv = chr->opaque;  
     int fd = drv->fd;  
     uint8_t b;  
   
     switch(cmd) {  
     case CHR_IOCTL_PP_READ_DATA:  
         if (ioctl(fd, PPRDATA, &b) < 0)  
             return -ENOTSUP;  
         *(uint8_t *)arg = b;  
         break;  
     case CHR_IOCTL_PP_WRITE_DATA:  
         b = *(uint8_t *)arg;  
         if (ioctl(fd, PPWDATA, &b) < 0)  
             return -ENOTSUP;  
         break;  
     case CHR_IOCTL_PP_READ_CONTROL:  
         if (ioctl(fd, PPRCONTROL, &b) < 0)  
             return -ENOTSUP;  
         /* Linux gives only the lowest bits, and no way to know data  
            direction! For better compatibility set the fixed upper  
            bits. */  
         *(uint8_t *)arg = b | 0xc0;  
         break;  
     case CHR_IOCTL_PP_WRITE_CONTROL:  
         b = *(uint8_t *)arg;  
         if (ioctl(fd, PPWCONTROL, &b) < 0)  
             return -ENOTSUP;  
         break;  
     case CHR_IOCTL_PP_READ_STATUS:  
         if (ioctl(fd, PPRSTATUS, &b) < 0)  
             return -ENOTSUP;  
         *(uint8_t *)arg = b;  
         break;  
     case CHR_IOCTL_PP_EPP_READ_ADDR:  
         if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {  
             struct ParallelIOArg *parg = arg;  
             int n = read(fd, parg->buffer, parg->count);  
             if (n != parg->count) {  
                 return -EIO;  
             }  
         }  
         break;  
     case CHR_IOCTL_PP_EPP_READ:  
         if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {  
             struct ParallelIOArg *parg = arg;  
             int n = read(fd, parg->buffer, parg->count);  
             if (n != parg->count) {  
                 return -EIO;  
             }  
         }  
         break;  
     case CHR_IOCTL_PP_EPP_WRITE_ADDR:  
         if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {  
             struct ParallelIOArg *parg = arg;  
             int n = write(fd, parg->buffer, parg->count);  
             if (n != parg->count) {  
                 return -EIO;  
             }  
         }  
         break;  
     case CHR_IOCTL_PP_EPP_WRITE:  
         if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {  
             struct ParallelIOArg *parg = arg;  
             int n = write(fd, parg->buffer, parg->count);  
             if (n != parg->count) {  
                 return -EIO;  
             }  
         }          }
         break;  
     default:  
         return -ENOTSUP;  
     }  
     return 0;  
 }  
   
 static void pp_close(CharDriverState *chr)  
 {  
     ParallelCharDriver *drv = chr->opaque;  
     int fd = drv->fd;  
   
     pp_hw_mode(drv, IEEE1284_MODE_COMPAT);  
     ioctl(fd, PPRELEASE);  
     close(fd);  
     qemu_free(drv);  
 }  
   
 static CharDriverState *qemu_chr_open_pp(const char *filename)  
 {  
     CharDriverState *chr;  
     ParallelCharDriver *drv;  
     int fd;  
   
     TFR(fd = open(filename, O_RDWR));  
     if (fd < 0)  
         return NULL;  
   
     if (ioctl(fd, PPCLAIM) < 0) {  
         close(fd);  
         return NULL;  
     }  
   
     drv = qemu_mallocz(sizeof(ParallelCharDriver));  
     if (!drv) {  
         close(fd);  
         return NULL;  
     }      }
     drv->fd = fd;  
     drv->mode = IEEE1284_MODE_COMPAT;  
   
     chr = qemu_mallocz(sizeof(CharDriverState));      if (get_param_value(buf, sizeof(buf), "if", str)) {
     if (!chr) {          pstrcpy(devname, sizeof(devname), buf);
         qemu_free(drv);          if (!strcmp(buf, "ide")) {
         close(fd);              type = IF_IDE;
         return NULL;              max_devs = MAX_IDE_DEVS;
           } else if (!strcmp(buf, "scsi")) {
               type = IF_SCSI;
               max_devs = MAX_SCSI_DEVS;
           } else if (!strcmp(buf, "floppy")) {
               type = IF_FLOPPY;
               max_devs = 0;
           } else if (!strcmp(buf, "pflash")) {
               type = IF_PFLASH;
               max_devs = 0;
           } else if (!strcmp(buf, "mtd")) {
               type = IF_MTD;
               max_devs = 0;
           } else if (!strcmp(buf, "sd")) {
               type = IF_SD;
               max_devs = 0;
           } else if (!strcmp(buf, "virtio")) {
               type = IF_VIRTIO;
               max_devs = 0;
           } else {
               fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);
               return -1;
           }
     }      }
     chr->chr_write = null_chr_write;  
     chr->chr_ioctl = pp_ioctl;  
     chr->chr_close = pp_close;  
     chr->opaque = drv;  
   
     qemu_chr_reset(chr);  
   
     return chr;  
 }  
 #endif /* __linux__ */  
   
 #else /* _WIN32 */  
   
 typedef struct {      if (get_param_value(buf, sizeof(buf), "index", str)) {
     int max_size;          index = strtol(buf, NULL, 0);
     HANDLE hcom, hrecv, hsend;          if (index < 0) {
     OVERLAPPED orecv, osend;              fprintf(stderr, "qemu: '%s' invalid index\n", str);
     BOOL fpipe;              return -1;
     DWORD len;          }
 } WinCharState;  
   
 #define NSENDBUF 2048  
 #define NRECVBUF 2048  
 #define MAXCONNECT 1  
 #define NTIMEOUT 5000  
   
 static int win_chr_poll(void *opaque);  
 static int win_chr_pipe_poll(void *opaque);  
   
 static void win_chr_close(CharDriverState *chr)  
 {  
     WinCharState *s = chr->opaque;  
   
     if (s->hsend) {  
         CloseHandle(s->hsend);  
         s->hsend = NULL;  
     }  
     if (s->hrecv) {  
         CloseHandle(s->hrecv);  
         s->hrecv = NULL;  
     }  
     if (s->hcom) {  
         CloseHandle(s->hcom);  
         s->hcom = NULL;  
     }      }
     if (s->fpipe)  
         qemu_del_polling_cb(win_chr_pipe_poll, chr);  
     else  
         qemu_del_polling_cb(win_chr_poll, chr);  
 }  
   
 static int win_chr_init(CharDriverState *chr, const char *filename)  
 {  
     WinCharState *s = chr->opaque;  
     COMMCONFIG comcfg;  
     COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};  
     COMSTAT comstat;  
     DWORD size;  
     DWORD err;  
   
     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);      if (get_param_value(buf, sizeof(buf), "cyls", str)) {
     if (!s->hsend) {          cyls = strtol(buf, NULL, 0);
         fprintf(stderr, "Failed CreateEvent\n");  
         goto fail;  
     }  
     s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);  
     if (!s->hrecv) {  
         fprintf(stderr, "Failed CreateEvent\n");  
         goto fail;  
     }      }
   
     s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,      if (get_param_value(buf, sizeof(buf), "heads", str)) {
                       OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);          heads = strtol(buf, NULL, 0);
     if (s->hcom == INVALID_HANDLE_VALUE) {  
         fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());  
         s->hcom = NULL;  
         goto fail;  
     }      }
   
     if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {      if (get_param_value(buf, sizeof(buf), "secs", str)) {
         fprintf(stderr, "Failed SetupComm\n");          secs = strtol(buf, NULL, 0);
         goto fail;  
     }      }
   
     ZeroMemory(&comcfg, sizeof(COMMCONFIG));      if (cyls || heads || secs) {
     size = sizeof(COMMCONFIG);          if (cyls < 1 || cyls > 16383) {
     GetDefaultCommConfig(filename, &comcfg, &size);              fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", str);
     comcfg.dcb.DCBlength = sizeof(DCB);              return -1;
     CommConfigDialog(filename, NULL, &comcfg);          }
           if (heads < 1 || heads > 16) {
     if (!SetCommState(s->hcom, &comcfg.dcb)) {              fprintf(stderr, "qemu: '%s' invalid physical heads number\n", str);
         fprintf(stderr, "Failed SetCommState\n");              return -1;
         goto fail;          }
           if (secs < 1 || secs > 63) {
               fprintf(stderr, "qemu: '%s' invalid physical secs number\n", str);
               return -1;
           }
     }      }
   
     if (!SetCommMask(s->hcom, EV_ERR)) {      if (get_param_value(buf, sizeof(buf), "trans", str)) {
         fprintf(stderr, "Failed SetCommMask\n");          if (!cyls) {
         goto fail;              fprintf(stderr,
                       "qemu: '%s' trans must be used with cyls,heads and secs\n",
                       str);
               return -1;
           }
           if (!strcmp(buf, "none"))
               translation = BIOS_ATA_TRANSLATION_NONE;
           else if (!strcmp(buf, "lba"))
               translation = BIOS_ATA_TRANSLATION_LBA;
           else if (!strcmp(buf, "auto"))
               translation = BIOS_ATA_TRANSLATION_AUTO;
           else {
               fprintf(stderr, "qemu: '%s' invalid translation type\n", str);
               return -1;
           }
     }      }
   
     cto.ReadIntervalTimeout = MAXDWORD;      if (get_param_value(buf, sizeof(buf), "media", str)) {
     if (!SetCommTimeouts(s->hcom, &cto)) {          if (!strcmp(buf, "disk")) {
         fprintf(stderr, "Failed SetCommTimeouts\n");              media = MEDIA_DISK;
         goto fail;          } else if (!strcmp(buf, "cdrom")) {
               if (cyls || secs || heads) {
                   fprintf(stderr,
                           "qemu: '%s' invalid physical CHS format\n", str);
                   return -1;
               }
               media = MEDIA_CDROM;
           } else {
               fprintf(stderr, "qemu: '%s' invalid media\n", str);
               return -1;
           }
     }      }
   
     if (!ClearCommError(s->hcom, &err, &comstat)) {      if (get_param_value(buf, sizeof(buf), "snapshot", str)) {
         fprintf(stderr, "Failed ClearCommError\n");          if (!strcmp(buf, "on"))
         goto fail;              snapshot = 1;
           else if (!strcmp(buf, "off"))
               snapshot = 0;
           else {
               fprintf(stderr, "qemu: '%s' invalid snapshot option\n", str);
               return -1;
           }
     }      }
     qemu_add_polling_cb(win_chr_poll, chr);  
     return 0;  
   
  fail:  
     win_chr_close(chr);  
     return -1;  
 }  
   
 static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)  
 {  
     WinCharState *s = chr->opaque;  
     DWORD len, ret, size, err;  
   
     len = len1;      if (get_param_value(buf, sizeof(buf), "cache", str)) {
     ZeroMemory(&s->osend, sizeof(s->osend));          if (!strcmp(buf, "off") || !strcmp(buf, "none"))
     s->osend.hEvent = s->hsend;              cache = 0;
     while (len > 0) {          else if (!strcmp(buf, "writethrough"))
         if (s->hsend)              cache = 1;
             ret = WriteFile(s->hcom, buf, len, &size, &s->osend);          else if (!strcmp(buf, "writeback"))
         else              cache = 2;
             ret = WriteFile(s->hcom, buf, len, &size, NULL);          else {
         if (!ret) {             fprintf(stderr, "qemu: invalid cache option\n");
             err = GetLastError();             return -1;
             if (err == ERROR_IO_PENDING) {  
                 ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);  
                 if (ret) {  
                     buf += size;  
                     len -= size;  
                 } else {  
                     break;  
                 }  
             } else {  
                 break;  
             }  
         } else {  
             buf += size;  
             len -= size;  
         }          }
     }      }
     return len1 - len;  
 }  
   
 static int win_chr_read_poll(CharDriverState *chr)  
 {  
     WinCharState *s = chr->opaque;  
   
     s->max_size = qemu_chr_can_read(chr);  
     return s->max_size;  
 }  
   
 static void win_chr_readfile(CharDriverState *chr)  
 {  
     WinCharState *s = chr->opaque;  
     int ret, err;  
     uint8_t buf[1024];  
     DWORD size;  
   
     ZeroMemory(&s->orecv, sizeof(s->orecv));      if (get_param_value(buf, sizeof(buf), "format", str)) {
     s->orecv.hEvent = s->hrecv;         if (strcmp(buf, "?") == 0) {
     ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);              fprintf(stderr, "qemu: Supported formats:");
     if (!ret) {              bdrv_iterate_format(bdrv_format_print, NULL);
         err = GetLastError();              fprintf(stderr, "\n");
         if (err == ERROR_IO_PENDING) {              return -1;
             ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);  
         }          }
     }          drv = bdrv_find_format(buf);
           if (!drv) {
     if (size > 0) {              fprintf(stderr, "qemu: '%s' invalid format\n", buf);
         qemu_chr_read(chr, buf, size);              return -1;
     }  
 }  
   
 static void win_chr_read(CharDriverState *chr)  
 {  
     WinCharState *s = chr->opaque;  
   
     if (s->len > s->max_size)  
         s->len = s->max_size;  
     if (s->len == 0)  
         return;  
   
     win_chr_readfile(chr);  
 }  
   
 static int win_chr_poll(void *opaque)  
 {  
     CharDriverState *chr = opaque;  
     WinCharState *s = chr->opaque;  
     COMSTAT status;  
     DWORD comerr;  
   
     ClearCommError(s->hcom, &comerr, &status);  
     if (status.cbInQue > 0) {  
         s->len = status.cbInQue;  
         win_chr_read_poll(chr);  
         win_chr_read(chr);  
         return 1;  
     }  
     return 0;  
 }  
   
 static CharDriverState *qemu_chr_open_win(const char *filename)  
 {  
     CharDriverState *chr;  
     WinCharState *s;  
   
     chr = qemu_mallocz(sizeof(CharDriverState));  
     if (!chr)  
         return NULL;  
     s = qemu_mallocz(sizeof(WinCharState));  
     if (!s) {  
         free(chr);  
         return NULL;  
     }  
     chr->opaque = s;  
     chr->chr_write = win_chr_write;  
     chr->chr_close = win_chr_close;  
   
     if (win_chr_init(chr, filename) < 0) {  
         free(s);  
         free(chr);  
         return NULL;  
     }  
     qemu_chr_reset(chr);  
     return chr;  
 }  
   
 static int win_chr_pipe_poll(void *opaque)  
 {  
     CharDriverState *chr = opaque;  
     WinCharState *s = chr->opaque;  
     DWORD size;  
   
     PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);  
     if (size > 0) {  
         s->len = size;  
         win_chr_read_poll(chr);  
         win_chr_read(chr);  
         return 1;  
     }  
     return 0;  
 }  
   
 static int win_chr_pipe_init(CharDriverState *chr, const char *filename)  
 {  
     WinCharState *s = chr->opaque;  
     OVERLAPPED ov;  
     int ret;  
     DWORD size;  
     char openname[256];  
   
     s->fpipe = TRUE;  
   
     s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);  
     if (!s->hsend) {  
         fprintf(stderr, "Failed CreateEvent\n");  
         goto fail;  
     }  
     s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);  
     if (!s->hrecv) {  
         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 |  
                               PIPE_WAIT,  
                               MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);  
     if (s->hcom == INVALID_HANDLE_VALUE) {  
         fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError());  
         s->hcom = NULL;  
         goto fail;  
     }  
   
     ZeroMemory(&ov, sizeof(ov));  
     ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);  
     ret = ConnectNamedPipe(s->hcom, &ov);  
     if (ret) {  
         fprintf(stderr, "Failed ConnectNamedPipe\n");  
         goto fail;  
     }  
   
     ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);  
     if (!ret) {  
         fprintf(stderr, "Failed GetOverlappedResult\n");  
         if (ov.hEvent) {  
             CloseHandle(ov.hEvent);  
             ov.hEvent = NULL;  
         }          }
         goto fail;  
     }  
   
     if (ov.hEvent) {  
         CloseHandle(ov.hEvent);  
         ov.hEvent = NULL;  
     }      }
     qemu_add_polling_cb(win_chr_pipe_poll, chr);  
     return 0;  
   
  fail:  
     win_chr_close(chr);  
     return -1;  
 }  
   
   
 static CharDriverState *qemu_chr_open_win_pipe(const char *filename)  
 {  
     CharDriverState *chr;  
     WinCharState *s;  
   
     chr = qemu_mallocz(sizeof(CharDriverState));  
     if (!chr)  
         return NULL;  
     s = qemu_mallocz(sizeof(WinCharState));  
     if (!s) {  
         free(chr);  
         return NULL;  
     }  
     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);  
         return NULL;  
     }  
     qemu_chr_reset(chr);  
     return chr;  
 }  
   
 static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)  
 {  
     CharDriverState *chr;  
     WinCharState *s;  
   
     chr = qemu_mallocz(sizeof(CharDriverState));  
     if (!chr)  
         return NULL;  
     s = qemu_mallocz(sizeof(WinCharState));  
     if (!s) {  
         free(chr);  
         return NULL;  
     }  
     s->hcom = fd_out;  
     chr->opaque = s;  
     chr->chr_write = win_chr_write;  
     qemu_chr_reset(chr);  
     return chr;  
 }  
   
 static CharDriverState *qemu_chr_open_win_con(const char *filename)  
 {  
     return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));  
 }  
   
 static CharDriverState *qemu_chr_open_win_file_out(const char *file_out)  
 {  
     HANDLE fd_out;  
   
     fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,  
                         OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);  
     if (fd_out == INVALID_HANDLE_VALUE)  
         return NULL;  
   
     return qemu_chr_open_win_file(fd_out);  
 }  
 #endif /* !_WIN32 */  
   
 /***********************************************************/  
 /* UDP Net console */  
   
 typedef struct {  
     int fd;  
     struct sockaddr_in daddr;  
     uint8_t buf[1024];  
     int bufcnt;  
     int bufptr;  
     int max_size;  
 } NetCharDriver;  
   
 static int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)  
 {  
     NetCharDriver *s = chr->opaque;  
   
     return sendto(s->fd, buf, len, 0,  
                   (struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in));  
 }  
   
 static int udp_chr_read_poll(void *opaque)  
 {  
     CharDriverState *chr = opaque;  
     NetCharDriver *s = chr->opaque;  
   
     s->max_size = qemu_chr_can_read(chr);  
   
     /* If there were any stray characters in the queue process them  
      * first  
      */  
     while (s->max_size > 0 && s->bufptr < s->bufcnt) {  
         qemu_chr_read(chr, &s->buf[s->bufptr], 1);  
         s->bufptr++;  
         s->max_size = qemu_chr_can_read(chr);  
     }  
     return s->max_size;  
 }  
   
 static void udp_chr_read(void *opaque)  
 {  
     CharDriverState *chr = opaque;  
     NetCharDriver *s = chr->opaque;  
   
     if (s->max_size == 0)  
         return;  
     s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0);  
     s->bufptr = s->bufcnt;  
     if (s->bufcnt <= 0)  
         return;  
   
     s->bufptr = 0;  
     while (s->max_size > 0 && s->bufptr < s->bufcnt) {  
         qemu_chr_read(chr, &s->buf[s->bufptr], 1);  
         s->bufptr++;  
         s->max_size = qemu_chr_can_read(chr);  
     }  
 }  
   
 static void udp_chr_update_read_handler(CharDriverState *chr)  
 {  
     NetCharDriver *s = chr->opaque;  
   
     if (s->fd >= 0) {  
         qemu_set_fd_handler2(s->fd, udp_chr_read_poll,  
                              udp_chr_read, NULL, chr);  
     }  
 }  
   
 int parse_host_port(struct sockaddr_in *saddr, const char *str);  
 #ifndef _WIN32  
 static int parse_unix_path(struct sockaddr_un *uaddr, const char *str);  
 #endif  
 int parse_host_src_port(struct sockaddr_in *haddr,  
                         struct sockaddr_in *saddr,  
                         const char *str);  
   
 static CharDriverState *qemu_chr_open_udp(const char *def)  
 {  
     CharDriverState *chr = NULL;  
     NetCharDriver *s = NULL;  
     int fd = -1;  
     struct sockaddr_in saddr;  
   
     chr = qemu_mallocz(sizeof(CharDriverState));  
     if (!chr)  
         goto return_err;  
     s = qemu_mallocz(sizeof(NetCharDriver));  
     if (!s)  
         goto return_err;  
   
     fd = socket(PF_INET, SOCK_DGRAM, 0);  
     if (fd < 0) {  
         perror("socket(PF_INET, SOCK_DGRAM)");  
         goto return_err;  
     }  
   
     if (parse_host_src_port(&s->daddr, &saddr, def) < 0) {  
         printf("Could not parse: %s\n", def);  
         goto return_err;  
     }  
   
     if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)  
     {  
         perror("bind");  
         goto return_err;  
     }  
   
     s->fd = fd;  
     s->bufcnt = 0;  
     s->bufptr = 0;  
     chr->opaque = s;  
     chr->chr_write = udp_chr_write;  
     chr->chr_update_read_handler = udp_chr_update_read_handler;  
     return chr;  
   
 return_err:  
     if (chr)  
         free(chr);  
     if (s)  
         free(s);  
     if (fd >= 0)  
         closesocket(fd);  
     return NULL;  
 }  
   
 /***********************************************************/  
 /* TCP Net console */  
   
 typedef struct {  
     int fd, listen_fd;  
     int connected;  
     int max_size;  
     int do_telnetopt;  
     int do_nodelay;  
     int is_unix;  
 } TCPCharDriver;  
   
 static void tcp_chr_accept(void *opaque);  
   
 static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)  
 {  
     TCPCharDriver *s = chr->opaque;  
     if (s->connected) {  
         return send_all(s->fd, buf, len);  
     } else {  
         /* XXX: indicate an error ? */  
         return len;  
     }  
 }  
   
 static int tcp_chr_read_poll(void *opaque)  
 {  
     CharDriverState *chr = opaque;  
     TCPCharDriver *s = chr->opaque;  
     if (!s->connected)  
         return 0;  
     s->max_size = qemu_chr_can_read(chr);  
     return s->max_size;  
 }  
   
 #define IAC 255  
 #define IAC_BREAK 243  
 static void tcp_chr_process_IAC_bytes(CharDriverState *chr,  
                                       TCPCharDriver *s,  
                                       uint8_t *buf, int *size)  
 {  
     /* Handle any telnet client's basic IAC options to satisfy char by  
      * char mode with no echo.  All IAC options will be removed from  
      * the buf and the do_telnetopt variable will be used to track the  
      * state of the width of the IAC information.  
      *  
      * IAC commands come in sets of 3 bytes with the exception of the  
      * "IAC BREAK" command and the double IAC.  
      */  
   
     int i;  
     int j = 0;  
   
     for (i = 0; i < *size; i++) {  
         if (s->do_telnetopt > 1) {  
             if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {  
                 /* Double IAC means send an IAC */  
                 if (j != i)  
                     buf[j] = buf[i];  
                 j++;  
                 s->do_telnetopt = 1;  
             } else {  
                 if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {  
                     /* Handle IAC break commands by sending a serial break */  
                     qemu_chr_event(chr, CHR_EVENT_BREAK);  
                     s->do_telnetopt++;  
                 }  
                 s->do_telnetopt++;  
             }  
             if (s->do_telnetopt >= 4) {  
                 s->do_telnetopt = 1;  
             }  
         } else {  
             if ((unsigned char)buf[i] == IAC) {  
                 s->do_telnetopt = 2;  
             } else {  
                 if (j != i)  
                     buf[j] = buf[i];  
                 j++;  
             }  
         }  
     }  
     *size = j;  
 }  
   
 static void tcp_chr_read(void *opaque)  
 {  
     CharDriverState *chr = opaque;  
     TCPCharDriver *s = chr->opaque;  
     uint8_t buf[1024];  
     int len, size;  
   
     if (!s->connected || s->max_size <= 0)  
         return;  
     len = sizeof(buf);  
     if (len > s->max_size)  
         len = s->max_size;  
     size = recv(s->fd, buf, len, 0);  
     if (size == 0) {  
         /* connection closed */  
         s->connected = 0;  
         if (s->listen_fd >= 0) {  
             qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);  
         }  
         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);  
         closesocket(s->fd);  
         s->fd = -1;  
     } else if (size > 0) {  
         if (s->do_telnetopt)  
             tcp_chr_process_IAC_bytes(chr, s, buf, &size);  
         if (size > 0)  
             qemu_chr_read(chr, buf, size);  
     }  
 }  
   
 static void tcp_chr_connect(void *opaque)  
 {  
     CharDriverState *chr = opaque;  
     TCPCharDriver *s = chr->opaque;  
   
     s->connected = 1;  
     qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,  
                          tcp_chr_read, NULL, chr);  
     qemu_chr_reset(chr);  
 }  
   
 #define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;  
 static void tcp_chr_telnet_init(int fd)  
 {  
     char buf[3];  
     /* Send the telnet negotion to put telnet in binary, no echo, single char mode */  
     IACSET(buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */  
     send(fd, (char *)buf, 3, 0);  
     IACSET(buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */  
     send(fd, (char *)buf, 3, 0);  
     IACSET(buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */  
     send(fd, (char *)buf, 3, 0);  
     IACSET(buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */  
     send(fd, (char *)buf, 3, 0);  
 }  
   
 static void socket_set_nodelay(int fd)  
 {  
     int val = 1;  
     setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));  
 }  
   
 static void tcp_chr_accept(void *opaque)  
 {  
     CharDriverState *chr = opaque;  
     TCPCharDriver *s = chr->opaque;  
     struct sockaddr_in saddr;  
 #ifndef _WIN32  
     struct sockaddr_un uaddr;  
 #endif  
     struct sockaddr *addr;  
     socklen_t len;  
     int fd;  
   
     for(;;) {  
 #ifndef _WIN32  
         if (s->is_unix) {  
             len = sizeof(uaddr);  
             addr = (struct sockaddr *)&uaddr;  
         } else  
 #endif  
         {  
             len = sizeof(saddr);  
             addr = (struct sockaddr *)&saddr;  
         }  
         fd = accept(s->listen_fd, addr, &len);  
         if (fd < 0 && errno != EINTR) {  
             return;  
         } else if (fd >= 0) {  
             if (s->do_telnetopt)  
                 tcp_chr_telnet_init(fd);  
             break;  
         }  
     }  
     socket_set_nonblock(fd);  
     if (s->do_nodelay)  
         socket_set_nodelay(fd);  
     s->fd = fd;  
     qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);  
     tcp_chr_connect(chr);  
 }  
   
 static void tcp_chr_close(CharDriverState *chr)  
 {  
     TCPCharDriver *s = chr->opaque;  
     if (s->fd >= 0)  
         closesocket(s->fd);  
     if (s->listen_fd >= 0)  
         closesocket(s->listen_fd);  
     qemu_free(s);  
 }  
   
 static CharDriverState *qemu_chr_open_tcp(const char *host_str,  
                                           int is_telnet,  
                                           int is_unix)  
 {  
     CharDriverState *chr = NULL;  
     TCPCharDriver *s = NULL;  
     int fd = -1, ret, err, val;  
     int is_listen = 0;  
     int is_waitconnect = 1;  
     int do_nodelay = 0;  
     const char *ptr;  
     struct sockaddr_in saddr;  
 #ifndef _WIN32  
     struct sockaddr_un uaddr;  
 #endif  
     struct sockaddr *addr;  
     socklen_t addrlen;  
   
 #ifndef _WIN32  
     if (is_unix) {  
         addr = (struct sockaddr *)&uaddr;  
         addrlen = sizeof(uaddr);  
         if (parse_unix_path(&uaddr, host_str) < 0)  
             goto fail;  
     } else  
 #endif  
     {  
         addr = (struct sockaddr *)&saddr;  
         addrlen = sizeof(saddr);  
         if (parse_host_port(&saddr, host_str) < 0)  
             goto fail;  
     }  
   
     ptr = host_str;  
     while((ptr = strchr(ptr,','))) {  
         ptr++;  
         if (!strncmp(ptr,"server",6)) {  
             is_listen = 1;  
         } else if (!strncmp(ptr,"nowait",6)) {  
             is_waitconnect = 0;  
         } else if (!strncmp(ptr,"nodelay",6)) {  
             do_nodelay = 1;  
         } else {  
             printf("Unknown option: %s\n", ptr);  
             goto fail;  
         }  
     }  
     if (!is_listen)  
         is_waitconnect = 0;  
   
     chr = qemu_mallocz(sizeof(CharDriverState));  
     if (!chr)  
         goto fail;  
     s = qemu_mallocz(sizeof(TCPCharDriver));  
     if (!s)  
         goto fail;  
   
 #ifndef _WIN32  
     if (is_unix)  
         fd = socket(PF_UNIX, SOCK_STREAM, 0);  
     else  
 #endif  
         fd = socket(PF_INET, SOCK_STREAM, 0);  
   
     if (fd < 0)  
         goto fail;  
   
     if (!is_waitconnect)  
         socket_set_nonblock(fd);  
   
     s->connected = 0;  
     s->fd = -1;  
     s->listen_fd = -1;  
     s->is_unix = is_unix;  
     s->do_nodelay = do_nodelay && !is_unix;  
   
     chr->opaque = s;  
     chr->chr_write = tcp_chr_write;  
     chr->chr_close = tcp_chr_close;  
   
     if (is_listen) {  
         /* allow fast reuse */  
 #ifndef _WIN32  
         if (is_unix) {  
             char path[109];  
             strncpy(path, uaddr.sun_path, 108);  
             path[108] = 0;  
             unlink(path);  
         } else  
 #endif  
         {  
             val = 1;  
             setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));  
         }  
   
         ret = bind(fd, addr, addrlen);  
         if (ret < 0)  
             goto fail;  
   
         ret = listen(fd, 0);  
         if (ret < 0)  
             goto fail;  
   
         s->listen_fd = fd;  
         qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);  
         if (is_telnet)  
             s->do_telnetopt = 1;  
     } else {  
         for(;;) {  
             ret = connect(fd, addr, addrlen);  
             if (ret < 0) {  
                 err = socket_error();  
                 if (err == EINTR || err == EWOULDBLOCK) {  
                 } else if (err == EINPROGRESS) {  
                     break;  
 #ifdef _WIN32  
                 } else if (err == WSAEALREADY) {  
                     break;  
 #endif  
                 } else {  
                     goto fail;  
                 }  
             } else {  
                 s->connected = 1;  
                 break;  
             }  
         }  
         s->fd = fd;  
         socket_set_nodelay(fd);  
         if (s->connected)  
             tcp_chr_connect(chr);  
         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);  
         socket_set_nonblock(s->listen_fd);  
     }  
   
     return chr;  
  fail:  
     if (fd >= 0)  
         closesocket(fd);  
     qemu_free(s);  
     qemu_free(chr);  
     return NULL;  
 }  
   
 CharDriverState *qemu_chr_open(const char *filename)  
 {  
     const char *p;  
   
     if (!strcmp(filename, "vc")) {  
         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  
     if (strstart(filename, "tcp:", &p)) {  
         return qemu_chr_open_tcp(p, 0, 0);  
     } else  
     if (strstart(filename, "telnet:", &p)) {  
         return qemu_chr_open_tcp(p, 1, 0);  
     } else  
     if (strstart(filename, "udp:", &p)) {  
         return qemu_chr_open_udp(p);  
     } else  
     if (strstart(filename, "mon:", &p)) {  
         CharDriverState *drv = qemu_chr_open(p);  
         if (drv) {  
             drv = qemu_chr_open_mux(drv);  
             monitor_init(drv, !nographic);  
             return drv;  
         }  
         printf("Unable to open driver: %s\n", p);  
         return 0;  
     } else  
 #ifndef _WIN32  
     if (strstart(filename, "unix:", &p)) {  
         return qemu_chr_open_tcp(p, 0, 1);  
     } else if (strstart(filename, "file:", &p)) {  
         return qemu_chr_open_file_out(p);  
     } else if (strstart(filename, "pipe:", &p)) {  
         return qemu_chr_open_pipe(p);  
     } else if (!strcmp(filename, "pty")) {  
         return qemu_chr_open_pty();  
     } else if (!strcmp(filename, "stdio")) {  
         return qemu_chr_open_stdio();  
     } else  
 #if defined(__linux__)  
     if (strstart(filename, "/dev/parport", NULL)) {  
         return qemu_chr_open_pp(filename);  
     } else  
 #endif  
 #if defined(__linux__) || defined(__sun__)  
     if (strstart(filename, "/dev/", NULL)) {  
         return qemu_chr_open_tty(filename);  
     } else  
 #endif  
 #else /* !_WIN32 */  
     if (strstart(filename, "COM", NULL)) {  
         return qemu_chr_open_win(filename);  
     } else  
     if (strstart(filename, "pipe:", &p)) {  
         return qemu_chr_open_win_pipe(p);  
     } else  
     if (strstart(filename, "con:", NULL)) {  
         return qemu_chr_open_win_con(filename);  
     } else  
     if (strstart(filename, "file:", &p)) {  
         return qemu_chr_open_win_file_out(p);  
     }  
 #endif  
     {  
         return NULL;  
     }  
 }  
   
 void qemu_chr_close(CharDriverState *chr)  
 {  
     if (chr->chr_close)  
         chr->chr_close(chr);  
 }  
   
 /***********************************************************/  
 /* network device redirectors */  
   
 __attribute__ (( unused ))  
 static void hex_dump(FILE *f, const uint8_t *buf, int size)  
 {  
     int len, i, j, c;  
   
     for(i=0;i<size;i+=16) {  
         len = size - i;  
         if (len > 16)  
             len = 16;  
         fprintf(f, "%08x ", i);  
         for(j=0;j<16;j++) {  
             if (j < len)  
                 fprintf(f, " %02x", buf[i+j]);  
             else  
                 fprintf(f, "   ");  
         }  
         fprintf(f, " ");  
         for(j=0;j<len;j++) {  
             c = buf[i+j];  
             if (c < ' ' || c > '~')  
                 c = '.';  
             fprintf(f, "%c", c);  
         }  
         fprintf(f, "\n");  
     }  
 }  
   
 static int parse_macaddr(uint8_t *macaddr, const char *p)  
 {  
     int i;  
     char *last_char;  
     long int offset;  
   
     errno = 0;  
     offset = strtol(p, &last_char, 0);      
     if (0 == errno && '\0' == *last_char &&  
             offset >= 0 && offset <= 0xFFFFFF) {  
         macaddr[3] = (offset & 0xFF0000) >> 16;  
         macaddr[4] = (offset & 0xFF00) >> 8;  
         macaddr[5] = offset & 0xFF;  
         return 0;  
     } else {  
         for(i = 0; i < 6; i++) {  
             macaddr[i] = strtol(p, (char **)&p, 16);  
             if (i == 5) {  
                 if (*p != '\0')  
                     return -1;  
             } else {  
                 if (*p != ':' && *p != '-')  
                     return -1;  
                 p++;  
             }  
         }  
         return 0;      
     }  
   
     return -1;  
 }  
   
 static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)  
 {  
     const char *p, *p1;  
     int len;  
     p = *pp;  
     p1 = strchr(p, sep);  
     if (!p1)  
         return -1;  
     len = p1 - p;  
     p1++;  
     if (buf_size > 0) {  
         if (len > buf_size - 1)  
             len = buf_size - 1;  
         memcpy(buf, p, len);  
         buf[len] = '\0';  
     }  
     *pp = p1;  
     return 0;  
 }  
   
 int parse_host_src_port(struct sockaddr_in *haddr,  
                         struct sockaddr_in *saddr,  
                         const char *input_str)  
 {  
     char *str = strdup(input_str);  
     char *host_str = str;  
     char *src_str;  
     char *ptr;  
   
     /*  
      * Chop off any extra arguments at the end of the string which  
      * would start with a comma, then fill in the src port information  
      * if it was provided else use the "any address" and "any port".  
      */  
     if ((ptr = strchr(str,',')))  
         *ptr = '\0';  
   
     if ((src_str = strchr(input_str,'@'))) {  
         *src_str = '\0';  
         src_str++;  
     }  
   
     if (parse_host_port(haddr, host_str) < 0)  
         goto fail;  
   
     if (!src_str || *src_str == '\0')  
         src_str = ":0";  
   
     if (parse_host_port(saddr, src_str) < 0)  
         goto fail;  
   
     free(str);  
     return(0);  
   
 fail:  
     free(str);  
     return -1;  
 }  
   
 int parse_host_port(struct sockaddr_in *saddr, const char *str)  
 {  
     char buf[512];  
     struct hostent *he;  
     const char *p, *r;  
     int port;  
   
     p = str;  
     if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)  
         return -1;  
     saddr->sin_family = AF_INET;  
     if (buf[0] == '\0') {  
         saddr->sin_addr.s_addr = 0;  
     } else {  
         if (isdigit(buf[0])) {  
             if (!inet_aton(buf, &saddr->sin_addr))  
                 return -1;  
         } else {  
             if ((he = gethostbyname(buf)) == NULL)  
                 return - 1;  
             saddr->sin_addr = *(struct in_addr *)he->h_addr;  
         }  
     }  
     port = strtol(p, (char **)&r, 0);  
     if (r == p)  
         return -1;  
     saddr->sin_port = htons(port);  
     return 0;  
 }  
   
 #ifndef _WIN32  
 static int parse_unix_path(struct sockaddr_un *uaddr, const char *str)  
 {  
     const char *p;  
     int len;  
   
     len = MIN(108, strlen(str));  
     p = strchr(str, ',');  
     if (p)  
         len = MIN(len, p - str);  
   
     memset(uaddr, 0, sizeof(*uaddr));  
   
     uaddr->sun_family = AF_UNIX;  
     memcpy(uaddr->sun_path, str, len);  
   
     return 0;  
 }  
 #endif  
   
 /* find or alloc a new VLAN */  
 VLANState *qemu_find_vlan(int id)  
 {  
     VLANState **pvlan, *vlan;  
     for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {  
         if (vlan->id == id)  
             return vlan;  
     }  
     vlan = qemu_mallocz(sizeof(VLANState));  
     if (!vlan)  
         return NULL;  
     vlan->id = id;  
     vlan->next = NULL;  
     pvlan = &first_vlan;  
     while (*pvlan != NULL)  
         pvlan = &(*pvlan)->next;  
     *pvlan = vlan;  
     return vlan;  
 }  
   
 VLANClientState *qemu_new_vlan_client(VLANState *vlan,  
                                       IOReadHandler *fd_read,  
                                       IOCanRWHandler *fd_can_read,  
                                       void *opaque)  
 {  
     VLANClientState *vc, **pvc;  
     vc = qemu_mallocz(sizeof(VLANClientState));  
     if (!vc)  
         return NULL;  
     vc->fd_read = fd_read;  
     vc->fd_can_read = fd_can_read;  
     vc->opaque = opaque;  
     vc->vlan = vlan;  
   
     vc->next = NULL;  
     pvc = &vlan->first_client;  
     while (*pvc != NULL)  
         pvc = &(*pvc)->next;  
     *pvc = vc;  
     return vc;  
 }  
   
 int qemu_can_send_packet(VLANClientState *vc1)  
 {  
     VLANState *vlan = vc1->vlan;  
     VLANClientState *vc;  
   
     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 1;  
         }  
     }  
     return 0;  
 }  
   
 void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size)  
 {  
     VLANState *vlan = vc1->vlan;  
     VLANClientState *vc;  
   
 #if 0  
     printf("vlan %d send:\n", vlan->id);  
     hex_dump(stdout, buf, size);  
 #endif  
     for(vc = vlan->first_client; vc != NULL; vc = vc->next) {  
         if (vc != vc1) {  
             vc->fd_read(vc->opaque, buf, size);  
         }  
     }  
 }  
   
 #if defined(CONFIG_SLIRP)  
   
 /* slirp network adapter */  
   
 static int slirp_inited;  
 static VLANClientState *slirp_vc;  
   
 int slirp_can_output(void)  
 {  
     return !slirp_vc || qemu_can_send_packet(slirp_vc);  
 }  
   
 void slirp_output(const uint8_t *pkt, int pkt_len)  
 {  
 #if 0  
     printf("slirp output:\n");  
     hex_dump(stdout, pkt, pkt_len);  
 #endif  
     if (!slirp_vc)  
         return;  
     qemu_send_packet(slirp_vc, pkt, pkt_len);  
 }  
   
 static void slirp_receive(void *opaque, const uint8_t *buf, int size)  
 {  
 #if 0  
     printf("slirp input:\n");  
     hex_dump(stdout, buf, size);  
 #endif  
     slirp_input(buf, size);  
 }  
   
 static int net_slirp_init(VLANState *vlan)  
 {  
     if (!slirp_inited) {  
         slirp_inited = 1;  
         slirp_init();  
     }  
     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;  
 }  
   
 static void net_slirp_redir(const char *redir_str)  
 {  
     int is_udp;  
     char buf[256], *r;  
     const char *p;  
     struct in_addr guest_addr;  
     int host_port, guest_port;  
   
     if (!slirp_inited) {  
         slirp_inited = 1;  
         slirp_init();  
     }  
   
     p = redir_str;  
     if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)  
         goto fail;  
     if (!strcmp(buf, "tcp")) {  
         is_udp = 0;  
     } else if (!strcmp(buf, "udp")) {  
         is_udp = 1;  
     } else {  
         goto fail;  
     }  
   
     if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)  
         goto fail;  
     host_port = strtol(buf, &r, 0);  
     if (r == buf)  
         goto fail;  
   
     if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)  
         goto fail;  
     if (buf[0] == '\0') {  
         pstrcpy(buf, sizeof(buf), "10.0.2.15");  
     }  
     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);  
     }  
     return;  
  fail:  
     fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n");  
     exit(1);  
 }  
   
 #ifndef _WIN32  
   
 char smb_dir[1024];  
   
 static void smb_exit(void)  
 {  
     DIR *d;  
     struct dirent *de;  
     char filename[1024];  
   
     /* erase all the files in the directory */  
     d = opendir(smb_dir);  
     for(;;) {  
         de = readdir(d);  
         if (!de)  
             break;  
         if (strcmp(de->d_name, ".") != 0 &&  
             strcmp(de->d_name, "..") != 0) {  
             snprintf(filename, sizeof(filename), "%s/%s",  
                      smb_dir, de->d_name);  
             unlink(filename);  
         }  
     }  
     closedir(d);  
     rmdir(smb_dir);  
 }  
   
 /* automatic user mode samba server configuration */  
 static void net_slirp_smb(const char *exported_dir)  
 {  
     char smb_conf[1024];  
     char smb_cmdline[1024];  
     FILE *f;  
   
     if (!slirp_inited) {  
         slirp_inited = 1;  
         slirp_init();  
     }  
   
     /* XXX: better tmp dir construction */  
     snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%d", getpid());  
     if (mkdir(smb_dir, 0700) < 0) {  
         fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_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,  
             "[global]\n"  
             "private dir=%s\n"  
             "smb ports=0\n"  
             "socket address=127.0.0.1\n"  
             "pid directory=%s\n"  
             "lock directory=%s\n"  
             "log file=%s/log.smbd\n"  
             "smb passwd file=%s/smbpasswd\n"  
             "security = share\n"  
             "[qemu]\n"  
             "path=%s\n"  
             "read only=no\n"  
             "guest ok=yes\n",  
             smb_dir,  
             smb_dir,  
             smb_dir,  
             smb_dir,  
             smb_dir,  
             exported_dir  
             );  
     fclose(f);  
     atexit(smb_exit);  
   
     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 */  
   
 #if !defined(_WIN32)  
   
 typedef struct TAPState {  
     VLANClientState *vc;  
     int fd;  
     char down_script[1024];  
 } TAPState;  
   
 static void tap_receive(void *opaque, const uint8_t *buf, int size)  
 {  
     TAPState *s = opaque;  
     int ret;  
     for(;;) {  
         ret = write(s->fd, buf, size);  
         if (ret < 0 && (errno == EINTR || errno == EAGAIN)) {  
         } else {  
             break;  
         }  
     }  
 }  
   
 static void tap_send(void *opaque)  
 {  
     TAPState *s = opaque;  
     uint8_t buf[4096];  
     int size;  
   
 #ifdef __sun__  
     struct strbuf sbuf;  
     int f = 0;  
     sbuf.maxlen = sizeof(buf);  
     sbuf.buf = buf;  
     size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1;  
 #else  
     size = read(s->fd, buf, sizeof(buf));  
 #endif  
     if (size > 0) {  
         qemu_send_packet(s->vc, buf, size);  
     }  
 }  
   
 /* fd support */  
   
 static TAPState *net_tap_fd_init(VLANState *vlan, int fd)  
 {  
     TAPState *s;  
   
     s = qemu_mallocz(sizeof(TAPState));  
     if (!s)  
         return NULL;  
     s->fd = fd;  
     s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s);  
     qemu_set_fd_handler(s->fd, tap_send, NULL, s);  
     snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd);  
     return s;  
 }  
   
 #if defined (_BSD) || defined (__FreeBSD_kernel__)  
 static int tap_open(char *ifname, int ifname_size)  
 {  
     int fd;  
     char *dev;  
     struct stat s;  
   
     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;  
     }  
   
     fstat(fd, &s);  
     dev = devname(s.st_rdev, S_IFCHR);  
     pstrcpy(ifname, ifname_size, dev);  
   
     fcntl(fd, F_SETFL, O_NONBLOCK);  
     return fd;  
 }  
 #elif defined(__sun__)  
 #define TUNNEWPPA       (('T'<<16) | 0x0001)  
 /*  
  * 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;  
     static int ip_fd = 0;  
     char *ptr;  
   
     static int arp_fd = 0;  
     int ip_muxid, arp_muxid;  
     struct strioctl  strioc_if, strioc_ppa;  
     int link_type = I_PLINK;;  
     struct lifreq ifr;  
     char actual_name[32] = "";  
   
     memset(&ifr, 0x0, sizeof(ifr));  
   
     if( *dev ){  
        ptr = dev;  
        while( *ptr && !isdigit((int)*ptr) ) ptr++;  
        ppa = atoi(ptr);  
     }  
   
     /* Check if IP device was opened */  
     if( ip_fd )  
        close(ip_fd);  
   
     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;  
     }  
   
     TFR(tap_fd = open("/dev/tap", O_RDWR, 0));  
     if (tap_fd < 0) {  
        syslog(LOG_ERR, "Can't open /dev/tap");  
        return -1;  
     }  
   
     /* Assign a new PPA and get its unit number. */  
     strioc_ppa.ic_cmd = TUNNEWPPA;  
     strioc_ppa.ic_timout = 0;  
     strioc_ppa.ic_len = sizeof(ppa);  
     strioc_ppa.ic_dp = (char *)&ppa;  
     if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)  
        syslog (LOG_ERR, "Can't assign new interface");  
   
     TFR(if_fd = open("/dev/tap", O_RDWR, 0));  
     if (if_fd < 0) {  
        syslog(LOG_ERR, "Can't open /dev/tap (2)");  
        return -1;  
     }  
     if(ioctl(if_fd, I_PUSH, "ip") < 0){  
        syslog(LOG_ERR, "Can't push IP module");  
        return -1;  
     }  
   
     if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)  
         syslog(LOG_ERR, "Can't get flags\n");  
   
     snprintf (actual_name, 32, "tap%d", ppa);  
     strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name));  
   
     ifr.lifr_ppa = ppa;  
     /* Assign ppa according to the unit number returned by tun device */  
   
     if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)  
         syslog (LOG_ERR, "Can't set PPA %d", ppa);  
     if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)  
         syslog (LOG_ERR, "Can't get flags\n");  
     /* Push arp module to if_fd */  
     if (ioctl (if_fd, I_PUSH, "arp") < 0)  
         syslog (LOG_ERR, "Can't push ARP module (2)");  
   
     /* Push arp module to ip_fd */  
     if (ioctl (ip_fd, I_POP, NULL) < 0)  
         syslog (LOG_ERR, "I_POP failed\n");  
     if (ioctl (ip_fd, I_PUSH, "arp") < 0)  
         syslog (LOG_ERR, "Can't push ARP module (3)\n");  
     /* Open arp_fd */  
     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 */  
     strioc_if.ic_cmd = SIOCSLIFNAME;  
     strioc_if.ic_timout = 0;  
     strioc_if.ic_len = sizeof(ifr);  
     strioc_if.ic_dp = (char *)&ifr;  
     if (ioctl(arp_fd, I_STR, &strioc_if) < 0){  
         syslog (LOG_ERR, "Can't set ifname to arp\n");  
     }  
   
     if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){  
        syslog(LOG_ERR, "Can't link TAP device to IP");  
        return -1;  
     }  
   
     if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)  
         syslog (LOG_ERR, "Can't link TAP device to ARP");  
   
     close (if_fd);  
   
     memset(&ifr, 0x0, sizeof(ifr));  
     strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name));  
     ifr.lifr_ip_muxid  = ip_muxid;  
     ifr.lifr_arp_muxid = arp_muxid;  
   
     if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)  
     {  
       ioctl (ip_fd, I_PUNLINK , arp_muxid);  
       ioctl (ip_fd, I_PUNLINK, ip_muxid);  
       syslog (LOG_ERR, "Can't set multiplexor id");  
     }  
   
     sprintf(dev, "tap%d", ppa);  
     return tap_fd;  
 }  
   
 static int tap_open(char *ifname, int ifname_size)  
 {  
     char  dev[10]="";  
     int fd;  
     if( (fd = tap_alloc(dev)) < 0 ){  
        fprintf(stderr, "Cannot allocate TAP device\n");  
        return -1;  
     }  
     pstrcpy(ifname, ifname_size, dev);  
     fcntl(fd, F_SETFL, O_NONBLOCK);  
     return fd;  
 }  
 #else  
 static int tap_open(char *ifname, int ifname_size)  
 {  
     struct ifreq ifr;  
     int fd, ret;  
   
     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;  
     }  
     memset(&ifr, 0, sizeof(ifr));  
     ifr.ifr_flags = IFF_TAP | IFF_NO_PI;  
     if (ifname[0] != '\0')  
         pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);  
     else  
         pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");  
     ret = ioctl(fd, TUNSETIFF, (void *) &ifr);  
     if (ret != 0) {  
         fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n");  
         close(fd);  
         return -1;  
     }  
     pstrcpy(ifname, ifname_size, ifr.ifr_name);  
     fcntl(fd, F_SETFL, O_NONBLOCK);  
     return fd;  
 }  
 #endif  
   
 static int launch_script(const char *setup_script, const char *ifname, int fd)  
 {  
     int pid, status;  
     char *args[3];  
     char **parg;  
   
         /* try to launch network script */  
         pid = fork();  
         if (pid >= 0) {  
             if (pid == 0) {  
                 int open_max = sysconf (_SC_OPEN_MAX), i;  
                 for (i = 0; i < open_max; i++)  
                     if (i != STDIN_FILENO &&  
                         i != STDOUT_FILENO &&  
                         i != STDERR_FILENO &&  
                         i != fd)  
                         close(i);  
   
                 parg = args;  
                 *parg++ = (char *)setup_script;  
                 *parg++ = (char *)ifname;  
                 *parg++ = NULL;  
                 execv(setup_script, args);  
                 _exit(1);  
             }  
             while (waitpid(pid, &status, 0) != pid);  
             if (!WIFEXITED(status) ||  
                 WEXITSTATUS(status) != 0) {  
                 fprintf(stderr, "%s: could not launch network script\n",  
                         setup_script);  
                 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),  
              "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;  
 }  
   
 #endif /* !_WIN32 */  
   
 /* network connection */  
 typedef struct NetSocketState {  
     VLANClientState *vc;  
     int fd;  
     int state; /* 0 = getting length, 1 = getting data */  
     int index;  
     int packet_len;  
     uint8_t buf[4096];  
     struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */  
 } NetSocketState;  
   
 typedef struct NetSocketListenState {  
     VLANState *vlan;  
     int fd;  
 } NetSocketListenState;  
   
 /* XXX: we consider we can send the whole packet without blocking */  
 static void net_socket_receive(void *opaque, const uint8_t *buf, int size)  
 {  
     NetSocketState *s = opaque;  
     uint32_t len;  
     len = htonl(size);  
   
     send_all(s->fd, (const uint8_t *)&len, sizeof(len));  
     send_all(s->fd, buf, size);  
 }  
   
 static void net_socket_receive_dgram(void *opaque, const uint8_t *buf, int size)  
 {  
     NetSocketState *s = opaque;  
     sendto(s->fd, buf, size, 0,  
            (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));  
 }  
   
 static void net_socket_send(void *opaque)  
 {  
     NetSocketState *s = opaque;  
     int l, size, err;  
     uint8_t buf1[4096];  
     const uint8_t *buf;  
   
     size = recv(s->fd, buf1, sizeof(buf1), 0);  
     if (size < 0) {  
         err = socket_error();  
         if (err != EWOULDBLOCK)  
             goto eoc;  
     } else if (size == 0) {  
         /* end of connection */  
     eoc:  
         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);  
         closesocket(s->fd);  
         return;  
     }  
     buf = buf1;  
     while (size > 0) {  
         /* reassemble a packet from the network */  
         switch(s->state) {  
         case 0:  
             l = 4 - s->index;  
             if (l > size)  
                 l = size;  
             memcpy(s->buf + s->index, buf, l);  
             buf += l;  
             size -= l;  
             s->index += l;  
             if (s->index == 4) {  
                 /* got length */  
                 s->packet_len = ntohl(*(uint32_t *)s->buf);  
                 s->index = 0;  
                 s->state = 1;  
             }  
             break;  
         case 1:  
             l = s->packet_len - s->index;  
             if (l > size)  
                 l = size;  
             memcpy(s->buf + s->index, buf, l);  
             s->index += l;  
             buf += l;  
             size -= l;  
             if (s->index >= s->packet_len) {  
                 qemu_send_packet(s->vc, s->buf, s->packet_len);  
                 s->index = 0;  
                 s->state = 0;  
             }  
             break;  
         }  
     }  
 }  
   
 static void net_socket_send_dgram(void *opaque)  
 {  
     NetSocketState *s = opaque;  
     int size;  
   
     size = recv(s->fd, s->buf, sizeof(s->buf), 0);  
     if (size < 0)  
         return;  
     if (size == 0) {  
         /* end of connection */  
         qemu_set_fd_handler(s->fd, NULL, NULL, NULL);  
         return;  
     }  
     qemu_send_packet(s->vc, s->buf, size);  
 }  
   
 static int net_socket_mcast_create(struct sockaddr_in *mcastaddr)  
 {  
     struct ip_mreq imr;  
     int fd;  
     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),  
                 (int)ntohl(mcastaddr->sin_addr.s_addr));  
         return -1;  
   
     }  
     fd = socket(PF_INET, SOCK_DGRAM, 0);  
     if (fd < 0) {  
         perror("socket(PF_INET, SOCK_DGRAM)");  
         return -1;  
     }  
   
     val = 1;  
     ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,  
                    (const char *)&val, sizeof(val));  
     if (ret < 0) {  
         perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");  
         goto fail;  
     }  
   
     ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));  
     if (ret < 0) {  
         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,  
                      (const char *)&imr, sizeof(struct ip_mreq));  
     if (ret < 0) {  
         perror("setsockopt(IP_ADD_MEMBERSHIP)");  
         goto fail;  
     }  
   
     /* Force mcast msgs to loopback (eg. several QEMUs in same host */  
     val = 1;  
     ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,  
                    (const char *)&val, sizeof(val));  
     if (ret < 0) {  
         perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");  
         goto fail;  
     }  
   
     socket_set_nonblock(fd);  
     return fd;  
 fail:  
     if (fd >= 0)  
         closesocket(fd);  
     return -1;  
 }  
   
 static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan, int fd,  
                                           int is_connected)  
 {  
     struct sockaddr_in saddr;  
     int newfd;  
     socklen_t saddr_len;  
     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()  
      * by ONLY ONE process: we must "clone" this dgram socket --jjo  
      */  
   
     if (is_connected) {  
         if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {  
             /* must be bound */  
             if (saddr.sin_addr.s_addr==0) {  
                 fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",  
                         fd);  
                 return NULL;  
             }  
             /* clone dgram socket */  
             newfd = net_socket_mcast_create(&saddr);  
             if (newfd < 0) {  
                 /* error already reported by net_socket_mcast_create() */  
                 close(fd);  
                 return NULL;  
             }  
             /* 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));  
             return NULL;  
         }  
     }  
   
     s = qemu_mallocz(sizeof(NetSocketState));  
     if (!s)  
         return NULL;  
     s->fd = fd;  
   
     s->vc = qemu_new_vlan_client(vlan, net_socket_receive_dgram, NULL, s);  
     qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);  
   
     /* mcast: save bound address as dst */  
     if (is_connected) s->dgram_dst=saddr;  
   
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),  
             "socket: fd=%d (%s mcast=%s:%d)",  
             fd, is_connected? "cloned" : "",  
             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));  
     return s;  
 }  
   
 static void net_socket_connect(void *opaque)  
 {  
     NetSocketState *s = opaque;  
     qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);  
 }  
   
 static NetSocketState *net_socket_fd_init_stream(VLANState *vlan, int fd,  
                                           int is_connected)  
 {  
     NetSocketState *s;  
     s = qemu_mallocz(sizeof(NetSocketState));  
     if (!s)  
         return NULL;  
     s->fd = fd;  
     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);  
     if (is_connected) {  
         net_socket_connect(s);  
     } else {  
         qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);  
     }  
     return s;  
 }  
   
 static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd,  
                                           int is_connected)  
 {  
     int so_type=-1, optlen=sizeof(so_type);  
   
     if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,  
         (socklen_t *)&optlen)< 0) {  
         fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);  
         return NULL;  
     }  
     switch(so_type) {  
     case SOCK_DGRAM:  
         return net_socket_fd_init_dgram(vlan, fd, is_connected);  
     case SOCK_STREAM:  
         return net_socket_fd_init_stream(vlan, fd, is_connected);  
     default:  
         /* who knows ... this could be a eg. a pty, do warn and continue as stream */  
         fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);  
         return net_socket_fd_init_stream(vlan, fd, is_connected);  
     }  
     return NULL;  
 }  
   
 static void net_socket_accept(void *opaque)  
 {  
     NetSocketListenState *s = opaque;  
     NetSocketState *s1;  
     struct sockaddr_in saddr;  
     socklen_t len;  
     int fd;  
   
     for(;;) {  
         len = sizeof(saddr);  
         fd = accept(s->fd, (struct sockaddr *)&saddr, &len);  
         if (fd < 0 && errno != EINTR) {  
             return;  
         } else if (fd >= 0) {  
             break;  
         }  
     }  
     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",  
                  inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));  
     }  
 }  
   
 static int net_socket_listen_init(VLANState *vlan, const char *host_str)  
 {  
     NetSocketListenState *s;  
     int fd, val, ret;  
     struct sockaddr_in saddr;  
   
     if (parse_host_port(&saddr, host_str) < 0)  
         return -1;  
   
     s = qemu_mallocz(sizeof(NetSocketListenState));  
     if (!s)  
         return -1;  
   
     fd = socket(PF_INET, SOCK_STREAM, 0);  
     if (fd < 0) {  
         perror("socket");  
         return -1;  
     }  
     socket_set_nonblock(fd);  
   
     /* 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");  
         return -1;  
     }  
     ret = listen(fd, 0);  
     if (ret < 0) {  
         perror("listen");  
         return -1;  
     }  
     s->vlan = vlan;  
     s->fd = fd;  
     qemu_set_fd_handler(fd, net_socket_accept, NULL, s);  
     return 0;  
 }  
   
 static int net_socket_connect_init(VLANState *vlan, const char *host_str)  
 {  
     NetSocketState *s;  
     int fd, connected, ret, err;  
     struct sockaddr_in saddr;  
   
     if (parse_host_port(&saddr, host_str) < 0)  
         return -1;  
   
     fd = socket(PF_INET, SOCK_STREAM, 0);  
     if (fd < 0) {  
         perror("socket");  
         return -1;  
     }  
     socket_set_nonblock(fd);  
   
     connected = 0;  
     for(;;) {  
         ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));  
         if (ret < 0) {  
             err = socket_error();  
             if (err == EINTR || err == EWOULDBLOCK) {  
             } else if (err == EINPROGRESS) {  
                 break;  
 #ifdef _WIN32  
             } else if (err == WSAEALREADY) {  
                 break;  
 #endif  
             } else {  
                 perror("connect");  
                 closesocket(fd);  
                 return -1;  
             }  
         } else {  
             connected = 1;  
             break;  
         }  
     }  
     s = net_socket_fd_init(vlan, fd, connected);  
     if (!s)  
         return -1;  
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),  
              "socket: connect to %s:%d",  
              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));  
     return 0;  
 }  
   
 static int net_socket_mcast_init(VLANState *vlan, const char *host_str)  
 {  
     NetSocketState *s;  
     int fd;  
     struct sockaddr_in saddr;  
   
     if (parse_host_port(&saddr, host_str) < 0)  
         return -1;  
   
   
     fd = net_socket_mcast_create(&saddr);  
     if (fd < 0)  
         return -1;  
   
     s = net_socket_fd_init(vlan, fd, 0);  
     if (!s)  
         return -1;  
   
     s->dgram_dst = saddr;  
   
     snprintf(s->vc->info_str, sizeof(s->vc->info_str),  
              "socket: mcast=%s:%d",  
              inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));  
     return 0;  
   
 }  
   
 static const char *get_word(char *buf, int buf_size, const char *p)  
 {  
     char *q;  
     int substring;  
   
     substring = 0;  
     q = buf;  
     while (*p != '\0') {  
         if (*p == '\\') {  
             p++;  
             if (*p == '\0')  
                 break;  
         } else if (*p == '\"') {  
             substring = !substring;  
             p++;  
             continue;  
         } else if (!substring && (*p == ',' || *p == '='))  
             break;  
         if (q && (q - buf) < buf_size - 1)  
             *q++ = *p;  
         p++;  
     }  
     if (q)  
         *q = '\0';  
   
     return p;  
 }  
   
 static int get_param_value(char *buf, int buf_size,  
                            const char *tag, const char *str)  
 {  
     const char *p;  
     char option[128];  
   
     p = str;  
     for(;;) {  
         p = get_word(option, sizeof(option), p);  
         if (*p != '=')  
             break;  
         p++;  
         if (!strcmp(tag, option)) {  
             (void)get_word(buf, buf_size, p);  
             return strlen(buf);  
         } else {  
             p = get_word(NULL, 0, p);  
         }  
         if (*p != ',')  
             break;  
         p++;  
     }  
     return 0;  
 }  
   
 static int check_params(char *buf, int buf_size,  
                         char **params, const char *str)  
 {  
     const char *p;  
     int i;  
   
     p = str;  
     for(;;) {  
         p = get_word(buf, buf_size, p);  
         if (*p != '=')  
             return -1;  
         p++;  
         for(i = 0; params[i] != NULL; i++)  
             if (!strcmp(params[i], buf))  
                 break;  
         if (params[i] == NULL)  
             return -1;  
         p = get_word(NULL, 0, p);  
         if (*p != ',')  
             break;  
         p++;  
     }  
     return 0;  
 }  
   
   
 static int net_client_init(const char *str)  
 {  
     const char *p;  
     char *q;  
     char device[64];  
     char buf[1024];  
     int vlan_id, ret;  
     VLANState *vlan;  
   
     p = str;  
     q = device;  
     while (*p != '\0' && *p != ',') {  
         if ((q - device) < sizeof(device) - 1)  
             *q++ = *p;  
         p++;  
     }  
     *q = '\0';  
     if (*p == ',')  
         p++;  
     vlan_id = 0;  
     if (get_param_value(buf, sizeof(buf), "vlan", p)) {  
         vlan_id = strtol(buf, NULL, 0);  
     }  
     vlan = qemu_find_vlan(vlan_id);  
     if (!vlan) {  
         fprintf(stderr, "Could not create vlan %d\n", vlan_id);  
         return -1;  
     }  
     if (!strcmp(device, "nic")) {  
         NICInfo *nd;  
         uint8_t *macaddr;  
   
         if (nb_nics >= MAX_NICS) {  
             fprintf(stderr, "Too Many NICs\n");  
             return -1;  
         }  
         nd = &nd_table[nb_nics];  
         macaddr = nd->macaddr;  
         macaddr[0] = 0x52;  
         macaddr[1] = 0x54;  
         macaddr[2] = 0x00;  
         macaddr[3] = 0x12;  
         macaddr[4] = 0x34;  
         macaddr[5] = 0x56 + nb_nics;  
   
         if (get_param_value(buf, sizeof(buf), "macaddr", p)) {  
             if (parse_macaddr(macaddr, buf) < 0) {  
                 fprintf(stderr, "invalid syntax for ethernet address\n");  
                 return -1;  
             }  
         }  
         if (get_param_value(buf, sizeof(buf), "model", p)) {  
             nd->model = strdup(buf);  
         }  
         nd->vlan = vlan;  
         nb_nics++;  
         vlan->nb_guest_devs++;  
         ret = 0;  
     } else  
     if (!strcmp(device, "none")) {  
         /* does nothing. It is needed to signal that no network cards  
            are wanted */  
         ret = 0;  
     } else  
 #ifdef CONFIG_SLIRP  
     if (!strcmp(device, "user")) {  
         if (get_param_value(buf, sizeof(buf), "hostname", p)) {  
             pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf);  
         }  
         vlan->nb_host_devs++;  
         ret = net_slirp_init(vlan);  
     } else  
 #endif  
 #ifdef _WIN32  
     if (!strcmp(device, "tap")) {  
         char ifname[64];  
         if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {  
             fprintf(stderr, "tap: no interface name\n");  
             return -1;  
         }  
         vlan->nb_host_devs++;  
         ret = tap_win32_init(vlan, ifname);  
     } else  
 #else  
     if (!strcmp(device, "tap")) {  
         char ifname[64];  
         char setup_script[1024], down_script[1024];  
         int fd;  
         vlan->nb_host_devs++;  
         if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {  
             fd = strtol(buf, NULL, 0);  
             ret = -1;  
             if (net_tap_fd_init(vlan, fd))  
                 ret = 0;  
         } else {  
             if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {  
                 ifname[0] = '\0';  
             }  
             if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) {  
                 pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT);  
             }  
             if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) {  
                 pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT);  
             }  
             ret = net_tap_init(vlan, ifname, setup_script, down_script);  
         }  
     } else  
 #endif  
     if (!strcmp(device, "socket")) {  
         if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {  
             int fd;  
             fd = strtol(buf, NULL, 0);  
             ret = -1;  
             if (net_socket_fd_init(vlan, fd, 1))  
                 ret = 0;  
         } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) {  
             ret = net_socket_listen_init(vlan, buf);  
         } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) {  
             ret = net_socket_connect_init(vlan, buf);  
         } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {  
             ret = net_socket_mcast_init(vlan, buf);  
         } else {  
             fprintf(stderr, "Unknown socket options: %s\n", p);  
             return -1;  
         }  
         vlan->nb_host_devs++;  
     } else  
     {  
         fprintf(stderr, "Unknown network device: %s\n", device);  
         return -1;  
     }  
     if (ret < 0) {  
         fprintf(stderr, "Could not initialize device '%s'\n", device);  
     }  
   
     return ret;  
 }  
   
 void do_info_network(void)  
 {  
     VLANState *vlan;  
     VLANClientState *vc;  
   
     for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {  
         term_printf("VLAN %d devices:\n", vlan->id);  
         for(vc = vlan->first_client; vc != NULL; vc = vc->next)  
             term_printf("  %s\n", vc->info_str);  
     }  
 }  
   
 #define HD_ALIAS "file=\"%s\",index=%d,media=disk"  
 #ifdef TARGET_PPC  
 #define CDROM_ALIAS "index=1,media=cdrom"  
 #else  
 #define CDROM_ALIAS "index=2,media=cdrom"  
 #endif  
 #define FD_ALIAS "index=%d,if=floppy"  
 #define PFLASH_ALIAS "file=\"%s\",if=pflash"  
 #define MTD_ALIAS "file=\"%s\",if=mtd"  
 #define SD_ALIAS "index=0,if=sd"  
   
 static int drive_add(const char *fmt, ...)  
 {  
     va_list ap;  
   
     if (nb_drives_opt >= MAX_DRIVES) {  
         fprintf(stderr, "qemu: too many drives\n");  
         exit(1);  
     }  
   
     va_start(ap, fmt);  
     vsnprintf(drives_opt[nb_drives_opt], sizeof(drives_opt[0]), fmt, ap);  
     va_end(ap);  
   
     return nb_drives_opt++;  
 }  
   
 int drive_get_index(BlockInterfaceType type, int bus, int unit)  
 {  
     int index;  
   
     /* seek interface, bus and unit */  
   
     for (index = 0; index < nb_drives; index++)  
         if (drives_table[index].type == type &&  
             drives_table[index].bus == bus &&  
             drives_table[index].unit == unit)  
         return index;  
   
     return -1;  
 }  
   
 int drive_get_max_bus(BlockInterfaceType type)  
 {  
     int max_bus;  
     int index;  
   
     max_bus = -1;  
     for (index = 0; index < nb_drives; index++) {  
         if(drives_table[index].type == type &&  
            drives_table[index].bus > max_bus)  
             max_bus = drives_table[index].bus;  
     }  
     return max_bus;  
 }  
   
 static int drive_init(const char *str, int snapshot, QEMUMachine *machine)  
 {  
     char buf[128];  
     char file[1024];  
     char devname[128];  
     const char *mediastr = "";  
     BlockInterfaceType type;  
     enum { MEDIA_DISK, MEDIA_CDROM } media;  
     int bus_id, unit_id;  
     int cyls, heads, secs, translation;  
     BlockDriverState *bdrv;  
     int max_devs;  
     int index;  
     int cache;  
     int bdrv_flags;  
     char *params[] = { "bus", "unit", "if", "index", "cyls", "heads",  
                        "secs", "trans", "media", "snapshot", "file",  
                        "cache", NULL };  
   
     if (check_params(buf, sizeof(buf), params, str) < 0) {  
          fprintf(stderr, "qemu: unknowm parameter '%s' in '%s'\n",  
                          buf, str);  
          return -1;  
     }  
   
     file[0] = 0;  
     cyls = heads = secs = 0;  
     bus_id = 0;  
     unit_id = -1;  
     translation = BIOS_ATA_TRANSLATION_AUTO;  
     index = -1;  
     cache = 1;  
   
     if (!strcmp(machine->name, "realview") ||  
         !strcmp(machine->name, "SS-5") ||  
         !strcmp(machine->name, "SS-10") ||  
         !strcmp(machine->name, "SS-600MP") ||  
         !strcmp(machine->name, "versatilepb") ||  
         !strcmp(machine->name, "versatileab")) {  
         type = IF_SCSI;  
         max_devs = MAX_SCSI_DEVS;  
         strcpy(devname, "scsi");  
     } else {  
         type = IF_IDE;  
         max_devs = MAX_IDE_DEVS;  
         strcpy(devname, "ide");  
     }  
     media = MEDIA_DISK;  
   
     /* extract parameters */  
   
     if (get_param_value(buf, sizeof(buf), "bus", str)) {  
         bus_id = strtol(buf, NULL, 0);  
         if (bus_id < 0) {  
             fprintf(stderr, "qemu: '%s' invalid bus id\n", str);  
             return -1;  
         }  
     }  
   
     if (get_param_value(buf, sizeof(buf), "unit", str)) {  
         unit_id = strtol(buf, NULL, 0);  
         if (unit_id < 0) {  
             fprintf(stderr, "qemu: '%s' invalid unit id\n", str);  
             return -1;  
         }  
     }  
   
     if (get_param_value(buf, sizeof(buf), "if", str)) {  
         strncpy(devname, buf, sizeof(devname));  
         if (!strcmp(buf, "ide")) {  
             type = IF_IDE;  
             max_devs = MAX_IDE_DEVS;  
         } else if (!strcmp(buf, "scsi")) {  
             type = IF_SCSI;  
             max_devs = MAX_SCSI_DEVS;  
         } else if (!strcmp(buf, "floppy")) {  
             type = IF_FLOPPY;  
             max_devs = 0;  
         } else if (!strcmp(buf, "pflash")) {  
             type = IF_PFLASH;  
             max_devs = 0;  
         } else if (!strcmp(buf, "mtd")) {  
             type = IF_MTD;  
             max_devs = 0;  
         } else if (!strcmp(buf, "sd")) {  
             type = IF_SD;  
             max_devs = 0;  
         } else {  
             fprintf(stderr, "qemu: '%s' unsupported bus type '%s'\n", str, buf);  
             return -1;  
         }  
     }  
   
     if (get_param_value(buf, sizeof(buf), "index", str)) {  
         index = strtol(buf, NULL, 0);  
         if (index < 0) {  
             fprintf(stderr, "qemu: '%s' invalid index\n", str);  
             return -1;  
         }  
     }  
   
     if (get_param_value(buf, sizeof(buf), "cyls", str)) {  
         cyls = strtol(buf, NULL, 0);  
     }  
   
     if (get_param_value(buf, sizeof(buf), "heads", str)) {  
         heads = strtol(buf, NULL, 0);  
     }  
   
     if (get_param_value(buf, sizeof(buf), "secs", str)) {  
         secs = strtol(buf, NULL, 0);  
     }  
   
     if (cyls || heads || secs) {  
         if (cyls < 1 || cyls > 16383) {  
             fprintf(stderr, "qemu: '%s' invalid physical cyls number\n", str);  
             return -1;  
         }  
         if (heads < 1 || heads > 16) {  
             fprintf(stderr, "qemu: '%s' invalid physical heads number\n", str);  
             return -1;  
         }  
         if (secs < 1 || secs > 63) {  
             fprintf(stderr, "qemu: '%s' invalid physical secs number\n", str);  
             return -1;  
         }  
     }  
   
     if (get_param_value(buf, sizeof(buf), "trans", str)) {  
         if (!cyls) {  
             fprintf(stderr,  
                     "qemu: '%s' trans must be used with cyls,heads and secs\n",  
                     str);  
             return -1;  
         }  
         if (!strcmp(buf, "none"))  
             translation = BIOS_ATA_TRANSLATION_NONE;  
         else if (!strcmp(buf, "lba"))  
             translation = BIOS_ATA_TRANSLATION_LBA;  
         else if (!strcmp(buf, "auto"))  
             translation = BIOS_ATA_TRANSLATION_AUTO;  
         else {  
             fprintf(stderr, "qemu: '%s' invalid translation type\n", str);  
             return -1;  
         }  
     }  
   
     if (get_param_value(buf, sizeof(buf), "media", str)) {  
         if (!strcmp(buf, "disk")) {  
             media = MEDIA_DISK;  
         } else if (!strcmp(buf, "cdrom")) {  
             if (cyls || secs || heads) {  
                 fprintf(stderr,  
                         "qemu: '%s' invalid physical CHS format\n", str);  
                 return -1;  
             }  
             media = MEDIA_CDROM;  
         } else {  
             fprintf(stderr, "qemu: '%s' invalid media\n", str);  
             return -1;  
         }  
     }  
   
     if (get_param_value(buf, sizeof(buf), "snapshot", str)) {  
         if (!strcmp(buf, "on"))  
             snapshot = 1;  
         else if (!strcmp(buf, "off"))  
             snapshot = 0;  
         else {  
             fprintf(stderr, "qemu: '%s' invalid snapshot option\n", str);  
             return -1;  
         }  
     }  
   
     if (get_param_value(buf, sizeof(buf), "cache", str)) {  
         if (!strcmp(buf, "off"))  
             cache = 0;  
         else if (!strcmp(buf, "on"))  
             cache = 1;  
         else {  
            fprintf(stderr, "qemu: invalid cache option\n");  
            return -1;  
         }  
     }  
   
     get_param_value(file, sizeof(file), "file", str);  
   
     /* compute bus and unit according index */  
   
     if (index != -1) {  
         if (bus_id != 0 || unit_id != -1) {  
             fprintf(stderr,  
                     "qemu: '%s' index cannot be used with bus and unit\n", str);  
             return -1;  
         }  
         if (max_devs == 0)  
         {  
             unit_id = index;  
             bus_id = 0;  
         } else {  
             unit_id = index % max_devs;  
             bus_id = index / max_devs;  
         }  
     }  
   
     /* if user doesn't specify a unit_id,  
      * try to find the first free  
      */  
   
     if (unit_id == -1) {  
        unit_id = 0;  
        while (drive_get_index(type, bus_id, unit_id) != -1) {  
            unit_id++;  
            if (max_devs && unit_id >= max_devs) {  
                unit_id -= max_devs;  
                bus_id++;  
            }  
        }  
     }  
   
     /* check unit id */  
   
     if (max_devs && unit_id >= max_devs) {  
         fprintf(stderr, "qemu: '%s' unit %d too big (max is %d)\n",  
                         str, unit_id, max_devs - 1);  
         return -1;  
     }  
   
     /*  
      * ignore multiple definitions  
      */  
   
     if (drive_get_index(type, bus_id, unit_id) != -1)  
         return 0;  
   
     /* init */  
   
     if (type == IF_IDE || type == IF_SCSI)  
         mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";  
     if (max_devs)  
         snprintf(buf, sizeof(buf), "%s%i%s%i",  
                  devname, bus_id, mediastr, unit_id);  
     else  
         snprintf(buf, sizeof(buf), "%s%s%i",  
                  devname, mediastr, unit_id);  
     bdrv = bdrv_new(buf);  
     drives_table[nb_drives].bdrv = bdrv;  
     drives_table[nb_drives].type = type;  
     drives_table[nb_drives].bus = bus_id;  
     drives_table[nb_drives].unit = unit_id;  
     nb_drives++;  
   
     switch(type) {  
     case IF_IDE:  
     case IF_SCSI:  
         switch(media) {  
         case MEDIA_DISK:  
             if (cyls != 0) {  
                 bdrv_set_geometry_hint(bdrv, cyls, heads, secs);  
                 bdrv_set_translation_hint(bdrv, translation);  
             }  
             break;  
         case MEDIA_CDROM:  
             bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);  
             break;  
         }  
         break;  
     case IF_SD:  
         /* FIXME: This isn't really a floppy, but it's a reasonable  
            approximation.  */  
     case IF_FLOPPY:  
         bdrv_set_type_hint(bdrv, BDRV_TYPE_FLOPPY);  
         break;  
     case IF_PFLASH:  
     case IF_MTD:  
         break;  
     }  
     if (!file[0])  
         return 0;  
     bdrv_flags = 0;  
     if (snapshot)  
         bdrv_flags |= BDRV_O_SNAPSHOT;  
     if (!cache)  
         bdrv_flags |= BDRV_O_DIRECT;  
     if (bdrv_open(bdrv, file, bdrv_flags) < 0 || qemu_key_check(bdrv, file)) {  
         fprintf(stderr, "qemu: could not open disk image %s\n",  
                         file);  
         return -1;  
     }  
     return 0;  
 }  
   
 /***********************************************************/  
 /* USB devices */  
   
 static USBPort *used_usb_ports;  
 static USBPort *free_usb_ports;  
   
 /* ??? Maybe change this to register a hub to keep track of the topology.  */  
 void qemu_register_usb_port(USBPort *port, void *opaque, int index,  
                             usb_attachfn attach)  
 {  
     port->opaque = opaque;  
     port->index = index;  
     port->attach = attach;  
     port->next = free_usb_ports;  
     free_usb_ports = port;  
 }  
   
 static int usb_device_add(const char *devname)  
 {  
     const char *p;  
     USBDevice *dev;  
     USBPort *port;  
   
     if (!free_usb_ports)  
         return -1;  
   
     if (strstart(devname, "host:", &p)) {  
         dev = usb_host_device_open(p);  
     } else if (!strcmp(devname, "mouse")) {  
         dev = usb_mouse_init();  
     } else if (!strcmp(devname, "tablet")) {  
         dev = usb_tablet_init();  
     } else if (!strcmp(devname, "keyboard")) {  
         dev = usb_keyboard_init();  
     } else if (strstart(devname, "disk:", &p)) {  
         dev = usb_msd_init(p);  
     } else if (!strcmp(devname, "wacom-tablet")) {  
         dev = usb_wacom_init();  
     } else {  
         return -1;  
     }  
     if (!dev)  
         return -1;  
   
     /* Find a USB port to add the device to.  */  
     port = free_usb_ports;  
     if (!port->next) {  
         USBDevice *hub;  
   
         /* Create a new hub and chain it on.  */  
         free_usb_ports = NULL;  
         port->next = used_usb_ports;  
         used_usb_ports = port;  
   
         hub = usb_hub_init(VM_USB_HUB_SIZE);  
         usb_attach(port, hub);  
         port = free_usb_ports;  
     }  
   
     free_usb_ports = port->next;  
     port->next = used_usb_ports;  
     used_usb_ports = port;  
     usb_attach(port, dev);  
     return 0;  
 }  
   
 static int usb_device_del(const char *devname)  
 {  
     USBPort *port;  
     USBPort **lastp;  
     USBDevice *dev;  
     int bus_num, addr;  
     const char *p;  
   
     if (!used_usb_ports)  
         return -1;  
   
     p = strchr(devname, '.');  
     if (!p)  
         return -1;  
     bus_num = strtoul(devname, NULL, 0);  
     addr = strtoul(p + 1, NULL, 0);  
     if (bus_num != 0)  
         return -1;  
   
     lastp = &used_usb_ports;  
     port = used_usb_ports;  
     while (port && port->dev->addr != addr) {  
         lastp = &port->next;  
         port = port->next;  
     }  
   
     if (!port)  
         return -1;  
   
     dev = port->dev;  
     *lastp = port->next;  
     usb_attach(port, NULL);  
     dev->handle_destroy(dev);  
     port->next = free_usb_ports;  
     free_usb_ports = port;  
     return 0;  
 }  
   
 void do_usb_add(const char *devname)  
 {  
     int ret;  
     ret = usb_device_add(devname);  
     if (ret < 0)  
         term_printf("Could not add USB device '%s'\n", devname);  
 }  
   
 void do_usb_del(const char *devname)  
 {  
     int ret;  
     ret = usb_device_del(devname);  
     if (ret < 0)  
         term_printf("Could not remove USB device '%s'\n", devname);  
 }  
   
 void usb_info(void)  
 {  
     USBDevice *dev;  
     USBPort *port;  
     const char *speed_str;  
   
     if (!usb_enabled) {  
         term_printf("USB support not enabled\n");  
         return;  
     }  
   
     for (port = used_usb_ports; port; port = port->next) {  
         dev = port->dev;  
         if (!dev)  
             continue;  
         switch(dev->speed) {  
         case USB_SPEED_LOW:  
             speed_str = "1.5";  
             break;  
         case USB_SPEED_FULL:  
             speed_str = "12";  
             break;  
         case USB_SPEED_HIGH:  
             speed_str = "480";  
             break;  
         default:  
             speed_str = "?";  
             break;  
         }  
         term_printf("  Device %d.%d, Speed %s Mb/s, Product %s\n",  
                     0, dev->addr, speed_str, dev->devname);  
     }  
 }  
   
 /***********************************************************/  
 /* PCMCIA/Cardbus */  
   
 static struct pcmcia_socket_entry_s {  
     struct pcmcia_socket_s *socket;  
     struct pcmcia_socket_entry_s *next;  
 } *pcmcia_sockets = 0;  
   
 void pcmcia_socket_register(struct pcmcia_socket_s *socket)  
 {  
     struct pcmcia_socket_entry_s *entry;  
   
     entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s));  
     entry->socket = socket;  
     entry->next = pcmcia_sockets;  
     pcmcia_sockets = entry;  
 }  
   
 void pcmcia_socket_unregister(struct pcmcia_socket_s *socket)  
 {  
     struct pcmcia_socket_entry_s *entry, **ptr;  
   
     ptr = &pcmcia_sockets;  
     for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr)  
         if (entry->socket == socket) {  
             *ptr = entry->next;  
             qemu_free(entry);  
         }  
 }  
   
 void pcmcia_info(void)  
 {  
     struct pcmcia_socket_entry_s *iter;  
     if (!pcmcia_sockets)  
         term_printf("No PCMCIA sockets\n");  
   
     for (iter = pcmcia_sockets; iter; iter = iter->next)  
         term_printf("%s: %s\n", iter->socket->slot_string,  
                     iter->socket->attached ? iter->socket->card_string :  
                     "Empty");  
 }  
   
 /***********************************************************/  
 /* dumb display */  
   
 static void dumb_update(DisplayState *ds, int x, int y, int w, int h)  
 {  
 }  
   
 static void dumb_resize(DisplayState *ds, int w, int h)  
 {  
 }  
   
 static void dumb_refresh(DisplayState *ds)  
 {  
 #if defined(CONFIG_SDL)  
     vga_hw_update();  
 #endif  
 }  
   
 static void dumb_display_init(DisplayState *ds)  
 {  
     ds->data = NULL;  
     ds->linesize = 0;  
     ds->depth = 0;  
     ds->dpy_update = dumb_update;  
     ds->dpy_resize = dumb_resize;  
     ds->dpy_refresh = dumb_refresh;  
 }  
   
 /***********************************************************/  
 /* I/O handling */  
   
 #define MAX_IO_HANDLERS 64  
   
 typedef struct IOHandlerRecord {  
     int fd;  
     IOCanRWHandler *fd_read_poll;  
     IOHandler *fd_read;  
     IOHandler *fd_write;  
     int deleted;  
     void *opaque;  
     /* temporary data */  
     struct pollfd *ufd;  
     struct IOHandlerRecord *next;  
 } IOHandlerRecord;  
   
 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,  
                          void *opaque)  
 {  
     IOHandlerRecord **pioh, *ioh;  
   
     if (!fd_read && !fd_write) {  
         pioh = &first_io_handler;  
         for(;;) {  
             ioh = *pioh;  
             if (ioh == NULL)  
                 break;  
             if (ioh->fd == fd) {  
                 ioh->deleted = 1;  
                 break;  
             }  
             pioh = &ioh->next;  
         }  
     } else {  
         for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {  
             if (ioh->fd == fd)  
                 goto found;  
         }  
         ioh = qemu_mallocz(sizeof(IOHandlerRecord));  
         if (!ioh)  
             return -1;  
         ioh->next = first_io_handler;  
         first_io_handler = ioh;  
     found:  
         ioh->fd = fd;  
         ioh->fd_read_poll = fd_read_poll;  
         ioh->fd_read = fd_read;  
         ioh->fd_write = fd_write;  
         ioh->opaque = opaque;  
         ioh->deleted = 0;  
     }  
     return 0;  
 }  
   
 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);  
 }  
   
 /***********************************************************/  
 /* Polling handling */  
   
 typedef struct PollingEntry {  
     PollingFunc *func;  
     void *opaque;  
     struct PollingEntry *next;  
 } PollingEntry;  
   
 static PollingEntry *first_polling_entry;      if (arg->file == NULL)
           get_param_value(file, sizeof(file), "file", str);
       else
           pstrcpy(file, sizeof(file), arg->file);
   
 int qemu_add_polling_cb(PollingFunc *func, void *opaque)      if (!get_param_value(serial, sizeof(serial), "serial", str))
 {              memset(serial, 0,  sizeof(serial));
     PollingEntry **ppe, *pe;  
     pe = qemu_mallocz(sizeof(PollingEntry));  
     if (!pe)  
         return -1;  
     pe->func = func;  
     pe->opaque = opaque;  
     for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);  
     *ppe = pe;  
     return 0;  
 }  
   
 void qemu_del_polling_cb(PollingFunc *func, void *opaque)      onerror = BLOCK_ERR_STOP_ENOSPC;
 {      if (get_param_value(buf, sizeof(serial), "werror", str)) {
     PollingEntry **ppe, *pe;          if (type != IF_IDE && type != IF_SCSI && type != IF_VIRTIO) {
     for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {              fprintf(stderr, "werror is no supported by this format\n");
         pe = *ppe;              return -1;
         if (pe->func == func && pe->opaque == opaque) {          }
             *ppe = pe->next;          if (!strcmp(buf, "ignore"))
             qemu_free(pe);              onerror = BLOCK_ERR_IGNORE;
             break;          else if (!strcmp(buf, "enospc"))
               onerror = BLOCK_ERR_STOP_ENOSPC;
           else if (!strcmp(buf, "stop"))
               onerror = BLOCK_ERR_STOP_ANY;
           else if (!strcmp(buf, "report"))
               onerror = BLOCK_ERR_REPORT;
           else {
               fprintf(stderr, "qemu: '%s' invalid write error action\n", buf);
               return -1;
         }          }
     }      }
 }  
   
 #ifdef _WIN32      /* compute bus and unit according index */
 /***********************************************************/  
 /* Wait objects support */  
 typedef struct WaitObjects {  
     int num;  
     HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];  
     WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];  
     void *opaque[MAXIMUM_WAIT_OBJECTS + 1];  
 } WaitObjects;  
   
 static WaitObjects wait_objects = {0};      if (index != -1) {
           if (bus_id != 0 || unit_id != -1) {
               fprintf(stderr,
                       "qemu: '%s' index cannot be used with bus and unit\n", str);
               return -1;
           }
           if (max_devs == 0)
           {
               unit_id = index;
               bus_id = 0;
           } else {
               unit_id = index % max_devs;
               bus_id = index / max_devs;
           }
       }
   
 int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)      /* if user doesn't specify a unit_id,
 {       * try to find the first free
     WaitObjects *w = &wait_objects;       */
   
     if (w->num >= MAXIMUM_WAIT_OBJECTS)      if (unit_id == -1) {
         return -1;         unit_id = 0;
     w->events[w->num] = handle;         while (drive_get_index(type, bus_id, unit_id) != -1) {
     w->func[w->num] = func;             unit_id++;
     w->opaque[w->num] = opaque;             if (max_devs && unit_id >= max_devs) {
     w->num++;                 unit_id -= max_devs;
     return 0;                 bus_id++;
 }             }
          }
       }
   
 void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)      /* check unit id */
 {  
     int i, found;  
     WaitObjects *w = &wait_objects;  
   
     found = 0;      if (max_devs && unit_id >= max_devs) {
     for (i = 0; i < w->num; i++) {          fprintf(stderr, "qemu: '%s' unit %d too big (max is %d)\n",
         if (w->events[i] == handle)                          str, unit_id, max_devs - 1);
             found = 1;          return -1;
         if (found) {  
             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--;  
 }  
 #endif  
   
 /***********************************************************/      /*
 /* savevm/loadvm support */       * ignore multiple definitions
        */
   
 #define IO_BUF_SIZE 32768      if (drive_get_index(type, bus_id, unit_id) != -1)
           return -2;
   
 struct QEMUFile {      /* init */
     FILE *outfile;  
     BlockDriverState *bs;  
     int is_file;  
     int is_writable;  
     int64_t base_offset;  
     int64_t buf_offset; /* start of buffer when writing, end of buffer  
                            when reading */  
     int buf_index;  
     int buf_size; /* 0 when writing */  
     uint8_t buf[IO_BUF_SIZE];  
 };  
   
 QEMUFile *qemu_fopen(const char *filename, const char *mode)      if (type == IF_IDE || type == IF_SCSI)
 {          mediastr = (media == MEDIA_CDROM) ? "-cd" : "-hd";
     QEMUFile *f;      if (max_devs)
           snprintf(buf, sizeof(buf), "%s%i%s%i",
                    devname, bus_id, mediastr, unit_id);
       else
           snprintf(buf, sizeof(buf), "%s%s%i",
                    devname, mediastr, unit_id);
       bdrv = bdrv_new(buf);
       drives_table_idx = drive_get_free_idx();
       drives_table[drives_table_idx].bdrv = bdrv;
       drives_table[drives_table_idx].type = type;
       drives_table[drives_table_idx].bus = bus_id;
       drives_table[drives_table_idx].unit = unit_id;
       drives_table[drives_table_idx].onerror = onerror;
       drives_table[drives_table_idx].drive_opt_idx = arg - drives_opt;
       strncpy(drives_table[nb_drives].serial, serial, sizeof(serial));
       nb_drives++;
   
     f = qemu_mallocz(sizeof(QEMUFile));      switch(type) {
     if (!f)      case IF_IDE:
         return NULL;      case IF_SCSI:
     if (!strcmp(mode, "wb")) {          switch(media) {
         f->is_writable = 1;          case MEDIA_DISK:
     } else if (!strcmp(mode, "rb")) {              if (cyls != 0) {
         f->is_writable = 0;                  bdrv_set_geometry_hint(bdrv, cyls, heads, secs);
     } else {                  bdrv_set_translation_hint(bdrv, translation);
         goto fail;              }
               break;
           case MEDIA_CDROM:
               bdrv_set_type_hint(bdrv, BDRV_TYPE_CDROM);
               break;
           }
           break;
       case IF_SD:
           /* FIXME: This isn't really a floppy, but it's a reasonable
              approximation.  */
       case IF_FLOPPY:
           bdrv_set_type_hint(bdrv, BDRV_TYPE_FLOPPY);
           break;
       case IF_PFLASH:
       case IF_MTD:
       case IF_VIRTIO:
           break;
     }      }
     f->outfile = fopen(filename, mode);      if (!file[0])
     if (!f->outfile)          return -2;
         goto fail;      bdrv_flags = 0;
     f->is_file = 1;      if (snapshot) {
     return f;          bdrv_flags |= BDRV_O_SNAPSHOT;
  fail:          cache = 2; /* always use write-back with snapshot */
     if (f->outfile)      }
         fclose(f->outfile);      if (cache == 0) /* no caching */
     qemu_free(f);          bdrv_flags |= BDRV_O_NOCACHE;
     return NULL;      else if (cache == 2) /* write-back */
           bdrv_flags |= BDRV_O_CACHE_WB;
       else if (cache == 3) /* not specified */
           bdrv_flags |= BDRV_O_CACHE_DEF;
       if (bdrv_open2(bdrv, file, bdrv_flags, drv) < 0 || qemu_key_check(bdrv, file)) {
           fprintf(stderr, "qemu: could not open disk image %s\n",
                           file);
           return -1;
       }
       return drives_table_idx;
 }  }
   
 static QEMUFile *qemu_fopen_bdrv(BlockDriverState *bs, int64_t offset, int is_writable)  /***********************************************************/
 {  /* USB devices */
     QEMUFile *f;  
   
     f = qemu_mallocz(sizeof(QEMUFile));  static USBPort *used_usb_ports;
     if (!f)  static USBPort *free_usb_ports;
         return NULL;  
     f->is_file = 0;  
     f->bs = bs;  
     f->is_writable = is_writable;  
     f->base_offset = offset;  
     return f;  
 }  
   
 void qemu_fflush(QEMUFile *f)  /* ??? Maybe change this to register a hub to keep track of the topology.  */
   void qemu_register_usb_port(USBPort *port, void *opaque, int index,
                               usb_attachfn attach)
 {  {
     if (!f->is_writable)      port->opaque = opaque;
         return;      port->index = index;
     if (f->buf_index > 0) {      port->attach = attach;
         if (f->is_file) {      port->next = free_usb_ports;
             fseek(f->outfile, f->buf_offset, SEEK_SET);      free_usb_ports = port;
             fwrite(f->buf, 1, f->buf_index, f->outfile);  
         } else {  
             bdrv_pwrite(f->bs, f->base_offset + f->buf_offset,  
                         f->buf, f->buf_index);  
         }  
         f->buf_offset += f->buf_index;  
         f->buf_index = 0;  
     }  
 }  }
   
 static void qemu_fill_buffer(QEMUFile *f)  int usb_device_add_dev(USBDevice *dev)
 {  {
     int len;      USBPort *port;
   
     if (f->is_writable)      /* Find a USB port to add the device to.  */
         return;      port = free_usb_ports;
     if (f->is_file) {      if (!port->next) {
         fseek(f->outfile, f->buf_offset, SEEK_SET);          USBDevice *hub;
         len = fread(f->buf, 1, IO_BUF_SIZE, f->outfile);  
         if (len < 0)  
             len = 0;  
     } else {  
         len = bdrv_pread(f->bs, f->base_offset + f->buf_offset,  
                          f->buf, IO_BUF_SIZE);  
         if (len < 0)  
             len = 0;  
     }  
     f->buf_index = 0;  
     f->buf_size = len;  
     f->buf_offset += len;  
 }  
   
 void qemu_fclose(QEMUFile *f)          /* Create a new hub and chain it on.  */
 {          free_usb_ports = NULL;
     if (f->is_writable)          port->next = used_usb_ports;
         qemu_fflush(f);          used_usb_ports = port;
     if (f->is_file) {  
         fclose(f->outfile);  
     }  
     qemu_free(f);  
 }  
   
 void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size)          hub = usb_hub_init(VM_USB_HUB_SIZE);
 {          usb_attach(port, hub);
     int l;          port = free_usb_ports;
     while (size > 0) {  
         l = IO_BUF_SIZE - f->buf_index;  
         if (l > size)  
             l = size;  
         memcpy(f->buf + f->buf_index, buf, l);  
         f->buf_index += l;  
         buf += l;  
         size -= l;  
         if (f->buf_index >= IO_BUF_SIZE)  
             qemu_fflush(f);  
     }      }
 }  
   
 void qemu_put_byte(QEMUFile *f, int v)      free_usb_ports = port->next;
 {      port->next = used_usb_ports;
     f->buf[f->buf_index++] = v;      used_usb_ports = port;
     if (f->buf_index >= IO_BUF_SIZE)      usb_attach(port, dev);
         qemu_fflush(f);      return 0;
 }  }
   
 int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size1)  static int usb_device_add(const char *devname)
 {  {
     int size, l;      const char *p;
       USBDevice *dev;
     size = size1;  
     while (size > 0) {  
         l = f->buf_size - f->buf_index;  
         if (l == 0) {  
             qemu_fill_buffer(f);  
             l = f->buf_size - f->buf_index;  
             if (l == 0)  
                 break;  
         }  
         if (l > size)  
             l = size;  
         memcpy(buf, f->buf + f->buf_index, l);  
         f->buf_index += l;  
         buf += l;  
         size -= l;  
     }  
     return size1 - size;  
 }  
   
 int qemu_get_byte(QEMUFile *f)      if (!free_usb_ports)
 {          return -1;
     if (f->buf_index >= f->buf_size) {  
         qemu_fill_buffer(f);  
         if (f->buf_index >= f->buf_size)  
             return 0;  
     }  
     return f->buf[f->buf_index++];  
 }  
   
 int64_t qemu_ftell(QEMUFile *f)      if (strstart(devname, "host:", &p)) {
 {          dev = usb_host_device_open(p);
     return f->buf_offset - f->buf_size + f->buf_index;      } else if (!strcmp(devname, "mouse")) {
 }          dev = usb_mouse_init();
       } else if (!strcmp(devname, "tablet")) {
           dev = usb_tablet_init();
       } else if (!strcmp(devname, "keyboard")) {
           dev = usb_keyboard_init();
       } else if (strstart(devname, "disk:", &p)) {
           dev = usb_msd_init(p);
       } else if (!strcmp(devname, "wacom-tablet")) {
           dev = usb_wacom_init();
       } else if (strstart(devname, "serial:", &p)) {
           dev = usb_serial_init(p);
   #ifdef CONFIG_BRLAPI
       } else if (!strcmp(devname, "braille")) {
           dev = usb_baum_init();
   #endif
       } else if (strstart(devname, "net:", &p)) {
           int nic = nb_nics;
   
 int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence)          if (net_client_init("nic", p) < 0)
 {              return -1;
     if (whence == SEEK_SET) {          nd_table[nic].model = "usb";
         /* nothing to do */          dev = usb_net_init(&nd_table[nic]);
     } else if (whence == SEEK_CUR) {      } else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) {
         pos += qemu_ftell(f);          dev = usb_bt_init(devname[2] ? hci_init(p) :
                           bt_new_hci(qemu_find_bt_vlan(0)));
     } else {      } else {
         /* SEEK_END not supported */  
         return -1;          return -1;
     }      }
     if (f->is_writable) {      if (!dev)
         qemu_fflush(f);          return -1;
         f->buf_offset = pos;  
     } else {  
         f->buf_offset = pos;  
         f->buf_index = 0;  
         f->buf_size = 0;  
     }  
     return pos;  
 }  
   
 void qemu_put_be16(QEMUFile *f, unsigned int v)  
 {  
     qemu_put_byte(f, v >> 8);  
     qemu_put_byte(f, v);  
 }  
   
 void qemu_put_be32(QEMUFile *f, unsigned int v)  
 {  
     qemu_put_byte(f, v >> 24);  
     qemu_put_byte(f, v >> 16);  
     qemu_put_byte(f, v >> 8);  
     qemu_put_byte(f, v);  
 }  
   
 void qemu_put_be64(QEMUFile *f, uint64_t v)  
 {  
     qemu_put_be32(f, v >> 32);  
     qemu_put_be32(f, v);  
 }  
   
 unsigned int qemu_get_be16(QEMUFile *f)  
 {  
     unsigned int v;  
     v = qemu_get_byte(f) << 8;  
     v |= qemu_get_byte(f);  
     return v;  
 }  
   
 unsigned int qemu_get_be32(QEMUFile *f)      return usb_device_add_dev(dev);
 {  
     unsigned int v;  
     v = qemu_get_byte(f) << 24;  
     v |= qemu_get_byte(f) << 16;  
     v |= qemu_get_byte(f) << 8;  
     v |= qemu_get_byte(f);  
     return v;  
 }  }
   
 uint64_t qemu_get_be64(QEMUFile *f)  int usb_device_del_addr(int bus_num, int addr)
 {  {
     uint64_t v;      USBPort *port;
     v = (uint64_t)qemu_get_be32(f) << 32;      USBPort **lastp;
     v |= qemu_get_be32(f);      USBDevice *dev;
     return v;  
 }  
   
 typedef struct SaveStateEntry {      if (!used_usb_ports)
     char idstr[256];          return -1;
     int instance_id;  
     int version_id;  
     SaveStateHandler *save_state;  
     LoadStateHandler *load_state;  
     void *opaque;  
     struct SaveStateEntry *next;  
 } SaveStateEntry;  
   
 static SaveStateEntry *first_se;      if (bus_num != 0)
           return -1;
   
 int register_savevm(const char *idstr,      lastp = &used_usb_ports;
                     int instance_id,      port = used_usb_ports;
                     int version_id,      while (port && port->dev->addr != addr) {
                     SaveStateHandler *save_state,          lastp = &port->next;
                     LoadStateHandler *load_state,          port = port->next;
                     void *opaque)      }
 {  
     SaveStateEntry *se, **pse;  
   
     se = qemu_malloc(sizeof(SaveStateEntry));      if (!port)
     if (!se)  
         return -1;          return -1;
     pstrcpy(se->idstr, sizeof(se->idstr), idstr);  
     se->instance_id = instance_id;      dev = port->dev;
     se->version_id = version_id;      *lastp = port->next;
     se->save_state = save_state;      usb_attach(port, NULL);
     se->load_state = load_state;      dev->handle_destroy(dev);
     se->opaque = opaque;      port->next = free_usb_ports;
     se->next = NULL;      free_usb_ports = port;
   
     /* add at the end of list */  
     pse = &first_se;  
     while (*pse != NULL)  
         pse = &(*pse)->next;  
     *pse = se;  
     return 0;      return 0;
 }  }
   
 #define QEMU_VM_FILE_MAGIC   0x5145564d  static int usb_device_del(const char *devname)
 #define QEMU_VM_FILE_VERSION 0x00000002  
   
 static int qemu_savevm_state(QEMUFile *f)  
 {  {
     SaveStateEntry *se;      int bus_num, addr;
     int len, ret;      const char *p;
     int64_t cur_pos, len_pos, total_len_pos;  
   
     qemu_put_be32(f, QEMU_VM_FILE_MAGIC);  
     qemu_put_be32(f, QEMU_VM_FILE_VERSION);  
     total_len_pos = qemu_ftell(f);  
     qemu_put_be64(f, 0); /* total size */  
   
     for(se = first_se; se != NULL; se = se->next) {  
         /* ID string */  
         len = strlen(se->idstr);  
         qemu_put_byte(f, len);  
         qemu_put_buffer(f, (uint8_t *)se->idstr, len);  
   
         qemu_put_be32(f, se->instance_id);  
         qemu_put_be32(f, se->version_id);  
   
         /* record size: filled later */  
         len_pos = qemu_ftell(f);  
         qemu_put_be32(f, 0);  
         se->save_state(f, se->opaque);  
   
         /* fill record size */  
         cur_pos = qemu_ftell(f);  
         len = cur_pos - len_pos - 4;  
         qemu_fseek(f, len_pos, SEEK_SET);  
         qemu_put_be32(f, len);  
         qemu_fseek(f, cur_pos, SEEK_SET);  
     }  
     cur_pos = qemu_ftell(f);  
     qemu_fseek(f, total_len_pos, SEEK_SET);  
     qemu_put_be64(f, cur_pos - total_len_pos - 8);  
     qemu_fseek(f, cur_pos, SEEK_SET);  
   
     ret = 0;  
     return ret;  
 }  
   
 static SaveStateEntry *find_se(const char *idstr, int instance_id)      if (strstart(devname, "host:", &p))
 {          return usb_host_device_close(p);
     SaveStateEntry *se;  
   
     for(se = first_se; se != NULL; se = se->next) {      if (!used_usb_ports)
         if (!strcmp(se->idstr, idstr) &&          return -1;
             instance_id == se->instance_id)  
             return se;  
     }  
     return NULL;  
 }  
   
 static int qemu_loadvm_state(QEMUFile *f)      p = strchr(devname, '.');
 {      if (!p)
     SaveStateEntry *se;          return -1;
     int len, ret, instance_id, record_len, version_id;      bus_num = strtoul(devname, NULL, 0);
     int64_t total_len, end_pos, cur_pos;      addr = strtoul(p + 1, NULL, 0);
     unsigned int v;  
     char idstr[256];  
   
     v = qemu_get_be32(f);      return usb_device_del_addr(bus_num, addr);
     if (v != QEMU_VM_FILE_MAGIC)  
         goto fail;  
     v = qemu_get_be32(f);  
     if (v != QEMU_VM_FILE_VERSION) {  
     fail:  
         ret = -1;  
         goto the_end;  
     }  
     total_len = qemu_get_be64(f);  
     end_pos = total_len + qemu_ftell(f);  
     for(;;) {  
         if (qemu_ftell(f) >= end_pos)  
             break;  
         len = qemu_get_byte(f);  
         qemu_get_buffer(f, (uint8_t *)idstr, len);  
         idstr[len] = '\0';  
         instance_id = qemu_get_be32(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",  
                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",  
                     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",  
                         instance_id, idstr);  
             }  
         }  
         /* always seek to exact end of record */  
         qemu_fseek(f, cur_pos + record_len, SEEK_SET);  
     }  
     ret = 0;  
  the_end:  
     return ret;  
 }  }
   
 /* device can contain snapshots */  void do_usb_add(const char *devname)
 static int bdrv_can_snapshot(BlockDriverState *bs)  
 {  {
     return (bs &&      usb_device_add(devname);
             !bdrv_is_removable(bs) &&  
             !bdrv_is_read_only(bs));  
 }  }
   
 /* device must be snapshots in order to have a reliable snapshot */  void do_usb_del(const char *devname)
 static int bdrv_has_snapshot(BlockDriverState *bs)  
 {  {
     return (bs &&      usb_device_del(devname);
             !bdrv_is_removable(bs) &&  
             !bdrv_is_read_only(bs));  
 }  }
   
 static BlockDriverState *get_bs_snapshots(void)  void usb_info(void)
 {  {
     BlockDriverState *bs;      USBDevice *dev;
     int i;      USBPort *port;
       const char *speed_str;
   
     if (bs_snapshots)      if (!usb_enabled) {
         return bs_snapshots;          term_printf("USB support not enabled\n");
     for(i = 0; i <= nb_drives; i++) {          return;
         bs = drives_table[i].bdrv;  
         if (bdrv_can_snapshot(bs))  
             goto ok;  
     }      }
     return NULL;  
  ok:      for (port = used_usb_ports; port; port = port->next) {
     bs_snapshots = bs;          dev = port->dev;
     return bs;          if (!dev)
 }              continue;
           switch(dev->speed) {
 static int bdrv_snapshot_find(BlockDriverState *bs, QEMUSnapshotInfo *sn_info,          case USB_SPEED_LOW:
                               const char *name)              speed_str = "1.5";
 {              break;
     QEMUSnapshotInfo *sn_tab, *sn;          case USB_SPEED_FULL:
     int nb_sns, i, ret;              speed_str = "12";
               break;
     ret = -ENOENT;          case USB_SPEED_HIGH:
     nb_sns = bdrv_snapshot_list(bs, &sn_tab);              speed_str = "480";
     if (nb_sns < 0)              break;
         return ret;          default:
     for(i = 0; i < nb_sns; i++) {              speed_str = "?";
         sn = &sn_tab[i];  
         if (!strcmp(sn->id_str, name) || !strcmp(sn->name, name)) {  
             *sn_info = *sn;  
             ret = 0;  
             break;              break;
         }          }
           term_printf("  Device %d.%d, Speed %s Mb/s, Product %s\n",
                       0, dev->addr, speed_str, dev->devname);
     }      }
     qemu_free(sn_tab);  
     return ret;  
 }  }
   
 void do_savevm(const char *name)  /***********************************************************/
 {  /* PCMCIA/Cardbus */
     BlockDriverState *bs, *bs1;  
     QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;  
     int must_delete, ret, i;  
     BlockDriverInfo bdi1, *bdi = &bdi1;  
     QEMUFile *f;  
     int saved_vm_running;  
 #ifdef _WIN32  
     struct _timeb tb;  
 #else  
     struct timeval tv;  
 #endif  
   
     bs = get_bs_snapshots();  
     if (!bs) {  
         term_printf("No block device can accept snapshots\n");  
         return;  
     }  
   
     /* ??? Should this occur after vm_stop?  */  
     qemu_aio_flush();  
   
     saved_vm_running = vm_running;  
     vm_stop(0);  
   
     must_delete = 0;  static struct pcmcia_socket_entry_s {
     if (name) {      struct pcmcia_socket_s *socket;
         ret = bdrv_snapshot_find(bs, old_sn, name);      struct pcmcia_socket_entry_s *next;
         if (ret >= 0) {  } *pcmcia_sockets = 0;
             must_delete = 1;  
         }  
     }  
     memset(sn, 0, sizeof(*sn));  
     if (must_delete) {  
         pstrcpy(sn->name, sizeof(sn->name), old_sn->name);  
         pstrcpy(sn->id_str, sizeof(sn->id_str), old_sn->id_str);  
     } else {  
         if (name)  
             pstrcpy(sn->name, sizeof(sn->name), name);  
     }  
   
     /* fill auxiliary fields */  void pcmcia_socket_register(struct pcmcia_socket_s *socket)
 #ifdef _WIN32  {
     _ftime(&tb);      struct pcmcia_socket_entry_s *entry;
     sn->date_sec = tb.time;  
     sn->date_nsec = tb.millitm * 1000000;  
 #else  
     gettimeofday(&tv, NULL);  
     sn->date_sec = tv.tv_sec;  
     sn->date_nsec = tv.tv_usec * 1000;  
 #endif  
     sn->vm_clock_nsec = qemu_get_clock(vm_clock);  
   
     if (bdrv_get_info(bs, bdi) < 0 || bdi->vm_state_offset <= 0) {  
         term_printf("Device %s does not support VM state snapshots\n",  
                     bdrv_get_device_name(bs));  
         goto the_end;  
     }  
   
     /* save the VM state */  
     f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 1);  
     if (!f) {  
         term_printf("Could not open VM state file\n");  
         goto the_end;  
     }  
     ret = qemu_savevm_state(f);  
     sn->vm_state_size = qemu_ftell(f);  
     qemu_fclose(f);  
     if (ret < 0) {  
         term_printf("Error %d while writing VM\n", ret);  
         goto the_end;  
     }  
   
     /* create the snapshots */  
   
     for(i = 0; i < nb_drives; i++) {  
         bs1 = drives_table[i].bdrv;  
         if (bdrv_has_snapshot(bs1)) {  
             if (must_delete) {  
                 ret = bdrv_snapshot_delete(bs1, old_sn->id_str);  
                 if (ret < 0) {  
                     term_printf("Error while deleting snapshot on '%s'\n",  
                                 bdrv_get_device_name(bs1));  
                 }  
             }  
             ret = bdrv_snapshot_create(bs1, sn);  
             if (ret < 0) {  
                 term_printf("Error while creating snapshot on '%s'\n",  
                             bdrv_get_device_name(bs1));  
             }  
         }  
     }  
   
  the_end:      entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s));
     if (saved_vm_running)      entry->socket = socket;
         vm_start();      entry->next = pcmcia_sockets;
       pcmcia_sockets = entry;
 }  }
   
 void do_loadvm(const char *name)  void pcmcia_socket_unregister(struct pcmcia_socket_s *socket)
 {  {
     BlockDriverState *bs, *bs1;      struct pcmcia_socket_entry_s *entry, **ptr;
     BlockDriverInfo bdi1, *bdi = &bdi1;  
     QEMUFile *f;  
     int i, ret;  
     int saved_vm_running;  
   
     bs = get_bs_snapshots();  
     if (!bs) {  
         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();  
   
     saved_vm_running = vm_running;  
     vm_stop(0);  
   
     for(i = 0; i <= nb_drives; i++) {  
         bs1 = drives_table[i].bdrv;  
         if (bdrv_has_snapshot(bs1)) {  
             ret = bdrv_snapshot_goto(bs1, name);  
             if (ret < 0) {  
                 if (bs != bs1)  
                     term_printf("Warning: ");  
                 switch(ret) {  
                 case -ENOTSUP:  
                     term_printf("Snapshots not supported on device '%s'\n",  
                                 bdrv_get_device_name(bs1));  
                     break;  
                 case -ENOENT:  
                     term_printf("Could not find snapshot '%s' on device '%s'\n",  
                                 name, bdrv_get_device_name(bs1));  
                     break;  
                 default:  
                     term_printf("Error %d while activating snapshot on '%s'\n",  
                                 ret, bdrv_get_device_name(bs1));  
                     break;  
                 }  
                 /* fatal on snapshot block device */  
                 if (bs == bs1)  
                     goto the_end;  
             }  
         }  
     }  
   
     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));  
         return;  
     }  
   
     /* restore the VM state */  
     f = qemu_fopen_bdrv(bs, bdi->vm_state_offset, 0);  
     if (!f) {  
         term_printf("Could not open VM state file\n");  
         goto the_end;  
     }  
     ret = qemu_loadvm_state(f);  
     qemu_fclose(f);  
     if (ret < 0) {  
         term_printf("Error %d while loading VM state\n", ret);  
     }  
  the_end:  
     if (saved_vm_running)  
         vm_start();  
 }  
   
 void do_delvm(const char *name)  
 {  
     BlockDriverState *bs, *bs1;  
     int i, ret;  
   
     bs = get_bs_snapshots();  
     if (!bs) {  
         term_printf("No block device supports snapshots\n");  
         return;  
     }  
   
     for(i = 0; i <= nb_drives; i++) {      ptr = &pcmcia_sockets;
         bs1 = drives_table[i].bdrv;      for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr)
         if (bdrv_has_snapshot(bs1)) {          if (entry->socket == socket) {
             ret = bdrv_snapshot_delete(bs1, name);              *ptr = entry->next;
             if (ret < 0) {              qemu_free(entry);
                 if (ret == -ENOTSUP)  
                     term_printf("Snapshots not supported on device '%s'\n",  
                                 bdrv_get_device_name(bs1));  
                 else  
                     term_printf("Error %d while deleting snapshot on '%s'\n",  
                                 ret, bdrv_get_device_name(bs1));  
             }  
         }          }
     }  
 }  }
   
 void do_info_snapshots(void)  void pcmcia_info(void)
 {  {
     BlockDriverState *bs, *bs1;      struct pcmcia_socket_entry_s *iter;
     QEMUSnapshotInfo *sn_tab, *sn;      if (!pcmcia_sockets)
     int nb_sns, i;          term_printf("No PCMCIA sockets\n");
     char buf[256];  
       for (iter = pcmcia_sockets; iter; iter = iter->next)
     bs = get_bs_snapshots();          term_printf("%s: %s\n", iter->socket->slot_string,
     if (!bs) {                      iter->socket->attached ? iter->socket->card_string :
         term_printf("No available block device supports snapshots\n");                      "Empty");
         return;  
     }  
     term_printf("Snapshot devices:");  
     for(i = 0; i <= nb_drives; i++) {  
         bs1 = drives_table[i].bdrv;  
         if (bdrv_has_snapshot(bs1)) {  
             if (bs == bs1)  
                 term_printf(" %s", bdrv_get_device_name(bs1));  
         }  
     }  
     term_printf("\n");  
   
     nb_sns = bdrv_snapshot_list(bs, &sn_tab);  
     if (nb_sns < 0) {  
         term_printf("bdrv_snapshot_list: error %d\n", nb_sns);  
         return;  
     }  
     term_printf("Snapshot list (from %s):\n", bdrv_get_device_name(bs));  
     term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), NULL));  
     for(i = 0; i < nb_sns; i++) {  
         sn = &sn_tab[i];  
         term_printf("%s\n", bdrv_snapshot_dump(buf, sizeof(buf), sn));  
     }  
     qemu_free(sn_tab);  
 }  }
   
 /***********************************************************/  /***********************************************************/
 /* cpu save/restore */  /* register display */
   
 #if defined(TARGET_I386)  
   
 static void cpu_put_seg(QEMUFile *f, SegmentCache *dt)  void register_displaystate(DisplayState *ds)
 {  {
     qemu_put_be32(f, dt->selector);      DisplayState **s;
     qemu_put_betl(f, dt->base);      s = &display_state;
     qemu_put_be32(f, dt->limit);      while (*s != NULL)
     qemu_put_be32(f, dt->flags);          s = &(*s)->next;
       ds->next = NULL;
       *s = ds;
 }  }
   
 static void cpu_get_seg(QEMUFile *f, SegmentCache *dt)  DisplayState *get_displaystate(void)
 {  {
     dt->selector = qemu_get_be32(f);      return display_state;
     dt->base = qemu_get_betl(f);  
     dt->limit = qemu_get_be32(f);  
     dt->flags = qemu_get_be32(f);  
 }  }
   
 void cpu_save(QEMUFile *f, void *opaque)  /* dumb display */
 {  
     CPUState *env = 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;  
     fptag = 0;  
     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);  
   
 #ifdef USE_X86LDOUBLE  static void dumb_display_init(void)
     fpregs_format = 0;  {
 #else      DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
     fpregs_format = 1;      ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4);
 #endif      register_displaystate(ds);
     qemu_put_be16s(f, &fpregs_format);  }
   
     for(i = 0; i < 8; i++) {  /***********************************************************/
 #ifdef USE_X86LDOUBLE  /* I/O handling */
         {  
             uint64_t mant;  
             uint16_t exp;  
             /* we save the real CPU data (in case of MMX usage only 'mant'  
                contains the MMX register */  
             cpu_get_fp80(&mant, &exp, env->fpregs[i].d);  
             qemu_put_be64(f, mant);  
             qemu_put_be16(f, exp);  
         }  
 #else  
         /* if we use doubles for float emulation, we save the doubles to  
            avoid losing information in case of MMX usage. It can give  
            problems if the image is restored on a CPU where long  
            doubles are used instead. */  
         qemu_put_be64(f, env->fpregs[i].mmx.MMX_Q(0));  
 #endif  
     }  
   
     for(i = 0; i < 6; i++)  #define MAX_IO_HANDLERS 64
         cpu_put_seg(f, &env->segs[i]);  
     cpu_put_seg(f, &env->ldt);  
     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]);  
   
     /* MMU */  
     qemu_put_be32s(f, &env->a20_mask);  
   
     /* XMM */  
     qemu_put_be32s(f, &env->mxcsr);  
     for(i = 0; i < CPU_NB_REGS; i++) {  
         qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(0));  
         qemu_put_be64s(f, &env->xmm_regs[i].XMM_Q(1));  
     }  
   
 #ifdef TARGET_X86_64  
     qemu_put_be64s(f, &env->efer);  
     qemu_put_be64s(f, &env->star);  
     qemu_put_be64s(f, &env->lstar);  
     qemu_put_be64s(f, &env->cstar);  
     qemu_put_be64s(f, &env->fmask);  
     qemu_put_be64s(f, &env->kernelgsbase);  
 #endif  
     qemu_put_be32s(f, &env->smbase);  
 }  
   
 #ifdef USE_X86LDOUBLE  
 /* XXX: add that in a FPU generic layer */  
 union x86_longdouble {  
     uint64_t mant;  
     uint16_t exp;  
 };  
   
 #define MANTD1(fp)      (fp & ((1LL << 52) - 1))  typedef struct IOHandlerRecord {
 #define EXPBIAS1 1023      int fd;
 #define EXPD1(fp)       ((fp >> 52) & 0x7FF)      IOCanRWHandler *fd_read_poll;
 #define SIGND1(fp)      ((fp >> 32) & 0x80000000)      IOHandler *fd_read;
       IOHandler *fd_write;
       int deleted;
       void *opaque;
       /* temporary data */
       struct pollfd *ufd;
       struct IOHandlerRecord *next;
   } IOHandlerRecord;
   
 static void fp64_to_fp80(union x86_longdouble *p, uint64_t temp)  static IOHandlerRecord *first_io_handler;
 {  
     int e;  
     /* mantissa */  
     p->mant = (MANTD1(temp) << 11) | (1LL << 63);  
     /* exponent + sign */  
     e = EXPD1(temp) - EXPBIAS1 + 16383;  
     e |= SIGND1(temp) >> 16;  
     p->exp = e;  
 }  
 #endif  
   
 int cpu_load(QEMUFile *f, void *opaque, int version_id)  /* 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,
                            void *opaque)
 {  {
     CPUState *env = opaque;      IOHandlerRecord **pioh, *ioh;
     int i, guess_mmx;  
     uint32_t hflags;  
     uint16_t fpus, fpuc, fptag, fpregs_format;  
   
     if (version_id != 3 && version_id != 4)      if (!fd_read && !fd_write) {
         return -EINVAL;          pioh = &first_io_handler;
     for(i = 0; i < CPU_NB_REGS; i++)          for(;;) {
         qemu_get_betls(f, &env->regs[i]);              ioh = *pioh;
     qemu_get_betls(f, &env->eip);              if (ioh == NULL)
     qemu_get_betls(f, &env->eflags);                  break;
     qemu_get_be32s(f, &hflags);              if (ioh->fd == fd) {
                   ioh->deleted = 1;
     qemu_get_be16s(f, &fpuc);                  break;
     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. */  
     guess_mmx = ((fptag == 0xff) && (fpus & 0x3800) == 0);  
     for(i = 0; i < 8; i++) {  
         uint64_t mant;  
         uint16_t exp;  
   
         switch(fpregs_format) {  
         case 0:  
             mant = qemu_get_be64(f);  
             exp = qemu_get_be16(f);  
 #ifdef USE_X86LDOUBLE  
             env->fpregs[i].d = cpu_set_fp80(mant, exp);  
 #else  
             /* difficult case */  
             if (guess_mmx)  
                 env->fpregs[i].mmx.MMX_Q(0) = mant;  
             else  
                 env->fpregs[i].d = cpu_set_fp80(mant, exp);  
 #endif  
             break;  
         case 1:  
             mant = qemu_get_be64(f);  
 #ifdef USE_X86LDOUBLE  
             {  
                 union x86_longdouble *p;  
                 /* difficult case */  
                 p = (void *)&env->fpregs[i];  
                 if (guess_mmx) {  
                     p->mant = mant;  
                     p->exp = 0xffff;  
                 } else {  
                     fp64_to_fp80(p, mant);  
                 }  
             }              }
 #else              pioh = &ioh->next;
             env->fpregs[i].mmx.MMX_Q(0) = mant;          }
 #endif      } else {
             break;          for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
         default:              if (ioh->fd == fd)
             return -EINVAL;                  goto found;
         }          }
           ioh = qemu_mallocz(sizeof(IOHandlerRecord));
           ioh->next = first_io_handler;
           first_io_handler = ioh;
       found:
           ioh->fd = fd;
           ioh->fd_read_poll = fd_read_poll;
           ioh->fd_read = fd_read;
           ioh->fd_write = fd_write;
           ioh->opaque = opaque;
           ioh->deleted = 0;
     }      }
   
     env->fpuc = fpuc;  
     /* XXX: restore FPU round state */  
     env->fpstt = (fpus >> 11) & 7;  
     env->fpus = fpus & ~0x3800;  
     fptag ^= 0xff;  
     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]);  
   
     /* MMU */  
     qemu_get_be32s(f, &env->a20_mask);  
   
     qemu_get_be32s(f, &env->mxcsr);  
     for(i = 0; i < CPU_NB_REGS; i++) {  
         qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(0));  
         qemu_get_be64s(f, &env->xmm_regs[i].XMM_Q(1));  
     }  
   
 #ifdef TARGET_X86_64  
     qemu_get_be64s(f, &env->efer);  
     qemu_get_be64s(f, &env->star);  
     qemu_get_be64s(f, &env->lstar);  
     qemu_get_be64s(f, &env->cstar);  
     qemu_get_be64s(f, &env->fmask);  
     qemu_get_be64s(f, &env->kernelgsbase);  
 #endif  
     if (version_id >= 4)  
         qemu_get_be32s(f, &env->smbase);  
   
     /* XXX: compute hflags from scratch, except for CPL and IIF */  
     env->hflags = hflags;  
     tlb_flush(env, 1);  
     return 0;  
 }  
   
 #elif defined(TARGET_PPC)  
 void cpu_save(QEMUFile *f, void *opaque)  
 {  
 }  
   
 int cpu_load(QEMUFile *f, void *opaque, int version_id)  
 {  
     return 0;      return 0;
 }  }
   
 #elif defined(TARGET_MIPS)  int qemu_set_fd_handler(int fd,
 void cpu_save(QEMUFile *f, void *opaque)                          IOHandler *fd_read,
                           IOHandler *fd_write,
                           void *opaque)
 {  {
       return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque);
 }  }
   
 int cpu_load(QEMUFile *f, void *opaque, int version_id)  #ifdef _WIN32
 {  /***********************************************************/
     return 0;  /* Polling handling */
 }  
   
 #elif defined(TARGET_SPARC)  typedef struct PollingEntry {
 void cpu_save(QEMUFile *f, void *opaque)      PollingFunc *func;
 {      void *opaque;
     CPUState *env = opaque;      struct PollingEntry *next;
     int i;  } PollingEntry;
     uint32_t tmp;  
   
     for(i = 0; i < 8; i++)  static PollingEntry *first_polling_entry;
         qemu_put_betls(f, &env->gregs[i]);  
     for(i = 0; i < NWINDOWS * 16; i++)  
         qemu_put_betls(f, &env->regbase[i]);  
   
     /* FPU */  
     for(i = 0; i < TARGET_FPREGS; i++) {  
         union {  
             float32 f;  
             uint32_t i;  
         } u;  
         u.f = env->fpr[i];  
         qemu_put_be32(f, u.i);  
     }  
   
     qemu_put_betls(f, &env->pc);  
     qemu_put_betls(f, &env->npc);  
     qemu_put_betls(f, &env->y);  
     tmp = GET_PSR(env);  
     qemu_put_be32(f, tmp);  
     qemu_put_betls(f, &env->fsr);  
     qemu_put_betls(f, &env->tbr);  
 #ifndef TARGET_SPARC64  
     qemu_put_be32s(f, &env->wim);  
     /* MMU */  
     for(i = 0; i < 16; i++)  
         qemu_put_be32s(f, &env->mmuregs[i]);  
 #endif  
 }  
   
 int cpu_load(QEMUFile *f, void *opaque, int version_id)  int qemu_add_polling_cb(PollingFunc *func, void *opaque)
 {  {
     CPUState *env = opaque;      PollingEntry **ppe, *pe;
     int i;      pe = qemu_mallocz(sizeof(PollingEntry));
     uint32_t tmp;      pe->func = func;
       pe->opaque = opaque;
     for(i = 0; i < 8; i++)      for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next);
         qemu_get_betls(f, &env->gregs[i]);      *ppe = pe;
     for(i = 0; i < NWINDOWS * 16; i++)  
         qemu_get_betls(f, &env->regbase[i]);  
   
     /* FPU */  
     for(i = 0; i < TARGET_FPREGS; i++) {  
         union {  
             float32 f;  
             uint32_t i;  
         } u;  
         u.i = qemu_get_be32(f);  
         env->fpr[i] = u.f;  
     }  
   
     qemu_get_betls(f, &env->pc);  
     qemu_get_betls(f, &env->npc);  
     qemu_get_betls(f, &env->y);  
     tmp = qemu_get_be32(f);  
     env->cwp = 0; /* needed to ensure that the wrapping registers are  
                      correctly updated */  
     PUT_PSR(env, tmp);  
     qemu_get_betls(f, &env->fsr);  
     qemu_get_betls(f, &env->tbr);  
 #ifndef TARGET_SPARC64  
     qemu_get_be32s(f, &env->wim);  
     /* MMU */  
     for(i = 0; i < 16; i++)  
         qemu_get_be32s(f, &env->mmuregs[i]);  
 #endif  
     tlb_flush(env, 1);  
     return 0;      return 0;
 }  }
   
 #elif defined(TARGET_ARM)  void qemu_del_polling_cb(PollingFunc *func, void *opaque)
   
 void cpu_save(QEMUFile *f, void *opaque)  
 {  {
     int i;      PollingEntry **ppe, *pe;
     CPUARMState *env = (CPUARMState *)opaque;      for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) {
           pe = *ppe;
     for (i = 0; i < 16; i++) {          if (pe->func == func && pe->opaque == opaque) {
         qemu_put_be32(f, env->regs[i]);              *ppe = pe->next;
     }              qemu_free(pe);
     qemu_put_be32(f, cpsr_read(env));              break;
     qemu_put_be32(f, env->spsr);  
     for (i = 0; i < 6; i++) {  
         qemu_put_be32(f, env->banked_spsr[i]);  
         qemu_put_be32(f, env->banked_r13[i]);  
         qemu_put_be32(f, env->banked_r14[i]);  
     }  
     for (i = 0; i < 5; i++) {  
         qemu_put_be32(f, env->usr_regs[i]);  
         qemu_put_be32(f, env->fiq_regs[i]);  
     }  
     qemu_put_be32(f, env->cp15.c0_cpuid);  
     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.c1_xscaleauxcr);  
     qemu_put_be32(f, env->cp15.c2_base0);  
     qemu_put_be32(f, env->cp15.c2_base1);  
     qemu_put_be32(f, env->cp15.c2_mask);  
     qemu_put_be32(f, env->cp15.c2_data);  
     qemu_put_be32(f, env->cp15.c2_insn);  
     qemu_put_be32(f, env->cp15.c3);  
     qemu_put_be32(f, env->cp15.c5_insn);  
     qemu_put_be32(f, env->cp15.c5_data);  
     for (i = 0; i < 8; i++) {  
         qemu_put_be32(f, env->cp15.c6_region[i]);  
     }  
     qemu_put_be32(f, env->cp15.c6_insn);  
     qemu_put_be32(f, env->cp15.c6_data);  
     qemu_put_be32(f, env->cp15.c9_insn);  
     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);  
   
     if (arm_feature(env, ARM_FEATURE_VFP)) {  
         for (i = 0;  i < 16; i++) {  
             CPU_DoubleU u;  
             u.d = env->vfp.regs[i];  
             qemu_put_be32(f, u.l.upper);  
             qemu_put_be32(f, u.l.lower);  
         }  
         for (i = 0; i < 16; i++) {  
             qemu_put_be32(f, env->vfp.xregs[i]);  
         }  
   
         /* 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)) {  /***********************************************************/
         for (i = 0; i < 16; i++) {  /* Wait objects support */
             qemu_put_be64(f, env->iwmmxt.regs[i]);  typedef struct WaitObjects {
         }      int num;
         for (i = 0; i < 16; i++) {      HANDLE events[MAXIMUM_WAIT_OBJECTS + 1];
             qemu_put_be32(f, env->iwmmxt.cregs[i]);      WaitObjectFunc *func[MAXIMUM_WAIT_OBJECTS + 1];
         }      void *opaque[MAXIMUM_WAIT_OBJECTS + 1];
     }  } WaitObjects;
   
     if (arm_feature(env, ARM_FEATURE_M)) {  static WaitObjects wait_objects = {0};
         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)  int qemu_add_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
 {  {
     CPUARMState *env = (CPUARMState *)opaque;      WaitObjects *w = &wait_objects;
     int i;  
   
     if (version_id != ARM_CPU_SAVE_VERSION)      if (w->num >= MAXIMUM_WAIT_OBJECTS)
         return -EINVAL;          return -1;
       w->events[w->num] = handle;
       w->func[w->num] = func;
       w->opaque[w->num] = opaque;
       w->num++;
       return 0;
   }
   
     for (i = 0; i < 16; i++) {  void qemu_del_wait_object(HANDLE handle, WaitObjectFunc *func, void *opaque)
         env->regs[i] = qemu_get_be32(f);  {
     }      int i, found;
     cpsr_write(env, qemu_get_be32(f), 0xffffffff);      WaitObjects *w = &wait_objects;
     env->spsr = qemu_get_be32(f);  
     for (i = 0; i < 6; i++) {  
         env->banked_spsr[i] = qemu_get_be32(f);  
         env->banked_r13[i] = qemu_get_be32(f);  
         env->banked_r14[i] = qemu_get_be32(f);  
     }  
     for (i = 0; i < 5; i++) {  
         env->usr_regs[i] = qemu_get_be32(f);  
         env->fiq_regs[i] = qemu_get_be32(f);  
     }  
     env->cp15.c0_cpuid = qemu_get_be32(f);  
     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.c1_xscaleauxcr = qemu_get_be32(f);  
     env->cp15.c2_base0 = qemu_get_be32(f);  
     env->cp15.c2_base1 = qemu_get_be32(f);  
     env->cp15.c2_mask = qemu_get_be32(f);  
     env->cp15.c2_data = qemu_get_be32(f);  
     env->cp15.c2_insn = qemu_get_be32(f);  
     env->cp15.c3 = qemu_get_be32(f);  
     env->cp15.c5_insn = qemu_get_be32(f);  
     env->cp15.c5_data = qemu_get_be32(f);  
     for (i = 0; i < 8; i++) {  
         env->cp15.c6_region[i] = qemu_get_be32(f);  
     }  
     env->cp15.c6_insn = qemu_get_be32(f);  
     env->cp15.c6_data = qemu_get_be32(f);  
     env->cp15.c9_insn = qemu_get_be32(f);  
     env->cp15.c9_data = qemu_get_be32(f);  
     env->cp15.c13_fcse = qemu_get_be32(f);  
     env->cp15.c13_context = qemu_get_be32(f);  
     env->cp15.c13_tls1 = qemu_get_be32(f);  
     env->cp15.c13_tls2 = qemu_get_be32(f);  
     env->cp15.c13_tls3 = qemu_get_be32(f);  
     env->cp15.c15_cpar = qemu_get_be32(f);  
   
     env->features = qemu_get_be32(f);  
   
     if (arm_feature(env, ARM_FEATURE_VFP)) {  
         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;  
         }  
         for (i = 0; i < 16; i++) {  
             env->vfp.xregs[i] = qemu_get_be32(f);  
         }  
   
         /* TODO: Should use proper FPSCR access functions.  */  
         env->vfp.vec_len = qemu_get_be32(f);  
         env->vfp.vec_stride = qemu_get_be32(f);  
   
         if (arm_feature(env, ARM_FEATURE_VFP3)) {  
             for (i = 0;  i < 16; i++) {  
                 CPU_DoubleU u;  
                 u.l.upper = qemu_get_be32(f);  
                 u.l.lower = qemu_get_be32(f);  
                 env->vfp.regs[i] = u.d;  
             }  
         }  
     }  
   
     if (arm_feature(env, ARM_FEATURE_IWMMXT)) {      found = 0;
         for (i = 0; i < 16; i++) {      for (i = 0; i < w->num; i++) {
             env->iwmmxt.regs[i] = qemu_get_be64(f);          if (w->events[i] == handle)
         }              found = 1;
         for (i = 0; i < 16; i++) {          if (found) {
             env->iwmmxt.cregs[i] = qemu_get_be32(f);              w->events[i] = w->events[i + 1];
               w->func[i] = w->func[i + 1];
               w->opaque[i] = w->opaque[i + 1];
         }          }
     }      }
       if (found)
     if (arm_feature(env, ARM_FEATURE_M)) {          w->num--;
         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  
   
 #endif  #endif
   
 /***********************************************************/  /***********************************************************/
Line 6776  static int ram_get_page(QEMUFile *f, uin Line 3035  static int ram_get_page(QEMUFile *f, uin
     default:      default:
         return -EINVAL;          return -EINVAL;
     }      }
   
       if (qemu_file_has_error(f))
           return -EIO;
   
     return 0;      return 0;
 }  }
   
 static int ram_load_v1(QEMUFile *f, void *opaque)  static int ram_load_v1(QEMUFile *f, void *opaque)
 {  {
     int i, ret;      int ret;
       ram_addr_t i;
   
     if (qemu_get_be32(f) != phys_ram_size)      if (qemu_get_be32(f) != phys_ram_size)
         return -EINVAL;          return -EINVAL;
Line 6797  static int ram_load_v1(QEMUFile *f, void Line 3061  static int ram_load_v1(QEMUFile *f, void
 #define IOBUF_SIZE 4096  #define IOBUF_SIZE 4096
 #define RAM_CBLOCK_MAGIC 0xfabe  #define RAM_CBLOCK_MAGIC 0xfabe
   
 typedef struct RamCompressState {  
     z_stream zstream;  
     QEMUFile *f;  
     uint8_t buf[IOBUF_SIZE];  
 } RamCompressState;  
   
 static int ram_compress_open(RamCompressState *s, QEMUFile *f)  
 {  
     int ret;  
     memset(s, 0, sizeof(*s));  
     s->f = f;  
     ret = deflateInit2(&s->zstream, 1,  
                        Z_DEFLATED, 15,  
                        9, Z_DEFAULT_STRATEGY);  
     if (ret != Z_OK)  
         return -1;  
     s->zstream.avail_out = IOBUF_SIZE;  
     s->zstream.next_out = s->buf;  
     return 0;  
 }  
   
 static void ram_put_cblock(RamCompressState *s, const uint8_t *buf, int len)  
 {  
     qemu_put_be16(s->f, RAM_CBLOCK_MAGIC);  
     qemu_put_be16(s->f, len);  
     qemu_put_buffer(s->f, buf, len);  
 }  
   
 static int ram_compress_buf(RamCompressState *s, const uint8_t *buf, int len)  
 {  
     int ret;  
   
     s->zstream.avail_in = len;  
     s->zstream.next_in = (uint8_t *)buf;  
     while (s->zstream.avail_in > 0) {  
         ret = deflate(&s->zstream, Z_NO_FLUSH);  
         if (ret != Z_OK)  
             return -1;  
         if (s->zstream.avail_out == 0) {  
             ram_put_cblock(s, s->buf, IOBUF_SIZE);  
             s->zstream.avail_out = IOBUF_SIZE;  
             s->zstream.next_out = s->buf;  
         }  
     }  
     return 0;  
 }  
   
 static void ram_compress_close(RamCompressState *s)  
 {  
     int len, ret;  
   
     /* compress last bytes */  
     for(;;) {  
         ret = deflate(&s->zstream, Z_FINISH);  
         if (ret == Z_OK || ret == Z_STREAM_END) {  
             len = IOBUF_SIZE - s->zstream.avail_out;  
             if (len > 0) {  
                 ram_put_cblock(s, s->buf, len);  
             }  
             s->zstream.avail_out = IOBUF_SIZE;  
             s->zstream.next_out = s->buf;  
             if (ret == Z_STREAM_END)  
                 break;  
         } else {  
             goto fail;  
         }  
     }  
 fail:  
     deflateEnd(&s->zstream);  
 }  
   
 typedef struct RamDecompressState {  typedef struct RamDecompressState {
     z_stream zstream;      z_stream zstream;
     QEMUFile *f;      QEMUFile *f;
Line 6915  static void ram_decompress_close(RamDeco Line 3108  static void ram_decompress_close(RamDeco
     inflateEnd(&s->zstream);      inflateEnd(&s->zstream);
 }  }
   
 static void ram_save(QEMUFile *f, void *opaque)  #define RAM_SAVE_FLAG_FULL      0x01
   #define RAM_SAVE_FLAG_COMPRESS  0x02
   #define RAM_SAVE_FLAG_MEM_SIZE  0x04
   #define RAM_SAVE_FLAG_PAGE      0x08
   #define RAM_SAVE_FLAG_EOS       0x10
   
   static int is_dup_page(uint8_t *page, uint8_t ch)
 {  {
       uint32_t val = ch << 24 | ch << 16 | ch << 8 | ch;
       uint32_t *array = (uint32_t *)page;
     int i;      int i;
     RamCompressState s1, *s = &s1;  
     uint8_t buf[10];  
   
     qemu_put_be32(f, phys_ram_size);      for (i = 0; i < (TARGET_PAGE_SIZE / 4); i++) {
     if (ram_compress_open(s, f) < 0)          if (array[i] != val)
         return;              return 0;
     for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) {      }
 #if 0  
         if (tight_savevm_enabled) {      return 1;
             int64_t sector_num;  }
             int j;  
   static int ram_save_block(QEMUFile *f)
             /* find if the memory block is available on a virtual  {
                block device */      static ram_addr_t current_addr = 0;
             sector_num = -1;      ram_addr_t saved_addr = current_addr;
             for(j = 0; j < nb_drives; j++) {      ram_addr_t addr = 0;
                 sector_num = bdrv_hash_find(drives_table[j].bdrv,      int found = 0;
                                             phys_ram_base + i,  
                                             BDRV_HASH_BLOCK_SIZE);      while (addr < phys_ram_size) {
                 if (sector_num >= 0)          if (cpu_physical_memory_get_dirty(current_addr, MIGRATION_DIRTY_FLAG)) {
                     break;              uint8_t ch;
   
               cpu_physical_memory_reset_dirty(current_addr,
                                               current_addr + TARGET_PAGE_SIZE,
                                               MIGRATION_DIRTY_FLAG);
   
               ch = *(phys_ram_base + current_addr);
   
               if (is_dup_page(phys_ram_base + current_addr, ch)) {
                   qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_COMPRESS);
                   qemu_put_byte(f, ch);
               } else {
                   qemu_put_be64(f, current_addr | RAM_SAVE_FLAG_PAGE);
                   qemu_put_buffer(f, phys_ram_base + current_addr, TARGET_PAGE_SIZE);
             }              }
             if (j == nb_drives)  
                 goto normal_compress;              found = 1;
             buf[0] = 1;              break;
             buf[1] = j;  
             cpu_to_be64wu((uint64_t *)(buf + 2), sector_num);  
             ram_compress_buf(s, buf, 10);  
         } else  
 #endif  
         {  
             //        normal_compress:  
             buf[0] = 0;  
             ram_compress_buf(s, buf, 1);  
             ram_compress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE);  
         }          }
           addr += TARGET_PAGE_SIZE;
           current_addr = (saved_addr + addr) % phys_ram_size;
     }      }
     ram_compress_close(s);  
       return found;
 }  }
   
 static int ram_load(QEMUFile *f, void *opaque, int version_id)  static ram_addr_t ram_save_threshold = 10;
   
   static ram_addr_t ram_save_remaining(void)
   {
       ram_addr_t addr;
       ram_addr_t count = 0;
   
       for (addr = 0; addr < phys_ram_size; addr += TARGET_PAGE_SIZE) {
           if (cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG))
               count++;
       }
   
       return count;
   }
   
   static int ram_save_live(QEMUFile *f, int stage, void *opaque)
   {
       ram_addr_t addr;
   
       if (stage == 1) {
           /* Make sure all dirty bits are set */
           for (addr = 0; addr < phys_ram_size; addr += TARGET_PAGE_SIZE) {
               if (!cpu_physical_memory_get_dirty(addr, MIGRATION_DIRTY_FLAG))
                   cpu_physical_memory_set_dirty(addr);
           }
           
           /* Enable dirty memory tracking */
           cpu_physical_memory_set_dirty_tracking(1);
   
           qemu_put_be64(f, phys_ram_size | RAM_SAVE_FLAG_MEM_SIZE);
       }
   
       while (!qemu_file_rate_limit(f)) {
           int ret;
   
           ret = ram_save_block(f);
           if (ret == 0) /* no more blocks */
               break;
       }
   
       /* try transferring iterative blocks of memory */
   
       if (stage == 3) {
           cpu_physical_memory_set_dirty_tracking(0);
   
           /* flush all remaining blocks regardless of rate limiting */
           while (ram_save_block(f) != 0);
       }
   
       qemu_put_be64(f, RAM_SAVE_FLAG_EOS);
   
       return (stage == 2) && (ram_save_remaining() < ram_save_threshold);
   }
   
   static int ram_load_dead(QEMUFile *f, void *opaque)
 {  {
     RamDecompressState s1, *s = &s1;      RamDecompressState s1, *s = &s1;
     uint8_t buf[10];      uint8_t buf[10];
     int i;      ram_addr_t i;
   
     if (version_id == 1)  
         return ram_load_v1(f, opaque);  
     if (version_id != 2)  
         return -EINVAL;  
     if (qemu_get_be32(f) != phys_ram_size)  
         return -EINVAL;  
     if (ram_decompress_open(s, f) < 0)      if (ram_decompress_open(s, f) < 0)
         return -EINVAL;          return -EINVAL;
     for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) {      for(i = 0; i < phys_ram_size; i+= BDRV_HASH_BLOCK_SIZE) {
Line 6979  static int ram_load(QEMUFile *f, void *o Line 3232  static int ram_load(QEMUFile *f, void *o
         }          }
         if (buf[0] == 0) {          if (buf[0] == 0) {
             if (ram_decompress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE) < 0) {              if (ram_decompress_buf(s, phys_ram_base + i, BDRV_HASH_BLOCK_SIZE) < 0) {
                 fprintf(stderr, "Error while reading ram block address=0x%08x", i);                  fprintf(stderr, "Error while reading ram block address=0x%08" PRIx64, (uint64_t)i);
                 goto error;                  goto error;
             }              }
         } else          } else {
 #if 0  
         if (buf[0] == 1) {  
             int bs_index;  
             int64_t sector_num;  
   
             ram_decompress_buf(s, buf + 1, 9);  
             bs_index = buf[1];  
             sector_num = be64_to_cpupu((const uint64_t *)(buf + 2));  
             if (bs_index >= nb_drives) {  
                 fprintf(stderr, "Invalid block device index %d\n", bs_index);  
                 goto error;  
             }  
             if (bdrv_read(drives_table[bs_index].bdrv, sector_num,  
                           phys_ram_base + i,  
                           BDRV_HASH_BLOCK_SIZE / 512) < 0) {  
                 fprintf(stderr, "Error while reading sector %d:%" PRId64 "\n",  
                         bs_index, sector_num);  
                 goto error;  
             }  
         } else  
 #endif  
         {  
         error:          error:
             printf("Error block header\n");              printf("Error block header\n");
             return -EINVAL;              return -EINVAL;
         }          }
     }      }
     ram_decompress_close(s);      ram_decompress_close(s);
   
       return 0;
   }
   
   static int ram_load(QEMUFile *f, void *opaque, int version_id)
   {
       ram_addr_t addr;
       int flags;
   
       if (version_id == 1)
           return ram_load_v1(f, opaque);
   
       if (version_id == 2) {
           if (qemu_get_be32(f) != phys_ram_size)
               return -EINVAL;
           return ram_load_dead(f, opaque);
       }
   
       if (version_id != 3)
           return -EINVAL;
   
       do {
           addr = qemu_get_be64(f);
   
           flags = addr & ~TARGET_PAGE_MASK;
           addr &= TARGET_PAGE_MASK;
   
           if (flags & RAM_SAVE_FLAG_MEM_SIZE) {
               if (addr != phys_ram_size)
                   return -EINVAL;
           }
   
           if (flags & RAM_SAVE_FLAG_FULL) {
               if (ram_load_dead(f, opaque) < 0)
                   return -EINVAL;
           }
           
           if (flags & RAM_SAVE_FLAG_COMPRESS) {
               uint8_t ch = qemu_get_byte(f);
               memset(phys_ram_base + addr, ch, TARGET_PAGE_SIZE);
           } else if (flags & RAM_SAVE_FLAG_PAGE)
               qemu_get_buffer(f, phys_ram_base + addr, TARGET_PAGE_SIZE);
       } while (!(flags & RAM_SAVE_FLAG_EOS));
   
     return 0;      return 0;
 }  }
   
   void qemu_service_io(void)
   {
       CPUState *env = cpu_single_env;
       if (env) {
           cpu_interrupt(env, CPU_INTERRUPT_EXIT);
   #ifdef USE_KQEMU
           if (env->kqemu_enabled) {
               kqemu_cpu_interrupt(env);
           }
   #endif
       }
   }
   
 /***********************************************************/  /***********************************************************/
 /* bottom halves (can be seen as timers which expire ASAP) */  /* bottom halves (can be seen as timers which expire ASAP) */
   
Line 7021  struct QEMUBH { Line 3309  struct QEMUBH {
     QEMUBHFunc *cb;      QEMUBHFunc *cb;
     void *opaque;      void *opaque;
     int scheduled;      int scheduled;
       int idle;
       int deleted;
     QEMUBH *next;      QEMUBH *next;
 };  };
   
Line 7030  QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void Line 3320  QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void
 {  {
     QEMUBH *bh;      QEMUBH *bh;
     bh = qemu_mallocz(sizeof(QEMUBH));      bh = qemu_mallocz(sizeof(QEMUBH));
     if (!bh)  
         return NULL;  
     bh->cb = cb;      bh->cb = cb;
     bh->opaque = opaque;      bh->opaque = opaque;
       bh->next = first_bh;
       first_bh = bh;
     return bh;      return bh;
 }  }
   
 int qemu_bh_poll(void)  int qemu_bh_poll(void)
 {  {
     QEMUBH *bh, **pbh;      QEMUBH *bh, **bhp;
     int ret;      int ret;
   
     ret = 0;      ret = 0;
     for(;;) {      for (bh = first_bh; bh; bh = bh->next) {
         pbh = &first_bh;          if (!bh->deleted && bh->scheduled) {
         bh = *pbh;              bh->scheduled = 0;
         if (!bh)              if (!bh->idle)
             break;                  ret = 1;
         ret = 1;              bh->idle = 0;
         *pbh = bh->next;              bh->cb(bh->opaque);
         bh->scheduled = 0;          }
         bh->cb(bh->opaque);      }
   
       /* remove deleted bhs */
       bhp = &first_bh;
       while (*bhp) {
           bh = *bhp;
           if (bh->deleted) {
               *bhp = bh->next;
               qemu_free(bh);
           } else
               bhp = &bh->next;
     }      }
   
     return ret;      return ret;
 }  }
   
   void qemu_bh_schedule_idle(QEMUBH *bh)
   {
       if (bh->scheduled)
           return;
       bh->scheduled = 1;
       bh->idle = 1;
   }
   
 void qemu_bh_schedule(QEMUBH *bh)  void qemu_bh_schedule(QEMUBH *bh)
 {  {
     CPUState *env = cpu_single_env;      CPUState *env = cpu_single_env;
     if (bh->scheduled)      if (bh->scheduled)
         return;          return;
     bh->scheduled = 1;      bh->scheduled = 1;
     bh->next = first_bh;      bh->idle = 0;
     first_bh = bh;  
   
     /* stop the currently executing CPU to execute the BH ASAP */      /* stop the currently executing CPU to execute the BH ASAP */
     if (env) {      if (env) {
         cpu_interrupt(env, CPU_INTERRUPT_EXIT);          cpu_interrupt(env, CPU_INTERRUPT_EXIT);
Line 7073  void qemu_bh_schedule(QEMUBH *bh) Line 3380  void qemu_bh_schedule(QEMUBH *bh)
   
 void qemu_bh_cancel(QEMUBH *bh)  void qemu_bh_cancel(QEMUBH *bh)
 {  {
     QEMUBH **pbh;      bh->scheduled = 0;
     if (bh->scheduled) {  
         pbh = &first_bh;  
         while (*pbh != bh)  
             pbh = &(*pbh)->next;  
         *pbh = bh->next;  
         bh->scheduled = 0;  
     }  
 }  }
   
 void qemu_bh_delete(QEMUBH *bh)  void qemu_bh_delete(QEMUBH *bh)
 {  {
     qemu_bh_cancel(bh);      bh->scheduled = 0;
     qemu_free(bh);      bh->deleted = 1;
   }
   
   static void qemu_bh_update_timeout(int *timeout)
   {
       QEMUBH *bh;
   
       for (bh = first_bh; bh; bh = bh->next) {
           if (!bh->deleted && bh->scheduled) {
               if (bh->idle) {
                   /* idle bottom halves will be polled at least
                    * every 10ms */
                   *timeout = MIN(10, *timeout);
               } else {
                   /* non-idle bottom halves will be executed
                    * immediately */
                   *timeout = 0;
                   break;
               }
           }
       }
 }  }
   
 /***********************************************************/  /***********************************************************/
 /* machine registration */  /* machine registration */
   
 QEMUMachine *first_machine = NULL;  static QEMUMachine *first_machine = NULL;
   QEMUMachine *current_machine = NULL;
   
 int qemu_register_machine(QEMUMachine *m)  int qemu_register_machine(QEMUMachine *m)
 {  {
Line 7121  static QEMUMachine *find_machine(const c Line 3442  static QEMUMachine *find_machine(const c
   
 static void gui_update(void *opaque)  static void gui_update(void *opaque)
 {  {
       uint64_t interval = GUI_REFRESH_INTERVAL;
     DisplayState *ds = opaque;      DisplayState *ds = opaque;
     ds->dpy_refresh(ds);      DisplayChangeListener *dcl = ds->listeners;
     qemu_mod_timer(ds->gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock));  
       dpy_refresh(ds);
   
       while (dcl != NULL) {
           if (dcl->gui_timer_interval &&
               dcl->gui_timer_interval < interval)
               interval = dcl->gui_timer_interval;
           dcl = dcl->next;
       }
       qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock(rt_clock));
   }
   
   static void nographic_update(void *opaque)
   {
       uint64_t interval = GUI_REFRESH_INTERVAL;
   
       qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock));
 }  }
   
 struct vm_change_state_entry {  struct vm_change_state_entry {
Line 7140  VMChangeStateEntry *qemu_add_vm_change_s Line 3478  VMChangeStateEntry *qemu_add_vm_change_s
     VMChangeStateEntry *e;      VMChangeStateEntry *e;
   
     e = qemu_mallocz(sizeof (*e));      e = qemu_mallocz(sizeof (*e));
     if (!e)  
         return NULL;  
   
     e->cb = cb;      e->cb = cb;
     e->opaque = opaque;      e->opaque = opaque;
Line 7155  void qemu_del_vm_change_state_handler(VM Line 3491  void qemu_del_vm_change_state_handler(VM
     qemu_free (e);      qemu_free (e);
 }  }
   
 static void vm_state_notify(int running)  static void vm_state_notify(int running, int reason)
 {  {
     VMChangeStateEntry *e;      VMChangeStateEntry *e;
   
     for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {      for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) {
         e->cb(e->opaque, running);          e->cb(e->opaque, running, reason);
     }      }
 }  }
   
 /* XXX: support several handlers */  
 static VMStopHandler *vm_stop_cb;  
 static void *vm_stop_opaque;  
   
 int qemu_add_vm_stop_handler(VMStopHandler *cb, void *opaque)  
 {  
     vm_stop_cb = cb;  
     vm_stop_opaque = opaque;  
     return 0;  
 }  
   
 void qemu_del_vm_stop_handler(VMStopHandler *cb, void *opaque)  
 {  
     vm_stop_cb = NULL;  
 }  
   
 void vm_start(void)  void vm_start(void)
 {  {
     if (!vm_running) {      if (!vm_running) {
         cpu_enable_ticks();          cpu_enable_ticks();
         vm_running = 1;          vm_running = 1;
         vm_state_notify(1);          vm_state_notify(1, 0);
         qemu_rearm_alarm_timer(alarm_timer);          qemu_rearm_alarm_timer(alarm_timer);
     }      }
 }  }
Line 7195  void vm_stop(int reason) Line 3515  void vm_stop(int reason)
     if (vm_running) {      if (vm_running) {
         cpu_disable_ticks();          cpu_disable_ticks();
         vm_running = 0;          vm_running = 0;
         if (reason != 0) {          vm_state_notify(0, reason);
             if (vm_stop_cb) {  
                 vm_stop_cb(vm_stop_opaque, reason);  
             }  
         }  
         vm_state_notify(0);  
     }      }
 }  }
   
Line 7217  static int reset_requested; Line 3532  static int reset_requested;
 static int shutdown_requested;  static int shutdown_requested;
 static int powerdown_requested;  static int powerdown_requested;
   
   int qemu_shutdown_requested(void)
   {
       int r = shutdown_requested;
       shutdown_requested = 0;
       return r;
   }
   
   int qemu_reset_requested(void)
   {
       int r = reset_requested;
       reset_requested = 0;
       return r;
   }
   
   int qemu_powerdown_requested(void)
   {
       int r = powerdown_requested;
       powerdown_requested = 0;
       return r;
   }
   
 void qemu_register_reset(QEMUResetHandler *func, void *opaque)  void qemu_register_reset(QEMUResetHandler *func, void *opaque)
 {  {
     QEMUResetEntry **pre, *re;      QEMUResetEntry **pre, *re;
Line 7231  void qemu_register_reset(QEMUResetHandle Line 3567  void qemu_register_reset(QEMUResetHandle
     *pre = re;      *pre = re;
 }  }
   
 static void qemu_system_reset(void)  void qemu_system_reset(void)
 {  {
     QEMUResetEntry *re;      QEMUResetEntry *re;
   
Line 7266  void qemu_system_powerdown_request(void) Line 3602  void qemu_system_powerdown_request(void)
         cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);          cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
 }  }
   
 void main_loop_wait(int timeout)  
 {  
     IOHandlerRecord *ioh;  
     fd_set rfds, wfds, xfds;  
     int ret, nfds;  
 #ifdef _WIN32  #ifdef _WIN32
     int ret2, i;  static void host_main_loop_wait(int *timeout)
 #endif  {
     struct timeval tv;      int ret, ret2, i;
     PollingEntry *pe;      PollingEntry *pe;
   
   
Line 7283  void main_loop_wait(int timeout) Line 3614  void main_loop_wait(int timeout)
     for(pe = first_polling_entry; pe != NULL; pe = pe->next) {      for(pe = first_polling_entry; pe != NULL; pe = pe->next) {
         ret |= pe->func(pe->opaque);          ret |= pe->func(pe->opaque);
     }      }
 #ifdef _WIN32  
     if (ret == 0) {      if (ret == 0) {
         int err;          int err;
         WaitObjects *w = &wait_objects;          WaitObjects *w = &wait_objects;
   
         ret = WaitForMultipleObjects(w->num, w->events, FALSE, timeout);          ret = WaitForMultipleObjects(w->num, w->events, FALSE, *timeout);
         if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {          if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
             if (w->func[ret - WAIT_OBJECT_0])              if (w->func[ret - WAIT_OBJECT_0])
                 w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);                  w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
Line 7313  void main_loop_wait(int timeout) Line 3643  void main_loop_wait(int timeout)
             fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);              fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
         }          }
     }      }
   
       *timeout = 0;
   }
   #else
   static void host_main_loop_wait(int *timeout)
   {
   }
 #endif  #endif
   
   void main_loop_wait(int timeout)
   {
       IOHandlerRecord *ioh;
       fd_set rfds, wfds, xfds;
       int ret, nfds;
       struct timeval tv;
   
       qemu_bh_update_timeout(&timeout);
   
       host_main_loop_wait(&timeout);
   
     /* poll any events */      /* poll any events */
     /* XXX: separate device handlers from system ones */      /* XXX: separate device handlers from system ones */
     nfds = -1;      nfds = -1;
Line 7337  void main_loop_wait(int timeout) Line 3686  void main_loop_wait(int timeout)
         }          }
     }      }
   
     tv.tv_sec = 0;      tv.tv_sec = timeout / 1000;
 #ifdef _WIN32      tv.tv_usec = (timeout % 1000) * 1000;
     tv.tv_usec = 0;  
 #else  
     tv.tv_usec = timeout * 1000;  
 #endif  
 #if defined(CONFIG_SLIRP)  #if defined(CONFIG_SLIRP)
     if (slirp_inited) {      if (slirp_is_inited()) {
         slirp_select_fill(&nfds, &rfds, &wfds, &xfds);          slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
     }      }
 #endif  #endif
Line 7373  void main_loop_wait(int timeout) Line 3719  void main_loop_wait(int timeout)
         }          }
     }      }
 #if defined(CONFIG_SLIRP)  #if defined(CONFIG_SLIRP)
     if (slirp_inited) {      if (slirp_is_inited()) {
         if (ret < 0) {          if (ret < 0) {</