added I/O API - io port API change - added multiple network interface support - redir...
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 14 Mar 2004 21:44:30 +0000 (21:44 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sun, 14 Mar 2004 21:44:30 +0000 (21:44 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@663 c046a42c-6fe2-441c-8c8c-71466251a162

vl.c
vl.h

diff --git a/vl.c b/vl.c
index 432bc06..8472f0a 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -39,6 +39,7 @@
 #include <sys/poll.h>
 #include <errno.h>
 #include <sys/wait.h>
+#include <pty.h>
 
 #include <sys/ioctl.h>
 #include <sys/socket.h>
@@ -81,6 +82,7 @@ const char *bios_dir = CONFIG_QEMU_SHAREDIR;
 char phys_ram_file[1024];
 CPUState *global_env;
 CPUState *cpu_single_env;
+void *ioport_opaque[MAX_IOPORTS];
 IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
 IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
 BlockDriverState *bs_table[MAX_DISKS], *fd_table[MAX_FD];
@@ -93,11 +95,14 @@ int boot_device = 'c';
 static int ram_size;
 static char network_script[1024];
 int pit_min_timer_count = 0;
+int nb_nics;
+NetDriverState nd_table[MAX_NICS];
+SerialState *serial_console;
 
 /***********************************************************/
 /* x86 io ports */
 
-uint32_t default_ioport_readb(CPUState *env, uint32_t address)
+uint32_t default_ioport_readb(void *opaque, uint32_t address)
 {
 #ifdef DEBUG_UNUSED_IOPORT
     fprintf(stderr, "inb: port=0x%04x\n", address);
@@ -105,7 +110,7 @@ uint32_t default_ioport_readb(CPUState *env, uint32_t address)
     return 0xff;
 }
 
-void default_ioport_writeb(CPUState *env, uint32_t address, uint32_t data)
+void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
 {
 #ifdef DEBUG_UNUSED_IOPORT
     fprintf(stderr, "outb: port=0x%04x data=0x%02x\n", address, data);
@@ -113,21 +118,21 @@ void default_ioport_writeb(CPUState *env, uint32_t address, uint32_t data)
 }
 
 /* default is to make two byte accesses */
-uint32_t default_ioport_readw(CPUState *env, uint32_t address)
+uint32_t default_ioport_readw(void *opaque, uint32_t address)
 {
     uint32_t data;
-    data = ioport_read_table[0][address & (MAX_IOPORTS - 1)](env, address);
-    data |= ioport_read_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1) << 8;
+    data = ioport_read_table[0][address & (MAX_IOPORTS - 1)](opaque, address);
+    data |= ioport_read_table[0][(address + 1) & (MAX_IOPORTS - 1)](opaque, address + 1) << 8;
     return data;
 }
 
-void default_ioport_writew(CPUState *env, uint32_t address, uint32_t data)
+void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
 {
-    ioport_write_table[0][address & (MAX_IOPORTS - 1)](env, address, data & 0xff);
-    ioport_write_table[0][(address + 1) & (MAX_IOPORTS - 1)](env, address + 1, (data >> 8) & 0xff);
+    ioport_write_table[0][address & (MAX_IOPORTS - 1)](opaque, address, data & 0xff);
+    ioport_write_table[0][(address + 1) & (MAX_IOPORTS - 1)](opaque, address + 1, (data >> 8) & 0xff);
 }
 
-uint32_t default_ioport_readl(CPUState *env, uint32_t address)
+uint32_t default_ioport_readl(void *opaque, uint32_t address)
 {
 #ifdef DEBUG_UNUSED_IOPORT
     fprintf(stderr, "inl: port=0x%04x\n", address);
@@ -135,7 +140,7 @@ uint32_t default_ioport_readl(CPUState *env, uint32_t address)
     return 0xffffffff;
 }
 
-void default_ioport_writel(CPUState *env, uint32_t address, uint32_t data)
+void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
 {
 #ifdef DEBUG_UNUSED_IOPORT
     fprintf(stderr, "outl: port=0x%04x data=0x%02x\n", address, data);
@@ -157,38 +162,52 @@ void init_ioports(void)
 }
 
 /* size is the word size in byte */
-int register_ioport_read(int start, int length, IOPortReadFunc *func, int size)
+int register_ioport_read(int start, int length, int size, 
+                         IOPortReadFunc *func, void *opaque)
 {
     int i, bsize;
 
-    if (size == 1)
+    if (size == 1) {
         bsize = 0;
-    else if (size == 2)
+    } else if (size == 2) {
         bsize = 1;
-    else if (size == 4)
+    } else if (size == 4) {
         bsize = 2;
-    else
+    } else {
+        hw_error("register_ioport_read: invalid size");
         return -1;
-    for(i = start; i < start + length; i += size)
+    }
+    for(i = start; i < start + length; i += size) {
         ioport_read_table[bsize][i] = func;
+        if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
+            hw_error("register_ioport_read: invalid opaque");
+        ioport_opaque[i] = opaque;
+    }
     return 0;
 }
 
 /* size is the word size in byte */
-int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size)
+int register_ioport_write(int start, int length, int size, 
+                          IOPortWriteFunc *func, void *opaque)
 {
     int i, bsize;
 
-    if (size == 1)
+    if (size == 1) {
         bsize = 0;
-    else if (size == 2)
+    } else if (size == 2) {
         bsize = 1;
-    else if (size == 4)
+    } else if (size == 4) {
         bsize = 2;
-    else
+    } else {
+        hw_error("register_ioport_write: invalid size");
         return -1;
-    for(i = start; i < start + length; i += size)
+    }
+    for(i = start; i < start + length; i += size) {
         ioport_write_table[bsize][i] = func;
+        if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
+            hw_error("register_ioport_read: invalid opaque");
+        ioport_opaque[i] = opaque;
+    }
     return 0;
 }
 
