return qemu_put_mouse_event_absolute;
}
-/***********************************************************/
-/* timers */
-
-#if defined(__powerpc__)
-
-static inline uint32_t get_tbl(void)
+/* compute with 96 bit intermediate result: (a*b)/c */
+uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c)
{
- uint32_t tbl;
- asm volatile("mftb %0" : "=r" (tbl));
- return tbl;
-}
+ union {
+ uint64_t ll;
+ struct {
+#ifdef WORDS_BIGENDIAN
+ uint32_t high, low;
+#else
+ uint32_t low, high;
+#endif
+ } l;
+ } u, res;
+ uint64_t rl, rh;
-static inline uint32_t get_tbu(void)
-{
- uint32_t tbl;
- asm volatile("mftbu %0" : "=r" (tbl));
- return tbl;
+ u.ll = a;
+ rl = (uint64_t)u.l.low * (uint64_t)b;
+ rh = (uint64_t)u.l.high * (uint64_t)b;
+ rh += (rl >> 32);
+ res.l.high = rh / c;
+ res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
+ return res.ll;
}
-int64_t cpu_get_real_ticks(void)
-{
- uint32_t l, h, h1;
- /* NOTE: we test if wrapping has occurred */
- do {
- h = get_tbu();
- l = get_tbl();
- h1 = get_tbu();
- } while (h != h1);
- return ((int64_t)h << 32) | l;
-}
+/***********************************************************/
+/* real time host monotonic timer */
-#elif defined(__i386__)
+#define QEMU_TIMER_BASE 1000000000LL
-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
-}
+#ifdef WIN32
-#elif defined(__x86_64__)
+static int64_t clock_freq;
-int64_t cpu_get_real_ticks(void)
+static void init_get_clock(void)
{
- uint32_t low,high;
- int64_t val;
- asm volatile("rdtsc" : "=a" (low), "=d" (high));
- val = high;
- val <<= 32;
- val |= low;
- return val;
+ LARGE_INTEGER freq;
+ int ret;
+ ret = QueryPerformanceFrequency(&freq);
+ if (ret == 0) {
+ fprintf(stderr, "Could not calibrate ticks\n");
+ exit(1);
+ }
+ clock_freq = freq.QuadPart;
}
-#elif defined(__ia64)
-
-int64_t cpu_get_real_ticks(void)
+static int64_t get_clock(void)
{
- int64_t val;
- asm volatile ("mov %0 = ar.itc" : "=r"(val) :: "memory");
- return val;
+ LARGE_INTEGER ti;
+ QueryPerformanceCounter(&ti);
+ return muldiv64(ti.QuadPart, QEMU_TIMER_BASE, clock_freq);
}
-#elif defined(__s390__)
+#else
+
+static int use_rt_clock;
-int64_t cpu_get_real_ticks(void)
+static void init_get_clock(void)
{
- int64_t val;
- asm volatile("stck 0(%1)" : "=m" (val) : "a" (&val) : "cc");
- return val;
+ use_rt_clock = 0;
+#if defined(__linux__)
+ {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ use_rt_clock = 1;
+ }
+ }
+#endif
}
-#elif defined(__sparc__) && defined(HOST_SOLARIS)
-
-uint64_t cpu_get_real_ticks (void)
+static int64_t get_clock(void)
{
-#if defined(_LP64)
- uint64_t rval;
- asm volatile("rd %%tick,%0" : "=r"(rval));
- return rval;
-#else
- union {
- uint64_t i64;
- struct {
- uint32_t high;
- uint32_t low;
- } i32;
- } rval;
- asm volatile("rd %%tick,%1; srlx %1,32,%0"
- : "=r"(rval.i32.high), "=r"(rval.i32.low));
- return rval.i64;
+#if defined(__linux__)
+ if (use_rt_clock) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec * 1000000000LL + ts.tv_nsec;
+ } else
#endif
+ {
+ /* XXX: using gettimeofday leads to problems if the date
+ changes, so it should be avoided. */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 1000000000LL + (tv.tv_usec * 1000);
+ }
}
-#else
-#error unsupported CPU
#endif
+/***********************************************************/
+/* guest cycle counter */
+
static int64_t cpu_ticks_prev;
static int64_t cpu_ticks_offset;
+static int64_t cpu_clock_offset;
static int cpu_ticks_enabled;
-static inline int64_t cpu_get_ticks(void)
+/* return the host CPU cycle counter and handle stop/restart */
+int64_t cpu_get_ticks(void)
{
if (!cpu_ticks_enabled) {
return cpu_ticks_offset;
}
}
+/* return the host CPU monotonic timer and handle stop/restart */
+static int64_t cpu_get_clock(void)
+{
+ int64_t ti;
+ if (!cpu_ticks_enabled) {
+ return cpu_clock_offset;
+ } else {
+ ti = get_clock();
+ return ti + cpu_clock_offset;
+ }
+}
+
/* enable cpu_get_ticks() */
void cpu_enable_ticks(void)
{
if (!cpu_ticks_enabled) {
cpu_ticks_offset -= cpu_get_real_ticks();
+ cpu_clock_offset -= get_clock();
cpu_ticks_enabled = 1;
}
}
{
if (cpu_ticks_enabled) {
cpu_ticks_offset = cpu_get_ticks();
+ cpu_clock_offset = cpu_get_clock();
cpu_ticks_enabled = 0;
}
}
-#ifdef _WIN32
-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;
-}
-
-void cpu_calibrate_ticks(void)
-{
- int64_t usec, ticks;
-
- usec = get_clock();
- ticks = cpu_get_real_ticks();
- usleep(50 * 1000);
- 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)
-{
- union {
- uint64_t ll;
- struct {
-#ifdef WORDS_BIGENDIAN
- uint32_t high, low;
-#else
- uint32_t low, high;
-#endif
- } l;
- } u, res;
- uint64_t rl, rh;
-
- u.ll = a;
- rl = (uint64_t)u.l.low * (uint64_t)b;
- rh = (uint64_t)u.l.high * (uint64_t)b;
- rh += (rl >> 32);
- res.l.high = rh / c;
- res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c;
- return res.ll;
-}
-
+/***********************************************************/
+/* timers */
+
#define QEMU_TIMER_REALTIME 0
#define QEMU_TIMER_VIRTUAL 1
{
switch(clock->type) {
case QEMU_TIMER_REALTIME:
-#ifdef _WIN32
- return GetTickCount();
-#else
- {
- struct tms tp;
-
- /* Note that using gettimeofday() is not a good solution
- for timers because its value change when the date is
- modified. */
- if (timer_freq == 100) {
- return times(&tp) * 10;
- } else {
- return ((int64_t)times(&tp) * 1000) / timer_freq;
- }
- }
-#endif
+ return get_clock() / 1000000;
default:
case QEMU_TIMER_VIRTUAL:
- return cpu_get_ticks();
+ return cpu_get_clock();
}
}
+static void init_timers(void)
+{
+ init_get_clock();
+ ticks_per_sec = QEMU_TIMER_BASE;
+ rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
+ vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
+}
+
/* save a timer */
void qemu_put_timer(QEMUFile *f, QEMUTimer *ts)
{
#endif /* !defined(_WIN32) */
-static void init_timers(void)
+static void init_timer_alarm(void)
{
- rt_clock = qemu_new_clock(QEMU_TIMER_REALTIME);
- vm_clock = qemu_new_clock(QEMU_TIMER_VIRTUAL);
-
#ifdef _WIN32
{
int count=0;
static int term_got_escape, client_index;
static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
-int term_fifo_size;
+static int term_fifo_size;
+static int term_timestamps;
+static int64_t term_timestamps_start;
void term_print_help(void)
{
"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"
);
goto send_char;
}
break;
+ case 't':
+ term_timestamps = !term_timestamps;
+ term_timestamps_start = -1;
+ break;
case TERM_ESCAPE:
goto send_char;
}
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 len;
+ }
+}
+
/* init terminal so that we can grab keys */
static struct termios oldtty;
static int old_fd0_flags;
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;
}
int parse_host_port(struct sockaddr_in *saddr, const char *str);
+int parse_host_src_port(struct sockaddr_in *haddr,
+ struct sockaddr_in *saddr,
+ const char *str);
CharDriverState *qemu_chr_open_udp(const char *def)
{
CharDriverState *chr = NULL;
NetCharDriver *s = NULL;
int fd = -1;
- int con_type;
- struct sockaddr_in addr;
- const char *p, *r;
- int port;
+ struct sockaddr_in saddr;
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
goto return_err;
}
- /* There are three types of port definitions
- * 1) udp:remote_port
- * Juse use 0.0.0.0 for the IP and send to remote
- * 2) udp:remote_host:port
- * Use a IP and send traffic to remote
- * 3) udp:local_port:remote_host:remote_port
- * Use local_port as the originator + #2
- */
- con_type = 0;
- p = def;
- while ((p = strchr(p, ':'))) {
- p++;
- con_type++;
- }
-
- p = def;
- memset(&addr,0,sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- s->daddr.sin_family = AF_INET;
- s->daddr.sin_addr.s_addr = htonl(INADDR_ANY);
-
- switch (con_type) {
- case 0:
- port = strtol(p, (char **)&r, 0);
- if (r == p) {
- fprintf(stderr, "Error parsing port number\n");
- goto return_err;
- }
- s->daddr.sin_port = htons((short)port);
- break;
- case 2:
- port = strtol(p, (char **)&r, 0);
- if (r == p) {
- fprintf(stderr, "Error parsing port number\n");
- goto return_err;
- }
- addr.sin_port = htons((short)port);
- p = r + 1;
- /* Fall through to case 1 now that we have the local port */
- case 1:
- if (parse_host_port(&s->daddr, p) < 0) {
- fprintf(stderr, "Error parsing host name and port\n");
- goto return_err;
- }
- break;
- default:
- fprintf(stderr, "Too many ':' characters\n");
- goto return_err;
+ if (parse_host_src_port(&s->daddr, &saddr, def) < 0) {
+ printf("Could not parse: %s\n", def);
+ goto return_err;
}
- if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
{
perror("bind");
goto return_err;
int fd, listen_fd;
int connected;
int max_size;
+ int do_telnetopt;
} TCPCharDriver;
static void tcp_chr_accept(void *opaque);
return s->max_size;
}
+#define IAC 255
+#define IAC_BREAK 243
+static void tcp_chr_process_IAC_bytes(CharDriverState *chr,
+ TCPCharDriver *s,
+ char *buf, int *size)
+{
+ /* Handle any telnet client's basic IAC options to satisfy char by
+ * char mode with no echo. All IAC options will be removed from
+ * the buf and the do_telnetopt variable will be used to track the
+ * state of the width of the IAC information.
+ *
+ * IAC commands come in sets of 3 bytes with the exception of the
+ * "IAC BREAK" command and the double IAC.
+ */
+
+ int i;
+ int j = 0;
+
+ for (i = 0; i < *size; i++) {
+ if (s->do_telnetopt > 1) {
+ if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
+ /* Double IAC means send an IAC */
+ if (j != i)
+ buf[j] = buf[i];
+ j++;
+ s->do_telnetopt = 1;
+ } else {
+ if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
+ /* Handle IAC break commands by sending a serial break */
+ chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK);
+ s->do_telnetopt++;
+ }
+ s->do_telnetopt++;
+ }
+ if (s->do_telnetopt >= 4) {
+ s->do_telnetopt = 1;
+ }
+ } else {
+ if ((unsigned char)buf[i] == IAC) {
+ s->do_telnetopt = 2;
+ } else {
+ if (j != i)
+ buf[j] = buf[i];
+ j++;
+ }
+ }
+ }
+ *size = j;
+}
+
static void tcp_chr_read(void *opaque)
{
CharDriverState *chr = opaque;
closesocket(s->fd);
s->fd = -1;
} else if (size > 0) {
- s->fd_read(s->fd_opaque, buf, size);
+ if (s->do_telnetopt)
+ tcp_chr_process_IAC_bytes(chr, s, buf, &size);
+ if (size > 0)
+ s->fd_read(s->fd_opaque, buf, size);
}
}
tcp_chr_read, NULL, chr);
}
+#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
+static void tcp_chr_telnet_init(int fd)
+{
+ char buf[3];
+ /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
+ IACSET(buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
+ send(fd, (char *)buf, 3, 0);
+ IACSET(buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
+ send(fd, (char *)buf, 3, 0);
+ IACSET(buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
+ send(fd, (char *)buf, 3, 0);
+ IACSET(buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
+ send(fd, (char *)buf, 3, 0);
+}
+
static void tcp_chr_accept(void *opaque)
{
CharDriverState *chr = opaque;
if (fd < 0 && errno != EINTR) {
return;
} else if (fd >= 0) {
+ if (s->do_telnetopt)
+ tcp_chr_telnet_init(fd);
break;
}
}
}
static CharDriverState *qemu_chr_open_tcp(const char *host_str,
- int is_listen)
+ int is_telnet)
{
CharDriverState *chr = NULL;
TCPCharDriver *s = NULL;
int fd = -1, ret, err, val;
+ int is_listen = 0;
+ int is_waitconnect = 1;
+ const char *ptr;
struct sockaddr_in saddr;
if (parse_host_port(&saddr, host_str) < 0)
goto fail;
+ ptr = host_str;
+ while((ptr = strchr(ptr,','))) {
+ ptr++;
+ if (!strncmp(ptr,"server",6)) {
+ is_listen = 1;
+ } else if (!strncmp(ptr,"nowait",6)) {
+ is_waitconnect = 0;
+ } else {
+ printf("Unknown option: %s\n", ptr);
+ goto fail;
+ }
+ }
+ if (!is_listen)
+ is_waitconnect = 0;
+
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
goto fail;
fd = socket(PF_INET, SOCK_STREAM, 0);
if (fd < 0)
goto fail;
- socket_set_nonblock(fd);
+
+ if (!is_waitconnect)
+ socket_set_nonblock(fd);
s->connected = 0;
s->fd = -1;
goto fail;
s->listen_fd = fd;
qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
+ if (is_telnet)
+ s->do_telnetopt = 1;
} else {
for(;;) {
ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
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 && is_waitconnect) {
+ printf("QEMU waiting for connection on: %s\n", host_str);
+ tcp_chr_accept(chr);
+ socket_set_nonblock(s->listen_fd);
+ }
+
return chr;
fail:
if (fd >= 0)
if (strstart(filename, "tcp:", &p)) {
return qemu_chr_open_tcp(p, 0);
} else
- if (strstart(filename, "tcpl:", &p)) {
+ if (strstart(filename, "telnet:", &p)) {
return qemu_chr_open_tcp(p, 1);
} else
if (strstart(filename, "udp:", &p)) {
return 0;
}
+int parse_host_src_port(struct sockaddr_in *haddr,
+ struct sockaddr_in *saddr,
+ const char *input_str)
+{
+ char *str = strdup(input_str);
+ char *host_str = str;
+ char *src_str;
+ char *ptr;
+
+ /*
+ * Chop off any extra arguments at the end of the string which
+ * would start with a comma, then fill in the src port information
+ * if it was provided else use the "any address" and "any port".
+ */
+ if ((ptr = strchr(str,',')))
+ *ptr = '\0';
+
+ if ((src_str = strchr(input_str,'@'))) {
+ *src_str = '\0';
+ src_str++;
+ }
+
+ if (parse_host_port(haddr, host_str) < 0)
+ goto fail;
+
+ if (!src_str || *src_str == '\0')
+ src_str = ":0";
+
+ if (parse_host_port(saddr, src_str) < 0)
+ goto fail;
+
+ free(str);
+ return(0);
+
+fail:
+ free(str);
+ return -1;
+}
+
int parse_host_port(struct sockaddr_in *saddr, const char *str)
{
char buf[512];
{
USBPort *port;
USBPort **lastp;
+ USBDevice *dev;
int bus_num, addr;
const char *p;
if (!port)
return -1;
+ dev = port->dev;
*lastp = port->next;
usb_attach(port, NULL);
+ dev->handle_destroy(dev);
port->next = free_usb_ports;
free_usb_ports = port;
return 0;
speed_str = "?";
break;
}
- term_printf(" Device %d.%d, speed %s Mb/s\n",
- 0, dev->addr, speed_str);
+ term_printf(" Device %d.%d, Speed %s Mb/s, Product %s\n",
+ 0, dev->addr, speed_str, dev->devname);
}
}
}
/***********************************************************/
+/* bottom halves (can be seen as timers which expire ASAP) */
+
+struct QEMUBH {
+ QEMUBHFunc *cb;
+ void *opaque;
+ int scheduled;
+ QEMUBH *next;
+};
+
+static QEMUBH *first_bh = NULL;
+
+QEMUBH *qemu_bh_new(QEMUBHFunc *cb, void *opaque)
+{
+ QEMUBH *bh;
+ bh = qemu_mallocz(sizeof(QEMUBH));
+ if (!bh)
+ return NULL;
+ bh->cb = cb;
+ bh->opaque = opaque;
+ return bh;
+}
+
+void qemu_bh_poll(void)
+{
+ QEMUBH *bh, **pbh;
+
+ for(;;) {
+ pbh = &first_bh;
+ bh = *pbh;
+ if (!bh)
+ break;
+ *pbh = bh->next;
+ bh->scheduled = 0;
+ bh->cb(bh->opaque);
+ }
+}
+
+void qemu_bh_schedule(QEMUBH *bh)
+{
+ CPUState *env = cpu_single_env;
+ if (bh->scheduled)
+ return;
+ bh->scheduled = 1;
+ bh->next = first_bh;
+ first_bh = bh;
+
+ /* stop the currently executing CPU to execute the BH ASAP */
+ if (env) {
+ cpu_interrupt(env, CPU_INTERRUPT_EXIT);
+ }
+}
+
+void qemu_bh_cancel(QEMUBH *bh)
+{
+ QEMUBH **pbh;
+ if (bh->scheduled) {
+ pbh = &first_bh;
+ while (*pbh != bh)
+ pbh = &(*pbh)->next;
+ *pbh = bh->next;
+ bh->scheduled = 0;
+ }
+}
+
+void qemu_bh_delete(QEMUBH *bh)
+{
+ qemu_bh_cancel(bh);
+ qemu_free(bh);
+}
+
+/***********************************************************/
/* machine registration */
QEMUMachine *first_machine = NULL;
#ifdef _WIN32
tap_win32_poll();
#endif
+ qemu_aio_poll();
+ qemu_bh_poll();
if (vm_running) {
qemu_run_timers(&active_timers[QEMU_TIMER_VIRTUAL],
}
#else
SetConsoleCtrlHandler(qemu_ctrl_handler, TRUE);
+ /* Note: cpu_interrupt() is currently not SMP safe, so we force
+ QEMU to run on a single CPU */
+ {
+ HANDLE h;
+ DWORD mask, smask;
+ int i;
+ h = GetCurrentProcess();
+ if (GetProcessAffinityMask(h, &mask, &smask)) {
+ for(i = 0; i < 32; i++) {
+ if (mask & (1 << i))
+ break;
+ }
+ if (i != 32) {
+ mask = 1 << i;
+ SetProcessAffinityMask(h, mask);
+ }
+ }
+ }
#endif
- init_timers();
register_machines();
machine = first_machine;
setvbuf(stdout, NULL, _IOLBF, 0);
+ init_timers();
+ init_timer_alarm();
+ qemu_aio_init();
+
#ifdef _WIN32
socket_init();
#endif
snprintf(buf, sizeof(buf), "hd%c", i + 'a');
bs_table[i] = bdrv_new(buf);
}
- if (bdrv_open(bs_table[i], hd_filename[i], snapshot) < 0) {
+ 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);
bdrv_set_type_hint(fd_table[i], BDRV_TYPE_FLOPPY);
}
if (fd_filename[i] != '\0') {
- if (bdrv_open(fd_table[i], fd_filename[i], snapshot) < 0) {
+ 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",
fd_filename[i]);
exit(1);
register_savevm("ram", 0, 1, ram_save, ram_load, NULL);
init_ioports();
- cpu_calibrate_ticks();
/* terminal init */
if (nographic) {
exit(1);
}
if (!strcmp(serial_devices[i], "vc"))
- qemu_chr_printf(serial_hds[i], "serial%d console\n", i);
+ qemu_chr_printf(serial_hds[i], "serial%d console\r\n", i);
}
}
exit(1);
}
if (!strcmp(parallel_devices[i], "vc"))
- qemu_chr_printf(parallel_hds[i], "parallel%d console\n", i);
+ qemu_chr_printf(parallel_hds[i], "parallel%d console\r\n", i);
}
}