X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/42550fde7e16ac040fbd391bb2c65c3f5fa08d60..833c7174ce5145397d2b3405f6857ca607fed1f1:/vl.c diff --git a/vl.c b/vl.c index bdd46c3283..61c6c1a013 100644 --- a/vl.c +++ b/vl.c @@ -1,7 +1,7 @@ /* * QEMU System Emulator * - * Copyright (c) 2003-2006 Fabrice Bellard + * Copyright (c) 2003-2007 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -55,6 +55,22 @@ #include #include #include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include // must come after ip.h +#include +#include +#include +#include +#include #endif #endif #endif @@ -89,6 +105,11 @@ #include "exec-all.h" #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" +#ifdef __sun__ +#define SMBD_COMMAND "/usr/sfw/sbin/smbd" +#else +#define SMBD_COMMAND "/usr/sbin/smbd" +#endif //#define DEBUG_UNUSED_IOPORT //#define DEBUG_IOPORT @@ -109,8 +130,6 @@ /* XXX: use a two level table to limit memory usage */ #define MAX_IOPORTS 65536 -#define DISK_OPTIONS_SIZE 256 - const char *bios_dir = CONFIG_QEMU_SHAREDIR; char phys_ram_file[1024]; void *ioport_opaque[MAX_IOPORTS]; @@ -119,13 +138,12 @@ IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS]; /* Note: bs_table[MAX_DISKS] is a dummy block driver if none available to store the VM snapshots */ BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD]; +BlockDriverState *pflash_table[MAX_PFLASH]; +BlockDriverState *sd_bdrv; +BlockDriverState *mtd_bdrv; /* point to the block driver where the snapshots are managed */ BlockDriverState *bs_snapshots; -BlockDriverState *bs_scsi_table[MAX_SCSI_DISKS]; -SCSIDiskInfo scsi_disks_info[MAX_SCSI_DISKS]; -int scsi_hba_lsi; /* Count of scsi disks/cdrom using this lsi adapter */ int vga_ram_size; -int bios_size; static DisplayState display_state; int nographic; const char* keyboard_layout = NULL; @@ -139,15 +157,18 @@ QEMUTimer *gui_timer; int vm_running; int rtc_utc = 1; int cirrus_vga_enabled = 1; +int vmsvga_enabled = 0; #ifdef TARGET_SPARC int graphic_width = 1024; int graphic_height = 768; +int graphic_depth = 8; #else int graphic_width = 800; int graphic_height = 600; -#endif int graphic_depth = 15; +#endif int full_screen = 0; +int no_frame = 0; int no_quit = 0; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; @@ -168,7 +189,18 @@ const char *vnc_display; int acpi_enabled = 1; int fd_bootchk = 1; int no_reboot = 0; +int cursor_hide = 1; +int graphic_rotate = 0; int daemonize = 0; +const char *option_rom[MAX_OPTION_ROMS]; +int nb_option_roms; +int semihosting_enabled = 0; +int autostart = 1; +const char *qemu_name; +#ifdef TARGET_SPARC +unsigned int nb_prom_envs = 0; +const char *prom_envs[MAX_PROM_ENVS]; +#endif /***********************************************************/ /* x86 ISA bus support */ @@ -179,7 +211,7 @@ PicState2 *isa_pic; uint32_t default_ioport_readb(void *opaque, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT - fprintf(stderr, "inb: port=0x%04x\n", address); + fprintf(stderr, "unused inb: port=0x%04x\n", address); #endif return 0xff; } @@ -187,7 +219,7 @@ uint32_t default_ioport_readb(void *opaque, uint32_t address) 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); + fprintf(stderr, "unused outb: port=0x%04x data=0x%02x\n", address, data); #endif } @@ -211,7 +243,7 @@ void default_ioport_writew(void *opaque, uint32_t address, uint32_t data) uint32_t default_ioport_readl(void *opaque, uint32_t address) { #ifdef DEBUG_UNUSED_IOPORT - fprintf(stderr, "inl: port=0x%04x\n", address); + fprintf(stderr, "unused inl: port=0x%04x\n", address); #endif return 0xffffffff; } @@ -219,7 +251,7 @@ uint32_t default_ioport_readl(void *opaque, uint32_t address) 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); + fprintf(stderr, "unused outl: port=0x%04x data=0x%02x\n", address, data); #endif } @@ -281,7 +313,7 @@ int register_ioport_write(int start, int length, int 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"); + hw_error("register_ioport_write: invalid opaque"); ioport_opaque[i] = opaque; } return 0; @@ -304,49 +336,6 @@ void isa_unassign_ioport(int start, int length) /***********************************************************/ -void pstrcpy(char *buf, int buf_size, const char *str) -{ - int c; - char *q = buf; - - if (buf_size <= 0) - return; - - for(;;) { - c = *str++; - if (c == 0 || q >= buf + buf_size - 1) - break; - *q++ = c; - } - *q = '\0'; -} - -/* strcat and truncate. */ -char *pstrcat(char *buf, int buf_size, const char *s) -{ - int len; - len = strlen(buf); - if (len < buf_size) - pstrcpy(buf + len, buf_size - len, s); - return buf; -} - -int strstart(const char *str, const char *val, const char **ptr) -{ - const char *p, *q; - p = str; - q = val; - while (*q != '\0') { - if (*p != *q) - return 0; - p++; - q++; - } - if (ptr) - *ptr = p; - return 1; -} - void cpu_outb(CPUState *env, int addr, int val) { #ifdef DEBUG_IOPORT @@ -458,9 +447,8 @@ void hw_error(const char *fmt, ...) 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; +static QEMUPutMouseEntry *qemu_put_mouse_event_head; +static QEMUPutMouseEntry *qemu_put_mouse_event_current; void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { @@ -468,11 +456,68 @@ 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, int absolute) +QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, + void *opaque, int absolute, + const char *name) +{ + QEMUPutMouseEntry *s, *cursor; + + s = qemu_mallocz(sizeof(QEMUPutMouseEntry)); + if (!s) + return NULL; + + s->qemu_put_mouse_event = func; + s->qemu_put_mouse_event_opaque = opaque; + s->qemu_put_mouse_event_absolute = absolute; + s->qemu_put_mouse_event_name = qemu_strdup(name); + s->next = NULL; + + if (!qemu_put_mouse_event_head) { + qemu_put_mouse_event_head = qemu_put_mouse_event_current = s; + return s; + } + + cursor = qemu_put_mouse_event_head; + while (cursor->next != NULL) + cursor = cursor->next; + + cursor->next = s; + qemu_put_mouse_event_current = s; + + return s; +} + +void qemu_remove_mouse_event_handler(QEMUPutMouseEntry *entry) { - qemu_put_mouse_event_opaque = opaque; - qemu_put_mouse_event = func; - qemu_put_mouse_event_absolute = absolute; + QEMUPutMouseEntry *prev = NULL, *cursor; + + if (!qemu_put_mouse_event_head || entry == NULL) + return; + + cursor = qemu_put_mouse_event_head; + while (cursor != NULL && cursor != entry) { + prev = cursor; + cursor = cursor->next; + } + + if (cursor == NULL) // does not exist or list empty + return; + else if (prev == NULL) { // entry is head + qemu_put_mouse_event_head = cursor->next; + if (qemu_put_mouse_event_current == entry) + qemu_put_mouse_event_current = cursor->next; + qemu_free(entry->qemu_put_mouse_event_name); + qemu_free(entry); + return; + } + + prev->next = entry->next; + + if (qemu_put_mouse_event_current == entry) + qemu_put_mouse_event_current = prev; + + qemu_free(entry->qemu_put_mouse_event_name); + qemu_free(entry); } void kbd_put_keycode(int keycode) @@ -484,15 +529,82 @@ void kbd_put_keycode(int keycode) void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) { - if (qemu_put_mouse_event) { - qemu_put_mouse_event(qemu_put_mouse_event_opaque, - dx, dy, dz, buttons_state); + QEMUPutMouseEvent *mouse_event; + void *mouse_event_opaque; + int width; + + if (!qemu_put_mouse_event_current) { + return; + } + + mouse_event = + qemu_put_mouse_event_current->qemu_put_mouse_event; + mouse_event_opaque = + qemu_put_mouse_event_current->qemu_put_mouse_event_opaque; + + if (mouse_event) { + if (graphic_rotate) { + if (qemu_put_mouse_event_current->qemu_put_mouse_event_absolute) + width = 0x7fff; + else + width = graphic_width; + mouse_event(mouse_event_opaque, + width - dy, dx, dz, buttons_state); + } else + mouse_event(mouse_event_opaque, + dx, dy, dz, buttons_state); } } int kbd_mouse_is_absolute(void) { - return qemu_put_mouse_event_absolute; + if (!qemu_put_mouse_event_current) + return 0; + + return qemu_put_mouse_event_current->qemu_put_mouse_event_absolute; +} + +void do_info_mice(void) +{ + QEMUPutMouseEntry *cursor; + int index = 0; + + if (!qemu_put_mouse_event_head) { + term_printf("No mouse devices connected\n"); + return; + } + + term_printf("Mouse devices available:\n"); + cursor = qemu_put_mouse_event_head; + while (cursor != NULL) { + term_printf("%c Mouse #%d: %s\n", + (cursor == qemu_put_mouse_event_current ? '*' : ' '), + index, cursor->qemu_put_mouse_event_name); + index++; + cursor = cursor->next; + } +} + +void do_mouse_set(int index) +{ + QEMUPutMouseEntry *cursor; + int i = 0; + + if (!qemu_put_mouse_event_head) { + term_printf("No mouse devices connected\n"); + return; + } + + cursor = qemu_put_mouse_event_head; + while (cursor != NULL && index != i) { + i++; + cursor = cursor->next; + } + + if (cursor != NULL) + qemu_put_mouse_event_current = cursor; + else + term_printf("Mouse at given index not found\n"); } /* compute with 96 bit intermediate result: (a*b)/c */ @@ -1045,6 +1157,29 @@ void quit_timers(void) /***********************************************************/ /* character device */ +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; + qemu_chr_event(s, CHR_EVENT_RESET); + qemu_bh_delete(s->bh); + s->bh = NULL; +} + +void qemu_chr_reset(CharDriverState *s) +{ + if (s->bh == NULL) { + s->bh = qemu_bh_new(qemu_chr_reset_bh, s); + qemu_bh_schedule(s->bh); + } +} + int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len) { return s->chr_write(s, buf, len); @@ -1057,6 +1192,19 @@ int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg) return s->chr_ioctl(s, cmd, arg); } +int qemu_chr_can_read(CharDriverState *s) +{ + if (!s->chr_can_read) + return 0; + return s->chr_can_read(s->handler_opaque); +} + +void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len) +{ + s->chr_read(s->handler_opaque, buf, len); +} + + void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) { char buf[4096]; @@ -1073,41 +1221,249 @@ void qemu_chr_send_event(CharDriverState *s, int event) s->chr_send_event(s, event); } -void qemu_chr_add_read_handler(CharDriverState *s, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +void qemu_chr_add_handlers(CharDriverState *s, + IOCanRWHandler *fd_can_read, + IOReadHandler *fd_read, + IOEventHandler *fd_event, + void *opaque) { - s->chr_add_read_handler(s, fd_can_read, fd_read, opaque); + s->chr_can_read = fd_can_read; + 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); } -void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event) +static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { - s->chr_event = chr_event; + return len; } -static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +static CharDriverState *qemu_chr_open_null(void) { - return len; + CharDriverState *chr; + + chr = qemu_mallocz(sizeof(CharDriverState)); + if (!chr) + return NULL; + chr->chr_write = null_chr_write; + return chr; } -static void null_chr_add_read_handler(CharDriverState *chr, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +/* MUX driver for serial I/O splitting */ +static int term_timestamps; +static int64_t term_timestamps_start; +#define MAX_MUX 4 +typedef struct { + IOCanRWHandler *chr_can_read[MAX_MUX]; + IOReadHandler *chr_read[MAX_MUX]; + IOEventHandler *chr_event[MAX_MUX]; + void *ext_opaque[MAX_MUX]; + CharDriverState *drv; + int mux_cnt; + int term_got_escape; + int max_size; +} MuxDriver; + + +static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { + MuxDriver *d = chr->opaque; + int ret; + if (!term_timestamps) { + ret = d->drv->chr_write(d->drv, buf, len); + } else { + int i; + + ret = 0; + for(i = 0; i < len; i++) { + ret += d->drv->chr_write(d->drv, buf+i, 1); + if (buf[i] == '\n') { + char buf1[64]; + int64_t ti; + int secs; + + ti = get_clock(); + if (term_timestamps_start == -1) + term_timestamps_start = ti; + 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, buf1, strlen(buf1)); + } + } + } + return ret; } -CharDriverState *qemu_chr_open_null(void) +static char *mux_help[] = { + "% h print this help\n\r", + "% 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; + char ebuf[15] = "Escape-Char"; + 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, 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, ebuf, strlen(ebuf)); + else + chr->chr_write(chr, &mux_help[i][j], 1); + } + } +} + +static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) +{ + if (d->term_got_escape) { + d->term_got_escape = 0; + if (ch == term_escape_char) + goto send_char; + switch(ch) { + case '?': + case 'h': + mux_print_help(chr); + break; + case 'x': + { + char *term = "QEMU: Terminated\n\r"; + chr->chr_write(chr,term,strlen(term)); + exit(0); + break; + } + case 's': + { + int i; + for (i = 0; i < MAX_DISKS; i++) { + if (bs_table[i]) + bdrv_commit(bs_table[i]); + } + if (mtd_bdrv) + bdrv_commit(mtd_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; + case 't': + 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; +} + +static int mux_chr_can_read(void *opaque) +{ + CharDriverState *chr = opaque; + MuxDriver *d = chr->opaque; + 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) +{ + CharDriverState *chr = opaque; + MuxDriver *d = chr->opaque; + int i; + for(i = 0; i < size; i++) + if (mux_proc_byte(chr, d, buf[i])) + d->chr_read[chr->focus](d->ext_opaque[chr->focus], &buf[i], 1); +} + +static void mux_chr_event(void *opaque, int event) +{ + CharDriverState *chr = opaque; + MuxDriver *d = chr->opaque; + int i; + + /* Send the event to all registered listeners */ + 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) +{ + MuxDriver *d = chr->opaque; + + if (d->mux_cnt >= MAX_MUX) { + fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n"); + return; + } + d->ext_opaque[d->mux_cnt] = chr->handler_opaque; + d->chr_can_read[d->mux_cnt] = chr->chr_can_read; + d->chr_read[d->mux_cnt] = chr->chr_read; + d->chr_event[d->mux_cnt] = chr->chr_event; + /* 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++; +} + +CharDriverState *qemu_chr_open_mux(CharDriverState *drv) { CharDriverState *chr; + MuxDriver *d; chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) return NULL; - chr->chr_write = null_chr_write; - chr->chr_add_read_handler = null_chr_add_read_handler; + d = qemu_mallocz(sizeof(MuxDriver)); + if (!d) { + free(chr); + return NULL; + } + + chr->opaque = d; + d->drv = drv; + chr->focus = -1; + chr->chr_write = mux_chr_write; + chr->chr_update_read_handler = mux_chr_update_read_handler; return chr; } + #ifdef _WIN32 static void socket_cleanup(void) @@ -1196,16 +1552,11 @@ void socket_set_nonblock(int fd) typedef struct { int fd_in, fd_out; - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *fd_opaque; int max_size; } FDCharDriver; -#define STDIO_MAX_CLIENTS 2 - -static int stdio_nb_clients; -static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; +#define STDIO_MAX_CLIENTS 1 +static int stdio_nb_clients = 0; static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { @@ -1218,7 +1569,7 @@ static int fd_chr_read_poll(void *opaque) CharDriverState *chr = opaque; FDCharDriver *s = chr->opaque; - s->max_size = s->fd_can_read(s->fd_opaque); + s->max_size = qemu_chr_can_read(chr); return s->max_size; } @@ -1241,20 +1592,15 @@ static void fd_chr_read(void *opaque) return; } if (size > 0) { - s->fd_read(s->fd_opaque, buf, size); + qemu_chr_read(chr, buf, size); } } -static void fd_chr_add_read_handler(CharDriverState *chr, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +static void fd_chr_update_read_handler(CharDriverState *chr) { FDCharDriver *s = chr->opaque; if (s->fd_in >= 0) { - s->fd_can_read = fd_can_read; - s->fd_read = fd_read; - s->fd_opaque = opaque; if (nographic && s->fd_in == 0) { } else { qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, @@ -1264,7 +1610,7 @@ static void fd_chr_add_read_handler(CharDriverState *chr, } /* open a character device to a unix fd */ -CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) +static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) { CharDriverState *chr; FDCharDriver *s; @@ -1281,11 +1627,14 @@ CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out) s->fd_out = fd_out; chr->opaque = s; chr->chr_write = fd_chr_write; - chr->chr_add_read_handler = fd_chr_add_read_handler; + chr->chr_update_read_handler = fd_chr_update_read_handler; + + qemu_chr_reset(chr); + return chr; } -CharDriverState *qemu_chr_open_file_out(const char *file_out) +static CharDriverState *qemu_chr_open_file_out(const char *file_out) { int fd_out; @@ -1295,180 +1644,70 @@ CharDriverState *qemu_chr_open_file_out(const char *file_out) return qemu_chr_open_fd(-1, fd_out); } -CharDriverState *qemu_chr_open_pipe(const char *filename) +static CharDriverState *qemu_chr_open_pipe(const char *filename) { - int fd; - - fd = open(filename, O_RDWR | O_BINARY); - if (fd < 0) - return NULL; - return qemu_chr_open_fd(fd, fd); + int fd_in, fd_out; + char filename_in[256], filename_out[256]; + + snprintf(filename_in, 256, "%s.in", filename); + snprintf(filename_out, 256, "%s.out", filename); + fd_in = open(filename_in, O_RDWR | O_BINARY); + fd_out = open(filename_out, O_RDWR | O_BINARY); + if (fd_in < 0 || fd_out < 0) { + if (fd_in >= 0) + close(fd_in); + if (fd_out >= 0) + close(fd_out); + fd_in = fd_out = open(filename, O_RDWR | O_BINARY); + 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 (nographic mode) */ -#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */ - #define TERM_FIFO_MAX_SIZE 1 -static int term_got_escape, client_index; static uint8_t term_fifo[TERM_FIFO_MAX_SIZE]; static int term_fifo_size; -static int term_timestamps; -static int64_t term_timestamps_start; - -void term_print_help(void) -{ - printf("\n" - "C-a h print this help\n" - "C-a x exit emulator\n" - "C-a s save disk data back to file (if -snapshot)\n" - "C-a b send break (magic sysrq)\n" - "C-a t toggle console timestamps\n" - "C-a c switch between console and monitor\n" - "C-a C-a send C-a\n" - ); -} - -/* called when a char is received */ -static void stdio_received_byte(int ch) -{ - 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': - if (client_index < stdio_nb_clients) { - CharDriverState *chr; - FDCharDriver *s; - - chr = stdio_clients[client_index]; - s = chr->opaque; - chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK); - } - break; - case 'c': - client_index++; - if (client_index >= stdio_nb_clients) - client_index = 0; - if (client_index == 0) { - /* send a new line in the monitor to get the prompt */ - ch = '\r'; - goto send_char; - } - break; - case 't': - term_timestamps = !term_timestamps; - term_timestamps_start = -1; - break; - case TERM_ESCAPE: - goto send_char; - } - } else if (ch == TERM_ESCAPE) { - term_got_escape = 1; - } else { - send_char: - if (client_index < stdio_nb_clients) { - uint8_t buf[1]; - CharDriverState *chr; - FDCharDriver *s; - - chr = stdio_clients[client_index]; - s = chr->opaque; - if (s->fd_can_read(s->fd_opaque) > 0) { - buf[0] = ch; - s->fd_read(s->fd_opaque, buf, 1); - } else if (term_fifo_size == 0) { - term_fifo[term_fifo_size++] = ch; - } - } - } -} static int stdio_read_poll(void *opaque) { - CharDriverState *chr; - FDCharDriver *s; + CharDriverState *chr = opaque; - if (client_index < stdio_nb_clients) { - chr = stdio_clients[client_index]; - s = chr->opaque; - /* try to flush the queue if needed */ - if (term_fifo_size != 0 && s->fd_can_read(s->fd_opaque) > 0) { - s->fd_read(s->fd_opaque, term_fifo, 1); - term_fifo_size = 0; - } - /* see if we can absorb more chars */ - if (term_fifo_size == 0) - return 1; - else - return 0; - } else { - return 1; + /* try to flush the queue if needed */ + if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) { + qemu_chr_read(chr, term_fifo, 1); + term_fifo_size = 0; } + /* see if we can absorb more chars */ + if (term_fifo_size == 0) + return 1; + else + return 0; } static void stdio_read(void *opaque) { int size; 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) - stdio_received_byte(buf[0]); -} - -static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len) -{ - FDCharDriver *s = chr->opaque; - if (!term_timestamps) { - return unix_write(s->fd_out, buf, len); - } else { - int i; - char buf1[64]; - - for(i = 0; i < len; i++) { - unix_write(s->fd_out, buf + i, 1); - if (buf[i] == '\n') { - int64_t ti; - int secs; - - ti = get_clock(); - if (term_timestamps_start == -1) - term_timestamps_start = ti; - 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)); - unix_write(s->fd_out, buf1, strlen(buf1)); - } + 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]; } - return len; } } @@ -1509,33 +1748,22 @@ static void term_init(void) fcntl(0, F_SETFL, O_NONBLOCK); } -CharDriverState *qemu_chr_open_stdio(void) +static CharDriverState *qemu_chr_open_stdio(void) { CharDriverState *chr; - if (nographic) { - if (stdio_nb_clients >= STDIO_MAX_CLIENTS) - return NULL; - chr = qemu_chr_open_fd(0, 1); - chr->chr_write = stdio_write; - if (stdio_nb_clients == 0) - qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL); - client_index = stdio_nb_clients; - } else { - if (stdio_nb_clients != 0) - return NULL; - chr = qemu_chr_open_fd(0, 1); - } - stdio_clients[stdio_nb_clients++] = chr; - if (stdio_nb_clients == 1) { - /* set the terminal in raw mode */ - term_init(); - } + 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__) -CharDriverState *qemu_chr_open_pty(void) +static CharDriverState *qemu_chr_open_pty(void) { struct termios tty; char slave_name[1024]; @@ -1674,7 +1902,7 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } -CharDriverState *qemu_chr_open_tty(const char *filename) +static CharDriverState *qemu_chr_open_tty(const char *filename) { CharDriverState *chr; int fd; @@ -1688,12 +1916,30 @@ CharDriverState *qemu_chr_open_tty(const char *filename) if (!chr) return NULL; chr->chr_ioctl = tty_serial_ioctl; + qemu_chr_reset(chr); return chr; } +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) { - int fd = (int)chr->opaque; + ParallelCharDriver *drv = chr->opaque; + int fd = drv->fd; uint8_t b; switch(cmd) { @@ -1710,7 +1956,10 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) case CHR_IOCTL_PP_READ_CONTROL: if (ioctl(fd, PPRCONTROL, &b) < 0) return -ENOTSUP; - *(uint8_t *)arg = b; + /* 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; @@ -1722,15 +1971,63 @@ static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) 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; } -CharDriverState *qemu_chr_open_pp(const char *filename) +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; fd = open(filename, O_RDWR); @@ -1742,20 +2039,32 @@ CharDriverState *qemu_chr_open_pp(const char *filename) 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 (!chr) { + qemu_free(drv); close(fd); return NULL; } - chr->opaque = (void *)fd; chr->chr_write = null_chr_write; - chr->chr_add_read_handler = null_chr_add_read_handler; chr->chr_ioctl = pp_ioctl; + chr->chr_close = pp_close; + chr->opaque = drv; + + qemu_chr_reset(chr); + return chr; } #else -CharDriverState *qemu_chr_open_pty(void) +static CharDriverState *qemu_chr_open_pty(void) { return NULL; } @@ -1765,9 +2074,6 @@ CharDriverState *qemu_chr_open_pty(void) #ifdef _WIN32 typedef struct { - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *win_opaque; int max_size; HANDLE hcom, hrecv, hsend; OVERLAPPED orecv, osend; @@ -1783,8 +2089,10 @@ typedef struct { static int win_chr_poll(void *opaque); static int win_chr_pipe_poll(void *opaque); -static void win_chr_close2(WinCharState *s) +static void win_chr_close(CharDriverState *chr) { + WinCharState *s = chr->opaque; + if (s->hsend) { CloseHandle(s->hsend); s->hsend = NULL; @@ -1798,19 +2106,14 @@ static void win_chr_close2(WinCharState *s) s->hcom = NULL; } if (s->fpipe) - qemu_del_polling_cb(win_chr_pipe_poll, s); + qemu_del_polling_cb(win_chr_pipe_poll, chr); else - qemu_del_polling_cb(win_chr_poll, s); + qemu_del_polling_cb(win_chr_poll, chr); } -static void win_chr_close(CharDriverState *chr) +static int win_chr_init(CharDriverState *chr, const char *filename) { 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; @@ -1867,11 +2170,11 @@ static int win_chr_init(WinCharState *s, const char *filename) fprintf(stderr, "Failed ClearCommError\n"); goto fail; } - qemu_add_polling_cb(win_chr_poll, s); + qemu_add_polling_cb(win_chr_poll, chr); return 0; fail: - win_chr_close2(s); + win_chr_close(chr); return -1; } @@ -1909,14 +2212,17 @@ static int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1) return len1 - len; } -static int win_chr_read_poll(WinCharState *s) +static int win_chr_read_poll(CharDriverState *chr) { - s->max_size = s->fd_can_read(s->win_opaque); + WinCharState *s = chr->opaque; + + s->max_size = qemu_chr_can_read(chr); return s->max_size; } - -static void win_chr_readfile(WinCharState *s) + +static void win_chr_readfile(CharDriverState *chr) { + WinCharState *s = chr->opaque; int ret, err; uint8_t buf[1024]; DWORD size; @@ -1932,48 +2238,40 @@ static void win_chr_readfile(WinCharState *s) } if (size > 0) { - s->fd_read(s->win_opaque, buf, size); + qemu_chr_read(chr, buf, size); } } -static void win_chr_read(WinCharState *s) +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(s); + win_chr_readfile(chr); } static int win_chr_poll(void *opaque) { - WinCharState *s = 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(s); - win_chr_read(s); + win_chr_read_poll(chr); + win_chr_read(chr); 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) +static CharDriverState *qemu_chr_open_win(const char *filename) { CharDriverState *chr; WinCharState *s; @@ -1988,34 +2286,36 @@ CharDriverState *qemu_chr_open_win(const char *filename) } 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) { + 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) { - WinCharState *s = 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(s); - win_chr_read(s); + win_chr_read_poll(chr); + win_chr_read(chr); return 1; } return 0; } -static int win_chr_pipe_init(WinCharState *s, const char *filename) +static int win_chr_pipe_init(CharDriverState *chr, const char *filename) { + WinCharState *s = chr->opaque; OVERLAPPED ov; int ret; DWORD size; @@ -2067,16 +2367,16 @@ static int win_chr_pipe_init(WinCharState *s, const char *filename) CloseHandle(ov.hEvent); ov.hEvent = NULL; } - qemu_add_polling_cb(win_chr_pipe_poll, s); + qemu_add_polling_cb(win_chr_pipe_poll, chr); return 0; fail: - win_chr_close2(s); + win_chr_close(chr); return -1; } -CharDriverState *qemu_chr_open_win_pipe(const char *filename) +static CharDriverState *qemu_chr_open_win_pipe(const char *filename) { CharDriverState *chr; WinCharState *s; @@ -2091,18 +2391,18 @@ CharDriverState *qemu_chr_open_win_pipe(const char *filename) } 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) { + if (win_chr_pipe_init(chr, filename) < 0) { free(s); free(chr); return NULL; } + qemu_chr_reset(chr); return chr; } -CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) +static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) { CharDriverState *chr; WinCharState *s; @@ -2118,11 +2418,16 @@ CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) s->hcom = fd_out; chr->opaque = s; chr->chr_write = win_chr_write; - chr->chr_add_read_handler = win_chr_add_read_handler; + qemu_chr_reset(chr); return chr; } - -CharDriverState *qemu_chr_open_win_file_out(const char *file_out) + +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; @@ -2139,9 +2444,6 @@ CharDriverState *qemu_chr_open_win_file_out(const char *file_out) /* UDP Net console */ typedef struct { - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *fd_opaque; int fd; struct sockaddr_in daddr; char buf[1024]; @@ -2163,15 +2465,15 @@ static int udp_chr_read_poll(void *opaque) CharDriverState *chr = opaque; NetCharDriver *s = chr->opaque; - s->max_size = s->fd_can_read(s->fd_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) { - s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1); + qemu_chr_read(chr, &s->buf[s->bufptr], 1); s->bufptr++; - s->max_size = s->fd_can_read(s->fd_opaque); + s->max_size = qemu_chr_can_read(chr); } return s->max_size; } @@ -2190,34 +2492,31 @@ static void udp_chr_read(void *opaque) s->bufptr = 0; while (s->max_size > 0 && s->bufptr < s->bufcnt) { - s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1); + qemu_chr_read(chr, &s->buf[s->bufptr], 1); s->bufptr++; - s->max_size = s->fd_can_read(s->fd_opaque); + s->max_size = qemu_chr_can_read(chr); } } -static void udp_chr_add_read_handler(CharDriverState *chr, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) +static void udp_chr_update_read_handler(CharDriverState *chr) { NetCharDriver *s = chr->opaque; if (s->fd >= 0) { - s->fd_can_read = fd_can_read; - s->fd_read = fd_read; - s->fd_opaque = opaque; 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); -int parse_unix_path(struct sockaddr_un *uaddr, 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); -CharDriverState *qemu_chr_open_udp(const char *def) +static CharDriverState *qemu_chr_open_udp(const char *def) { CharDriverState *chr = NULL; NetCharDriver *s = NULL; @@ -2253,7 +2552,7 @@ CharDriverState *qemu_chr_open_udp(const char *def) s->bufptr = 0; chr->opaque = s; chr->chr_write = udp_chr_write; - chr->chr_add_read_handler = udp_chr_add_read_handler; + chr->chr_update_read_handler = udp_chr_update_read_handler; return chr; return_err: @@ -2270,13 +2569,11 @@ return_err: /* TCP Net console */ typedef struct { - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *fd_opaque; int fd, listen_fd; int connected; int max_size; int do_telnetopt; + int do_nodelay; int is_unix; } TCPCharDriver; @@ -2299,9 +2596,7 @@ static int tcp_chr_read_poll(void *opaque) TCPCharDriver *s = chr->opaque; if (!s->connected) return 0; - if (!s->fd_can_read) - return 0; - s->max_size = s->fd_can_read(s->fd_opaque); + s->max_size = qemu_chr_can_read(chr); return s->max_size; } @@ -2334,7 +2629,7 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr, } else { if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) { /* Handle IAC break commands by sending a serial break */ - chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK); + qemu_chr_event(chr, CHR_EVENT_BREAK); s->do_telnetopt++; } s->do_telnetopt++; @@ -2381,21 +2676,10 @@ static void tcp_chr_read(void *opaque) if (s->do_telnetopt) tcp_chr_process_IAC_bytes(chr, s, buf, &size); if (size > 0) - s->fd_read(s->fd_opaque, buf, size); + qemu_chr_read(chr, buf, size); } } -static void tcp_chr_add_read_handler(CharDriverState *chr, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) -{ - TCPCharDriver *s = chr->opaque; - - s->fd_can_read = fd_can_read; - s->fd_read = fd_read; - s->fd_opaque = opaque; -} - static void tcp_chr_connect(void *opaque) { CharDriverState *chr = opaque; @@ -2404,6 +2688,7 @@ static void tcp_chr_connect(void *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; @@ -2421,6 +2706,12 @@ static void tcp_chr_telnet_init(int fd) 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; @@ -2454,6 +2745,8 @@ static void tcp_chr_accept(void *opaque) } } 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); @@ -2478,6 +2771,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, 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 @@ -2508,6 +2802,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, 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; @@ -2540,10 +2836,10 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, 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_add_read_handler = tcp_chr_add_read_handler; chr->chr_close = tcp_chr_close; if (is_listen) { @@ -2581,6 +2877,10 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, if (err == EINTR || err == EWOULDBLOCK) { } else if (err == EINPROGRESS) { break; +#ifdef _WIN32 + } else if (err == WSAEALREADY) { + break; +#endif } else { goto fail; } @@ -2590,6 +2890,7 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, } } s->fd = fd; + socket_set_nodelay(fd); if (s->connected) tcp_chr_connect(chr); else @@ -2629,6 +2930,16 @@ CharDriverState *qemu_chr_open(const char *filename) 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); @@ -2657,6 +2968,9 @@ CharDriverState *qemu_chr_open(const char *filename) 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); } @@ -2807,7 +3121,8 @@ int parse_host_port(struct sockaddr_in *saddr, const char *str) return 0; } -int parse_unix_path(struct sockaddr_un *uaddr, const char *str) +#ifndef _WIN32 +static int parse_unix_path(struct sockaddr_un *uaddr, const char *str) { const char *p; int len; @@ -2824,6 +3139,7 @@ int parse_unix_path(struct sockaddr_un *uaddr, const char *str) return 0; } +#endif /* find or alloc a new VLAN */ VLANState *qemu_find_vlan(int id) @@ -3069,8 +3385,8 @@ void net_slirp_smb(const char *exported_dir) fclose(f); atexit(smb_exit); - snprintf(smb_cmdline, sizeof(smb_cmdline), "/usr/sbin/smbd -s %s", - smb_conf); + snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s", + SMBD_COMMAND, smb_conf); slirp_add_exec(0, smb_cmdline, 4, 139); } @@ -3105,7 +3421,15 @@ static void tap_send(void *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); } @@ -3148,10 +3472,135 @@ static int tap_open(char *ifname, int ifname_size) 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); + + if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){ + syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)"); + return -1; + } + + if( (tap_fd = open("/dev/tap", O_RDWR, 0)) < 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"); + + if( (if_fd = open("/dev/tap", O_RDWR, 0)) < 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 */ + if ((arp_fd = open ("/dev/tap", O_RDWR, 0)) < 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 *)𝔦 + 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) { - fprintf(stderr, "warning: tap_open not yet implemented\n"); - return -1; + 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) @@ -3199,13 +3648,21 @@ static int net_tap_init(VLANState *vlan, const char *ifname1, if (fd < 0) return -1; - if (!setup_script) + if (!setup_script || !strcmp(setup_script, "no")) setup_script = ""; if (setup_script[0] != '\0') { /* try to launch network init 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++ = ifname; @@ -3487,7 +3944,7 @@ static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, int so_type=-1, optlen=sizeof(so_type); if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, &optlen)< 0) { - fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd); + fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd); return NULL; } switch(so_type) { @@ -3594,6 +4051,10 @@ static int net_socket_connect_init(VLANState *vlan, const char *host_str) if (err == EINTR || err == EWOULDBLOCK) { } else if (err == EINPROGRESS) { break; +#ifdef _WIN32 + } else if (err == WSAEALREADY) { + break; +#endif } else { perror("connect"); closesocket(fd); @@ -3680,7 +4141,7 @@ static int get_param_value(char *buf, int buf_size, return 0; } -int net_client_init(const char *str) +static int net_client_init(const char *str) { const char *p; char *q; @@ -3736,6 +4197,7 @@ int net_client_init(const char *str) } nd->vlan = vlan; nb_nics++; + vlan->nb_guest_devs++; ret = 0; } else if (!strcmp(device, "none")) { @@ -3748,6 +4210,7 @@ int net_client_init(const char *str) 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 @@ -3755,235 +4218,75 @@ int net_client_init(const char *str) 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; - } - ret = tap_win32_init(vlan, ifname); - } else -#else - if (!strcmp(device, "tap")) { - char ifname[64]; - char setup_script[1024]; - int fd; - 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 { - get_param_value(ifname, sizeof(ifname), "ifname", p); - if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { - pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); - } - ret = net_tap_init(vlan, ifname, setup_script); - } - } 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; - } - } 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); - } -} - -/* Parse IDE and SCSI disk options */ -static int disk_options_init(int num_ide_disks, - char ide_disk_options[][DISK_OPTIONS_SIZE], - int snapshot, - int num_scsi_disks, - char scsi_disk_options[][DISK_OPTIONS_SIZE], - int cdrom_index, - int cyls, - int heads, - int secs, - int translation) -{ - char buf[256]; - char dev_name[64]; - int id, i, j; - int cdrom_device; - int ide_cdrom_created = 0; - int scsi_index; - scsi_host_adapters temp_adapter; - - /* Process any IDE disks/cdroms */ - for (i=0; i< num_ide_disks; i++) { - for (j=0; j= 0 && (!ide_cdrom_created)) { - bs_table[cdrom_index] = bdrv_new("cdrom"); - bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); - } - - for(i = 0; i < num_scsi_disks; i++) { - - temp_adapter = SCSI_LSI_53C895A; - scsi_hba_lsi++; - - /*Check for sdx= parameter */ - if (get_param_value(buf, sizeof(buf), "sdx", scsi_disk_options[i])) { - if (buf[0] >= 'a' && buf[0] <= 'g') { - scsi_index = buf[0] - 'a'; - } else{ - fprintf(stderr, "qemu: sdx= option for SCSI must be one letter from a-g. %s \n",buf); - exit(1); - } - } else { - scsi_index = 0; - } - - /* Check for SCSI id specified. */ - if (get_param_value(buf, sizeof(buf),"id",scsi_disk_options[i])) { - id = strtol(buf, NULL, 0); - if (id < 0 || id > 6) { - fprintf(stderr, "qemu: SCSI id must be from 0-6: %d\n", id); - return -1; - } - /* Check if id already used */ - for(j = 0; j < MAX_SCSI_DISKS; j++) { - if (scsi_disks_info[j].device_type != SCSI_NONE && - j != i && - scsi_disks_info[j].adapter == temp_adapter && - scsi_disks_info[j].id == id ) { - fprintf(stderr, "qemu: SCSI id already used: %u\n", id); - return -1; - } - } - } else { - id = -1; - } - scsi_disks_info[i].adapter = temp_adapter; - scsi_disks_info[i].id = id; - - if (get_param_value(buf, sizeof(buf),"type",scsi_disk_options[i])) { - if (!strcmp(buf, "disk")) { - cdrom_device = 0; - } else if (!strcmp(buf, "cdrom")) { - cdrom_device = 1; - } else { - fprintf(stderr, "qemu: invalid SCSI disk type= value: %s\n", buf); - return -1; - } - } else { - cdrom_device = 0; - } - - if (cdrom_device) { - snprintf(dev_name, sizeof(buf), "cdrom%c", scsi_index); - scsi_disks_info[scsi_index].device_type = SCSI_CDROM; - } else { - snprintf(dev_name, sizeof(buf), "sd%c", scsi_index + 'a'); - scsi_disks_info[scsi_index].device_type = SCSI_DISK; - } - - if (!(bs_scsi_table[scsi_index] = bdrv_new(dev_name))) { - fprintf(stderr, "qemu: unable to create new block device for:%s\n",dev_name); + fprintf(stderr, "tap: no interface name\n"); return -1; } - - /* Get image filename from options and then try to open it */ - if (get_param_value(buf, sizeof(buf),"img",scsi_disk_options[i])) { - if (bdrv_open(bs_scsi_table[scsi_index], buf, 0) < 0) { - fprintf(stderr, "qemu: could not open SCSI disk image img='%s'\n",buf); - 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]; + int fd; + 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); + } + vlan->nb_host_devs++; + ret = net_tap_init(vlan, ifname, setup_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, "qemu: SCSI disk image not specified for sd%c \n", i + 'a'); + 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; } - - return 0; + 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); + } +} /***********************************************************/ /* USB devices */ @@ -4136,43 +4439,45 @@ void usb_info(void) } /***********************************************************/ -/* pid file */ - -static char *pid_filename; +/* PCMCIA/Cardbus */ -/* Remove PID file. Called on normal exit */ +static struct pcmcia_socket_entry_s { + struct pcmcia_socket_s *socket; + struct pcmcia_socket_entry_s *next; +} *pcmcia_sockets = 0; -static void remove_pidfile(void) +void pcmcia_socket_register(struct pcmcia_socket_s *socket) { - unlink (pid_filename); + 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; } -static void create_pidfile(const char *filename) +void pcmcia_socket_unregister(struct pcmcia_socket_s *socket) { - struct stat pidstat; - FILE *f; + struct pcmcia_socket_entry_s *entry, **ptr; - /* Try to write our PID to the named file */ - if (stat(filename, &pidstat) < 0) { - if (errno == ENOENT) { - if ((f = fopen (filename, "w")) == NULL) { - perror("Opening pidfile"); - exit(1); - } - fprintf(f, "%d\n", getpid()); - fclose(f); - pid_filename = qemu_strdup(filename); - if (!pid_filename) { - fprintf(stderr, "Could not save PID filename"); - exit(1); - } - atexit(remove_pidfile); + ptr = &pcmcia_sockets; + for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr) + if (entry->socket == socket) { + *ptr = entry->next; + qemu_free(entry); } - } else { - fprintf(stderr, "%s already exists. Remove it and try again.\n", - filename); - exit(1); - } +} + +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"); } /***********************************************************/ @@ -4211,6 +4516,7 @@ typedef struct IOHandlerRecord { IOCanRWHandler *fd_read_poll; IOHandler *fd_read; IOHandler *fd_write; + int deleted; void *opaque; /* temporary data */ struct pollfd *ufd; @@ -4236,8 +4542,7 @@ int qemu_set_fd_handler2(int fd, if (ioh == NULL) break; if (ioh->fd == fd) { - *pioh = ioh->next; - qemu_free(ioh); + ioh->deleted = 1; break; } pioh = &ioh->next; @@ -4258,6 +4563,7 @@ int qemu_set_fd_handler2(int fd, ioh->fd_read = fd_read; ioh->fd_write = fd_write; ioh->opaque = opaque; + ioh->deleted = 0; } return 0; } @@ -5380,13 +5686,144 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) #elif defined(TARGET_ARM) -/* ??? Need to implement these. */ void cpu_save(QEMUFile *f, void *opaque) { + int i; + CPUARMState *env = (CPUARMState *)opaque; + + for (i = 0; i < 16; i++) { + qemu_put_be32(f, env->regs[i]); + } + qemu_put_be32(f, cpsr_read(env)); + 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.c2_base); + 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.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_IWMMXT)) { + for (i = 0; i < 16; i++) { + qemu_put_be64(f, env->iwmmxt.regs[i]); + } + for (i = 0; i < 16; i++) { + qemu_put_be32(f, env->iwmmxt.cregs[i]); + } + } } int cpu_load(QEMUFile *f, void *opaque, int version_id) { + CPUARMState *env = (CPUARMState *)opaque; + int i; + + if (version_id != 0) + return -EINVAL; + + for (i = 0; i < 16; i++) { + env->regs[i] = qemu_get_be32(f); + } + cpsr_write(env, qemu_get_be32(f), 0xffffffff); + 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.c2_base = 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.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_IWMMXT)) { + for (i = 0; i < 16; i++) { + env->iwmmxt.regs[i] = qemu_get_be64(f); + } + for (i = 0; i < 16; i++) { + env->iwmmxt.cregs[i] = qemu_get_be32(f); + } + } + return 0; } @@ -5869,7 +6306,7 @@ void qemu_register_reset(QEMUResetHandler *func, void *opaque) *pre = re; } -void qemu_system_reset(void) +static void qemu_system_reset(void) { QEMUResetEntry *re; @@ -5906,9 +6343,12 @@ void qemu_system_powerdown_request(void) void main_loop_wait(int timeout) { - IOHandlerRecord *ioh, *ioh_next; + IOHandlerRecord *ioh; fd_set rfds, wfds, xfds; int ret, nfds; +#ifdef _WIN32 + int ret2, i; +#endif struct timeval tv; PollingEntry *pe; @@ -5919,7 +6359,7 @@ void main_loop_wait(int timeout) ret |= pe->func(pe->opaque); } #ifdef _WIN32 - if (ret == 0 && timeout > 0) { + if (ret == 0) { int err; WaitObjects *w = &wait_objects; @@ -5927,10 +6367,25 @@ void main_loop_wait(int timeout) if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) { if (w->func[ret - WAIT_OBJECT_0]) w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]); + + /* Check for additional signaled events */ + for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) { + + /* Check if event is signaled */ + ret2 = WaitForSingleObject(w->events[i], 0); + if(ret2 == WAIT_OBJECT_0) { + if (w->func[i]) + w->func[i](w->opaque[i]); + } else if (ret2 == WAIT_TIMEOUT) { + } else { + err = GetLastError(); + fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err); + } + } } else if (ret == WAIT_TIMEOUT) { } else { err = GetLastError(); - fprintf(stderr, "Wait error %d %d\n", ret, err); + fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err); } } #endif @@ -5941,6 +6396,8 @@ void main_loop_wait(int timeout) FD_ZERO(&wfds); FD_ZERO(&xfds); for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { + if (ioh->deleted) + continue; if (ioh->fd_read && (!ioh->fd_read_poll || ioh->fd_read_poll(ioh->opaque) != 0)) { @@ -5968,9 +6425,11 @@ void main_loop_wait(int timeout) #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) { - ioh_next = ioh->next; + IOHandlerRecord **pioh; + + for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { + if (ioh->deleted) + continue; if (FD_ISSET(ioh->fd, &rfds)) { ioh->fd_read(ioh->opaque); } @@ -5978,6 +6437,17 @@ void main_loop_wait(int timeout) ioh->fd_write(ioh->opaque); } } + + /* remove deleted IO handlers */ + pioh = &first_io_handler; + while (*pioh) { + ioh = *pioh; + if (ioh->deleted) { + *pioh = ioh->next; + qemu_free(ioh); + } else + pioh = &ioh->next; + } } #if defined(CONFIG_SLIRP) if (slirp_inited) { @@ -5990,7 +6460,6 @@ void main_loop_wait(int timeout) } #endif qemu_aio_poll(); - qemu_bh_poll(); if (vm_running) { qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL], @@ -5998,10 +6467,15 @@ void main_loop_wait(int timeout) /* run dma transfers, if any */ DMA_run(); } - + /* real time timers */ qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock)); + + /* Check bottom-halves last in case any of the earlier events triggered + them. */ + qemu_bh_poll(); + } static CPUState *cur_cpu; @@ -6031,13 +6505,16 @@ int main_loop(void) #ifdef CONFIG_PROFILER qemu_time += profile_getclock() - ti; #endif + if (ret == EXCP_HLT) { + /* Give the next CPU a chance to run. */ + cur_cpu = env; + continue; + } if (ret != EXCP_HALTED) break; /* all CPUs are halted ? */ - if (env == cur_cpu) { - ret = EXCP_HLT; + if (env == cur_cpu) break; - } } cur_cpu = env; @@ -6058,9 +6535,9 @@ int main_loop(void) if (ret == EXCP_DEBUG) { vm_stop(EXCP_DEBUG); } - /* if hlt instruction, we wait until the next IRQ */ + /* If all cpus are halted then wait until the next IRQ */ /* XXX: use timeout computed from timers */ - if (ret == EXCP_HLT) + if (ret == EXCP_HALTED) timeout = 10; else timeout = 0; @@ -6081,24 +6558,25 @@ int main_loop(void) void help(void) { - printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2006 Fabrice Bellard\n" + printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n" "usage: %s [options] [disk_image]\n" "\n" "'disk_image' is a raw hard image image for IDE hard disk 0\n" "\n" "Standard options:\n" "-M machine select emulated machine (-M ? for list)\n" + "-cpu cpu select CPU (-cpu ? for list)\n" "-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 image (cdrom is ide1 master)\n" - "-boot [a|c|d] boot on floppy (a), hard disk (c) or CD-ROM (d)\n" - "-disk ide,img=file[,hdx=a..dd][,type=disk|cdrom] \n" - " defaults are: hdx=a,type=disk \n" - "-disk scsi,img=file[,sdx=a..g][,type=disk|cdrom][,id=n] \n" - " defaults are: sdx=a,type=disk,id='auto assign' \n" + "-mtdblock file use 'file' as on-board Flash memory image\n" + "-sd file use 'file' as SecureDigital card image\n" + "-pflash file use 'file' as a parallel flash image\n" + "-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n" "-snapshot write to temporary files instead of disk image files\n" #ifdef CONFIG_SDL + "-no-frame open SDL window without a frame and window decorations\n" "-no-quit disable SDL window close capability\n" #endif #ifdef TARGET_I386 @@ -6107,6 +6585,7 @@ void help(void) "-m megs set virtual RAM size to megs MB [default=%d]\n" "-smp n set the number of CPUs to 'n' [default=1]\n" "-nographic disable graphical output and redirect serial I/Os to console\n" + "-portrait rotate graphical output 90 deg left (only PXA LCD)\n" #ifndef _WIN32 "-k language use keyboard layout (for example \"fr\" for French)\n" #endif @@ -6127,6 +6606,7 @@ void help(void) #if defined(TARGET_PPC) || defined(TARGET_SPARC) "-g WxH[xDEPTH] Set the initial graphical resolution and depth\n" #endif + "-name string set the name of the guest\n" "\n" "Network options:\n" "-net nic[,vlan=n][,macaddr=addr][,model=type]\n" @@ -6143,6 +6623,7 @@ void help(void) "-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\n" " connect the host TAP network interface to VLAN 'n' and use\n" " the network script 'file' (default=%s);\n" + " use 'script=no' to disable script execution;\n" " use 'fd=h' to connect to an already opened TAP interface\n" #endif "-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n" @@ -6153,7 +6634,8 @@ void help(void) " is provided, the default is '-net nic -net user'\n" "\n" #ifdef CONFIG_SLIRP - "-tftp prefix allow tftp access to files starting with prefix [-net user]\n" + "-tftp dir allow tftp access to files in dir [-net user]\n" + "-bootp file advertise file in BOOTP replies\n" #ifndef _WIN32 "-smb dir allow SMB access to files in 'dir' [-net user]\n" #endif @@ -6172,8 +6654,8 @@ void help(void) "-parallel dev redirect the parallel port to char device 'dev'\n" "-pidfile file Write PID to 'file'\n" "-S freeze CPU at startup (use 'c' to start execution)\n" - "-s wait gdb connection to port %d\n" - "-p port change gdb connection port\n" + "-s wait gdb connection to port\n" + "-p port set gdb connection port [default=%s]\n" "-d item1,... output log to %s (use -d ? for a list of log items)\n" "-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS\n" " translation (t=none or lba) (usually qemu can guess them)\n" @@ -6195,6 +6677,10 @@ void help(void) "-vnc display start a VNC server on display\n" #ifndef _WIN32 "-daemonize daemonize QEMU after initializing\n" +#endif + "-option-rom rom load a file, rom, into the option ROM space\n" +#ifdef TARGET_SPARC + "-prom-env variable=value set OpenBIOS nvram variables\n" #endif "\n" "During emulation, the following keys are useful:\n" @@ -6220,6 +6706,7 @@ enum { QEMU_OPTION_h, QEMU_OPTION_M, + QEMU_OPTION_cpu, QEMU_OPTION_fda, QEMU_OPTION_fdb, QEMU_OPTION_hda, @@ -6227,6 +6714,9 @@ enum { QEMU_OPTION_hdc, QEMU_OPTION_hdd, QEMU_OPTION_cdrom, + QEMU_OPTION_mtdblock, + QEMU_OPTION_sd, + QEMU_OPTION_pflash, QEMU_OPTION_boot, QEMU_OPTION_snapshot, #ifdef TARGET_I386 @@ -6234,6 +6724,7 @@ enum { #endif QEMU_OPTION_m, QEMU_OPTION_nographic, + QEMU_OPTION_portrait, #ifdef HAS_AUDIO QEMU_OPTION_audio_help, QEMU_OPTION_soundhw, @@ -6241,6 +6732,7 @@ enum { QEMU_OPTION_net, QEMU_OPTION_tftp, + QEMU_OPTION_bootp, QEMU_OPTION_smb, QEMU_OPTION_redir, @@ -6258,13 +6750,16 @@ enum { QEMU_OPTION_k, QEMU_OPTION_localtime, QEMU_OPTION_cirrusvga, + QEMU_OPTION_vmsvga, QEMU_OPTION_g, QEMU_OPTION_std_vga, + QEMU_OPTION_echr, QEMU_OPTION_monitor, QEMU_OPTION_serial, QEMU_OPTION_parallel, QEMU_OPTION_loadvm, QEMU_OPTION_full_screen, + QEMU_OPTION_no_frame, QEMU_OPTION_no_quit, QEMU_OPTION_pidfile, QEMU_OPTION_no_kqemu, @@ -6276,8 +6771,12 @@ enum { QEMU_OPTION_vnc, QEMU_OPTION_no_acpi, QEMU_OPTION_no_reboot, + QEMU_OPTION_show_cursor, QEMU_OPTION_daemonize, - QEMU_OPTION_disk, + QEMU_OPTION_option_rom, + QEMU_OPTION_semihosting, + QEMU_OPTION_name, + QEMU_OPTION_prom_env, }; typedef struct QEMUOption { @@ -6288,8 +6787,10 @@ typedef struct QEMUOption { const QEMUOption qemu_options[] = { { "h", 0, QEMU_OPTION_h }, + { "help", 0, QEMU_OPTION_h }, { "M", HAS_ARG, QEMU_OPTION_M }, + { "cpu", HAS_ARG, QEMU_OPTION_cpu }, { "fda", HAS_ARG, QEMU_OPTION_fda }, { "fdb", HAS_ARG, QEMU_OPTION_fdb }, { "hda", HAS_ARG, QEMU_OPTION_hda }, @@ -6297,6 +6798,9 @@ const QEMUOption qemu_options[] = { { "hdc", HAS_ARG, QEMU_OPTION_hdc }, { "hdd", HAS_ARG, QEMU_OPTION_hdd }, { "cdrom", HAS_ARG, QEMU_OPTION_cdrom }, + { "mtdblock", HAS_ARG, QEMU_OPTION_mtdblock }, + { "sd", HAS_ARG, QEMU_OPTION_sd }, + { "pflash", HAS_ARG, QEMU_OPTION_pflash }, { "boot", HAS_ARG, QEMU_OPTION_boot }, { "snapshot", 0, QEMU_OPTION_snapshot }, #ifdef TARGET_I386 @@ -6304,6 +6808,7 @@ const QEMUOption qemu_options[] = { #endif { "m", HAS_ARG, QEMU_OPTION_m }, { "nographic", 0, QEMU_OPTION_nographic }, + { "portrait", 0, QEMU_OPTION_portrait }, { "k", HAS_ARG, QEMU_OPTION_k }, #ifdef HAS_AUDIO { "audio-help", 0, QEMU_OPTION_audio_help }, @@ -6313,6 +6818,7 @@ const QEMUOption qemu_options[] = { { "net", HAS_ARG, QEMU_OPTION_net}, #ifdef CONFIG_SLIRP { "tftp", HAS_ARG, QEMU_OPTION_tftp }, + { "bootp", HAS_ARG, QEMU_OPTION_bootp }, #ifndef _WIN32 { "smb", HAS_ARG, QEMU_OPTION_smb }, #endif @@ -6339,12 +6845,14 @@ const QEMUOption qemu_options[] = { #endif { "localtime", 0, QEMU_OPTION_localtime }, { "std-vga", 0, QEMU_OPTION_std_vga }, + { "echr", 1, QEMU_OPTION_echr }, { "monitor", 1, QEMU_OPTION_monitor }, { "serial", 1, QEMU_OPTION_serial }, { "parallel", 1, QEMU_OPTION_parallel }, { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, { "full-screen", 0, QEMU_OPTION_full_screen }, #ifdef CONFIG_SDL + { "no-frame", 0, QEMU_OPTION_no_frame }, { "no-quit", 0, QEMU_OPTION_no_quit }, #endif { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, @@ -6352,14 +6860,23 @@ const QEMUOption qemu_options[] = { { "usbdevice", HAS_ARG, QEMU_OPTION_usbdevice }, { "smp", HAS_ARG, QEMU_OPTION_smp }, { "vnc", HAS_ARG, QEMU_OPTION_vnc }, - { "disk", HAS_ARG, QEMU_OPTION_disk }, - + /* temporary options */ { "usb", 0, QEMU_OPTION_usb }, { "cirrusvga", 0, QEMU_OPTION_cirrusvga }, + { "vmwarevga", 0, QEMU_OPTION_vmsvga }, { "no-acpi", 0, QEMU_OPTION_no_acpi }, { "no-reboot", 0, QEMU_OPTION_no_reboot }, + { "show-cursor", 0, QEMU_OPTION_show_cursor }, { "daemonize", 0, QEMU_OPTION_daemonize }, + { "option-rom", HAS_ARG, QEMU_OPTION_option_rom }, +#if defined(TARGET_ARM) || defined(TARGET_M68K) + { "semihosting", 0, QEMU_OPTION_semihosting }, +#endif + { "name", HAS_ARG, QEMU_OPTION_name }, +#if defined(TARGET_SPARC) + { "prom-env", HAS_ARG, QEMU_OPTION_prom_env }, +#endif { NULL }, }; @@ -6374,6 +6891,24 @@ static uint8_t *signal_stack; /* password input */ +int qemu_key_check(BlockDriverState *bs, const char *name) +{ + char password[256]; + int i; + + if (!bdrv_is_encrypted(bs)) + return 0; + + term_printf("%s is encrypted.\n", name); + for(i = 0; i < 3; i++) { + monitor_readline("Password: ", 1, password, sizeof(password)); + if (bdrv_set_key(bs, password) == 0) + return 0; + term_printf("invalid password\n"); + } + return -EPERM; +} + static BlockDriverState *get_bdrv(int index) { BlockDriverState *bs; @@ -6391,21 +6926,12 @@ static BlockDriverState *get_bdrv(int index) static void read_passwords(void) { BlockDriverState *bs; - int i, j; - char password[256]; + int i; for(i = 0; i < 6; i++) { bs = get_bdrv(i); - if (bs && bdrv_is_encrypted(bs)) { - term_printf("%s is encrypted.\n", bdrv_get_device_name(bs)); - for(j = 0; j < 3; j++) { - monitor_readline("Password: ", - 1, password, sizeof(password)); - if (bdrv_set_key(bs, password) == 0) - break; - term_printf("invalid password\n"); - } - } + if (bs) + qemu_key_check(bs, bdrv_get_device_name(bs)); } } @@ -6419,22 +6945,34 @@ void register_machines(void) qemu_register_machine(&heathrow_machine); qemu_register_machine(&core99_machine); qemu_register_machine(&prep_machine); + qemu_register_machine(&ref405ep_machine); + qemu_register_machine(&taihu_machine); #elif defined(TARGET_MIPS) qemu_register_machine(&mips_machine); + qemu_register_machine(&mips_malta_machine); + qemu_register_machine(&mips_pica61_machine); #elif defined(TARGET_SPARC) #ifdef TARGET_SPARC64 qemu_register_machine(&sun4u_machine); #else - qemu_register_machine(&sun4m_machine); + qemu_register_machine(&ss5_machine); + qemu_register_machine(&ss10_machine); #endif #elif defined(TARGET_ARM) - qemu_register_machine(&integratorcp926_machine); - qemu_register_machine(&integratorcp1026_machine); + qemu_register_machine(&integratorcp_machine); qemu_register_machine(&versatilepb_machine); qemu_register_machine(&versatileab_machine); qemu_register_machine(&realview_machine); + qemu_register_machine(&akitapda_machine); + qemu_register_machine(&spitzpda_machine); + qemu_register_machine(&borzoipda_machine); + qemu_register_machine(&terrierpda_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); +#elif defined(TARGET_ALPHA) + /* XXX: TODO */ +#elif defined(TARGET_M68K) + qemu_register_machine(&an5206_machine); #else #error unsupported CPU #endif @@ -6442,6 +6980,7 @@ void register_machines(void) #ifdef HAS_AUDIO struct soundhw soundhw[] = { +#ifdef HAS_AUDIO_CHOICE #ifdef TARGET_I386 { "pcspk", @@ -6490,6 +7029,7 @@ struct soundhw soundhw[] = { 0, { .init_pci = es1370_init } }, +#endif { NULL, NULL, 0, 0, { NULL } } }; @@ -6566,20 +7106,19 @@ static BOOL WINAPI qemu_ctrl_handler(DWORD type) int main(int argc, char **argv) { #ifdef CONFIG_GDBSTUB - int use_gdbstub, gdbstub_port; + int use_gdbstub; + const char *gdbstub_port; #endif - int i, cdrom_index; + int i, cdrom_index, pflash_index; int snapshot, linux_boot; const char *initrd_filename; - const char *fd_filename[MAX_FD]; - char scsi_options[MAX_SCSI_DISKS] [DISK_OPTIONS_SIZE]; - char ide_options[MAX_DISKS] [DISK_OPTIONS_SIZE]; - int num_ide_disks; - int num_scsi_disks; + const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD]; + const char *pflash_filename[MAX_PFLASH]; + const char *sd_filename; + const char *mtd_filename; const char *kernel_filename, *kernel_cmdline; DisplayState *ds = &display_state; int cyls, heads, secs, translation; - int start_emulation = 1; char net_clients[MAX_NET_CLIENTS][256]; int nb_net_clients; int optind; @@ -6592,9 +7131,12 @@ int main(int argc, char **argv) int parallel_device_index; const char *loadvm = NULL; QEMUMachine *machine; + const char *cpu_model; char usb_devices[MAX_USB_CMDLINE][128]; int usb_devices_index; int fds[2]; + const char *pid_file = NULL; + VLANState *vlan; LIST_INIT (&vm_change_state_head); #ifndef _WIN32 @@ -6629,23 +7171,19 @@ int main(int argc, char **argv) register_machines(); machine = first_machine; + cpu_model = NULL; initrd_filename = NULL; - for(i = 0; i < MAX_SCSI_DISKS; i++) { - scsi_disks_info[i].device_type = SCSI_NONE; - bs_scsi_table[i] = NULL; - } - - num_ide_disks = 0; - num_scsi_disks = 0; - for(i = 0; i < MAX_FD; i++) fd_filename[i] = NULL; - for(i = 0; i < MAX_DISKS; i++) { - ide_options[i][0] = '\0'; - } + for(i = 0; i < MAX_DISKS; i++) + hd_filename[i] = NULL; + for(i = 0; i < MAX_PFLASH; i++) + pflash_filename[i] = NULL; + pflash_index = 0; + sd_filename = NULL; + mtd_filename = NULL; ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; vga_ram_size = VGA_RAM_SIZE; - bios_size = BIOS_SIZE; #ifdef CONFIG_GDBSTUB use_gdbstub = 0; gdbstub_port = DEFAULT_GDBSTUB_PORT; @@ -6686,20 +7224,14 @@ int main(int argc, char **argv) break; r = argv[optind]; if (r[0] != '-') { - - /* Build new disk IDE syntax string */ - pstrcpy(ide_options[0], - 14, - "hdx=a,img="); - /*Add on image filename */ - pstrcpy(&(ide_options[0][13]), - sizeof(ide_options[0])-13, - argv[optind++]); - num_ide_disks++; + hd_filename[0] = argv[optind++]; } else { const QEMUOption *popt; optind++; + /* Treat --foo the same as -foo. */ + if (r[1] == '-') + r++; popt = qemu_options; for(;;) { if (!popt->name) { @@ -6736,6 +7268,23 @@ int main(int argc, char **argv) exit(1); } break; + case QEMU_OPTION_cpu: + /* hw initialization will check this */ + if (optarg[0] == '?') { +#if defined(TARGET_PPC) + ppc_cpu_list(stdout, &fprintf); +#elif defined(TARGET_ARM) + arm_cpu_list(); +#elif defined(TARGET_MIPS) + mips_cpu_list(stdout, &fprintf); +#elif defined(TARGET_SPARC) + sparc_cpu_list(stdout, &fprintf); +#endif + exit(1); + } else { + cpu_model = optarg; + } + break; case QEMU_OPTION_initrd: initrd_filename = optarg; break; @@ -6745,76 +7294,24 @@ int main(int argc, char **argv) case QEMU_OPTION_hdd: { int hd_index; - const char newIDE_DiskSyntax [][10] = { - "hdx=a,img=", "hdx=b,img=", "hdx=c,img=", "hdx=d,img=" }; - hd_index = popt->index - QEMU_OPTION_hda; - if (num_ide_disks >= MAX_DISKS){ - fprintf(stderr, "qemu: too many IDE disks defined.\n"); - exit(1); - } - /* Build new disk IDE syntax string */ - pstrcpy(ide_options[hd_index], - 11, - newIDE_DiskSyntax[hd_index]); - /* Add on image filename */ - pstrcpy(&(ide_options[hd_index][10]), - sizeof(ide_options[0])-10, - optarg); - num_ide_disks++; + hd_filename[hd_index] = optarg; + if (hd_index == cdrom_index) + cdrom_index = -1; } break; - case QEMU_OPTION_disk: /*Combined IDE and SCSI, for disk and CDROM */ - { - const char *p_input_char; - char *p_output_string; - char device[64]; - int disk_index; - - p_input_char = optarg; - p_output_string = device; - while (*p_input_char != '\0' && *p_input_char != ',') { - if ((p_output_string - device) < sizeof(device) - 1) - *p_output_string++ = *p_input_char; - p_input_char++; - } - *p_output_string = '\0'; - if (*p_input_char == ',') - p_input_char++; - - if (!strcmp(device, "scsi")) { - if (num_scsi_disks >= MAX_SCSI_DISKS) { - fprintf(stderr, "qemu: too many SCSI disks defined.\n"); - exit(1); - } - pstrcpy(scsi_options[num_scsi_disks], - sizeof(scsi_options[0]), - p_input_char); - num_scsi_disks++; - } else if (!strcmp(device,"ide")) { - if (num_ide_disks >= MAX_DISKS) { - fprintf(stderr, "qemu: too many IDE disks/cdroms defined.\n"); - exit(1); - } - disk_index = 0; /* default is hda */ - if (get_param_value(device, sizeof(device),"hdx",p_input_char)) { - if (device[0] >= 'a' && device[0] <= 'd') { - disk_index = device[0] - 'a'; - } else { - fprintf(stderr, "qemu: invalid IDE disk hdx= value: %s\n", device); - return -1; - } - } - else disk_index=0; - pstrcpy(ide_options[disk_index], - sizeof(ide_options[0]), - p_input_char); - num_ide_disks++; - } else { - fprintf(stderr, "qemu: -disk option must specify IDE or SCSI: %s \n",device); - exit(1); - } + case QEMU_OPTION_mtdblock: + mtd_filename = optarg; + break; + case QEMU_OPTION_sd: + sd_filename = optarg; + break; + case QEMU_OPTION_pflash: + if (pflash_index >= MAX_PFLASH) { + fprintf(stderr, "qemu: too many parallel flash images\n"); + exit(1); } + pflash_filename[pflash_index++] = optarg; break; case QEMU_OPTION_snapshot: snapshot = 1; @@ -6856,10 +7353,14 @@ int main(int argc, char **argv) } break; case QEMU_OPTION_nographic: - pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "null"); + pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); nographic = 1; break; + case QEMU_OPTION_portrait: + graphic_rotate = 1; + break; case QEMU_OPTION_kernel: kernel_filename = optarg; break; @@ -6867,28 +7368,14 @@ int main(int argc, char **argv) kernel_cmdline = optarg; break; case QEMU_OPTION_cdrom: - { - char buf[24]; - if (num_ide_disks >= MAX_DISKS) { - fprintf(stderr, "qemu: too many IDE disks/cdroms defined.\n"); - exit(1); - } - snprintf(buf, sizeof(buf), "type=cdrom,hdx=%c,img=", cdrom_index + 'a'); - /* Build new disk IDE syntax string */ - pstrcpy(ide_options[cdrom_index], - 25, - buf); - /* Add on image filename */ - pstrcpy(&(ide_options[cdrom_index][24]), - sizeof(ide_options[0])-24, - optarg); - num_ide_disks++; + if (cdrom_index >= 0) { + hd_filename[cdrom_index] = optarg; } break; case QEMU_OPTION_boot: boot_device = optarg[0]; if (boot_device != 'a' && -#ifdef TARGET_SPARC +#if defined(TARGET_SPARC) || defined(TARGET_I386) // Network boot boot_device != 'n' && #endif @@ -6925,6 +7412,9 @@ int main(int argc, char **argv) case QEMU_OPTION_tftp: tftp_prefix = optarg; break; + case QEMU_OPTION_bootp: + bootp_filename = optarg; + break; #ifndef _WIN32 case QEMU_OPTION_smb: net_slirp_smb(optarg); @@ -6977,14 +7467,14 @@ int main(int argc, char **argv) use_gdbstub = 1; break; case QEMU_OPTION_p: - gdbstub_port = atoi(optarg); + gdbstub_port = optarg; break; #endif case QEMU_OPTION_L: bios_dir = optarg; break; case QEMU_OPTION_S: - start_emulation = 0; + autostart = 0; break; case QEMU_OPTION_k: keyboard_layout = optarg; @@ -6994,9 +7484,15 @@ int main(int argc, char **argv) break; case QEMU_OPTION_cirrusvga: cirrus_vga_enabled = 1; + vmsvga_enabled = 0; + break; + case QEMU_OPTION_vmsvga: + cirrus_vga_enabled = 0; + vmsvga_enabled = 1; break; case QEMU_OPTION_std_vga: cirrus_vga_enabled = 0; + vmsvga_enabled = 0; break; case QEMU_OPTION_g: { @@ -7032,6 +7528,14 @@ int main(int argc, char **argv) graphic_depth = depth; } break; + case QEMU_OPTION_echr: + { + char *r; + term_escape_char = strtol(optarg, &r, 0); + if (r == optarg) + printf("Bad argument to echr\n"); + break; + } case QEMU_OPTION_monitor: pstrcpy(monitor_device, sizeof(monitor_device), optarg); break; @@ -7060,12 +7564,15 @@ int main(int argc, char **argv) full_screen = 1; break; #ifdef CONFIG_SDL + case QEMU_OPTION_no_frame: + no_frame = 1; + break; case QEMU_OPTION_no_quit: no_quit = 1; break; #endif case QEMU_OPTION_pidfile: - create_pidfile(optarg); + pid_file = optarg; break; #ifdef TARGET_I386 case QEMU_OPTION_win2k_hack: @@ -7110,9 +7617,36 @@ int main(int argc, char **argv) case QEMU_OPTION_no_reboot: no_reboot = 1; break; + case QEMU_OPTION_show_cursor: + cursor_hide = 0; + break; case QEMU_OPTION_daemonize: daemonize = 1; break; + case QEMU_OPTION_option_rom: + if (nb_option_roms >= MAX_OPTION_ROMS) { + fprintf(stderr, "Too many option ROMs\n"); + exit(1); + } + option_rom[nb_option_roms] = optarg; + nb_option_roms++; + break; + case QEMU_OPTION_semihosting: + semihosting_enabled = 1; + break; + case QEMU_OPTION_name: + qemu_name = optarg; + break; +#ifdef TARGET_SPARC + case QEMU_OPTION_prom_env: + if (nb_prom_envs >= MAX_PROM_ENVS) { + fprintf(stderr, "Too many prom variables\n"); + exit(1); + } + prom_envs[nb_prom_envs] = optarg; + nb_prom_envs++; + break; +#endif } } } @@ -7137,16 +7671,19 @@ int main(int argc, char **argv) close(fds[1]); again: - len = read(fds[0], &status, 1); - if (len == -1 && (errno == EINTR)) - goto again; - - if (len != 1 || status != 0) - exit(1); - else - exit(0); + len = read(fds[0], &status, 1); + if (len == -1 && (errno == EINTR)) + goto again; + + if (len != 1) + exit(1); + else if (status == 1) { + fprintf(stderr, "Could not acquire pidfile\n"); + exit(1); + } else + exit(0); } else if (pid < 0) - exit(1); + exit(1); setsid(); @@ -7165,6 +7702,15 @@ int main(int argc, char **argv) } #endif + if (pid_file && qemu_create_pidfile(pid_file) != 0) { + if (daemonize) { + uint8_t status = 1; + write(fds[1], &status, 1); + } else + fprintf(stderr, "Could not acquire pid file\n"); + exit(1); + } + #ifdef USE_KQEMU if (smp_cpus > 1) kqemu_allowed = 0; @@ -7172,10 +7718,20 @@ int main(int argc, char **argv) linux_boot = (kernel_filename != NULL); if (!linux_boot && - num_ide_disks == 0 && + boot_device != 'n' && + hd_filename[0] == '\0' && + (cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') && fd_filename[0] == '\0') help(); + /* boot to floppy or the default cd if no hard disk defined yet */ + if (hd_filename[0] == '\0' && boot_device == 'c') { + if (fd_filename[0] != '\0') + boot_device = 'a'; + else + boot_device = 'd'; + } + setvbuf(stdout, NULL, _IOLBF, 0); init_timers(); @@ -7200,9 +7756,43 @@ int main(int argc, char **argv) if (net_client_init(net_clients[i]) < 0) exit(1); } + for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { + if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0) + continue; + if (vlan->nb_guest_devs == 0) { + fprintf(stderr, "Invalid vlan (%d) with no nics\n", vlan->id); + exit(1); + } + if (vlan->nb_host_devs == 0) + fprintf(stderr, + "Warning: vlan %d is not connected to host network\n", + vlan->id); + } + +#ifdef TARGET_I386 + if (boot_device == 'n') { + for (i = 0; i < nb_nics; i++) { + const char *model = nd_table[i].model; + char buf[1024]; + if (model == NULL) + model = "ne2k_pci"; + snprintf(buf, sizeof(buf), "%s/pxe-%s.bin", bios_dir, model); + if (get_image_size(buf) > 0) { + option_rom[nb_option_roms] = strdup(buf); + nb_option_roms++; + break; + } + } + if (i == nb_nics) { + fprintf(stderr, "No valid PXE rom found for network device\n"); + exit(1); + } + boot_device = 'c'; /* to prevent confusion by the BIOS */ + } +#endif /* init the memory */ - phys_ram_size = ram_size + vga_ram_size + bios_size; + phys_ram_size = ram_size + vga_ram_size + MAX_BIOS_SIZE; phys_ram_base = qemu_vmalloc(phys_ram_size); if (!phys_ram_base) { @@ -7210,22 +7800,31 @@ int main(int argc, char **argv) exit(1); } + /* we always create the cdrom drive, even if no disk is there */ bdrv_init(); - - /* open the virtual block devices, disks or CDRoms */ - if (disk_options_init(num_ide_disks,ide_options,snapshot, - num_scsi_disks,scsi_options, - cdrom_index, - cyls, heads, secs, translation)){ - exit(1); + if (cdrom_index >= 0) { + bs_table[cdrom_index] = bdrv_new("cdrom"); + bdrv_set_type_hint(bs_table[cdrom_index], BDRV_TYPE_CDROM); } - /* boot to floppy or default cd if no hard disk */ - if (num_ide_disks == 0 && boot_device == 'c') { - if (fd_filename[0] != '\0') - boot_device = 'a'; - else - boot_device = 'd'; + /* open the virtual block devices */ + for(i = 0; i < MAX_DISKS; i++) { + if (hd_filename[i]) { + 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 ? BDRV_O_SNAPSHOT : 0) < 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); + bdrv_set_translation_hint(bs_table[i], translation); + } + } } /* we always create at least one floppy disk */ @@ -7240,7 +7839,7 @@ int main(int argc, char **argv) fd_table[i] = bdrv_new(buf); bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY); } - if (fd_filename[i] != '\0') { + if (fd_filename[i][0] != '\0') { if (bdrv_open(fd_table[i], fd_filename[i], snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { fprintf(stderr, "qemu: could not open floppy disk image '%s'\n", @@ -7251,6 +7850,48 @@ int main(int argc, char **argv) } } + /* Open the virtual parallel flash block devices */ + for(i = 0; i < MAX_PFLASH; i++) { + if (pflash_filename[i]) { + if (!pflash_table[i]) { + char buf[64]; + snprintf(buf, sizeof(buf), "fl%c", i + 'a'); + pflash_table[i] = bdrv_new(buf); + } + if (bdrv_open(pflash_table[i], pflash_filename[i], + snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { + fprintf(stderr, "qemu: could not open flash image '%s'\n", + pflash_filename[i]); + exit(1); + } + } + } + + sd_bdrv = bdrv_new ("sd"); + /* FIXME: This isn't really a floppy, but it's a reasonable + approximation. */ + bdrv_set_type_hint(sd_bdrv, BDRV_TYPE_FLOPPY); + if (sd_filename) { + if (bdrv_open(sd_bdrv, sd_filename, + snapshot ? BDRV_O_SNAPSHOT : 0) < 0) { + fprintf(stderr, "qemu: could not open SD card image %s\n", + sd_filename); + } else + qemu_key_check(sd_bdrv, sd_filename); + } + + if (mtd_filename) { + mtd_bdrv = bdrv_new ("mtd"); + if (bdrv_open(mtd_bdrv, mtd_filename, + snapshot ? BDRV_O_SNAPSHOT : 0) < 0 || + qemu_key_check(mtd_bdrv, mtd_filename)) { + fprintf(stderr, "qemu: could not open Flash image %s\n", + mtd_filename); + bdrv_delete(mtd_bdrv); + mtd_bdrv = 0; + } + } + register_savevm("timer", 0, 2, timer_save, timer_load, NULL); register_savevm("ram", 0, 2, ram_save, ram_load, NULL); @@ -7263,7 +7904,7 @@ int main(int argc, char **argv) vnc_display_init(ds, vnc_display); } else { #if defined(CONFIG_SDL) - sdl_display_init(ds, full_screen); + sdl_display_init(ds, full_screen, no_frame); #elif defined(CONFIG_COCOA) cocoa_display_init(ds, full_screen); #else @@ -7271,12 +7912,27 @@ int main(int argc, char **argv) #endif } - monitor_hd = qemu_chr_open(monitor_device); - if (!monitor_hd) { - fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); - exit(1); + /* Maintain compatibility with multiple stdio monitors */ + if (!strcmp(monitor_device,"stdio")) { + for (i = 0; i < MAX_SERIAL_PORTS; i++) { + if (!strcmp(serial_devices[i],"mon:stdio")) { + monitor_device[0] = '\0'; + break; + } else if (!strcmp(serial_devices[i],"stdio")) { + monitor_device[0] = '\0'; + pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "mon:stdio"); + break; + } + } + } + if (monitor_device[0] != '\0') { + monitor_hd = qemu_chr_open(monitor_device); + if (!monitor_hd) { + fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device); + exit(1); + } + monitor_init(monitor_hd, !nographic); } - monitor_init(monitor_hd, !nographic); for(i = 0; i < MAX_SERIAL_PORTS; i++) { const char *devname = serial_devices[i]; @@ -7308,7 +7964,7 @@ int main(int argc, char **argv) machine->init(ram_size, vga_ram_size, boot_device, ds, fd_filename, snapshot, - kernel_filename, kernel_cmdline, initrd_filename); + kernel_filename, kernel_cmdline, initrd_filename, cpu_model); /* init USB devices */ if (usb_enabled) { @@ -7325,12 +7981,12 @@ int main(int argc, char **argv) #ifdef CONFIG_GDBSTUB if (use_gdbstub) { + /* XXX: use standard host:port notation and modify options + accordingly. */ if (gdbserver_start(gdbstub_port) < 0) { - fprintf(stderr, "Could not open gdbserver socket on port %d\n", + fprintf(stderr, "qemu: could not open gdbstub device on port '%s'\n", gdbstub_port); exit(1); - } else { - printf("Waiting gdb connection on port %d\n", gdbstub_port); } } else #endif @@ -7340,7 +7996,7 @@ int main(int argc, char **argv) { /* XXX: simplify init */ read_passwords(); - if (start_emulation) { + if (autostart) { vm_start(); } }