X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=vl.c;h=e89091d0f8e883c3b10a760076a8dbf380826643;hb=d8d8aa4e2cc8e56d9e651e97ad16144289b00154;hp=cefe0e9ab4f6ca6811f745ec7c9e7344c787b2a2;hpb=702c651c4ae90ac399264c07aded66df2c0efacf;p=qemu diff --git a/vl.c b/vl.c index cefe0e9..e89091d 100644 --- a/vl.c +++ b/vl.c @@ -45,6 +45,10 @@ #include #endif +#if defined(CONFIG_SLIRP) +#include "libslirp.h" +#endif + #ifdef _WIN32 #include #include @@ -52,11 +56,24 @@ #define memalign(align, size) malloc(size) #endif +#ifdef CONFIG_SDL +/* SDL use the pthreads and they modify sigaction. We don't + want that. */ +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) +extern void __libc_sigaction(); +#define sigaction(sig, act, oact) __libc_sigaction(sig, act, oact) +#else +extern void __sigaction(); +#define sigaction(sig, act, oact) __sigaction(sig, act, oact) +#endif +#endif /* CONFIG_SDL */ #include "disas.h" #include "exec-all.h" +//#define DO_TB_FLUSH + #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" //#define DEBUG_UNUSED_IOPORT @@ -94,9 +111,12 @@ NetDriverState nd_table[MAX_NICS]; SerialState *serial_console; QEMUTimer *gui_timer; int vm_running; +int audio_enabled = 0; /***********************************************************/ -/* x86 io ports */ +/* x86 ISA bus support */ + +target_phys_addr_t isa_mem_base = 0; uint32_t default_ioport_readb(void *opaque, uint32_t address) { @@ -238,7 +258,7 @@ char *pstrcat(char *buf, int buf_size, const char *s) int load_image(const char *filename, uint8_t *addr) { int fd, size; - fd = open(filename, O_RDONLY); + fd = open(filename, O_RDONLY | O_BINARY); if (fd < 0) return -1; size = lseek(fd, 0, SEEK_END); @@ -345,6 +365,19 @@ int64_t cpu_get_real_ticks(void) return val; } +#elif defined(__x86_64__) + +int64_t cpu_get_real_ticks(void) +{ + uint32_t low,high; + int64_t val; + asm volatile("rdtsc" : "=a" (low), "=d" (high)); + val = high; + val <<= 32; + val |= low; + return val; +} + #else #error unsupported CPU #endif @@ -453,7 +486,9 @@ QEMUClock *rt_clock; QEMUClock *vm_clock; static QEMUTimer *active_timers[2]; -#ifndef _WIN32 +#ifdef _WIN32 +static MMRESULT timerID; +#else /* frequency of the times() clock tick */ static int timer_freq; #endif @@ -653,11 +688,11 @@ static void init_timers(void) #ifdef _WIN32 { int count=0; - MMRESULT timerID = timeSetEvent(10, // interval (ms) - 0, // resolution - host_alarm_handler, // function - (DWORD)&count, // user parameter - TIME_PERIODIC | TIME_CALLBACK_FUNCTION); + timerID = timeSetEvent(10, // interval (ms) + 0, // resolution + host_alarm_handler, // function + (DWORD)&count, // user parameter + TIME_PERIODIC | TIME_CALLBACK_FUNCTION); if( !timerID ) { perror("failed timer alarm"); exit(1); @@ -695,6 +730,13 @@ static void init_timers(void) #endif } +void quit_timers(void) +{ +#ifdef _WIN32 + timeKillEvent(timerID); +#endif +} + /***********************************************************/ /* serial device */ @@ -728,20 +770,121 @@ int serial_open_device(void) #endif /***********************************************************/ -/* Linux network device redirector */ +/* Linux network device redirectors */ -#ifdef _WIN32 +void hex_dump(FILE *f, const uint8_t *buf, int size) +{ + int len, i, j, c; -static int net_init(void) + for(i=0;i 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 '~') + c = '.'; + fprintf(f, "%c", c); + } + fprintf(f, "\n"); + } +} + +void qemu_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +{ + nd->send_packet(nd, buf, size); +} + +void qemu_add_read_packet(NetDriverState *nd, IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) { + nd->add_read_packet(nd, fd_can_read, fd_read, opaque); +} + +/* dummy network adapter */ + +static void dummy_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +{ +} + +static void dummy_add_read_packet(NetDriverState *nd, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ +} + +static int net_dummy_init(NetDriverState *nd) +{ + nd->send_packet = dummy_send_packet; + nd->add_read_packet = dummy_add_read_packet; + pstrcpy(nd->ifname, sizeof(nd->ifname), "dummy"); return 0; } -void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +#if defined(CONFIG_SLIRP) + +/* slirp network adapter */ + +static void *slirp_fd_opaque; +static IOCanRWHandler *slirp_fd_can_read; +static IOReadHandler *slirp_fd_read; +static int slirp_inited; + +int slirp_can_output(void) { + return slirp_fd_can_read(slirp_fd_opaque); } -#else +void slirp_output(const uint8_t *pkt, int pkt_len) +{ +#if 0 + printf("output:\n"); + hex_dump(stdout, pkt, pkt_len); +#endif + slirp_fd_read(slirp_fd_opaque, pkt, pkt_len); +} + +static void slirp_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +{ +#if 0 + printf("input:\n"); + hex_dump(stdout, buf, size); +#endif + slirp_input(buf, size); +} + +static void slirp_add_read_packet(NetDriverState *nd, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + slirp_fd_opaque = opaque; + slirp_fd_can_read = fd_can_read; + slirp_fd_read = fd_read; +} + +static int net_slirp_init(NetDriverState *nd) +{ + if (!slirp_inited) { + slirp_inited = 1; + slirp_init(); + } + nd->send_packet = slirp_send_packet; + nd->add_read_packet = slirp_add_read_packet; + pstrcpy(nd->ifname, sizeof(nd->ifname), "slirp"); + return 0; +} + +#endif /* CONFIG_SLIRP */ + +#if !defined(_WIN32) static int tun_open(char *ifname, int ifname_size) { @@ -768,60 +911,61 @@ static int tun_open(char *ifname, int ifname_size) return fd; } -static int net_init(void) +static void tun_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +{ + write(nd->fd, buf, size); +} + +static void tun_add_read_packet(NetDriverState *nd, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + qemu_add_fd_read_handler(nd->fd, fd_can_read, fd_read, opaque); +} + +static int net_tun_init(NetDriverState *nd) { - int pid, status, launch_script, i; - NetDriverState *nd; - char *args[MAX_NICS + 2]; + int pid, status; + char *args[3]; 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; - } - } + nd->fd = tun_open(nd->ifname, sizeof(nd->ifname)); + if (nd->fd < 0) + return -1; - 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); - } + /* try to launch network init script */ + pid = fork(); + if (pid >= 0) { + if (pid == 0) { + parg = args; + *parg++ = network_script; + *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); } } + nd->send_packet = tun_send_packet; + nd->add_read_packet = tun_add_read_packet; return 0; } -void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size) +static int net_fd_init(NetDriverState *nd, int fd) { -#ifdef DEBUG_NE2000 - printf("NE2000: sending packet size=%d\n", size); -#endif - write(nd->fd, buf, size); + nd->fd = fd; + nd->send_packet = tun_send_packet; + nd->add_read_packet = tun_add_read_packet; + pstrcpy(nd->ifname, sizeof(nd->ifname), "tunfd"); + return 0; } -#endif +#endif /* !_WIN32 */ /***********************************************************/ /* dumb display */ @@ -1181,6 +1325,9 @@ int qemu_loadvm(const char *filename) goto the_end; } for(;;) { +#if defined (DO_TB_FLUSH) + tb_flush(global_env); +#endif len = qemu_get_byte(f); if (feof(f)) break; @@ -1360,6 +1507,15 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) 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; +} #else #warning No CPU save/restore functions @@ -1509,7 +1665,11 @@ int main_loop(void) timeout = 10; } -#ifndef _WIN32 +#ifdef _WIN32 + if (timeout > 0) + Sleep(timeout); +#else + /* poll any events */ /* XXX: separate device handlers from system ones */ pf = ufds; @@ -1535,7 +1695,7 @@ int main_loop(void) } ioh->max_size = max_size; } - + ret = poll(ufds, pf - ufds, timeout); if (ret > 0) { /* XXX: better handling of removal */ @@ -1559,14 +1719,38 @@ int main_loop(void) } } } + +#if defined(CONFIG_SLIRP) + /* XXX: merge with poll() */ + if (slirp_inited) { + fd_set rfds, wfds, xfds; + int nfds; + struct timeval tv; + + nfds = -1; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + slirp_select_fill(&nfds, &rfds, &wfds, &xfds); + tv.tv_sec = 0; + tv.tv_usec = 0; + ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); + if (ret >= 0) { + slirp_select_poll(&rfds, &wfds, &xfds); + } + } +#endif + #endif if (vm_running) { qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], qemu_get_clock(vm_clock)); - /* XXX: add explicit timer */ - SB16_run(); + if (audio_enabled) { + /* XXX: add explicit timer */ + SB16_run(); + } /* run dma transfers, if any */ DMA_run(); @@ -1582,7 +1766,7 @@ int main_loop(void) void help(void) { - printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003 Fabrice Bellard\n" + printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n" "usage: %s [options] [disk_image]\n" "\n" "'disk_image' is a raw hard image image for IDE hard disk 0\n" @@ -1596,12 +1780,17 @@ void help(void) "-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" + "-enable-audio enable audio support\n" "\n" "Network options:\n" - "-n script set network init script [default=%s]\n" - "-nics n simulate 'n' network interfaces [default=1]\n" + "-nics n simulate 'n' network cards [default=1]\n" "-macaddr addr set the mac address of the first interface\n" - "-tun-fd fd0[,...] use these fds as already opened tap/tun interfaces\n" + "-n script set tap/tun network init script [default=%s]\n" + "-tun-fd fd use this fd as already opened tap/tun interface\n" +#ifdef CONFIG_SLIRP + "-user-net use user mode network stack [default if no tap/tun script]\n" +#endif + "-dummy-net use dummy network stack\n" "\n" "Linux boot specific:\n" "-kernel bzImage use 'bzImage' as kernel image\n" @@ -1657,21 +1846,12 @@ struct option long_options[] = { { "no-code-copy", 0, NULL, 0 }, { "nics", 1, NULL, 0 }, { "macaddr", 1, NULL, 0 }, + { "user-net", 0, NULL, 0 }, + { "dummy-net", 0, NULL, 0 }, + { "enable-audio", 0, NULL, 0 }, { NULL, 0, NULL, 0 }, }; -#ifdef CONFIG_SDL -/* SDL use the pthreads and they modify sigaction. We don't - want that. */ -#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2) -extern void __libc_sigaction(); -#define sigaction(sig, act, oact) __libc_sigaction(sig, act, oact) -#else -extern void __sigaction(); -#define sigaction(sig, act, oact) __sigaction(sig, act, oact) -#endif -#endif /* CONFIG_SDL */ - #if defined (TARGET_I386) && defined(USE_CODE_COPY) /* this stack is only used during signal handling */ @@ -1681,6 +1861,10 @@ static uint8_t *signal_stack; #endif +#define NET_IF_TUN 0 +#define NET_IF_USER 1 +#define NET_IF_DUMMY 2 + int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB @@ -1694,8 +1878,10 @@ int main(int argc, char **argv) const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs; + int start_emulation = 1; uint8_t macaddr[6]; - + int net_if_type, nb_tun_fds, tun_fds[MAX_NICS]; + #if !defined(CONFIG_SOFTMMU) /* we never want that malloc() uses mmap() */ mallopt(M_MMAP_THRESHOLD, 4096 * 1024); @@ -1719,6 +1905,8 @@ int main(int argc, char **argv) has_cdrom = 1; cyls = heads = secs = 0; + nb_tun_fds = 0; + net_if_type = -1; nb_nics = 1; /* default mac address of the first network interface */ macaddr[0] = 0x52; @@ -1727,9 +1915,10 @@ int main(int argc, char **argv) macaddr[3] = 0x12; macaddr[4] = 0x34; macaddr[5] = 0x56; - + + for(;;) { - c = getopt_long_only(argc, argv, "hm:d:n:sp:L:", long_options, &long_index); + c = getopt_long_only(argc, argv, "hm:d:n:sp:L:S", long_options, &long_index); if (c == -1) break; switch(c) { @@ -1779,23 +1968,13 @@ int main(int argc, char **argv) { 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); + if (nb_tun_fds < MAX_NICS) { + fd = strtol(optarg, (char **)&p, 0); + if (*p != '\0') { + fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_tun_fds); exit(1); - } else { - break; } + tun_fds[nb_tun_fds++] = fd; } } break; @@ -1855,6 +2034,15 @@ int main(int argc, char **argv) } } break; + case 18: + net_if_type = NET_IF_USER; + break; + case 19: + net_if_type = NET_IF_DUMMY; + break; + case 20: + audio_enabled = 1; + break; } break; case 'h': @@ -1900,6 +2088,9 @@ int main(int argc, char **argv) case 'L': bios_dir = optarg; break; + case 'S': + start_emulation = 0; + break; } } @@ -1932,9 +2123,18 @@ int main(int argc, char **argv) #endif /* init host network redirectors */ - for(i = 0; i < MAX_NICS; i++) { + if (net_if_type == -1) { + net_if_type = NET_IF_TUN; +#if defined(CONFIG_SLIRP) + if (access(network_script, R_OK) < 0) { + net_if_type = NET_IF_USER; + } +#endif + } + + for(i = 0; i < nb_nics; i++) { NetDriverState *nd = &nd_table[i]; - nd->fd = -1; + nd->index = i; /* init virtual mac address */ nd->macaddr[0] = macaddr[0]; nd->macaddr[1] = macaddr[1]; @@ -1942,8 +2142,28 @@ int main(int argc, char **argv) nd->macaddr[3] = macaddr[3]; nd->macaddr[4] = macaddr[4]; nd->macaddr[5] = macaddr[5] + i; + switch(net_if_type) { +#if defined(CONFIG_SLIRP) + case NET_IF_USER: + net_slirp_init(nd); + break; +#endif +#if !defined(_WIN32) + case NET_IF_TUN: + if (i < nb_tun_fds) { + net_fd_init(nd, tun_fds[i]); + } else { + if (net_tun_init(nd) < 0) + net_dummy_init(nd); + } + break; +#endif + case NET_IF_DUMMY: + default: + net_dummy_init(nd); + break; + } } - net_init(); /* init the memory */ phys_ram_size = ram_size + vga_ram_size; @@ -2026,7 +2246,7 @@ int main(int argc, char **argv) } 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", + fprintf(stderr, "qemu: could not open floppy disk image '%s'\n", fd_filename[i]); exit(1); } @@ -2034,8 +2254,6 @@ int main(int argc, char **argv) } } - init_timers(); - /* init CPU state */ env = cpu_init(); global_env = env; @@ -2059,25 +2277,13 @@ int main(int argc, char **argv) #endif } -#if defined(TARGET_I386) - pc_init(ram_size, vga_ram_size, boot_device, - ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, initrd_filename); -#elif defined(TARGET_PPC) - 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) #if defined (TARGET_I386) && defined(USE_CODE_COPY) { stack_t stk; - signal_stack = malloc(SIGNAL_STACK_SIZE); + signal_stack = memalign(16, SIGNAL_STACK_SIZE); stk.ss_sp = signal_stack; stk.ss_size = SIGNAL_STACK_SIZE; stk.ss_flags = 0; @@ -2114,6 +2320,21 @@ int main(int argc, char **argv) sigaction(SIGPIPE, &act, NULL); } #endif + init_timers(); + +#if defined(TARGET_I386) + pc_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename); +#elif defined(TARGET_PPC) + ppc_init(ram_size, vga_ram_size, boot_device, + ds, fd_filename, snapshot, + kernel_filename, kernel_cmdline, initrd_filename); +#endif + + /* launched after the device init so that it can display or not a + banner */ + monitor_init(); gui_timer = qemu_new_timer(rt_clock, gui_update, NULL); qemu_mod_timer(gui_timer, qemu_get_clock(rt_clock)); @@ -2129,10 +2350,12 @@ int main(int argc, char **argv) } } else #endif + if (start_emulation) { vm_start(); } term_init(); main_loop(); + quit_timers(); return 0; }