@@ -238,32 +257,38 @@ int load_image(const char *filename, uint8_t *addr)
 
 void cpu_outb(CPUState *env, int addr, int val)
 {
-    ioport_write_table[0][addr & (MAX_IOPORTS - 1)](env, addr, val);
+    addr &= (MAX_IOPORTS - 1);
+    ioport_write_table[0][addr](ioport_opaque[addr], addr, val);
 }
 
 void cpu_outw(CPUState *env, int addr, int val)
 {
-    ioport_write_table[1][addr & (MAX_IOPORTS - 1)](env, addr, val);
+    addr &= (MAX_IOPORTS - 1);
+    ioport_write_table[1][addr](ioport_opaque[addr], addr, val);
 }
 
 void cpu_outl(CPUState *env, int addr, int val)
 {
-    ioport_write_table[2][addr & (MAX_IOPORTS - 1)](env, addr, val);
+    addr &= (MAX_IOPORTS - 1);
+    ioport_write_table[2][addr](ioport_opaque[addr], addr, val);
 }
 
 int cpu_inb(CPUState *env, int addr)
 {
-    return ioport_read_table[0][addr & (MAX_IOPORTS - 1)](env, addr);
+    addr &= (MAX_IOPORTS - 1);
+    return ioport_read_table[0][addr](ioport_opaque[addr], addr);
 }
 
 int cpu_inw(CPUState *env, int addr)
 {
-    return ioport_read_table[1][addr & (MAX_IOPORTS - 1)](env, addr);
+    addr &= (MAX_IOPORTS - 1);
+    return ioport_read_table[1][addr](ioport_opaque[addr], addr);
 }
 
 int cpu_inl(CPUState *env, int addr)
 {
-    return ioport_read_table[2][addr & (MAX_IOPORTS - 1)](env, addr);
+    addr &= (MAX_IOPORTS - 1);
+    return ioport_read_table[2][addr](ioport_opaque[addr], addr);
 }
 
 /***********************************************************/
@@ -389,171 +414,34 @@ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
     return res.ll;
 }
 
-#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
-static int term_got_escape, term_command;
-static unsigned char term_cmd_buf[128];
-
-typedef struct term_cmd_t {
-    const unsigned char *name;
-    void (*handler)(unsigned char *params);
-} term_cmd_t;
-
-static void do_change_cdrom (unsigned char *params);
-static void do_change_fd0 (unsigned char *params);
-static void do_change_fd1 (unsigned char *params);
-
-static term_cmd_t term_cmds[] = {
-    { "changecd", &do_change_cdrom, },
-    { "changefd0", &do_change_fd0, },
-    { "changefd1", &do_change_fd1, },
-    { NULL, NULL, },
-};
-
-void term_print_help(void)
-{
-    printf("\n"
-           "C-a h    print this help\n"
-           "C-a x    exit emulatior\n"
-           "C-a d    switch on/off debug log\n"
-          "C-a s    save disk data back to file (if -snapshot)\n"
-           "C-a b    send break (magic sysrq)\n"
-           "C-a c    send qemu internal command\n"
-           "C-a C-a  send C-a\n"
-           );
-}
-
-static void do_change_cdrom (unsigned char *params)
-{
-    /* Dunno how to do it... */
-}
-
-static void do_change_fd (int fd, unsigned char *params)
-{
-    unsigned char *name_start, *name_end, *ros;
-    int ro;
-
-    for (name_start = params;
-         isspace(*name_start); name_start++)
-        continue;
-    if (*name_start == '\0')
-        return;
-    for (name_end = name_start;
-         !isspace(*name_end) && *name_end != '\0'; name_end++)
-        continue;
-    for (ros = name_end + 1; isspace(*ros); ros++)
-        continue;
-    if (ros[0] == 'r' && ros[1] == 'o')
-        ro = 1;
-    else
-        ro = 0;
-    *name_end = '\0';
-    printf("Change fd %d to %s (%s)\n", fd, name_start, params);
-    fdctrl_disk_change(fd, name_start, ro);
-}
-
-static void do_change_fd0 (unsigned char *params)
-{
-    do_change_fd(0, params);
-}
-
-static void do_change_fd1 (unsigned char *params)
-{
-    do_change_fd(1, params);
-}
+/***********************************************************/
+/* serial device */
 
