diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index c8b15f9..5e13fab
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -86,6 +86,7 @@ struct CharDriverState {
     guint fd_in_tag;
     guint fd_hup_tag;
     QemuOpts *opts;
+    bool replay;
     QTAILQ_ENTRY(CharDriverState) next;
 };
 
@@ -125,6 +126,8 @@ CharDriverState *qemu_chr_new_from_opts(QemuOpts *opts,
  */
 CharDriverState *qemu_chr_new(const char *label, const char *filename,
                               void (*init)(struct CharDriverState *s));
+CharDriverState *qemu_chr_new_replay(const char *label, const char *filename,
+                              void (*init)(struct CharDriverState *s));
 
 /**
  * @qemu_chr_delete:
@@ -320,6 +323,7 @@ int qemu_chr_be_can_write(CharDriverState *s);
  * @len the number of bytes to receive from the front end
  */
 void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len);
+void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len);
 
 
 /**

diff --git a/qemu-char.c b/qemu-char.c
index 51917de..4627eef
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -81,6 +81,7 @@
 
 #include "qemu/sockets.h"
 #include "ui/qemu-spice.h"
+#include "replay/replay.h"
 
 #define READ_BUF_LEN 4096
 #define READ_RETRIES 10
@@ -126,6 +127,9 @@ int qemu_chr_fe_write(CharDriverState *s, const uint8_t *buf, int len)
 
     qemu_mutex_lock(&s->chr_write_lock);
     ret = s->chr_write(s, buf, len);
+    if (s->replay) {
+        replay_data_int(&ret);
+    }
     qemu_mutex_unlock(&s->chr_write_lock);
     return ret;
 }
@@ -195,9 +199,18 @@ int qemu_chr_fe_read_all(CharDriverState *s, uint8_t *buf, int len)
 
 int qemu_chr_fe_ioctl(CharDriverState *s, int cmd, void *arg)
 {
-    if (!s->chr_ioctl)
-        return -ENOTSUP;
-    return s->chr_ioctl(s, cmd, arg);
+    int res;
+    if (!s->chr_ioctl) {
+        res = -ENOTSUP;
+    } else {
+        res = s->chr_ioctl(s, cmd, arg);
+        if (s->replay) {
+            fprintf(stderr, "Replay: ioctl is not supported for serial devices yet\n");
+            exit(1);
+        }
+    }
+
+    return res;
 }
 
 int qemu_chr_be_can_write(CharDriverState *s)
@@ -207,17 +220,34 @@ int qemu_chr_be_can_write(CharDriverState *s)
     return s->chr_can_read(s->handler_opaque);
 }
 
-void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
+void qemu_chr_be_write_impl(CharDriverState *s, uint8_t *buf, int len)
 {
     if (s->chr_read) {
         s->chr_read(s->handler_opaque, buf, len);
     }
 }
 
+void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len)
+{
+    if (s->replay) {
+        if (replay_mode == REPLAY_PLAY) {
+            fprintf(stderr, "Replay: calling qemu_chr_be_write in play mode\n");
+            exit(1);
+        }
+        replay_chr_be_write(s, buf, len);
+    } else {
+        qemu_chr_be_write_impl(s, buf, len);
+    }
+}
+
 int qemu_chr_fe_get_msgfd(CharDriverState *s)
 {
     int fd;
-    return (qemu_chr_fe_get_msgfds(s, &fd, 1) == 1) ? fd : -1;
+    int res = (qemu_chr_fe_get_msgfds(s, &fd, 1) == 1) ? fd : -1;
+    if (s->replay) {
+        replay_data_int(&res);
+    }
+    return res;
 }
 
 int qemu_chr_fe_get_msgfds(CharDriverState *s, int *fds, int len)
@@ -1923,6 +1953,8 @@ static int win_chr_pipe_poll(void *opaque)
     if (size > 0) {
         s->len = size;
         win_chr_read_poll(chr);
+        if (s->max_size == 0)
+            return 0;
         win_chr_read(chr);
         return 1;
     }
@@ -2034,19 +2066,41 @@ static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int
len)
 {
     HANDLE  hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
     DWORD   dwSize;
-    int     len1;
+    int     ret = 0;
+    CONSOLE_SCREEN_BUFFER_INFO info;
 
-    len1 = len;
-
-    while (len1 > 0) {
-        if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) {
-            break;
+    while (len > 0) {
+        if (len > 2 && buf[0] == '\033' && buf[1] == '[') {
+            switch (buf[2]) {
+            case 'D':
+                if (!WriteFile(hStdOut, "\b", 1, &dwSize, NULL)) {
+                    return ret;
+                }
+                break;
+            case 'K':
+                if (!GetConsoleScreenBufferInfo(hStdOut, &info)) {
+                    return ret;
+                }
+                if (!FillConsoleOutputCharacter(hStdOut, ' ', 
+                    info.dwSize.X - info.dwCursorPosition.X, 
+                    info.dwCursorPosition, &dwSize)) {
+                    return ret;
+                }
+                break;
+            }
+            dwSize = 3;
+        } else {
+            if (!WriteFile(hStdOut, buf, 1, &dwSize, NULL)) {
+                return ret;
+            }
         }
-        buf  += dwSize;
-        len1 -= dwSize;
+
+        buf += dwSize;
+        len -= dwSize;
+        ret += dwSize;
     }
 
-    return len - len1;
+    return ret;
 }
 
