X-Git-Url: http://vcs.maemo.org/git/?a=blobdiff_plain;f=vl.c;h=e828d316ad05bb696990f5946506ca254dc570de;hb=7ef4da1c3a753888e2678388150f1b846b025168;hp=6d319bc3305266789d932d0922568ff6d4067aa9;hpb=d861b05ea30e6ac177de9b679da96194ebe21afc;p=qemu diff --git a/vl.c b/vl.c index 6d319bc..e828d31 100644 --- a/vl.c +++ b/vl.c @@ -47,6 +47,7 @@ #include #endif #else +#ifndef __sun__ #include #include #include @@ -55,6 +56,7 @@ #include #endif #endif +#endif #if defined(CONFIG_SLIRP) #include "libslirp.h" @@ -64,12 +66,12 @@ #include #include #include -#include -#include #define getopt_long_only getopt_long #define memalign(align, size) malloc(size) #endif +#include "qemu_socket.h" + #ifdef CONFIG_SDL #ifdef __APPLE__ #include @@ -137,7 +139,6 @@ int graphic_height = 600; #endif int graphic_depth = 15; int full_screen = 0; -TextConsole *vga_console; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; #ifdef TARGET_I386 @@ -148,6 +149,7 @@ USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; USBDevice *vm_usb_hub; static VLANState *first_vlan; int smp_cpus = 1; +int vnc_display = -1; #if defined(TARGET_SPARC) #define MAX_CPUS 16 #elif defined(TARGET_I386) @@ -155,6 +157,7 @@ int smp_cpus = 1; #else #define MAX_CPUS 1 #endif +int acpi_enabled = 1; /***********************************************************/ /* x86 ISA bus support */ @@ -333,35 +336,6 @@ int strstart(const char *str, const char *val, const char **ptr) return 1; } -/* return the size or -1 if error */ -int get_image_size(const char *filename) -{ - int fd, size; - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - return -1; - size = lseek(fd, 0, SEEK_END); - close(fd); - return size; -} - -/* return the size or -1 if error */ -int load_image(const char *filename, uint8_t *addr) -{ - int fd, size; - fd = open(filename, O_RDONLY | O_BINARY); - if (fd < 0) - return -1; - size = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - if (read(fd, addr, size) != size) { - close(fd); - return -1; - } - close(fd); - return size; -} - void cpu_outb(CPUState *env, int addr, int val) { #ifdef DEBUG_IOPORT @@ -369,6 +343,10 @@ void cpu_outb(CPUState *env, int addr, int val) fprintf(logfile, "outb: %04x %02x\n", addr, val); #endif ioport_write_table[0][addr](ioport_opaque[addr], addr, val); +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); +#endif } void cpu_outw(CPUState *env, int addr, int val) @@ -378,6 +356,10 @@ void cpu_outw(CPUState *env, int addr, int val) fprintf(logfile, "outw: %04x %04x\n", addr, val); #endif ioport_write_table[1][addr](ioport_opaque[addr], addr, val); +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); +#endif } void cpu_outl(CPUState *env, int addr, int val) @@ -387,6 +369,10 @@ void cpu_outl(CPUState *env, int addr, int val) fprintf(logfile, "outl: %04x %08x\n", addr, val); #endif ioport_write_table[2][addr](ioport_opaque[addr], addr, val); +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); +#endif } int cpu_inb(CPUState *env, int addr) @@ -397,6 +383,10 @@ int cpu_inb(CPUState *env, int addr) if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inb : %04x %02x\n", addr, val); #endif +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); +#endif return val; } @@ -408,6 +398,10 @@ int cpu_inw(CPUState *env, int addr) if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inw : %04x %04x\n", addr, val); #endif +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); +#endif return val; } @@ -419,6 +413,10 @@ int cpu_inl(CPUState *env, int addr) if (loglevel & CPU_LOG_IOPORT) fprintf(logfile, "inl : %04x %08x\n", addr, val); #endif +#ifdef USE_KQEMU + if (env) + env->last_io_time = cpu_get_time_fast(); +#endif return val; } @@ -451,6 +449,7 @@ static QEMUPutKBDEvent *qemu_put_kbd_event; static void *qemu_put_kbd_event_opaque; static QEMUPutMouseEvent *qemu_put_mouse_event; static void *qemu_put_mouse_event_opaque; +static int qemu_put_mouse_event_absolute; void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { @@ -458,10 +457,11 @@ void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) qemu_put_kbd_event = func; } -void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque) +void qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute) { qemu_put_mouse_event_opaque = opaque; qemu_put_mouse_event = func; + qemu_put_mouse_event_absolute = absolute; } void kbd_put_keycode(int keycode) @@ -479,6 +479,11 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) } } +int kbd_mouse_is_absolute(void) +{ + return qemu_put_mouse_event_absolute; +} + /***********************************************************/ /* timers */ @@ -514,9 +519,15 @@ int64_t cpu_get_real_ticks(void) int64_t cpu_get_real_ticks(void) { +#ifdef _WIN32 + LARGE_INTEGER ti; + QueryPerformanceCounter(&ti); + return ti.QuadPart; +#else int64_t val; asm volatile ("rdtsc" : "=A" (val)); return val; +#endif } #elif defined(__x86_64__) @@ -554,6 +565,7 @@ int64_t cpu_get_real_ticks(void) #error unsupported CPU #endif +static int64_t cpu_ticks_prev; static int64_t cpu_ticks_offset; static int cpu_ticks_enabled; @@ -562,7 +574,15 @@ static inline int64_t cpu_get_ticks(void) if (!cpu_ticks_enabled) { return cpu_ticks_offset; } else { - return cpu_get_real_ticks() + cpu_ticks_offset; + int64_t ticks; + ticks = cpu_get_real_ticks(); + if (cpu_ticks_prev > ticks) { + /* Note: non increasing ticks may happen if the host uses + software suspend */ + cpu_ticks_offset += cpu_ticks_prev - ticks; + } + cpu_ticks_prev = ticks; + return ticks + cpu_ticks_offset; } } @@ -585,17 +605,26 @@ void cpu_disable_ticks(void) } } -static int64_t get_clock(void) -{ #ifdef _WIN32 - struct _timeb tb; - _ftime(&tb); - return ((int64_t)tb.time * 1000 + (int64_t)tb.millitm) * 1000; +void cpu_calibrate_ticks(void) +{ + LARGE_INTEGER freq; + int ret; + + ret = QueryPerformanceFrequency(&freq); + if (ret == 0) { + fprintf(stderr, "Could not calibrate ticks\n"); + exit(1); + } + ticks_per_sec = freq.QuadPart; +} + #else +static int64_t get_clock(void) +{ struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000000LL + tv.tv_usec; -#endif } void cpu_calibrate_ticks(void) @@ -604,15 +633,12 @@ void cpu_calibrate_ticks(void) usec = get_clock(); ticks = cpu_get_real_ticks(); -#ifdef _WIN32 - Sleep(50); -#else usleep(50 * 1000); -#endif usec = get_clock() - usec; ticks = cpu_get_real_ticks() - ticks; ticks_per_sec = (ticks * 1000000LL + (usec >> 1)) / usec; } +#endif /* !_WIN32 */ /* compute with 96 bit intermediate result: (a*b)/c */ uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) @@ -660,6 +686,8 @@ QEMUClock *vm_clock; static QEMUTimer *active_timers[2]; #ifdef _WIN32 static MMRESULT timerID; +static HANDLE host_alarm = NULL; +static unsigned int period = 1; #else /* frequency of the times() clock tick */ static int timer_freq; @@ -882,6 +910,9 @@ static void host_alarm_handler(int host_signum) qemu_get_clock(vm_clock)) || qemu_timer_expired(active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock))) { +#ifdef _WIN32 + SetEvent(host_alarm); +#endif CPUState *env = cpu_single_env; if (env) { /* stop the currently executing cpu because a timer occured */ @@ -942,8 +973,15 @@ static void init_timers(void) #ifdef _WIN32 { int count=0; + TIMECAPS tc; + + ZeroMemory(&tc, sizeof(TIMECAPS)); + timeGetDevCaps(&tc, sizeof(TIMECAPS)); + if (period < tc.wPeriodMin) + period = tc.wPeriodMin; + timeBeginPeriod(period); timerID = timeSetEvent(1, // interval (ms) - 0, // resolution + period, // resolution host_alarm_handler, // function (DWORD)&count, // user parameter TIME_PERIODIC | TIME_CALLBACK_FUNCTION); @@ -951,6 +989,12 @@ static void init_timers(void) perror("failed timer alarm"); exit(1); } + host_alarm = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!host_alarm) { + perror("failed CreateEvent"); + exit(1); + } + ResetEvent(host_alarm); } pit_min_timer_count = ((uint64_t)10000 * PIT_FREQ) / 1000000; #else @@ -980,7 +1024,11 @@ static void init_timers(void) getitimer(ITIMER_REAL, &itv); #if defined(__linux__) - if (itv.it_interval.tv_usec > 1000) { + /* XXX: force /dev/rtc usage because even 2.6 kernels may not + have timers with 1 ms resolution. The correct solution will + be to use the POSIX real time timers available in recent + 2.6 kernels */ + if (itv.it_interval.tv_usec > 1000 || 1) { /* try to use /dev/rtc to have a faster timer */ if (start_rtc_timer() < 0) goto use_itimer; @@ -1010,6 +1058,11 @@ void quit_timers(void) { #ifdef _WIN32 timeKillEvent(timerID); + timeEndPeriod(period); + if (host_alarm) { + CloseHandle(host_alarm); + host_alarm = NULL; + } #endif } @@ -1081,12 +1134,6 @@ CharDriverState *qemu_chr_open_null(void) #ifdef _WIN32 -#define socket_error() WSAGetLastError() -#undef EINTR -#define EWOULDBLOCK WSAEWOULDBLOCK -#define EINTR WSAEINTR -#define EINPROGRESS WSAEINPROGRESS - static void socket_cleanup(void) { WSACleanup(); @@ -1138,9 +1185,6 @@ void socket_set_nonblock(int fd) #else -#define socket_error() errno -#define closesocket(s) close(s) - static int unix_write(int fd, const uint8_t *buf, int len1) { int ret, len; @@ -1264,7 +1308,7 @@ CharDriverState *qemu_chr_open_file_out(const char *file_out) { int fd_out; - fd_out = open(file_out, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY); + 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); @@ -1690,11 +1734,381 @@ CharDriverState *qemu_chr_open_pty(void) #endif /* !defined(_WIN32) */ +#ifdef _WIN32 +typedef struct { + IOCanRWHandler *fd_can_read; + IOReadHandler *fd_read; + void *win_opaque; + int max_size; + HANDLE hcom, hrecv, hsend; + OVERLAPPED orecv, osend; + BOOL fpipe; + 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_close2(WinCharState *s) +{ + 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, s); + else + qemu_del_polling_cb(win_chr_poll, s); +} + +static void win_chr_close(CharDriverState *chr) +{ + WinCharState *s = chr->opaque; + win_chr_close2(s); +} + +static int win_chr_init(WinCharState *s, const char *filename) +{ + COMMCONFIG comcfg; + COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; + COMSTAT comstat; + DWORD size; + DWORD err; + + 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; + } + + s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL, + OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 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)) { + fprintf(stderr, "Failed SetupComm\n"); + goto fail; + } + + ZeroMemory(&comcfg, sizeof(COMMCONFIG)); + size = sizeof(COMMCONFIG); + GetDefaultCommConfig(filename, &comcfg, &size); + comcfg.dcb.DCBlength = sizeof(DCB); + CommConfigDialog(filename, NULL, &comcfg); + + if (!SetCommState(s->hcom, &comcfg.dcb)) { + fprintf(stderr, "Failed SetCommState\n"); + goto fail; + } + + if (!SetCommMask(s->hcom, EV_ERR)) { + fprintf(stderr, "Failed SetCommMask\n"); + goto fail; + } + + cto.ReadIntervalTimeout = MAXDWORD; + if (!SetCommTimeouts(s->hcom, &cto)) { + fprintf(stderr, "Failed SetCommTimeouts\n"); + goto fail; + } + + if (!ClearCommError(s->hcom, &err, &comstat)) { + fprintf(stderr, "Failed ClearCommError\n"); + goto fail; + } + qemu_add_polling_cb(win_chr_poll, s); + return 0; + + fail: + win_chr_close2(s); + 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; + ZeroMemory(&s->osend, sizeof(s->osend)); + s->osend.hEvent = s->hsend; + while (len > 0) { + if (s->hsend) + ret = WriteFile(s->hcom, buf, len, &size, &s->osend); + else + ret = WriteFile(s->hcom, buf, len, &size, NULL); + if (!ret) { + err = GetLastError(); + 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(WinCharState *s) +{ + s->max_size = s->fd_can_read(s->win_opaque); + return s->max_size; +} + +static void win_chr_readfile(WinCharState *s) +{ + int ret, err; + uint8_t buf[1024]; + DWORD size; + + ZeroMemory(&s->orecv, sizeof(s->orecv)); + s->orecv.hEvent = s->hrecv; + ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv); + if (!ret) { + err = GetLastError(); + if (err == ERROR_IO_PENDING) { + ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE); + } + } + + if (size > 0) { + s->fd_read(s->win_opaque, buf, size); + } +} + +static void win_chr_read(WinCharState *s) +{ + if (s->len > s->max_size) + s->len = s->max_size; + if (s->len == 0) + return; + + win_chr_readfile(s); +} + +static int win_chr_poll(void *opaque) +{ + WinCharState *s = opaque; + COMSTAT status; + DWORD comerr; + + ClearCommError(s->hcom, &comerr, &status); + if (status.cbInQue > 0) { + s->len = status.cbInQue; + win_chr_read_poll(s); + win_chr_read(s); + return 1; + } + return 0; +} + +static void win_chr_add_read_handler(CharDriverState *chr, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, void *opaque) +{ + WinCharState *s = chr->opaque; + + s->fd_can_read = fd_can_read; + s->fd_read = fd_read; + s->win_opaque = opaque; +} + +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_add_read_handler = win_chr_add_read_handler; + chr->chr_close = win_chr_close; + + if (win_chr_init(s, filename) < 0) { + free(s); + free(chr); + return NULL; + } + return chr; +} + +static int win_chr_pipe_poll(void *opaque) +{ + WinCharState *s = opaque; + DWORD size; + + PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL); + if (size > 0) { + s->len = size; + win_chr_read_poll(s); + win_chr_read(s); + return 1; + } + return 0; +} + +static int win_chr_pipe_init(WinCharState *s, const char *filename) +{ + 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, s); + return 0; + + fail: + win_chr_close2(s); + return -1; +} + + +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_add_read_handler = win_chr_add_read_handler; + chr->chr_close = win_chr_close; + + if (win_chr_pipe_init(s, filename) < 0) { + free(s); + free(chr); + return NULL; + } + return chr; +} + +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; + chr->chr_add_read_handler = win_chr_add_read_handler; + return chr; +} + +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 + CharDriverState *qemu_chr_open(const char *filename) { -#ifndef _WIN32 const char *p; -#endif if (!strcmp(filename, "vc")) { return text_console_init(&display_state); @@ -1720,11 +2134,28 @@ CharDriverState *qemu_chr_open(const char *filename) return qemu_chr_open_tty(filename); } else #endif +#ifdef _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, "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 */ @@ -1902,7 +2333,7 @@ static VLANClientState *slirp_vc; int slirp_can_output(void) { - return qemu_can_send_packet(slirp_vc); + return !slirp_vc || qemu_can_send_packet(slirp_vc); } void slirp_output(const uint8_t *pkt, int pkt_len) @@ -1911,6 +2342,8 @@ void slirp_output(const uint8_t *pkt, int pkt_len) printf("slirp output:\n"); hex_dump(stdout, pkt, pkt_len); #endif + if (!slirp_vc) + return; qemu_send_packet(slirp_vc, pkt, pkt_len); } @@ -2141,6 +2574,12 @@ static int tap_open(char *ifname, int ifname_size) fcntl(fd, F_SETFL, O_NONBLOCK); return fd; } +#elif defined(__sun__) +static int tap_open(char *ifname, int ifname_size) +{ + fprintf(stderr, "warning: tap_open not yet implemented\n"); + return -1; +} #else static int tap_open(char *ifname, int ifname_size) { @@ -2718,6 +3157,9 @@ int net_client_init(const char *str) return -1; } } + if (get_param_value(buf, sizeof(buf), "model", p)) { + nd->model = strdup(buf); + } nd->vlan = vlan; nb_nics++; ret = 0; @@ -2729,6 +3171,9 @@ int net_client_init(const char *str) } else #ifdef CONFIG_SLIRP if (!strcmp(device, "user")) { + if (get_param_value(buf, sizeof(buf), "hostname", p)) { + pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf); + } ret = net_slirp_init(vlan); } else #endif @@ -2827,6 +3272,10 @@ static int usb_device_add(const char *devname) dev = usb_mouse_init(); if (!dev) return -1; + } else if (!strcmp(devname, "tablet")) { + dev = usb_tablet_init(); + if (!dev) + return -1; } else { return -1; } @@ -2965,7 +3414,7 @@ static void dumb_resize(DisplayState *ds, int w, int h) static void dumb_refresh(DisplayState *ds) { - vga_update_display(); + vga_hw_update(); } void dumb_display_init(DisplayState *ds) @@ -3062,6 +3511,43 @@ int qemu_set_fd_handler(int fd, } /***********************************************************/ +/* Polling handling */ + +typedef struct PollingEntry { + PollingFunc *func; + void *opaque; + struct PollingEntry *next; +} PollingEntry; + +static PollingEntry *first_polling_entry; + +int qemu_add_polling_cb(PollingFunc *func, void *opaque) +{ + 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) +{ + PollingEntry **ppe, *pe; + for(ppe = &first_polling_entry; *ppe != NULL; ppe = &(*ppe)->next) { + pe = *ppe; + if (pe->func == func && pe->opaque == opaque) { + *ppe = pe->next; + qemu_free(pe); + break; + } + } +} + +/***********************************************************/ /* savevm/loadvm support */ void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) @@ -3924,21 +4410,42 @@ void qemu_system_powerdown_request(void) void main_loop_wait(int timeout) { IOHandlerRecord *ioh, *ioh_next; - fd_set rfds, wfds; + fd_set rfds, wfds, xfds; int ret, nfds; struct timeval tv; + PollingEntry *pe; + + /* XXX: need to suppress polling by better using win32 events */ + ret = 0; + for(pe = first_polling_entry; pe != NULL; pe = pe->next) { + ret |= pe->func(pe->opaque); + } #ifdef _WIN32 - /* XXX: see how to merge it with the select. The constraint is - that the select must be interrupted by the timer */ - if (timeout > 0) - Sleep(timeout); + if (ret == 0 && timeout > 0) { + int err; + HANDLE hEvents[1]; + + hEvents[0] = host_alarm; + ret = WaitForMultipleObjects(1, hEvents, FALSE, timeout); + switch(ret) { + case WAIT_OBJECT_0 + 0: + break; + case WAIT_TIMEOUT: + break; + default: + err = GetLastError(); + fprintf(stderr, "Wait error %d %d\n", ret, err); + break; + } + } #endif /* poll any events */ /* XXX: separate device handlers from system ones */ nfds = -1; FD_ZERO(&rfds); FD_ZERO(&wfds); + FD_ZERO(&xfds); for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { if (ioh->fd_read && (!ioh->fd_read_poll || @@ -3960,7 +4467,12 @@ void main_loop_wait(int timeout) #else tv.tv_usec = timeout * 1000; #endif - ret = select(nfds + 1, &rfds, &wfds, NULL, &tv); +#if defined(CONFIG_SLIRP) + if (slirp_inited) { + slirp_select_fill(&nfds, &rfds, &wfds, &xfds); + } +#endif + ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); if (ret > 0) { /* XXX: better handling of removal */ for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { @@ -3973,30 +4485,19 @@ void main_loop_wait(int timeout) } } } -#ifdef _WIN32 - tap_win32_poll(); -#endif - #if defined(CONFIG_SLIRP) - /* XXX: merge with the previous select() */ 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); + if (ret < 0) { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); } + slirp_select_poll(&rfds, &wfds, &xfds); } #endif +#ifdef _WIN32 + tap_win32_poll(); +#endif if (vm_running) { qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], @@ -4015,6 +4516,9 @@ static CPUState *cur_cpu; int main_loop(void) { int ret, timeout; +#ifdef CONFIG_PROFILER + int64_t ti; +#endif CPUState *env; cur_cpu = first_cpu; @@ -4027,7 +4531,13 @@ int main_loop(void) env = env->next_cpu; if (!env) env = first_cpu; +#ifdef CONFIG_PROFILER + ti = profile_getclock(); +#endif ret = cpu_exec(env); +#ifdef CONFIG_PROFILER + qemu_time += profile_getclock() - ti; +#endif if (ret != EXCP_HALTED) break; /* all CPUs are halted ? */ @@ -4064,7 +4574,13 @@ int main_loop(void) } else { timeout = 10; } +#ifdef CONFIG_PROFILER + ti = profile_getclock(); +#endif main_loop_wait(timeout); +#ifdef CONFIG_PROFILER + dev_time += profile_getclock() - ti; +#endif } cpu_disable_ticks(); return ret; @@ -4110,11 +4626,12 @@ void help(void) #endif "\n" "Network options:\n" - "-net nic[,vlan=n][,macaddr=addr]\n" + "-net nic[,vlan=n][,macaddr=addr][,model=type]\n" " create a new Network Interface Card and connect it to VLAN 'n'\n" #ifdef CONFIG_SLIRP - "-net user[,vlan=n]\n" - " connect the user mode network stack to VLAN 'n'\n" + "-net user[,vlan=n][,hostname=host]\n" + " connect the user mode network stack to VLAN 'n' and send\n" + " hostname 'host' to DHCP clients\n" #endif #ifdef _WIN32 "-net tap[,vlan=n],ifname=name\n" @@ -4159,6 +4676,7 @@ void help(void) " translation (t=none or lba) (usually qemu can guess them)\n" "-L path set the directory for the BIOS and VGA BIOS\n" #ifdef USE_KQEMU + "-kernel-kqemu enable KQEMU full virtualization (default is user mode only)\n" "-no-kqemu disable KQEMU kernel module usage\n" #endif #ifdef USE_CODE_COPY @@ -4167,8 +4685,10 @@ void help(void) #ifdef TARGET_I386 "-std-vga simulate a standard VGA card with VESA Bochs Extensions\n" " (default is CL-GD5446 PCI VGA)\n" + "-no-acpi disable ACPI\n" #endif "-loadvm file start right away with a saved state (loadvm in monitor)\n" + "-vnc display start a VNC server on display\n" "\n" "During emulation, the following keys are useful:\n" "ctrl-alt-f toggle full screen\n" @@ -4247,10 +4767,13 @@ enum { QEMU_OPTION_full_screen, QEMU_OPTION_pidfile, QEMU_OPTION_no_kqemu, + QEMU_OPTION_kernel_kqemu, QEMU_OPTION_win2k_hack, QEMU_OPTION_usb, QEMU_OPTION_usbdevice, QEMU_OPTION_smp, + QEMU_OPTION_vnc, + QEMU_OPTION_no_acpi, }; typedef struct QEMUOption { @@ -4302,6 +4825,7 @@ const QEMUOption qemu_options[] = { { "no-code-copy", 0, QEMU_OPTION_no_code_copy }, #ifdef USE_KQEMU { "no-kqemu", 0, QEMU_OPTION_no_kqemu }, + { "kernel-kqemu", 0, QEMU_OPTION_kernel_kqemu }, #endif #if defined(TARGET_PPC) || defined(TARGET_SPARC) { "g", 1, QEMU_OPTION_g }, @@ -4317,10 +4841,12 @@ const QEMUOption qemu_options[] = { { "win2k-hack", 0, QEMU_OPTION_win2k_hack }, { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, { "smp", HAS_ARG, QEMU_OPTION_smp }, + { "vnc", HAS_ARG, QEMU_OPTION_vnc }, /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, + { "no-acpi", 0, QEMU_OPTION_no_acpi }, { NULL }, }; @@ -4389,7 +4915,12 @@ void register_machines(void) qemu_register_machine(&sun4m_machine); #endif #elif defined(TARGET_ARM) - qemu_register_machine(&integratorcp_machine); + qemu_register_machine(&integratorcp926_machine); + qemu_register_machine(&integratorcp1026_machine); + qemu_register_machine(&versatilepb_machine); + qemu_register_machine(&versatileab_machine); +#elif defined(TARGET_SH4) + qemu_register_machine(&shix_machine); #else #error unsupported CPU #endif @@ -4397,6 +4928,15 @@ void register_machines(void) #ifdef HAS_AUDIO struct soundhw soundhw[] = { +#ifdef TARGET_I386 + { + "pcspk", + "PC speaker", + 0, + 1, + { .init_isa = pcspk_audio_init } + }, +#endif { "sb16", "Creative Sound Blaster 16", @@ -4876,6 +5416,9 @@ int main(int argc, char **argv) case QEMU_OPTION_no_kqemu: kqemu_allowed = 0; break; + case QEMU_OPTION_kernel_kqemu: + kqemu_allowed = 2; + break; #endif case QEMU_OPTION_usb: usb_enabled = 1; @@ -4898,6 +5441,16 @@ int main(int argc, char **argv) exit(1); } break; + case QEMU_OPTION_vnc: + vnc_display = atoi(optarg); + if (vnc_display < 0) { + fprintf(stderr, "Invalid VNC display\n"); + exit(1); + } + break; + case QEMU_OPTION_no_acpi: + acpi_enabled = 0; + break; } } } @@ -5063,6 +5616,8 @@ int main(int argc, char **argv) /* terminal init */ if (nographic) { dumb_display_init(ds); + } else if (vnc_display != -1) { + vnc_display_init(ds, vnc_display); } else { #if defined(CONFIG_SDL) sdl_display_init(ds, full_screen); @@ -5073,8 +5628,6 @@ int main(int argc, char **argv) #endif } - vga_console = graphic_console_init(ds); - monitor_hd = qemu_chr_open(monitor_device); if (!monitor_hd) { fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);