-static void term_treat_command(void)
+int serial_open_device(void)
 {
-    unsigned char *cmd_start, *cmd_end;
-    int i;
+    char slave_name[1024];
+    int master_fd, slave_fd;
 
-    for (cmd_start = term_cmd_buf; isspace(*cmd_start); cmd_start++)
-        continue;
-    for (cmd_end = cmd_start;
-         !isspace(*cmd_end) && *cmd_end != '\0'; cmd_end++)
-        continue;
-    for (i = 0; term_cmds[i].name != NULL; i++) {
-        if (strlen(term_cmds[i].name) == (cmd_end - cmd_start) &&
-            memcmp(term_cmds[i].name, cmd_start, cmd_end - cmd_start) == 0) {
-            (*term_cmds[i].handler)(cmd_end + 1);
-            return;
-        }
-    }
-    *cmd_end = '\0';
-    printf("Unknown term command: %s\n", cmd_start);
-}
-
-extern FILE *logfile;
-
-/* called when a char is received */
-void term_received_byte(int ch)
-{
-    if (term_command) {
-        if (ch == '\n' || ch == '\r' || term_command == 127) {
-            printf("\n");
-            term_treat_command();
-            term_command = 0;
-        } else {
-            if (ch == 0x7F || ch == 0x08) {
-                if (term_command > 1) {
-                    term_cmd_buf[--term_command - 1] = '\0';
-                    printf("\r                                               "
-                           "                               ");
-                    printf("\r> %s", term_cmd_buf);
-                }
-            } else if (ch > 0x1f) {
-                term_cmd_buf[term_command++ - 1] = ch;
-                term_cmd_buf[term_command - 1] = '\0';
-                printf("\r> %s", term_cmd_buf);
-            }
-            fflush(stdout);
-        }
-    } else if (term_got_escape) {
-        term_got_escape = 0;
-        switch(ch) {
-        case 'h':
-            term_print_help();
-            break;
-        case 'x':
-            exit(0);
-            break;
-       case 's': 
-            {
-                int i;
-                for (i = 0; i < MAX_DISKS; i++) {
-                    if (bs_table[i])
-                        bdrv_commit(bs_table[i]);
-                }
-           }
-            break;
-        case 'b':
-            serial_receive_break();
-            break;
-        case 'c':
-            printf("> ");
-            fflush(stdout);
-            term_command = 1;
-            break;
-        case 'd':
-            cpu_set_log(CPU_LOG_ALL);
-            break;
-        case TERM_ESCAPE:
-            goto send_char;
-        }
-    } else if (ch == TERM_ESCAPE) {
-        term_got_escape = 1;
+    if (serial_console == NULL && nographic) {
+        /* use console for serial port */
+        return 0;
     } else {
-    send_char:
-        serial_receive_byte(ch);
+        if (openpty(&master_fd, &slave_fd, slave_name, NULL, NULL) < 0) {
+            fprintf(stderr, "warning: could not create pseudo terminal for serial port\n");
+            return -1;
+        }
+        fprintf(stderr, "Serial port redirected to %s\n", slave_name);
+        return master_fd;
     }
 }
 
 /***********************************************************/
 /* Linux network device redirector */
 
-int net_init(void)
+static int tun_open(char *ifname, int ifname_size)
 {
     struct ifreq ifr;
-    int fd, ret, pid, status;
+    int fd, ret;
     
     fd = open("/dev/net/tun", O_RDWR);
     if (fd < 0) {
@@ -570,32 +458,62 @@ int net_init(void)
         return -1;
     }
     printf("Connected to host network interface: %s\n", ifr.ifr_name);
+    pstrcpy(ifname, ifname_size, ifr.ifr_name);
     fcntl(fd, F_SETFL, O_NONBLOCK);
-    net_fd = fd;
+    return fd;
+}
 
-    /* try to launch network init script */
-    pid = fork();
-    if (pid >= 0) {
-        if (pid == 0) {
-            execl(network_script, network_script, ifr.ifr_name, NULL);
-            exit(1);
+static int net_init(void)
+{
+    int pid, status, launch_script, i;
+    NetDriverState *nd;
+    char *args[MAX_NICS + 2];
+    char **parg;
+
+    launch_script = 0;
+    for(i = 0; i < nb_nics; i++) {
+        nd = &nd_table[i];
+        if (nd->fd < 0) {
+            nd->fd = tun_open(nd->ifname, sizeof(nd->ifname));
+            if (nd->fd >= 0) 
+                launch_script = 1;
         }
-        while (waitpid(pid, &status, 0) != pid);
-        if (!WIFEXITED(status) ||
-            WEXITSTATUS(status) != 0) {
-            fprintf(stderr, "%s: could not launch network script for '%s'\n",
-                    network_script, ifr.ifr_name);
+    }
+
+    if (launch_script) {
+        /* try to launch network init script */
+        pid = fork();
+        if (pid >= 0) {
+            if (pid == 0) {
+                parg = args;
+                *parg++ = network_script;
+                for(i = 0; i < nb_nics; i++) {
+                    nd = &nd_table[i];
+                    if (nd->fd >= 0) {
+                        *parg++ = nd->ifname;
+                    }
+                }
+                *parg++ = NULL;
+                execv(network_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",
+                        network_script);
+            }
         }
     }
     return 0;
 }
 
-void net_send_packet(int net_fd, const uint8_t *buf, int size)
+void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
 {
 #ifdef DEBUG_NE2000
     printf("NE2000: sending packet size=%d\n", size);
 #endif
-    write(net_fd, buf, size);
+    write(nd->fd, buf, size);
 }
 
 /***********************************************************/
@@ -702,6 +620,37 @@ static void host_alarm_handler(int host_signum, siginfo_t *info,
     }
 }
 
+#define MAX_IO_HANDLERS 64
+
+typedef struct IOHandlerRecord {
+    int fd;
+    IOCanRWHandler *fd_can_read;
+    IOReadHandler *fd_read;
+    void *opaque;
+    /* temporary data */
+    struct pollfd *ufd;
+    int max_size;
+} IOHandlerRecord;
+
+static IOHandlerRecord io_handlers[MAX_IO_HANDLERS];
+static int nb_io_handlers = 0;
+
+int add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, 
+                        IOReadHandler *fd_read, void *opaque)
+{
+    IOHandlerRecord *ioh;
+
+    if (nb_io_handlers >= MAX_IO_HANDLERS)
+        return -1;
+    ioh = &io_handlers[nb_io_handlers];
+    ioh->fd = fd;
+    ioh->fd_can_read = fd_can_read;
+    ioh->fd_read = fd_read;
+    ioh->opaque = opaque;
+    nb_io_handlers++;
+    return 0;
+}
+
 /* main execution loop */
 
 CPUState *cpu_gdbstub_get_env(void *opaque)
@@ -711,12 +660,10 @@ CPUState *cpu_gdbstub_get_env(void *opaque)
 
 int main_loop(void *opaque)
 {
-    struct pollfd ufds[3], *pf, *serial_ufd, *gdb_ufd;
-#if defined (TARGET_I386)
-    struct pollfd *net_ufd;
-#endif
-    int ret, n, timeout, serial_ok;
-    uint8_t ch;
+    struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf, *gdb_ufd;
+    int ret, n, timeout, serial_ok, max_size, i;
+    uint8_t buf[4096];
+    IOHandlerRecord *ioh;
     CPUState *env = global_env;
 
     if (!term_inited) {
@@ -747,24 +694,26 @@ int main_loop(void *opaque)
             timeout = 10;
         else
             timeout = 0;
+
         /* poll any events */
-        serial_ufd = NULL;
         pf = ufds;
-        if (serial_ok && serial_can_receive()) {
-            serial_ufd = pf;
-            pf->fd = 0;
-            pf->events = POLLIN;
-            pf++;
-        }
-#if defined (TARGET_I386)
-        net_ufd = NULL;
-        if (net_fd > 0 && ne2000_can_receive()) {
-            net_ufd = pf;
-            pf->fd = net_fd;
-            pf->events = POLLIN;
-            pf++;
+        ioh = io_handlers;
+        for(i = 0; i < nb_io_handlers; i++) {
+            max_size = ioh->fd_can_read(ioh->opaque);
+            if (max_size > 0) {
+                if (max_size > sizeof(buf))
+                    max_size = sizeof(buf);
+                pf->fd = ioh->fd;
+                pf->events = POLLIN;
+                ioh->ufd = pf;
+                pf++;
+            } else {
+                ioh->ufd = NULL;
+            }
+            ioh->max_size = max_size;
+            ioh++;
         }
-#endif
+
         gdb_ufd = NULL;
         if (gdbstub_fd > 0) {
             gdb_ufd = pf;
@@ -775,29 +724,17 @@ int main_loop(void *opaque)
 
         ret = poll(ufds, pf - ufds, timeout);
         if (ret > 0) {
-            if (serial_ufd && (serial_ufd->revents & POLLIN)) {
-                n = read(0, &ch, 1);
-                if (n == 1) {
-                    term_received_byte(ch);
-                } else {
-                   /* Closed, stop polling. */
-                    serial_ok = 0;
-                }
-            }
-#if defined (TARGET_I386)
-            if (net_ufd && (net_ufd->revents & POLLIN)) {
-                uint8_t buf[MAX_ETH_FRAME_SIZE];
-
-                n = read(net_fd, buf, MAX_ETH_FRAME_SIZE);
-                if (n > 0) {
-                    if (n < 60) {
-                        memset(buf + n, 0, 60 - n);
-                        n = 60;
+            ioh = io_handlers;
+            for(i = 0; i < nb_io_handlers; i++) {
+                pf = ioh->ufd;
+                if (pf) {
+                    n = read(ioh->fd, buf, ioh->max_size);
+                    if (n > 0) {
+                        ioh->fd_read(ioh->opaque, buf, n);
                     }
-                    ne2000_receive(buf, n);
                 }
+                ioh++;
             }
-#endif
             if (gdb_ufd && (gdb_ufd->revents & POLLIN)) {
                 uint8_t buf[1];
                 /* stop emulation if requested by gdb */
@@ -845,15 +782,18 @@ void help(void)
            "-fda/-fdb file  use 'file' as floppy disk 0/1 image\n"
            "-hda/-hdb file  use 'file' as IDE hard disk 0/1 image\n"
            "-hdc/-hdd file  use 'file' as IDE hard disk 2/3 image\n"
-           "-cdrom file     use 'file' as IDE cdrom 2 image\n"
+           "-cdrom file     use 'file' as IDE cdrom image (cdrom is ide1 master)\n"
            "-boot [a|b|c|d] boot on floppy (a, b), hard disk (c) or CD-ROM (d)\n"
           "-snapshot       write to temporary files instead of disk image files\n"
            "-m megs         set virtual RAM size to megs MB\n"
+           "-nographic      disable graphical output and redirect serial I/Os to console\n"
+           "\n"
+           "Network options:\n"
            "-n script       set network init script [default=%s]\n"
-           "-tun-fd fd      this fd talks to tap/tun, use it.\n"
-           "-nographic      disable graphical output\n"
+           "-nics n         simulate 'n' network interfaces [default=1]\n"
+           "-tun-fd fd0[,...] use these fds as already opened tap/tun interfaces\n"
            "\n"
-           "Linux boot specific (does not require PC BIOS):\n"
+           "Linux boot specific:\n"
            "-kernel bzImage use 'bzImage' as kernel image\n"
            "-append cmdline use 'cmdline' as kernel command line\n"
            "-initrd file    use 'file' as initial ram disk\n"
@@ -904,7 +844,8 @@ struct option long_options[] = {
     { "boot", 1, NULL, 0, },
     { "fda", 1, NULL, 0, },
     { "fdb", 1, NULL, 0, },
-    { "no-code-copy", 0, NULL, 0},
+    { "no-code-copy", 0, NULL, 0 },
+    { "nics", 1, NULL, 0 },
     { NULL, 0, NULL, 0 },
 };
 
@@ -931,7 +872,7 @@ static uint8_t *signal_stack;
 
 int main(int argc, char **argv)
 {
-    int c, i, use_gdbstub, gdbstub_port, long_index;
+    int c, i, use_gdbstub, gdbstub_port, long_index, has_cdrom;
     int snapshot, linux_boot;
     struct sigaction act;
     struct itimerval itv;
@@ -940,6 +881,7 @@ int main(int argc, char **argv)
     const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
     const char *kernel_filename, *kernel_cmdline;
     DisplayState *ds = &display_state;
+    int cyls, heads, secs;
 
     /* we never want that malloc() uses mmap() */
     mallopt(M_MMAP_THRESHOLD, 4096 * 1024);
@@ -950,15 +892,29 @@ int main(int argc, char **argv)
         hd_filename[i] = NULL;
     ram_size = 32 * 1024 * 1024;
     vga_ram_size = VGA_RAM_SIZE;
-#if defined (TARGET_I386)
     pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT);
-#endif
     use_gdbstub = 0;
     gdbstub_port = DEFAULT_GDBSTUB_PORT;
     snapshot = 0;
     nographic = 0;
     kernel_filename = NULL;
     kernel_cmdline = "";
+    has_cdrom = 1;
+    cyls = heads = secs = 0;
+
+    nb_nics = 1;
+    for(i = 0; i < MAX_NICS; i++) {
+        NetDriverState *nd = &nd_table[i];
+        nd->fd = -1;
+        /* init virtual mac address */
+        nd->macaddr[0] = 0x52;
+        nd->macaddr[1] = 0x54;
+        nd->macaddr[2] = 0x00;
+        nd->macaddr[3] = 0x12;
+        nd->macaddr[4] = 0x34;
+        nd->macaddr[5] = 0x56 + i;
+    }
+    
     for(;;) {
         c = getopt_long_only(argc, argv, "hm:dn:sp:L:", long_options, &long_index);
         if (c == -1)
@@ -980,7 +936,6 @@ int main(int argc, char **argv)
                 break;
             case 4:
                 {
-                    int cyls, heads, secs;
                     const char *p;
                     p = optarg;
                     cyls = strtol(p, (char **)&p, 0);
@@ -992,10 +947,10 @@ int main(int argc, char **argv)
                         goto chs_fail;
                     p++;
                     secs = strtol(p, (char **)&p, 0);
-                    if (*p != '\0')
-                        goto chs_fail;
-                    ide_set_geometry(0, cyls, heads, secs);
-                chs_fail: ;
+                    if (*p != '\0') {
+                    chs_fail:
+                        cyls = 0;
+                    }
                 }
                 break;
             case 5:
@@ -1007,20 +962,38 @@ int main(int argc, char **argv)
             case 7:
                 kernel_cmdline = optarg;
                 break;
-#if defined (TARGET_I386)
            case 8:
-               net_fd = atoi(optarg);
+                {
+                    const char *p;
+                    int fd;
+                    p = optarg;
+                    nb_nics = 0;
+                    for(;;) {
+                        fd = strtol(p, (char **)&p, 0);
+                        nd_table[nb_nics].fd = fd;
+                        snprintf(nd_table[nb_nics].ifname, 
+                                 sizeof(nd_table[nb_nics].ifname),
+                                 "fd%d", nb_nics);
+                        nb_nics++;
+                        if (*p == ',') {
+                            p++;
+                        } else if (*p != '\0') {
+                            fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_nics);
+                            exit(1);
+                        }
+                    }
+                }
                break;
-#endif
             case 9:
                 hd_filename[2] = optarg;
+                has_cdrom = 0;
                 break;
             case 10:
                 hd_filename[3] = optarg;
                 break;
             case 11:
                 hd_filename[2] = optarg;
-                ide_set_cdrom(2, 1);
+                has_cdrom = 1;
                 break;
             case 12:
                 boot_device = optarg[0];
@@ -1039,6 +1012,13 @@ int main(int argc, char **argv)
             case 15:
                 code_copy_enabled = 0;
                 break;
+            case 16:
+                nb_nics = atoi(optarg);
+                if (nb_nics < 1 || nb_nics > MAX_NICS) {
+                    fprintf(stderr, "qemu: invalid number of network interfaces\n");
+                    exit(1);
+                }
+                break;
             }
             break;
         case 'h':
@@ -1057,11 +1037,9 @@ int main(int argc, char **argv)
         case 'd':
             cpu_set_log(CPU_LOG_ALL);
             break;
-#if defined (TARGET_I386)
         case 'n':
             pstrcpy(network_script, sizeof(network_script), optarg);
             break;
-#endif
         case 's':
             use_gdbstub = 1;
             break;
@@ -1102,11 +1080,8 @@ int main(int argc, char **argv)
     setvbuf(stdout, NULL, _IOLBF, 0);
 #endif
 
-    /* init network tun interface */
-#if defined (TARGET_I386)
-    if (net_fd < 0)
-       net_init();
-#endif
+    /* init host network redirectors */
+    net_init();
 
     /* init the memory */
     phys_ram_size = ram_size + vga_ram_size;
@@ -1151,15 +1126,49 @@ int main(int argc, char **argv)
     }
 #endif
 
+    /* we always create the cdrom drive, even if no disk is there */
+    if (has_cdrom) {
+        bs_table[2] = bdrv_new("cdrom");
+        bdrv_set_type_hint(bs_table[2], BDRV_TYPE_CDROM);
+    }
+
     /* open the virtual block devices */
     for(i = 0; i < MAX_DISKS; i++) {
         if (hd_filename[i]) {
-            bs_table[i] = bdrv_open(hd_filename[i], snapshot);
             if (!bs_table[i]) {
+                char buf[64];
+                snprintf(buf, sizeof(buf), "hd%c", i + 'a');
+                bs_table[i] = bdrv_new(buf);
+            }
+            if (bdrv_open(bs_table[i], hd_filename[i], snapshot) < 0) {
                 fprintf(stderr, "qemu: could not open hard disk image '%s\n",
                         hd_filename[i]);
                 exit(1);
             }
+            if (i == 0 && cyls != 0) 
+                bdrv_set_geometry_hint(bs_table[i], cyls, heads, secs);
+        }
+    }
+
+    /* we always create at least one floppy disk */
+    fd_table[0] = bdrv_new("fda");
+    bdrv_set_type_hint(fd_table[0], BDRV_TYPE_FLOPPY);
+
+    for(i = 0; i < MAX_FD; i++) {
+        if (fd_filename[i]) {
+            if (!fd_table[i]) {
+                char buf[64];
+                snprintf(buf, sizeof(buf), "fd%c", i + 'a');
+                fd_table[i] = bdrv_new(buf);
+                bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY);
+            }
+            if (fd_filename[i] != '\0') {
+                if (bdrv_open(fd_table[i], fd_filename[i], snapshot) < 0) {
+                    fprintf(stderr, "qemu: could not open floppy disk image '%s\n",
+                            fd_filename[i]);
+                    exit(1);
+                }
+            }
         }
     }
 
@@ -1190,6 +1199,10 @@ int main(int argc, char **argv)
     ppc_init();
 #endif
 
+    /* launched after the device init so that it can display or not a
+       banner */
+    monitor_init();
+
     /* setup cpu signal handlers for MMU / self modifying code handling */
 #if !defined(CONFIG_SOFTMMU)
 
diff --git a/vl.h b/vl.h
index 026a5de..50e1609 100644 (file)
--- a/vl.h
+++ b/vl.h
@@ -31,16 +31,16 @@ extern int reset_requested;
 extern int64_t ticks_per_sec;
 extern int pit_min_timer_count;
 
-typedef void (IOPortWriteFunc)(struct CPUState *env, uint32_t address, uint32_t data);
-typedef uint32_t (IOPortReadFunc)(struct CPUState *env, uint32_t address);
+typedef void (IOPortWriteFunc)(void *opaque, uint32_t address, uint32_t data);
+typedef uint32_t (IOPortReadFunc)(void *opaque, uint32_t address);
 
-int register_ioport_read(int start, int length, IOPortReadFunc *func, int size);
-int register_ioport_write(int start, int length, IOPortWriteFunc *func, int size);
+int register_ioport_read(int start, int length, int size, 
+                         IOPortReadFunc *func, void *opaque);
+int register_ioport_write(int start, int length, int size, 
+                          IOPortWriteFunc *func, void *opaque);
 int64_t cpu_get_ticks(void);
 uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c);
 
-void net_send_packet(int net_fd, const uint8_t *buf, int size);
-
 void hw_error(const char *fmt, ...);
 
 int load_image(const char *filename, uint8_t *addr);
@@ -49,10 +49,37 @@ extern const char *bios_dir;
 void pstrcpy(char *buf, int buf_size, const char *str);
 char *pstrcat(char *buf, int buf_size, const char *s);
 
+int serial_open_device(void);
+
+/* network redirectors support */
+
+#define MAX_NICS 8
+
+typedef struct NetDriverState {
+    int fd;
+    uint8_t macaddr[6];
+    char ifname[16];
+} NetDriverState;
+
+extern int nb_nics;
+extern NetDriverState nd_table[MAX_NICS];
+
+void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size);
+
+/* async I/O support */
+
+typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size);
+typedef int IOCanRWHandler(void *opaque);
+
+int add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, 
+                        IOReadHandler *fd_read, void *opaque);
+
 /* block.c */
 typedef struct BlockDriverState BlockDriverState;
 
-BlockDriverState *bdrv_open(const char *filename, int snapshot);
+BlockDriverState *bdrv_new(const char *device_name);
+void bdrv_delete(BlockDriverState *bs);
+int bdrv_open(BlockDriverState *bs, const char *filename, int snapshot);
 void bdrv_close(BlockDriverState *bs);
 int bdrv_read(BlockDriverState *bs, int64_t sector_num, 
               uint8_t *buf, int nb_sectors);
@@ -62,6 +89,27 @@ void bdrv_get_geometry(BlockDriverState *bs, int64_t *nb_sectors_ptr);
 int bdrv_commit(BlockDriverState *bs);
 void bdrv_set_boot_sector(BlockDriverState *bs, const uint8_t *data, int size);
 
+#define BDRV_TYPE_HD     0
+#define BDRV_TYPE_CDROM  1
+#define BDRV_TYPE_FLOPPY 2
+
+void bdrv_set_geometry_hint(BlockDriverState *bs, 
+                            int cyls, int heads, int secs);
+void bdrv_set_type_hint(BlockDriverState *bs, int type);
+void bdrv_get_geometry_hint(BlockDriverState *bs, 
+                            int *pcyls, int *pheads, int *psecs);
+int bdrv_get_type_hint(BlockDriverState *bs);
+int bdrv_is_removable(BlockDriverState *bs);
+int bdrv_is_read_only(BlockDriverState *bs);
+int bdrv_is_inserted(BlockDriverState *bs);
+int bdrv_is_locked(BlockDriverState *bs);
+void bdrv_set_locked(BlockDriverState *bs, int locked);
+void bdrv_set_change_cb(BlockDriverState *bs, 
+                        void (*change_cb)(void *opaque), void *opaque);
+
+void bdrv_info(void);
+BlockDriverState *bdrv_find(const char *name);
+
 /* vga.c */
 
 #define VGA_RAM_SIZE (4096 * 1024)
@@ -97,9 +145,8 @@ void sdl_display_init(DisplayState *ds);
 
 extern BlockDriverState *bs_table[MAX_DISKS];
 
-void ide_init(void);
-void ide_set_geometry(int n, int cyls, int heads, int secs);
-void ide_set_cdrom(int n, int is_cdrom);
+void ide_init(int iobase, int iobase2, int irq,
+              BlockDriverState *hd0, BlockDriverState *hd1);
 
 /* oss.c */
 typedef enum {
@@ -138,20 +185,13 @@ void SB16_init (void);
 #define MAX_FD 2
 extern BlockDriverState *fd_table[MAX_FD];
 
-void cmos_register_fd (uint8_t fd0, uint8_t fd1);
 void fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped, uint32_t base,
-                  char boot_device);
-int fdctrl_disk_change (int idx, const unsigned char *filename, int ro);
+                  BlockDriverState **fds);
+int fdctrl_get_drive_type(int drive_num);
 
 /* ne2000.c */
 
-#define MAX_ETH_FRAME_SIZE 1514
-
-void ne2000_init(int base, int irq);
-int ne2000_can_receive(void);
-void ne2000_receive(uint8_t *buf, int size);
-
-extern int net_fd;
+void ne2000_init(int base, int irq, NetDriverState *nd);
 
 /* pckbd.c */
 
@@ -179,10 +219,14 @@ void rtc_timer(void);
 
 /* serial.c */
 
-void serial_init(int base, int irq);
-int serial_can_receive(void);
-void serial_receive_byte(int ch);
-void serial_receive_break(void);
+typedef struct SerialState SerialState;
+
+extern SerialState *serial_console;
+
+SerialState *serial_init(int base, int irq, int fd);
+int serial_can_receive(SerialState *s);
+void serial_receive_byte(SerialState *s, int ch);
+void serial_receive_break(SerialState *s);
 
 /* i8259.c */
 
@@ -206,7 +250,7 @@ typedef struct PITChannelState {
 
 extern PITChannelState pit_channels[3];
 
-void pit_init(void);
+void pit_init(int base);
 void pit_set_gate(PITChannelState *s, int val);
 int pit_get_out(PITChannelState *s);
 int pit_get_out_edges(PITChannelState *s);
@@ -217,4 +261,10 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
              const char *kernel_filename, const char *kernel_cmdline,
              const char *initrd_filename);
 
+/* monitor.c */
+void monitor_init(void);
+void term_printf(const char *fmt, ...);
+void term_flush(void);
+void term_print_help(void);
+
 #endif /* VL_H */