diff --git a/0052-virtio-console-patches.patch b/0052-virtio-console-patches.patch
new file mode 100644
index 0000000..c8570d9
--- /dev/null
+++ b/0052-virtio-console-patches.patch
@@ -0,0 +1,936 @@
+From 8fe39316da28bdff610da708148f87b21e7ba045 Mon Sep 17 00:00:00 2001
+From: Amit Shah <amit.shah@redhat.com>
+Date: Tue, 6 Apr 2010 23:36:50 +0530
+Subject: [PATCH] virtio-console patches
+
+Hey Justin,
+
+Attached are the kernel and qemu patches for the new abi. Rusty is ok
+with the kernel patches and Juan and Gerd are ok with the userspace
+ones.
+
+The kernel one is big because of some code movement.
+
+The qemu one is big because of code being moved and some fixes being
+applied to make the host less vulnerable to malicious guests.
+
+There's also a patch at
+
+http://lkml.org/lkml/2010/4/6/110
+
+that we should apply (affects the virt-console-fix-race.patch in the
+repo).
+
+Please let me know if you need any more information!
+
+Thanks,
+		Amit
+
+Content-Disposition: attachment; filename=",qemu-virtio-serial-rollup-2.patch"
+---
+ Makefile.hw            |    1 +
+ hw/iov.c               |   70 ++++++++++
+ hw/iov.h               |   19 +++
+ hw/virtio-balloon.c    |   31 +----
+ hw/virtio-console.c    |   11 +-
+ hw/virtio-net.c        |   20 +---
+ hw/virtio-serial-bus.c |  332 ++++++++++++++++++++++++++++++++++++------------
+ hw/virtio-serial.h     |   34 ++++--
+ 8 files changed, 372 insertions(+), 146 deletions(-)
+ create mode 100644 hw/iov.c
+ create mode 100644 hw/iov.h
+
+diff --git a/Makefile.hw b/Makefile.hw
+index 43ca541..079c5d2 100644
+--- a/Makefile.hw
++++ b/Makefile.hw
+@@ -13,6 +13,7 @@ QEMU_CFLAGS+=-I.. -I$(SRC_PATH)/fpu
+
+ obj-y =
+ obj-y += loader.o
++obj-y += iov.o
+ obj-y += virtio.o virtio-console.o
+ obj-y += fw_cfg.o
+ obj-y += watchdog.o
+diff --git a/hw/iov.c b/hw/iov.c
+new file mode 100644
+index 0000000..588cd04
+--- /dev/null
++++ b/hw/iov.c
+@@ -0,0 +1,70 @@
++/*
++ * Helpers for getting linearized buffers from iov / filling buffers into iovs
++ *
++ * Copyright IBM, Corp. 2007, 2008
++ * Copyright (C) 2010 Red Hat, Inc.
++ *
++ * Author(s):
++ *  Anthony Liguori <aliguori@us.ibm.com>
++ *  Amit Shah <amit.shah@redhat.com>
++ *
++ * This work is licensed under the terms of the GNU GPL, version 2.  See
++ * the COPYING file in the top-level directory.
++ */
++
++#include "iov.h"
++
++size_t iov_from_buf(struct iovec *iov, unsigned int iovcnt,
++                    const void *buf, size_t size)
++{
++    size_t offset;
++    unsigned int i;
++
++    offset = 0;
++    for (i = 0; offset < size && i < iovcnt; i++) {
++        size_t len;
++
++        len = MIN(iov[i].iov_len, size - offset);
++
++        memcpy(iov[i].iov_base, buf + offset, len);
++        offset += len;
++    }
++    return offset;
++}
++
++size_t iov_to_buf(const struct iovec *iov, const unsigned int iovcnt,
++                  void *buf, size_t offset, size_t size)
++{
++    uint8_t *ptr;
++    size_t iov_off, buf_off;
++    unsigned int i;
++
++    ptr = buf;
++    iov_off = 0;
++    buf_off = 0;
++    for (i = 0; i < iovcnt && size; i++) {
++        if (offset < (iov_off + iov[i].iov_len)) {
++            size_t len = MIN((iov_off + iov[i].iov_len) - offset , size);
++
++            memcpy(ptr + buf_off, iov[i].iov_base + (offset - iov_off), len);
++
++            buf_off += len;
++            offset += len;
++            size -= len;
++        }
++        iov_off += iov[i].iov_len;
++    }
++    return buf_off;
++}
++
++size_t iov_size(const struct iovec *iov, const unsigned int iovcnt)
++{
++    size_t len;
++    unsigned int i;
++
++    len = 0;
++    for (i = 0; i < iovcnt; i++) {
++        len += iov[i].iov_len;
++    }
++    return len;
++}
+diff --git a/hw/iov.h b/hw/iov.h
+new file mode 100644
+index 0000000..60a8547
+--- /dev/null
++++ b/hw/iov.h
+@@ -0,0 +1,19 @@
++/*
++ * Helpers for getting linearized buffers from iov / filling buffers into iovs
++ *
++ * Copyright (C) 2010 Red Hat, Inc.
++ *
++ * Author(s):
++ *  Amit Shah <amit.shah@redhat.com>
++ *
++ * This work is licensed under the terms of the GNU GPL, version 2.  See
++ * the COPYING file in the top-level directory.
++ */
++
++#include "qemu-common.h"
++
++size_t iov_from_buf(struct iovec *iov, unsigned int iovcnt,
++                    const void *buf, size_t size);
++size_t iov_to_buf(const struct iovec *iov, const unsigned int iovcnt,
++                  void *buf, size_t offset, size_t size);
++size_t iov_size(const struct iovec *iov, const unsigned int iovcnt);
+diff --git a/hw/virtio-balloon.c b/hw/virtio-balloon.c
+index 242c6c8..10e2647 100644
+--- a/hw/virtio-balloon.c
++++ b/hw/virtio-balloon.c
+@@ -11,6 +11,7 @@
+  *
+  */
+
++#include "iov.h"
+ #include "qemu-common.h"
+ #include "virtio.h"
+ #include "pc.h"
+@@ -47,33 +48,6 @@ static void balloon_page(void *addr, int deflate)
+ #endif
+ }
+
+-/* FIXME: once we do a virtio refactoring, this will get subsumed into common
+- * code */
+-static size_t memcpy_from_iovector(void *data, size_t offset, size_t size,
+-                                   struct iovec *iov, int iovlen)
+-{
+-    int i;
+-    uint8_t *ptr = data;
+-    size_t iov_off = 0;
+-    size_t data_off = 0;
+-
+-    for (i = 0; i < iovlen && size; i++) {
+-        if (offset < (iov_off + iov[i].iov_len)) {
+-            size_t len = MIN((iov_off + iov[i].iov_len) - offset , size);
+-
+-            memcpy(ptr + data_off, iov[i].iov_base + (offset - iov_off), len);
+-
+-            data_off += len;
+-            offset += len;
+-            size -= len;
+-        }
+-
+-        iov_off += iov[i].iov_len;
+-    }
+-
+-    return data_off;
+-}
+-
+ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+ {
+     VirtIOBalloon *s = to_virtio_balloon(vdev);
+@@ -83,8 +57,7 @@ static void virtio_balloon_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+         size_t offset = 0;
+         uint32_t pfn;
+
+-        while (memcpy_from_iovector(&pfn, offset, 4,
+-                                    elem.out_sg, elem.out_num) == 4) {
++        while (iov_to_buf(elem.out_sg, elem.out_num, &pfn, offset, 4) == 4) {
+             ram_addr_t pa;
+             ram_addr_t addr;
+
+diff --git a/hw/virtio-console.c b/hw/virtio-console.c
+index bd44ec6..caea11f 100644
+--- a/hw/virtio-console.c
++++ b/hw/virtio-console.c
+@@ -1,7 +1,7 @@
+ /*
+  * Virtio Console and Generic Serial Port Devices
+  *
+- * Copyright Red Hat, Inc. 2009
++ * Copyright Red Hat, Inc. 2009, 2010
+  *
+  * Authors:
+  *  Amit Shah <amit.shah@redhat.com>
+@@ -20,14 +20,11 @@ typedef struct VirtConsole {
+
+
+ /* Callback function that's called when the guest sends us data */
+-static size_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
++static void flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len)
+ {
+     VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port);
+-    ssize_t ret;
+
+-    ret = qemu_chr_write(vcon->chr, buf, len);
+-
+-    return ret < 0 ? 0 : ret;
++    qemu_chr_write(vcon->chr, buf, len);
+ }
+
+ /* Readiness of the guest to accept data on a port */
+@@ -99,6 +96,7 @@ static VirtIOSerialPortInfo virtconsole_info = {
+     .exit          = virtconsole_exitfn,
+     .qdev.props = (Property[]) {
+         DEFINE_PROP_UINT8("is_console", VirtConsole, port.is_console, 1),
++        DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
+         DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+         DEFINE_PROP_STRING("name", VirtConsole, port.name),
+         DEFINE_PROP_END_OF_LIST(),
+@@ -133,6 +131,7 @@ static VirtIOSerialPortInfo virtserialport_info = {
+     .init          = virtserialport_initfn,
+     .exit          = virtconsole_exitfn,
+     .qdev.props = (Property[]) {
++        DEFINE_PROP_UINT32("nr", VirtConsole, port.id, VIRTIO_CONSOLE_BAD_ID),
+         DEFINE_PROP_CHR("chardev", VirtConsole, chr),
+         DEFINE_PROP_STRING("name", VirtConsole, port.name),
+         DEFINE_PROP_END_OF_LIST(),
+diff --git a/hw/virtio-net.c b/hw/virtio-net.c
+index f8e228f..320e99f 100644
+--- a/hw/virtio-net.c
++++ b/hw/virtio-net.c
+@@ -11,6 +11,7 @@
+  *
+  */
+
++#include "iov.h"
+ #include "virtio.h"
+ #include "net.h"
+ #include "net/checksum.h"
+@@ -436,21 +437,6 @@ static void work_around_broken_dhclient(struct virtio_net_hdr *hdr,
+     }
+ }
+
+-static int iov_fill(struct iovec *iov, int iovcnt, const void *buf, int count)
+-{
+-    int offset, i;
+-
+-    offset = i = 0;
+-    while (offset < count && i < iovcnt) {
+-        int len = MIN(iov[i].iov_len, count - offset);
+-        memcpy(iov[i].iov_base, buf + offset, len);
+-        offset += len;
+-        i++;
+-    }
+-
+-    return offset;
+-}
+-
+ static int receive_header(VirtIONet *n, struct iovec *iov, int iovcnt,
+                           const void *buf, size_t size, size_t hdr_len)
+ {
+@@ -586,8 +572,8 @@ static ssize_t virtio_net_receive(VLANClientState *nc, const uint8_t *buf, size_
+         }
+
+         /* copy in packet.  ugh */
+-        len = iov_fill(sg, elem.in_num,
+-                       buf + offset, size - offset);
++        len = iov_from_buf(sg, elem.in_num,
++                           buf + offset, size - offset);
+         total += len;
+
+         /* signal other side */
+diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c
+index d0e0219..6245f6e 100644
+--- a/hw/virtio-serial-bus.c
++++ b/hw/virtio-serial-bus.c
+@@ -1,7 +1,7 @@
+ /*
+  * A bus for connecting virtio serial and console ports
+  *
+- * Copyright (C) 2009 Red Hat, Inc.
++ * Copyright (C) 2009, 2010 Red Hat, Inc.
+  *
+  * Author(s):
+  *  Amit Shah <amit.shah@redhat.com>
+@@ -15,6 +15,7 @@
+  * the COPYING file in the top-level directory.
+  */
+
++#include "iov.h"
+ #include "monitor.h"
+ #include "qemu-queue.h"
+ #include "sysbus.h"
+@@ -41,6 +42,10 @@ struct VirtIOSerial {
+     VirtIOSerialBus *bus;
+
+     QTAILQ_HEAD(, VirtIOSerialPort) ports;
++
++    /* bitmap for identifying active ports */
++    uint32_t *ports_map;
++
+     struct virtio_console_config config;
+ };
+
+@@ -48,6 +53,10 @@ static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
+ {
+     VirtIOSerialPort *port;
+
++    if (id == VIRTIO_CONSOLE_BAD_ID) {
++        return NULL;
++    }
++
+     QTAILQ_FOREACH(port, &vser->ports, next) {
+         if (port->id == id)
+             return port;
+@@ -76,30 +85,25 @@ static size_t write_to_port(VirtIOSerialPort *port,
+ {
+     VirtQueueElement elem;
+     VirtQueue *vq;
+-    size_t offset = 0;
+-    size_t len = 0;
++    size_t offset;
+
+     vq = port->ivq;
+     if (!virtio_queue_ready(vq)) {
+         return 0;
+     }
+-    if (!size) {
+-        return 0;
+-    }
+
++    offset = 0;
+     while (offset < size) {
+-        int i;
++        size_t len;
+
+         if (!virtqueue_pop(vq, &elem)) {
+             break;
+         }
+
+-        for (i = 0; offset < size && i < elem.in_num; i++) {
+-            len = MIN(elem.in_sg[i].iov_len, size - offset);
++        len = iov_from_buf(elem.in_sg, elem.in_num,
++                           buf + offset, size - offset);
++        offset += len;
+
+-            memcpy(elem.in_sg[i].iov_base, buf + offset, len);
+-            offset += len;
+-        }
+         virtqueue_push(vq, &elem, len);
+     }
+
+@@ -107,6 +111,29 @@ static size_t write_to_port(VirtIOSerialPort *port,
+     return offset;
+ }
+
++static void flush_queued_data(VirtIOSerialPort *port, bool discard)
++{
++    VirtQueue *vq;
++    VirtQueueElement elem;
++
++    vq = port->ovq;
++    while (virtqueue_pop(vq, &elem)) {
++        uint8_t *buf;
++        size_t ret, buf_size;
++
++        if (!discard) {
++            buf_size = iov_size(elem.out_sg, elem.out_num);
++            buf = qemu_malloc(buf_size);
++            ret = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, buf_size);
++
++            port->info->have_data(port, buf, ret);
++            qemu_free(buf);
++        }
++        virtqueue_push(vq, &elem, 0);
++    }
++    virtio_notify(&port->vser->vdev, vq);
++}
++
+ static size_t send_control_msg(VirtIOSerialPort *port, void *buf, size_t len)
+ {
+     VirtQueueElement elem;
+@@ -158,6 +185,13 @@ int virtio_serial_open(VirtIOSerialPort *port)
+ int virtio_serial_close(VirtIOSerialPort *port)
+ {
+     port->host_connected = false;
++    /*
++     * If there's any data the guest sent which the app didn't
++     * consume, discard it and reset the throttling flag.
++     */
++    flush_queued_data(port, true);
++    port->throttled = false;
++
+     send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN, 0);
+
+     return 0;
+@@ -199,8 +233,23 @@ size_t virtio_serial_guest_ready(VirtIOSerialPort *port)
+     return 0;
+ }
+
++void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle)
++{
++    if (!port) {
++        return;
++    }
++
++    if (throttle) {
++        port->throttled = true;
++        return;
++    }
++
++    port->throttled = false;
++    flush_queued_data(port, false);
++}
++
+ /* Guest wants to notify us of some event */
+-static void handle_control_message(VirtIOSerial *vser, void *buf)
++static void handle_control_message(VirtIOSerial *vser, void *buf, size_t len)
+ {
+     struct VirtIOSerialPort *port;
+     struct virtio_console_control cpkt, *gcpkt;
+@@ -208,15 +257,41 @@ static void handle_control_message(VirtIOSerial *vser, void *buf)
+     size_t buffer_len;
+
+     gcpkt = buf;
+-    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
+-    if (!port)
++
++    if (len < sizeof(cpkt)) {
++        /* The guest sent an invalid control packet */
+         return;
++    }
+
+     cpkt.event = lduw_p(&gcpkt->event);
+     cpkt.value = lduw_p(&gcpkt->value);
+
++    port = find_port_by_id(vser, ldl_p(&gcpkt->id));
++    if (!port && cpkt.event != VIRTIO_CONSOLE_DEVICE_READY)
++        return;
++
+     switch(cpkt.event) {
++    case VIRTIO_CONSOLE_DEVICE_READY:
++        if (!cpkt.value) {
++            qemu_error("virtio-serial-bus: Guest failure in adding device %s\n",
++                         vser->bus->qbus.name);
++            break;
++        }
++        /*
++         * The device is up, we can now tell the device about all the
++         * ports we have here.
++         */
++        QTAILQ_FOREACH(port, &vser->ports, next) {
++            send_control_event(port, VIRTIO_CONSOLE_PORT_ADD, 1);
++        }
++        break;
++
+     case VIRTIO_CONSOLE_PORT_READY:
++        if (!cpkt.value) {
++            qemu_error("virtio-serial-bus: Guest failure in adding port %u for device %s\n",
++                         port->id, vser->bus->qbus.name);
++            break;
++        }
+         /*
+          * Now that we know the guest asked for the port name, we're
+          * sure the guest has initialised whatever state is necessary
+@@ -281,12 +356,35 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq)
+ {
+     VirtQueueElement elem;
+     VirtIOSerial *vser;
++    uint8_t *buf;
++    size_t len;
+
+     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
+
++    len = 0;
++    buf = NULL;
+     while (virtqueue_pop(vq, &elem)) {
+-        handle_control_message(vser, elem.out_sg[0].iov_base);
+-        virtqueue_push(vq, &elem, elem.out_sg[0].iov_len);
++        size_t cur_len, copied;
++
++        cur_len = iov_size(elem.out_sg, elem.out_num);
++        /*
++         * Allocate a new buf only if we didn't have one previously or
++         * if the size of the buf differs
++         */
++        if (cur_len > len) {
++            if (len) {
++                qemu_free(buf);
++            }
++            buf = qemu_malloc(cur_len);
++            len = cur_len;
++        }
++        copied = iov_to_buf(elem.out_sg, elem.out_num, buf, 0, len);
++
++        handle_control_message(vser, buf, copied);
++        virtqueue_push(vq, &elem, 0);
++    }
++    if (len) {
++        qemu_free(buf);
+     }
+     virtio_notify(vdev, vq);
+ }
+@@ -295,38 +393,22 @@ static void control_out(VirtIODevice *vdev, VirtQueue *vq)
+ static void handle_output(VirtIODevice *vdev, VirtQueue *vq)
+ {
+     VirtIOSerial *vser;
+-    VirtQueueElement elem;
++    VirtIOSerialPort *port;
++    bool discard;
+
+     vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
++    port = find_port_by_vq(vser, vq);
+
+-    while (virtqueue_pop(vq, &elem)) {
+-        VirtIOSerialPort *port;
+-        size_t ret;
+-
+-        port = find_port_by_vq(vser, vq);
+-        if (!port) {
+-            ret = 0;
+-            goto next_buf;
+-        }
+-
+-        /*
+-         * A port may not have any handler registered for consuming the
+-         * data that the guest sends or it may not have a chardev associated
+-         * with it. Just ignore the data in that case.
+-         */
+-        if (!port->info->have_data) {
+-            ret = 0;
+-            goto next_buf;
+-        }
+-
+-        /* The guest always sends only one sg */
+-        ret = port->info->have_data(port, elem.out_sg[0].iov_base,
+-                                    elem.out_sg[0].iov_len);
++    discard = false;
++    if (!port || !port->host_connected || !port->info->have_data) {
++        discard = true;
++    }
+
+-    next_buf:
+-        virtqueue_push(vq, &elem, ret);
++    if (!discard && port->throttled) {
++        return;
+     }
+-    virtio_notify(vdev, vq);
++
++    flush_queued_data(port, discard);
+ }
+
+ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
+@@ -335,7 +417,10 @@ static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
+
+ static uint32_t get_features(VirtIODevice *vdev, uint32_t features)
+ {
+-    VirtIOSerial *vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
++    VirtIOSerial *vser;
++
++    vser = DO_UPCAST(VirtIOSerial, vdev, vdev);
++
+     if (vser->bus->max_nr_ports > 1) {
+         features |= (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+     }
+@@ -370,14 +455,20 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
+     /* The config space */
+     qemu_put_be16s(f, &s->config.cols);
+     qemu_put_be16s(f, &s->config.rows);
+-    qemu_put_be32s(f, &s->config.nr_ports);
+
+-    /* Items in struct VirtIOSerial */
++    qemu_put_be32s(f, &s->config.max_nr_ports);
++
++    /* The ports map */
++
++    qemu_put_buffer(f, (uint8_t *)s->ports_map,
++                    sizeof(uint32_t) * (s->config.max_nr_ports + 31) / 32);
++
++    /* Ports */
+
+-    /* Do this because we might have hot-unplugged some ports */
+     nr_active_ports = 0;
+-    QTAILQ_FOREACH(port, &s->ports, next)
++    QTAILQ_FOREACH(port, &s->ports, next) {
+         nr_active_ports++;
++    }
+
+     qemu_put_be32s(f, &nr_active_ports);
+
+@@ -385,13 +476,9 @@ static void virtio_serial_save(QEMUFile *f, void *opaque)
+      * Items in struct VirtIOSerialPort.
+      */
+     QTAILQ_FOREACH(port, &s->ports, next) {
+-        /*
+-         * We put the port number because we may not have an active
+-         * port at id 0 that's reserved for a console port, or in case
+-         * of ports that might have gotten unplugged
+-         */
+         qemu_put_be32s(f, &port->id);
+         qemu_put_byte(f, port->guest_connected);
++        qemu_put_byte(f, port->host_connected);
+     }
+ }
+
+@@ -399,7 +486,8 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
+ {
+     VirtIOSerial *s = opaque;
+     VirtIOSerialPort *port;
+-    uint32_t nr_active_ports;
++    size_t ports_map_size;
++    uint32_t max_nr_ports, nr_active_ports, *ports_map;
+     unsigned int i;
+
+     if (version_id > 2) {
+@@ -416,22 +504,50 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id)
+     /* The config space */
+     qemu_get_be16s(f, &s->config.cols);
+     qemu_get_be16s(f, &s->config.rows);
+-    s->config.nr_ports = qemu_get_be32(f);
+
+-    /* Items in struct VirtIOSerial */
++    qemu_get_be32s(f, &max_nr_ports);
++    if (max_nr_ports > s->config.max_nr_ports) {
++        /* Source could have had more ports than us. Fail migration. */
++        return -EINVAL;
++    }
++
++    ports_map_size = sizeof(uint32_t) * (max_nr_ports + 31) / 32;
++    ports_map = qemu_malloc(ports_map_size);
++    qemu_get_buffer(f, (uint8_t *)ports_map, ports_map_size);
++
++    for (i = 0; i < (max_nr_ports + 31) / 32; i++) {
++        if (ports_map[i] != s->ports_map[i]) {
++            /*
++             * Ports active on source and destination don't
++             * match. Fail migration.
++             */
++            qemu_free(ports_map);
++            return -EINVAL;
++        }
++    }
++    qemu_free(ports_map);
+
+     qemu_get_be32s(f, &nr_active_ports);
+
+     /* Items in struct VirtIOSerialPort */
+     for (i = 0; i < nr_active_ports; i++) {
+         uint32_t id;
++        bool host_connected;
+
+         id = qemu_get_be32(f);
+         port = find_port_by_id(s, id);
+
+         port->guest_connected = qemu_get_byte(f);
++        host_connected = qemu_get_byte(f);
++        if (host_connected != port->host_connected) {
++            /*
++             * We have to let the guest know of the host connection
++             * status change
++             */
++            send_control_event(port, VIRTIO_CONSOLE_PORT_OPEN,
++                               port->host_connected);
++        }
+     }
+-
+     return 0;
+ }
+
+@@ -466,6 +582,54 @@ static void virtser_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
+                    indent, "", port->host_connected);
+ }
+
++/* This function is only used if a port id is not provided by the user */
++static uint32_t find_free_port_id(VirtIOSerial *vser)
++{
++    unsigned int i;
++
++    for (i = 0; i < (vser->config.max_nr_ports + 31) / 32; i++) {
++        uint32_t map, bit;
++
++        map = vser->ports_map[i];
++        bit = ffs(~map);
++        if (bit) {
++            return (bit - 1) + i * 32;
++        }
++    }
++    return VIRTIO_CONSOLE_BAD_ID;
++}
++
++static void mark_port_added(VirtIOSerial *vser, uint32_t port_id)
++{
++    unsigned int i;
++
++    i = port_id / 32;
++    vser->ports_map[i] |= 1U << (port_id % 32);
++}
++
++static void add_port(VirtIOSerial *vser, uint32_t port_id)
++{
++    mark_port_added(vser, port_id);
++
++    send_control_event(find_port_by_id(vser, port_id),
++                       VIRTIO_CONSOLE_PORT_ADD, 1);
++}
++
++static void remove_port(VirtIOSerial *vser, uint32_t port_id)
++{
++    VirtIOSerialPort *port;
++    unsigned int i;
++
++    i = port_id / 32;
++    vser->ports_map[i] &= ~(1U << (port_id % 32));
++
++    port = find_port_by_id(vser, port_id);
++    /* Flush out any unconsumed buffers first */
++    flush_queued_data(port, true);
++
++    send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
++}
++
+ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
+ {
+     VirtIOSerialDevice *dev = DO_UPCAST(VirtIOSerialDevice, qdev, qdev);
+@@ -484,19 +648,36 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
+      */
+     plugging_port0 = port->is_console && !find_port_by_id(port->vser, 0);
+
+-    if (port->vser->config.nr_ports == bus->max_nr_ports && !plugging_port0) {
+-        qemu_error("virtio-serial-bus: Maximum device limit reached\n");
++    if (find_port_by_id(port->vser, port->id)) {
++        qemu_error("virtio-serial-bus: A port already exists at id %u\n",
++                     port->id);
+         return -1;
+     }
+-    dev->info = info;
+
++    if (port->id == VIRTIO_CONSOLE_BAD_ID) {
++        if (plugging_port0) {
++            port->id = 0;
++        } else {
++            port->id = find_free_port_id(port->vser);
++            if (port->id == VIRTIO_CONSOLE_BAD_ID) {
++                qemu_error("virtio-serial-bus: Maximum port limit for this device reached\n");
++                return -1;
++            }
++        }
++    }
++
++    if (port->id >= port->vser->config.max_nr_ports) {
++        qemu_error("virtio-serial-bus: Out-of-range port id specified, max. allowed: %u\n",
++                     port->vser->config.max_nr_ports - 1);
++        return -1;
++    }
++
++    dev->info = info;
+     ret = info->init(dev);
+     if (ret) {
+         return ret;
+     }
+
+-    port->id = plugging_port0 ? 0 : port->vser->config.nr_ports++;
+-
+     if (!use_multiport(port->vser)) {
+         /*
+          * Allow writes to guest in this case; we have no way of
+@@ -509,6 +690,8 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base)
+     port->ivq = port->vser->ivqs[port->id];
+     port->ovq = port->vser->ovqs[port->id];
+
++    add_port(port->vser, port->id);
++
+     /* Send an update to the guest about this new port added */
+     virtio_notify_config(&port->vser->vdev);
+
+@@ -521,26 +704,8 @@ static int virtser_port_qdev_exit(DeviceState *qdev)
+     VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev);
+     VirtIOSerial *vser = port->vser;
+
+-    send_control_event(port, VIRTIO_CONSOLE_PORT_REMOVE, 1);
++    remove_port(port->vser, port->id);
+
+-    /*
+-     * Don't decrement nr_ports here; thus we keep a linearly
+-     * increasing port id. Not utilising an id again saves us a couple
+-     * of complications:
+-     *
+-     * - Not having to bother about sending the port id to the guest
+-     *   kernel on hotplug or on addition of new ports; the guest can
+-     *   also linearly increment the port number. This is preferable
+-     *   because the config space won't have the need to store a
+-     *   ports_map.
+-     *
+-     * - Extra state to be stored for all the "holes" that got created
+-     *   so that we keep filling in the ids from the least available
+-     *   index.
+-     *
+-     * When such a functionality is desired, a control message to add
+-     * a port can be introduced.
+-     */
+     QTAILQ_REMOVE(&vser->ports, port, next);
+
+     if (port->info->exit)
+@@ -600,11 +765,12 @@ VirtIODevice *virtio_serial_init(DeviceState *dev, uint32_t max_nr_ports)
+     }
+
+     vser->config.max_nr_ports = max_nr_ports;
++    vser->ports_map = qemu_mallocz((max_nr_ports + 31) / 32);
+     /*
+      * Reserve location 0 for a console port for backward compat
+      * (old kernel, new qemu)
+      */
+-    vser->config.nr_ports = 1;
++    mark_port_added(vser, 0);
+
+     vser->vdev.get_features = get_features;
+     vser->vdev.get_config = get_config;
+diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h
+index f297b00..a93b545 100644
+--- a/hw/virtio-serial.h
++++ b/hw/virtio-serial.h
+@@ -2,7 +2,7 @@
+  * Virtio Serial / Console Support
+  *
+  * Copyright IBM, Corp. 2008
+- * Copyright Red Hat, Inc. 2009
++ * Copyright Red Hat, Inc. 2009, 2010
+  *
+  * Authors:
+  *  Christian Ehrhardt <ehrhardt@linux.vnet.ibm.com>
+@@ -27,6 +27,8 @@
+ /* Features supported */
+ #define VIRTIO_CONSOLE_F_MULTIPORT	1
+
++#define VIRTIO_CONSOLE_BAD_ID           (~(uint32_t)0)
++
+ struct virtio_console_config {
+     /*
+      * These two fields are used by VIRTIO_CONSOLE_F_SIZE which
+@@ -36,7 +38,6 @@ struct virtio_console_config {
+     uint16_t rows;
+
+     uint32_t max_nr_ports;
+-    uint32_t nr_ports;
+ } __attribute__((packed));
+
+ struct virtio_console_control {
+@@ -46,12 +47,14 @@ struct virtio_console_control {
+ };
+
+ /* Some events for the internal messages (control packets) */
+-#define VIRTIO_CONSOLE_PORT_READY	0
+-#define VIRTIO_CONSOLE_CONSOLE_PORT	1
+-#define VIRTIO_CONSOLE_RESIZE		2
+-#define VIRTIO_CONSOLE_PORT_OPEN	3
+-#define VIRTIO_CONSOLE_PORT_NAME	4
+-#define VIRTIO_CONSOLE_PORT_REMOVE	5
++#define VIRTIO_CONSOLE_DEVICE_READY	0
++#define VIRTIO_CONSOLE_PORT_ADD		1
++#define VIRTIO_CONSOLE_PORT_REMOVE	2
++#define VIRTIO_CONSOLE_PORT_READY	3
++#define VIRTIO_CONSOLE_CONSOLE_PORT	4
++#define VIRTIO_CONSOLE_RESIZE		5
++#define VIRTIO_CONSOLE_PORT_OPEN	6
++#define VIRTIO_CONSOLE_PORT_NAME	7
+
+ /* == In-qemu interface == */
+
+@@ -107,6 +110,8 @@ struct VirtIOSerialPort {
+     bool guest_connected;
+     /* Is this device open for IO on the host? */
+     bool host_connected;
++    /* Do apps not want to receive data? */
++    bool throttled;
+ };
+
+ struct VirtIOSerialPortInfo {
+@@ -133,10 +138,10 @@ struct VirtIOSerialPortInfo {
+
+     /*
+      * Guest wrote some data to the port. This data is handed over to
+-     * the app via this callback. The app should return the number of
+-     * bytes it successfully consumed.
++     * the app via this callback.  The app is supposed to consume all
++     * the data that is presented to it.
+      */
+-    size_t (*have_data)(VirtIOSerialPort *port, const uint8_t *buf, size_t len);
++    void (*have_data)(VirtIOSerialPort *port, const uint8_t *buf, size_t len);
+ };
+
+ /* Interface to the virtio-serial bus */
+@@ -170,4 +175,11 @@ ssize_t virtio_serial_write(VirtIOSerialPort *port, const uint8_t *buf,
+  */
+ size_t virtio_serial_guest_ready(VirtIOSerialPort *port);
+
++/*
++ * Flow control: Ports can signal to the virtio-serial core to stop
++ * sending data or re-start sending data, depending on the 'throttle'
++ * value here.
++ */
++void virtio_serial_throttle_port(VirtIOSerialPort *port, bool throttle);
++
+ #endif
+-- 
+1.6.6.1
+
diff --git a/qemu.spec b/qemu.spec
index d7e06e0..309b6f0 100644
--- a/qemu.spec
+++ b/qemu.spec
@@ -1,7 +1,7 @@
 Summary: QEMU is a FAST! processor emulator
 Name: qemu
 Version: 0.12.3
-Release: 4%{?dist}
+Release: 5%{?dist}
 # Epoch because we pushed a qemu-1.0 package
 Epoch: 2
 License: GPLv2+ and LGPLv2+ and BSD
@@ -85,6 +85,7 @@ Patch48: 0048-virtio-serial-pci-Allow-MSI-to-be-disabled.patch
 Patch49: 0049-migration-Clear-fd-also-in-error-cases.patch
 Patch50: 0050-raw-posix-Detect-CDROM-via-ioctl-on-linux.patch
 Patch51: 0051-usb-linux-increase-buffer-for-USB-control-requests.patch
+Patch52: 0052-virtio-console-patches.patch
 
 
 BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
@@ -328,6 +329,7 @@ such as kvmtrace and kvm_stat.
 %patch49 -p1
 %patch50 -p1
 %patch51 -p1
+%patch52 -p1
 
 %build
 # By default we build everything, but allow x86 to build a minimal version
@@ -630,6 +632,9 @@ fi
 %{_mandir}/man1/qemu-img.1*
 
 %changelog
+* Thu Apr 15 2010 Justin M. Forbes <jforbes@redhat.com> - 2:0.12.3-5
+- Update virtio console patches from upstream
+
 * Mon Mar 11 2010 Justin M. Forbes <jforbes@redhat.com> - 2:0.12.3-4
 - Detect cdrom via ioctl (#473154)
 - re add increased buffer for USB control requests (#546483)