From 1ffd2723e8298a84becb6b5e8099cb42319071f9 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Apr 02 2013 16:35:23 +0000 Subject: Fix -vga vmware crashes (bz #836260) Fix vhost crash (bz #918272) Fix kvm module permissions after first install (bz #907215) --- diff --git a/0001-e1000-Discard-oversized-packets-based-on-SBP-LPE.patch b/0001-e1000-Discard-oversized-packets-based-on-SBP-LPE.patch deleted file mode 100644 index c552128..0000000 --- a/0001-e1000-Discard-oversized-packets-based-on-SBP-LPE.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 55c6a5611acc88b9c97fff3324fc743fafc6d0c7 Mon Sep 17 00:00:00 2001 -From: Michael Contreras -Date: Sun, 2 Dec 2012 20:11:22 -0800 -Subject: [PATCH] e1000: Discard packets that are too long if !SBP and !LPE - -The e1000_receive function for the e1000 needs to discard packets longer than -1522 bytes if the SBP and LPE flags are disabled. The linux driver assumes -this behavior and allocates memory based on this assumption. - -Signed-off-by: Michael Contreras -Signed-off-by: Anthony Liguori -(cherry picked from commit b0d9ffcd0251161c7c92f94804dcf599dfa3edeb) - -Signed-off-by: Michael Roth ---- - hw/e1000.c | 10 ++++++++++ - 1 file changed, 10 insertions(+) - -diff --git a/hw/e1000.c b/hw/e1000.c -index 4d4ac32..b1d8508 100644 ---- a/hw/e1000.c -+++ b/hw/e1000.c -@@ -59,6 +59,9 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); - #define PNPMMIO_SIZE 0x20000 - #define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */ - -+/* this is the size past which hardware will drop packets when setting LPE=0 */ -+#define MAXIMUM_ETHERNET_VLAN_SIZE 1522 -+ - /* - * HW models: - * E1000_DEV_ID_82540EM works with Windows and Linux -@@ -795,6 +798,13 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) - size = sizeof(min_buf); - } - -+ /* Discard oversized packets if !LPE and !SBP. */ -+ if (size > MAXIMUM_ETHERNET_VLAN_SIZE -+ && !(s->mac_reg[RCTL] & E1000_RCTL_LPE) -+ && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) { -+ return size; -+ } -+ - if (!receive_filter(s, buf, size)) - return size; - --- -1.8.1 -From 2c0331f4f7d241995452b99afaf0aab00493334a Mon Sep 17 00:00:00 2001 -From: Michael Contreras -Date: Wed, 5 Dec 2012 13:31:30 -0500 -Subject: [PATCH] e1000: Discard oversized packets based on SBP|LPE - -Discard packets longer than 16384 when !SBP to match the hardware behavior. - -Signed-off-by: Michael Contreras -Signed-off-by: Stefan Hajnoczi ---- - hw/e1000.c | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/hw/e1000.c b/hw/e1000.c -index 92fb00a..8fd1654 100644 ---- a/hw/e1000.c -+++ b/hw/e1000.c -@@ -61,6 +61,8 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); - - /* this is the size past which hardware will drop packets when setting LPE=0 */ - #define MAXIMUM_ETHERNET_VLAN_SIZE 1522 -+/* this is the size past which hardware will drop packets when setting LPE=1 */ -+#define MAXIMUM_ETHERNET_LPE_SIZE 16384 - - /* - * HW models: -@@ -809,8 +811,9 @@ e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size) - } - - /* Discard oversized packets if !LPE and !SBP. */ -- if (size > MAXIMUM_ETHERNET_VLAN_SIZE -- && !(s->mac_reg[RCTL] & E1000_RCTL_LPE) -+ if ((size > MAXIMUM_ETHERNET_LPE_SIZE || -+ (size > MAXIMUM_ETHERNET_VLAN_SIZE -+ && !(s->mac_reg[RCTL] & E1000_RCTL_LPE))) - && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) { - return size; - } --- -1.8.1 - diff --git a/0001-qemu-1.0.1-VERSION.patch b/0001-qemu-1.0.1-VERSION.patch deleted file mode 100644 index 5adc9c8..0000000 --- a/0001-qemu-1.0.1-VERSION.patch +++ /dev/null @@ -1,34 +0,0 @@ -From be94aaec72dbacd0d948946ebab482864454b8ff Mon Sep 17 00:00:00 2001 -Message-Id: -From: Kenneth Salerno -Date: Sat, 18 Feb 2012 16:05:44 -0800 -Subject: [PATCH 1/3] qemu-1.0.1/VERSION - -Hello, - -The VERSION file in stable release qemu-1.0.1 has what I believe might be a typo: "1.0,1" rather than "1.0.1". This is causing a parsing issue for windres.exe in Win32 which chokes on: - #define CONFIG_FILEVERSION 1,0,1,0,1,0 - #define CONFIG_PRODUCTVERSION 1,0,1,0,1,0 - -when it should be seeing this: - #define CONFIG_FILEVERSION 1,0,1,0 - #define CONFIG_PRODUCTVERSION 1,0,1,0 - -Patch: - -Signed-off-by: Justin M. Forbes -Signed-off-by: Cole Robinson ---- - VERSION | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/VERSION b/VERSION -index b70c292..7dea76e 100644 ---- a/VERSION -+++ b/VERSION -@@ -1 +1 @@ --1.0,1 -+1.0.1 --- -1.7.11.4 - diff --git a/0001-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch b/0001-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch new file mode 100644 index 0000000..3707c49 --- /dev/null +++ b/0001-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch @@ -0,0 +1,52 @@ +From 8187027c26b65cac0e35edf81f0ca42672e793cb Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 19 Dec 2011 14:59:45 +0100 +Subject: [PATCH] usb-redir: Clear iso / irq error when stopping the stream + +And ignore status messages from the client which arrive after stream +stop (the stream stop send to the client and an error status reported by +the client my cross each other due to network latency). + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index fb91c92..7678f1a 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -410,6 +410,7 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep) + DPRINTF("iso stream stopped ep %02X\n", ep); + dev->endpoint[EP2I(ep)].iso_started = 0; + } ++ dev->endpoint[EP2I(ep)].iso_error = 0; + usbredir_free_bufpq(dev, ep); + } + +@@ -522,6 +523,7 @@ static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev, + DPRINTF("interrupt recv stopped ep %02X\n", ep); + dev->endpoint[EP2I(ep)].interrupt_started = 0; + } ++ dev->endpoint[EP2I(ep)].interrupt_error = 0; + usbredir_free_bufpq(dev, ep); + } + +@@ -1029,7 +1031,7 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id, + DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status, + ep, id); + +- if (!dev->dev.attached) { ++ if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) { + return; + } + +@@ -1050,7 +1052,7 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, + DPRINTF("interrupt recv status %d ep %02X id %u\n", + interrupt_receiving_status->status, ep, id); + +- if (!dev->dev.attached) { ++ if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) { + return; + } + diff --git a/0002-console-bounds-check-whenever-changing-the-cursor-du.patch b/0002-console-bounds-check-whenever-changing-the-cursor-du.patch deleted file mode 100644 index 7c8c7a1..0000000 --- a/0002-console-bounds-check-whenever-changing-the-cursor-du.patch +++ /dev/null @@ -1,129 +0,0 @@ -From 7a6b29b57272ab9559573aa45bc6c41bcb9d9718 Mon Sep 17 00:00:00 2001 -Message-Id: <7a6b29b57272ab9559573aa45bc6c41bcb9d9718.1349639034.git.crobinso@redhat.com> -In-Reply-To: -References: -From: Ian Campbell -Date: Tue, 4 Sep 2012 10:26:09 -0500 -Subject: [PATCH 2/3] console: bounds check whenever changing the cursor due - to an escape code - -This is XSA-17 / CVE-2012-3515 - -Signed-off-by: Ian Campbell -Signed-off-by: Anthony Liguori -(cherry picked from commit 3eea5498ca501922520b3447ba94815bfc109743) -Signed-off-by: Cole Robinson ---- - console.c | 57 ++++++++++++++++++++++++++++----------------------------- - 1 file changed, 28 insertions(+), 29 deletions(-) - -diff --git a/console.c b/console.c -index ed6a653..bfad360 100644 ---- a/console.c -+++ b/console.c -@@ -841,6 +841,26 @@ static void console_clear_xy(TextConsole *s, int x, int y) - update_xy(s, x, y); - } - -+/* set cursor, checking bounds */ -+static void set_cursor(TextConsole *s, int x, int y) -+{ -+ if (x < 0) { -+ x = 0; -+ } -+ if (y < 0) { -+ y = 0; -+ } -+ if (y >= s->height) { -+ y = s->height - 1; -+ } -+ if (x >= s->width) { -+ x = s->width - 1; -+ } -+ -+ s->x = x; -+ s->y = y; -+} -+ - static void console_putchar(TextConsole *s, int ch) - { - TextCell *c; -@@ -912,7 +932,8 @@ static void console_putchar(TextConsole *s, int ch) - s->esc_params[s->nb_esc_params] * 10 + ch - '0'; - } - } else { -- s->nb_esc_params++; -+ if (s->nb_esc_params < MAX_ESC_PARAMS) -+ s->nb_esc_params++; - if (ch == ';') - break; - #ifdef DEBUG_CONSOLE -@@ -926,59 +947,37 @@ static void console_putchar(TextConsole *s, int ch) - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; - } -- s->y -= s->esc_params[0]; -- if (s->y < 0) { -- s->y = 0; -- } -+ set_cursor(s, s->x, s->y - s->esc_params[0]); - break; - case 'B': - /* move cursor down */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; - } -- s->y += s->esc_params[0]; -- if (s->y >= s->height) { -- s->y = s->height - 1; -- } -+ set_cursor(s, s->x, s->y + s->esc_params[0]); - break; - case 'C': - /* move cursor right */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; - } -- s->x += s->esc_params[0]; -- if (s->x >= s->width) { -- s->x = s->width - 1; -- } -+ set_cursor(s, s->x + s->esc_params[0], s->y); - break; - case 'D': - /* move cursor left */ - if (s->esc_params[0] == 0) { - s->esc_params[0] = 1; - } -- s->x -= s->esc_params[0]; -- if (s->x < 0) { -- s->x = 0; -- } -+ set_cursor(s, s->x - s->esc_params[0], s->y); - break; - case 'G': - /* move cursor to column */ -- s->x = s->esc_params[0] - 1; -- if (s->x < 0) { -- s->x = 0; -- } -+ set_cursor(s, s->esc_params[0] - 1, s->y); - break; - case 'f': - case 'H': - /* move cursor to row, column */ -- s->x = s->esc_params[1] - 1; -- if (s->x < 0) { -- s->x = 0; -- } -- s->y = s->esc_params[0] - 1; -- if (s->y < 0) { -- s->y = 0; -- } -+ set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1); - break; - case 'J': - switch (s->esc_params[0]) { --- -1.7.11.4 - diff --git a/0002-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch b/0002-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch new file mode 100644 index 0000000..fd0279a --- /dev/null +++ b/0002-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch @@ -0,0 +1,99 @@ +From fb594e813ed4560598dda8deeabff07fd7292d65 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 19 Dec 2011 13:42:40 +0100 +Subject: [PATCH] usb-redir: Dynamically adjust iso buffering size based on ep + interval + +Note the bufpq_target_size id stored in the endpoint info struct, +even though it only used once. This is done because it will be +referenced from other code in a follow up patch. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 47 insertions(+), 5 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index 7678f1a..ab2c8fa 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -61,6 +61,7 @@ struct endp_data { + uint8_t interrupt_started; + uint8_t interrupt_error; + QTAILQ_HEAD(, buf_packet) bufpq; ++ int bufpq_target_size; + }; + + struct USBRedirDevice { +@@ -332,15 +333,41 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + uint8_t ep) + { + int status, len; +- + if (!dev->endpoint[EP2I(ep)].iso_started && + !dev->endpoint[EP2I(ep)].iso_error) { + struct usb_redir_start_iso_stream_header start_iso = { + .endpoint = ep, +- /* TODO maybe do something with these depending on ep interval? */ +- .pkts_per_urb = 32, +- .no_urbs = 3, + }; ++ int pkts_per_sec; ++ ++ if (dev->dev.speed == USB_SPEED_HIGH) ++ pkts_per_sec = 8000 / dev->endpoint[EP2I(ep)].interval; ++ else ++ pkts_per_sec = 1000 / dev->endpoint[EP2I(ep)].interval; ++ /* Testing has shown that we need circa 60 ms buffer */ ++ dev->endpoint[EP2I(ep)].bufpq_target_size = (pkts_per_sec * 60) / 1000; ++ ++ /* Aim for approx 100 interrupts / second on the client to ++ balance latency and interrupt load */ ++ start_iso.pkts_per_urb = pkts_per_sec / 100; ++ if (start_iso.pkts_per_urb < 1) { ++ start_iso.pkts_per_urb = 1; ++ } else if (start_iso.pkts_per_urb > 32) { ++ start_iso.pkts_per_urb = 32; ++ } ++ ++ start_iso.no_urbs = (dev->endpoint[EP2I(ep)].bufpq_target_size + ++ start_iso.pkts_per_urb - 1) / ++ start_iso.pkts_per_urb; ++ /* Output endpoints pre-fill only 1/2 of the packets, keeping the rest ++ as overflow buffer. Also see the usbredir protocol documentation */ ++ if (!(ep & USB_DIR_IN)) { ++ start_iso.no_urbs *= 2; ++ } ++ if (start_iso.no_urbs > 16) { ++ start_iso.no_urbs = 16; ++ } ++ + /* No id, we look at the ep when receiving a status back */ + usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso); + usbredirparser_do_write(dev->parser); +@@ -961,9 +988,24 @@ static void usbredir_ep_info(void *priv, + dev->endpoint[i].type = ep_info->type[i]; + dev->endpoint[i].interval = ep_info->interval[i]; + dev->endpoint[i].interface = ep_info->interface[i]; +- if (dev->endpoint[i].type != usb_redir_type_invalid) { ++ switch (dev->endpoint[i].type) { ++ case usb_redir_type_invalid: ++ break; ++ case usb_redir_type_iso: ++ case usb_redir_type_interrupt: ++ if (dev->endpoint[i].interval == 0) { ++ ERROR("Received 0 interval for isoc or irq endpoint\n"); ++ usbredir_device_disconnect(dev); ++ } ++ /* Fall through */ ++ case usb_redir_type_control: ++ case usb_redir_type_bulk: + DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i), + dev->endpoint[i].type, dev->endpoint[i].interface); ++ break; ++ default: ++ ERROR("Received invalid endpoint type\n"); ++ usbredir_device_disconnect(dev); + } + } + } diff --git a/0003-slirp-Fix-requeuing-of-batchq-packets-in-if_start.patch b/0003-slirp-Fix-requeuing-of-batchq-packets-in-if_start.patch deleted file mode 100644 index 3990cc8..0000000 --- a/0003-slirp-Fix-requeuing-of-batchq-packets-in-if_start.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 3c5ff5a0a14a2cd7098560f5637bd945cac7f17b Mon Sep 17 00:00:00 2001 -Message-Id: <3c5ff5a0a14a2cd7098560f5637bd945cac7f17b.1349639034.git.crobinso@redhat.com> -In-Reply-To: -References: -From: Jan Kiszka -Date: Fri, 17 Feb 2012 16:26:38 +0100 -Subject: [PATCH 3/3] slirp: Fix requeuing of batchq packets in if_start - -In case we requeued a packet that was the head of a longer session -queue, we failed to restore this ordering. Also, we did not properly -deal with changes to Slirp::next_m. - -Instead of a cumbersome roll back, this fix simply avoids any changes -until we know if the packet was actually sent. Both fixes crashes due -to inconsistent queues and simplifies the logic. - -Thanks to Zhi Yong Wu who found the reason for these crashes. - -CC: Zhi Yong Wu -CC: Fabien Chouteau -Signed-off-by: Jan Kiszka -(cherry picked from commit b248ede2ef2792d364bd305e5e92e24921c924a8) -Signed-off-by: Cole Robinson ---- - slirp/if.c | 35 +++++++++++++++++++---------------- - 1 file changed, 19 insertions(+), 16 deletions(-) - -diff --git a/slirp/if.c b/slirp/if.c -index 2852396..75a3c26 100644 ---- a/slirp/if.c -+++ b/slirp/if.c -@@ -156,6 +156,7 @@ if_start(Slirp *slirp) - { - uint64_t now = qemu_get_clock_ns(rt_clock); - int requeued = 0; -+ bool from_batchq = false; - struct mbuf *ifm, *ifqt; - - DEBUG_CALL("if_start"); -@@ -181,13 +182,26 @@ if_start(Slirp *slirp) - else - ifm = slirp->if_batchq.ifq_next; - -- /* Set which packet to send on next iteration */ -- slirp->next_m = ifm->ifq_next; -+ from_batchq = true; - } -+ -+ slirp->if_queued--; -+ -+ /* Try to send packet unless it already expired */ -+ if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) { -+ /* Packet is delayed due to pending ARP resolution */ -+ requeued++; -+ goto out; -+ } -+ -+ if (from_batchq) { -+ /* Set which packet to send on next iteration */ -+ slirp->next_m = ifm->ifq_next; -+ } -+ - /* Remove it from the queue */ - ifqt = ifm->ifq_prev; - remque(ifm); -- slirp->if_queued--; - - /* If there are more packets for this session, re-queue them */ - if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) { -@@ -202,20 +216,9 @@ if_start(Slirp *slirp) - ifm->ifq_so->so_nqueued = 0; - } - -- if (ifm->expiration_date < now) { -- /* Expired */ -- m_free(ifm); -- } else { -- /* Encapsulate the packet for sending */ -- if (if_encap(slirp, ifm)) { -- m_free(ifm); -- } else { -- /* re-queue */ -- insque(ifm, ifqt); -- requeued++; -- } -- } -+ m_free(ifm); - -+ out: - if (slirp->if_queued) - goto again; - --- -1.7.11.4 - diff --git a/0003-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch b/0003-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch new file mode 100644 index 0000000..26684da --- /dev/null +++ b/0003-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch @@ -0,0 +1,71 @@ +From c9b88c4b22dca99ffc2fde191da5a2f3f50eb2dd Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 19 Dec 2011 14:55:15 +0100 +Subject: [PATCH] usb-redir: Pre-fill our isoc input buffer before sending pkts + to the host + +This is something which should have been done from the first version of +usb-redir, but wasn't. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/usb-redir.c b/usb-redir.c +index ab2c8fa..17ea7a7 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -60,7 +60,9 @@ struct endp_data { + uint8_t iso_error; /* For reporting iso errors to the HC */ + uint8_t interrupt_started; + uint8_t interrupt_error; ++ uint8_t bufpq_prefilled; + QTAILQ_HEAD(, buf_packet) bufpq; ++ int bufpq_size; + int bufpq_target_size; + }; + +@@ -296,6 +298,7 @@ static struct buf_packet *bufp_alloc(USBRedirDevice *dev, + bufp->len = len; + bufp->status = status; + QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); ++ dev->endpoint[EP2I(ep)].bufpq_size++; + return bufp; + } + +@@ -303,6 +306,7 @@ static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp, + uint8_t ep) + { + QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); ++ dev->endpoint[EP2I(ep)].bufpq_size--; + free(bufp->data); + g_free(bufp); + } +@@ -373,14 +377,26 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + usbredirparser_do_write(dev->parser); + DPRINTF("iso stream started ep %02X\n", ep); + dev->endpoint[EP2I(ep)].iso_started = 1; ++ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0; + } + + if (ep & USB_DIR_IN) { + struct buf_packet *isop; + ++ if (dev->endpoint[EP2I(ep)].iso_started && ++ !dev->endpoint[EP2I(ep)].bufpq_prefilled) { ++ if (dev->endpoint[EP2I(ep)].bufpq_size < ++ dev->endpoint[EP2I(ep)].bufpq_target_size) { ++ return usbredir_handle_status(dev, 0, 0); ++ } ++ dev->endpoint[EP2I(ep)].bufpq_prefilled = 1; ++ } ++ + isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); + if (isop == NULL) { + DPRINTF2("iso-token-in ep %02X, no isop\n", ep); ++ /* Re-fill the buffer */ ++ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0; + /* Check iso_error for stream errors, otherwise its an underrun */ + status = dev->endpoint[EP2I(ep)].iso_error; + dev->endpoint[EP2I(ep)].iso_error = 0; diff --git a/0004-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch b/0004-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch new file mode 100644 index 0000000..a835d18 --- /dev/null +++ b/0004-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch @@ -0,0 +1,83 @@ +From 1910610b534d00f5687d9a566dc2a3f3ea93348b Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 20 Dec 2011 16:54:25 +0100 +Subject: [PATCH] usb-redir: Try to keep our buffer size near the target size + +Before this patch we would allow the (iso) buffer to grow unlimited +(and it would under certain circumstances) leading to way too high +latencies for iso data streams. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 30 +++++++++++++++++++++++++++--- + 1 file changed, 27 insertions(+), 3 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index 17ea7a7..88d941a 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -61,6 +61,7 @@ struct endp_data { + uint8_t interrupt_started; + uint8_t interrupt_error; + uint8_t bufpq_prefilled; ++ uint8_t bufpq_dropping_packets; + QTAILQ_HEAD(, buf_packet) bufpq; + int bufpq_size; + int bufpq_target_size; +@@ -290,16 +291,34 @@ static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) + } + } + +-static struct buf_packet *bufp_alloc(USBRedirDevice *dev, ++static void bufp_alloc(USBRedirDevice *dev, + uint8_t *data, int len, int status, uint8_t ep) + { +- struct buf_packet *bufp = g_malloc(sizeof(struct buf_packet)); ++ struct buf_packet *bufp; ++ ++ if (!dev->endpoint[EP2I(ep)].bufpq_dropping_packets && ++ dev->endpoint[EP2I(ep)].bufpq_size > ++ 2 * dev->endpoint[EP2I(ep)].bufpq_target_size) { ++ DPRINTF("bufpq overflow, dropping packets ep %02X\n", ep); ++ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 1; ++ } ++ /* Since we're interupting the stream anyways, drop enough packets to get ++ back to our target buffer size */ ++ if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) { ++ if (dev->endpoint[EP2I(ep)].bufpq_size > ++ dev->endpoint[EP2I(ep)].bufpq_target_size) { ++ free(data); ++ return; ++ } ++ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; ++ } ++ ++ bufp = g_malloc(sizeof(struct buf_packet)); + bufp->data = data; + bufp->len = len; + bufp->status = status; + QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); + dev->endpoint[EP2I(ep)].bufpq_size++; +- return bufp; + } + + static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp, +@@ -378,6 +397,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + DPRINTF("iso stream started ep %02X\n", ep); + dev->endpoint[EP2I(ep)].iso_started = 1; + dev->endpoint[EP2I(ep)].bufpq_prefilled = 0; ++ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; + } + + if (ep & USB_DIR_IN) { +@@ -504,6 +524,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, + usbredirparser_do_write(dev->parser); + DPRINTF("interrupt recv started ep %02X\n", ep); + dev->endpoint[EP2I(ep)].interrupt_started = 1; ++ /* We don't really want to drop interrupt packets ever, but ++ having some upper limit to how much we buffer is good. */ ++ dev->endpoint[EP2I(ep)].bufpq_target_size = 1000; ++ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; + } + + intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); diff --git a/0005-usb-redir-Improve-some-debugging-messages.patch b/0005-usb-redir-Improve-some-debugging-messages.patch new file mode 100644 index 0000000..f7dc024 --- /dev/null +++ b/0005-usb-redir-Improve-some-debugging-messages.patch @@ -0,0 +1,55 @@ +From e5a3a3c10613f3d4055b68232aba221b142c0c8b Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 20 Dec 2011 16:21:34 +0100 +Subject: [PATCH] usb-redir: Improve some debugging messages + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 13 ++++++++----- + 1 file changed, 8 insertions(+), 5 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index 88d941a..86bccf8 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -394,7 +394,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + /* No id, we look at the ep when receiving a status back */ + usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso); + usbredirparser_do_write(dev->parser); +- DPRINTF("iso stream started ep %02X\n", ep); ++ DPRINTF("iso stream started pkts/sec %d pkts/urb %d urbs %d ep %02X\n", ++ pkts_per_sec, start_iso.pkts_per_urb, start_iso.no_urbs, ep); + dev->endpoint[EP2I(ep)].iso_started = 1; + dev->endpoint[EP2I(ep)].bufpq_prefilled = 0; + dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; +@@ -414,7 +415,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + + isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); + if (isop == NULL) { +- DPRINTF2("iso-token-in ep %02X, no isop\n", ep); ++ DPRINTF("iso-token-in ep %02X, no isop, iso_error: %d\n", ++ ep, dev->endpoint[EP2I(ep)].iso_error); + /* Re-fill the buffer */ + dev->endpoint[EP2I(ep)].bufpq_prefilled = 0; + /* Check iso_error for stream errors, otherwise its an underrun */ +@@ -422,8 +424,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + dev->endpoint[EP2I(ep)].iso_error = 0; + return usbredir_handle_status(dev, status, 0); + } +- DPRINTF2("iso-token-in ep %02X status %d len %d\n", ep, isop->status, +- isop->len); ++ DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep, ++ isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); + + status = isop->status; + if (status != usb_redir_success) { +@@ -433,7 +435,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + + len = isop->len; + if (len > p->iov.size) { +- ERROR("received iso data is larger then packet ep %02X\n", ep); ++ ERROR("received iso data is larger then packet ep %02X (%d > %d)\n", ++ ep, len, (int)p->iov.size); + bufp_free(dev, isop, ep); + return USB_RET_NAK; + } diff --git a/0006-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch b/0006-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch new file mode 100644 index 0000000..53c835c --- /dev/null +++ b/0006-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch @@ -0,0 +1,53 @@ +From 7aff5c50d0d24c97220616fd96ec4d1974432ab6 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 21:57:47 +0100 +Subject: [PATCH] char: Split out tcp socket close code in a separate function + +Signed-off-by: Amit Shah +--- + qemu-char.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/qemu-char.c b/qemu-char.c +index 27abcb9..a5ca611 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -2163,6 +2163,21 @@ typedef struct { + + static void tcp_chr_accept(void *opaque); + ++static void tcp_closed(void *opaque) ++{ ++ CharDriverState *chr = opaque; ++ TCPCharDriver *s = chr->opaque; ++ ++ s->connected = 0; ++ if (s->listen_fd >= 0) { ++ qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); ++ } ++ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); ++ closesocket(s->fd); ++ s->fd = -1; ++ qemu_chr_be_event(chr, CHR_EVENT_CLOSED); ++} ++ + static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + { + TCPCharDriver *s = chr->opaque; +@@ -2313,15 +2328,7 @@ static void tcp_chr_read(void *opaque) + len = s->max_size; + size = tcp_chr_recv(chr, (void *)buf, len); + if (size == 0) { +- /* connection closed */ +- s->connected = 0; +- if (s->listen_fd >= 0) { +- qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); +- } +- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); +- closesocket(s->fd); +- s->fd = -1; +- qemu_chr_be_event(chr, CHR_EVENT_CLOSED); ++ tcp_closed(chr); + } else if (size > 0) { + if (s->do_telnetopt) + tcp_chr_process_IAC_bytes(chr, s, buf, &size); diff --git a/0007-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch b/0007-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch new file mode 100644 index 0000000..cb3508b --- /dev/null +++ b/0007-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch @@ -0,0 +1,868 @@ +From 99cc4ac45b73d64e0b96250b8091fc95cf29bf63 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 20:31:45 +0100 +Subject: [PATCH] char: Add a QemuChrHandlers struct to initialise chardev + handlers + +Instead of passing each handler in the qemu_add_handlers() function, +create a struct of handlers that can be passed to the function instead. + +Signed-off-by: Amit Shah +--- + gdbstub.c | 9 +++++++-- + hw/ccid-card-passthru.c | 11 +++++++---- + hw/debugcon.c | 2 +- + hw/escc.c | 9 +++++++-- + hw/etraxfs_ser.c | 13 +++++++++---- + hw/grlib_apbuart.c | 12 +++++++----- + hw/ivshmem.c | 28 ++++++++++++++++++++++------ + hw/lm32_juart.c | 8 +++++++- + hw/lm32_uart.c | 8 +++++++- + hw/mcf_uart.c | 9 +++++++-- + hw/milkymist-uart.c | 8 +++++++- + hw/pl011.c | 9 +++++++-- + hw/pxa2xx.c | 13 +++++++++---- + hw/serial.c | 9 +++++++-- + hw/sh_serial.c | 12 +++++++++--- + hw/spapr_vty.c | 8 ++++++-- + hw/strongarm.c | 12 +++++++----- + hw/syborg_serial.c | 9 +++++++-- + hw/usb-serial.c | 9 +++++++-- + hw/virtio-console.c | 11 ++++++++--- + hw/xen_console.c | 16 +++++++++++----- + hw/xilinx_uartlite.c | 11 +++++++++-- + monitor.c | 18 ++++++++++++++---- + net/slirp.c | 8 ++++++-- + qemu-char.c | 32 ++++++++++++++++++++++---------- + qemu-char.h | 13 +++++++++---- + usb-redir.c | 9 +++++++-- + 27 files changed, 233 insertions(+), 83 deletions(-) + +diff --git a/gdbstub.c b/gdbstub.c +index 640cf4e..b984e12 100644 +--- a/gdbstub.c ++++ b/gdbstub.c +@@ -2860,6 +2860,12 @@ static void gdb_sigterm_handler(int signal) + } + #endif + ++static const QemuChrHandlers gdb_handlers = { ++ .fd_can_read = gdb_chr_can_receive, ++ .fd_read = gdb_chr_receive, ++ .fd_event = gdb_chr_event, ++}; ++ + int gdbserver_start(const char *device) + { + GDBState *s; +@@ -2889,8 +2895,7 @@ int gdbserver_start(const char *device) + if (!chr) + return -1; + +- qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive, +- gdb_chr_event, NULL); ++ qemu_chr_add_handlers(chr, &gdb_handlers, NULL); + } + + s = gdbserver_state; +diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c +index 9f51c6c..c5bff01 100644 +--- a/hw/ccid-card-passthru.c ++++ b/hw/ccid-card-passthru.c +@@ -274,6 +274,12 @@ static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len) + return card->atr; + } + ++static const QemuChrHandlers passthru_handlers = { ++ .fd_can_read = ccid_card_vscard_can_read, ++ .fd_read = ccid_card_vscard_read, ++ .fd_event = ccid_card_vscard_event, ++}; ++ + static int passthru_initfn(CCIDCardState *base) + { + PassthruState *card = DO_UPCAST(PassthruState, base, base); +@@ -282,10 +288,7 @@ static int passthru_initfn(CCIDCardState *base) + card->vscard_in_hdr = 0; + if (card->cs) { + DPRINTF(card, D_INFO, "initing chardev\n"); +- qemu_chr_add_handlers(card->cs, +- ccid_card_vscard_can_read, +- ccid_card_vscard_read, +- ccid_card_vscard_event, card); ++ qemu_chr_add_handlers(card->cs, &passthru_handlers, card); + ccid_card_vscard_send_init(card); + } else { + error_report("missing chardev"); +diff --git a/hw/debugcon.c b/hw/debugcon.c +index c9ee6d9..1d3c3ca 100644 +--- a/hw/debugcon.c ++++ b/hw/debugcon.c +@@ -73,7 +73,7 @@ static void debugcon_init_core(DebugconState *s) + exit(1); + } + +- qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s); ++ qemu_chr_add_handlers(s->chr, NULL, s); + } + + static int debugcon_isa_initfn(ISADevice *dev) +diff --git a/hw/escc.c b/hw/escc.c +index 13c7e66..997377e 100644 +--- a/hw/escc.c ++++ b/hw/escc.c +@@ -867,6 +867,12 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, + sysbus_mmio_map(s, 0, base); + } + ++static const QemuChrHandlers serial_handlers = { ++ .fd_can_read = serial_can_receive, ++ .fd_read = serial_receive1, ++ .fd_event = serial_event, ++}; ++ + static int escc_init1(SysBusDevice *dev) + { + SerialState *s = FROM_SYSBUS(SerialState, dev); +@@ -879,8 +885,7 @@ static int escc_init1(SysBusDevice *dev) + s->chn[i].chn = 1 - i; + s->chn[i].clock = s->frequency / 2; + if (s->chn[i].chr) { +- qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, +- serial_receive1, serial_event, &s->chn[i]); ++ qemu_chr_add_handlers(s->chn[i].chr, &serial_handlers, &s->chn[i]); + } + } + s->chn[0].otherchn = &s->chn[1]; +diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c +index 298b985..29d486e 100644 +--- a/hw/etraxfs_ser.c ++++ b/hw/etraxfs_ser.c +@@ -208,6 +208,12 @@ static void etraxfs_ser_reset(DeviceState *d) + + } + ++static const QemuChrHandlers serial_handlers = { ++ .fd_can_read = serial_can_receive, ++ .fd_read = serial_receive, ++ .fd_event = serial_event, ++}; ++ + static int etraxfs_ser_init(SysBusDevice *dev) + { + struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev); +@@ -217,10 +223,9 @@ static int etraxfs_ser_init(SysBusDevice *dev) + sysbus_init_mmio_region(dev, &s->mmio); + + s->chr = qdev_init_chardev(&dev->qdev); +- if (s->chr) +- qemu_chr_add_handlers(s->chr, +- serial_can_receive, serial_receive, +- serial_event, s); ++ if (s->chr) { ++ qemu_chr_add_handlers(s->chr, &serial_handlers, s); ++ } + return 0; + } + +diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c +index c90b810..ac6c33b 100644 +--- a/hw/grlib_apbuart.c ++++ b/hw/grlib_apbuart.c +@@ -144,16 +144,18 @@ static CPUWriteMemoryFunc * const grlib_apbuart_write[] = { + NULL, NULL, grlib_apbuart_writel, + }; + ++static const QemuChrHandlers grlib_handlers = { ++ .fd_can_read = grlib_apbuart_can_receive, ++ .fd_read = grlib_apbuart_receive, ++ .fd_event = grlib_apbuart_event, ++}; ++ + static int grlib_apbuart_init(SysBusDevice *dev) + { + UART *uart = FROM_SYSBUS(typeof(*uart), dev); + int uart_regs = 0; + +- qemu_chr_add_handlers(uart->chr, +- grlib_apbuart_can_receive, +- grlib_apbuart_receive, +- grlib_apbuart_event, +- uart); ++ qemu_chr_add_handlers(uart->chr, &grlib_handlers, uart); + + sysbus_init_irq(dev, &uart->irq); + +diff --git a/hw/ivshmem.c b/hw/ivshmem.c +index 7b4dbf6..ee78576 100644 +--- a/hw/ivshmem.c ++++ b/hw/ivshmem.c +@@ -276,6 +276,18 @@ static void fake_irqfd(void *opaque, const uint8_t *buf, int size) { + msix_notify(pdev, entry->vector); + } + ++static const QemuChrHandlers ivshmem_handlers = { ++ .fd_can_read = ivshmem_can_receive, ++ .fd_read = ivshmem_receive, ++ .fd_event = ivshmem_event, ++}; ++ ++static const QemuChrHandlers ivshmem_msi_handlers = { ++ .fd_can_read = ivshmem_can_receive, ++ .fd_read = fake_irqfd, ++ .fd_event = ivshmem_event, ++}; ++ + static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd, + int vector) + { +@@ -295,11 +307,10 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd, + s->eventfd_table[vector].pdev = &s->dev; + s->eventfd_table[vector].vector = vector; + +- qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd, +- ivshmem_event, &s->eventfd_table[vector]); ++ qemu_chr_add_handlers(chr, &ivshmem_msi_handlers, ++ &s->eventfd_table[vector]); + } else { +- qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive, +- ivshmem_event, s); ++ qemu_chr_add_handlers(chr, &ivshmem_handlers, s); + } + + return chr; +@@ -614,6 +625,12 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id) + return 0; + } + ++static const QemuChrHandlers ivshmem_server_handlers = { ++ .fd_can_read = ivshmem_can_receive, ++ .fd_read = ivshmem_read, ++ .fd_event = ivshmem_event, ++}; ++ + static int pci_ivshmem_init(PCIDevice *dev) + { + IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev); +@@ -703,8 +720,7 @@ static int pci_ivshmem_init(PCIDevice *dev) + + s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *)); + +- qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read, +- ivshmem_event, s); ++ qemu_chr_add_handlers(s->server_chr, &ivshmem_server_handlers, s); + } else { + /* just map the file immediately, we're not using a server */ + int fd; +diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c +index 5454aa4..1b9fa07 100644 +--- a/hw/lm32_juart.c ++++ b/hw/lm32_juart.c +@@ -110,13 +110,19 @@ static void juart_reset(DeviceState *d) + s->jrx = 0; + } + ++static const QemuChrHandlers juart_handlers = { ++ .fd_can_read = juart_can_rx, ++ .fd_read = juart_rx, ++ .fd_event = juart_event, ++}; ++ + static int lm32_juart_init(SysBusDevice *dev) + { + LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev); + + s->chr = qdev_init_chardev(&dev->qdev); + if (s->chr) { +- qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s); ++ qemu_chr_add_handlers(s->chr, juart_handlers, s); + } + + return 0; +diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c +index 3678545..ccaf88c 100644 +--- a/hw/lm32_uart.c ++++ b/hw/lm32_uart.c +@@ -242,6 +242,12 @@ static void uart_reset(DeviceState *d) + s->regs[R_LSR] = LSR_THRE | LSR_TEMT; + } + ++static const QemuChrHandlers uart_handlers = { ++ .fd_can_read = uart_can_rx, ++ .fd_read = uart_rx, ++ .fd_event = uart_event, ++}; ++ + static int lm32_uart_init(SysBusDevice *dev) + { + LM32UartState *s = FROM_SYSBUS(typeof(*s), dev); +@@ -255,7 +261,7 @@ static int lm32_uart_init(SysBusDevice *dev) + + s->chr = qdev_init_chardev(&dev->qdev); + if (s->chr) { +- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); ++ qemu_chr_add_handlers(s->chr, uart_handlers, s); + } + + return 0; +diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c +index e6b2ab0..2870683 100644 +--- a/hw/mcf_uart.c ++++ b/hw/mcf_uart.c +@@ -268,6 +268,12 @@ static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) + mcf_uart_push_byte(s, buf[0]); + } + ++static const QemuChrHandlers mcf_uart_handlers = { ++ .fd_can_read = mcf_uart_can_receive, ++ .fd_read = mcf_uart_receive, ++ .fd_event = mcf_uart_event, ++}; ++ + void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) + { + mcf_uart_state *s; +@@ -276,8 +282,7 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) + s->chr = chr; + s->irq = irq; + if (chr) { +- qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive, +- mcf_uart_event, s); ++ qemu_chr_add_handlers(chr, &mcf_uart_handlers, s); + } + mcf_uart_reset(s); + return s; +diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c +index 5404ca9..fd10e12 100644 +--- a/hw/milkymist-uart.c ++++ b/hw/milkymist-uart.c +@@ -189,6 +189,12 @@ static void milkymist_uart_reset(DeviceState *d) + s->regs[R_STAT] = STAT_THRE; + } + ++static const QemuChrHandlers uart_handlers = { ++ .fd_can_read = uart_can_rx, ++ .fd_read = uart_rx, ++ .fd_event = uart_event, ++}; ++ + static int milkymist_uart_init(SysBusDevice *dev) + { + MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev); +@@ -201,7 +207,7 @@ static int milkymist_uart_init(SysBusDevice *dev) + + s->chr = qdev_init_chardev(&dev->qdev); + if (s->chr) { +- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); ++ qemu_chr_add_handlers(s->chr, uart_handlers, s); + } + + return 0; +diff --git a/hw/pl011.c b/hw/pl011.c +index 707a161..7482246 100644 +--- a/hw/pl011.c ++++ b/hw/pl011.c +@@ -260,6 +260,12 @@ static const VMStateDescription vmstate_pl011 = { + } + }; + ++static const QemuChrHandlers pl011_handlers = { ++ .fd_can_read = pl011_can_receive, ++ .fd_read = pl011_receive, ++ .fd_event = pl011_event, ++}; ++ + static int pl011_init(SysBusDevice *dev, const unsigned char *id) + { + int iomemtype; +@@ -278,8 +284,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id) + s->cr = 0x300; + s->flags = 0x90; + if (s->chr) { +- qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, +- pl011_event, s); ++ qemu_chr_add_handlers(s->chr, &pl011_handlers, s); + } + vmstate_register(&dev->qdev, -1, &vmstate_pl011, s); + return 0; +diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c +index e9a507e..24925b6 100644 +--- a/hw/pxa2xx.c ++++ b/hw/pxa2xx.c +@@ -1984,6 +1984,12 @@ static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) + return 0; + } + ++static const QemuChrHandlers pxa2xx_handlers = { ++ .fd_can_read = pxa2xx_fir_is_empty, ++ .fd_read = pxa2xx_fir_rx, ++ .fd_event = pxa2xx_fir_event, ++}; ++ + static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, + target_phys_addr_t base, + qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma, +@@ -2002,10 +2008,9 @@ static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, + memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000); + memory_region_add_subregion(sysmem, base, &s->iomem); + +- if (chr) +- qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, +- pxa2xx_fir_rx, pxa2xx_fir_event, s); +- ++ if (chr) { ++ qemu_chr_add_handlers(chr, &pxa2xx_handlers, s); ++ } + register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save, + pxa2xx_fir_load, s); + +diff --git a/hw/serial.c b/hw/serial.c +index d35c7a9..6499d4a 100644 +--- a/hw/serial.c ++++ b/hw/serial.c +@@ -728,6 +728,12 @@ static void serial_reset(void *opaque) + qemu_irq_lower(s->irq); + } + ++static const QemuChrHandlers serial_handlers = { ++ .fd_can_read = serial_can_receive1, ++ .fd_read = serial_receive1, ++ .fd_event = serial_event, ++}; ++ + static void serial_init_core(SerialState *s) + { + if (!s->chr) { +@@ -742,8 +748,7 @@ static void serial_init_core(SerialState *s) + + qemu_register_reset(serial_reset, s); + +- qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, +- serial_event, s); ++ qemu_chr_add_handlers(s->chr, &serial_handlers, s); + } + + /* Change the main reference oscillator frequency. */ +diff --git a/hw/sh_serial.c b/hw/sh_serial.c +index a20c59e..470ce7a 100644 +--- a/hw/sh_serial.c ++++ b/hw/sh_serial.c +@@ -350,6 +350,12 @@ static CPUWriteMemoryFunc * const sh_serial_writefn[] = { + &sh_serial_write, + }; + ++static const QemuChrHandlers sh_serial_handlers = { ++ .fd_can_read = sh_serial_can_receive1, ++ .fd_read = sh_serial_receive1, ++ .fd_event = sh_serial_event, ++}; ++ + void sh_serial_init (target_phys_addr_t base, int feat, + uint32_t freq, CharDriverState *chr, + qemu_irq eri_source, +@@ -389,9 +395,9 @@ void sh_serial_init (target_phys_addr_t base, int feat, + + s->chr = chr; + +- if (chr) +- qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1, +- sh_serial_event, s); ++ if (chr) { ++ qemu_chr_add_handlers(chr, &sh_serial_handlers, s); ++ } + + s->eri = eri_source; + s->rxi = rxi_source; +diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c +index 386ccf7..8ad8226 100644 +--- a/hw/spapr_vty.c ++++ b/hw/spapr_vty.c +@@ -54,6 +54,11 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) + qemu_chr_fe_write(dev->chardev, buf, len); + } + ++static const QemuChrHandlers vty_handlers = { ++ .fd_can_read = vty_can_receive, ++ .fd_read = vty_receive, ++}; ++ + static int spapr_vty_init(VIOsPAPRDevice *sdev) + { + VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; +@@ -63,8 +68,7 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev) + exit(1); + } + +- qemu_chr_add_handlers(dev->chardev, vty_can_receive, +- vty_receive, NULL, dev); ++ qemu_chr_add_handlers(dev->chardev, vty_handlers, dev); + + return 0; + } +diff --git a/hw/strongarm.c b/hw/strongarm.c +index a3d9080..8a8a219 100644 +--- a/hw/strongarm.c ++++ b/hw/strongarm.c +@@ -1160,6 +1160,12 @@ static const MemoryRegionOps strongarm_uart_ops = { + .endianness = DEVICE_NATIVE_ENDIAN, + }; + ++static const QemuChrHandlers strongarm_uart_handlers = { ++ .fd_can_read = strongarm_uart_can_receive, ++ .fd_read = strongarm_uart_receive, ++ .fd_event = strongarm_uart_event, ++}; ++ + static int strongarm_uart_init(SysBusDevice *dev) + { + StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev); +@@ -1172,11 +1178,7 @@ static int strongarm_uart_init(SysBusDevice *dev) + s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s); + + if (s->chr) { +- qemu_chr_add_handlers(s->chr, +- strongarm_uart_can_receive, +- strongarm_uart_receive, +- strongarm_uart_event, +- s); ++ qemu_chr_add_handlers(s->chr, &strongarm_uart_handlers, s); + } + + return 0; +diff --git a/hw/syborg_serial.c b/hw/syborg_serial.c +index c83f82c..fff76da 100644 +--- a/hw/syborg_serial.c ++++ b/hw/syborg_serial.c +@@ -292,6 +292,12 @@ static const VMStateDescription vmstate_syborg_serial = { + } + }; + ++static const QemuChrHandlers syborg_serial_handlers = { ++ .fd_can_read = syborg_serial_can_receive, ++ .fd_read = syborg_serial_receive, ++ .fd_event = syborg_serial_event, ++}; ++ + static int syborg_serial_init(SysBusDevice *dev) + { + SyborgSerialState *s = FROM_SYSBUS(SyborgSerialState, dev); +@@ -304,8 +310,7 @@ static int syborg_serial_init(SysBusDevice *dev) + sysbus_init_mmio(dev, 0x1000, iomemtype); + s->chr = qdev_init_chardev(&dev->qdev); + if (s->chr) { +- qemu_chr_add_handlers(s->chr, syborg_serial_can_receive, +- syborg_serial_receive, syborg_serial_event, s); ++ qemu_chr_add_handlers(s->chr, &syborg_serial_handlers, s); + } + if (s->fifo_size <= 0) { + fprintf(stderr, "syborg_serial: fifo too small\n"); +diff --git a/hw/usb-serial.c b/hw/usb-serial.c +index 7dbf6df..bcf6622 100644 +--- a/hw/usb-serial.c ++++ b/hw/usb-serial.c +@@ -482,6 +482,12 @@ static void usb_serial_event(void *opaque, int event) + } + } + ++static const QemuChrHandlers usb_serial_handlers = { ++ .fd_can_read = usb_serial_can_read, ++ .fd_read = usb_serial_read, ++ .fd_event = usb_serial_event, ++}; ++ + static int usb_serial_initfn(USBDevice *dev) + { + USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev); +@@ -493,8 +499,7 @@ static int usb_serial_initfn(USBDevice *dev) + return -1; + } + +- qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read, +- usb_serial_event, s); ++ qemu_chr_add_handlers(s->cs, &usb_serial_handlers, s); + usb_serial_handle_reset(dev); + return 0; + } +diff --git a/hw/virtio-console.c b/hw/virtio-console.c +index d3351c8..6d6f3ef 100644 +--- a/hw/virtio-console.c ++++ b/hw/virtio-console.c +@@ -95,6 +95,12 @@ static void chr_event(void *opaque, int event) + } + } + ++static const QemuChrHandlers chr_handlers = { ++ .fd_can_read = chr_can_read, ++ .fd_read = chr_read, ++ .fd_event = chr_event, ++}; ++ + static int virtconsole_initfn(VirtIOSerialPort *port) + { + VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); +@@ -107,8 +113,7 @@ static int virtconsole_initfn(VirtIOSerialPort *port) + } + + if (vcon->chr) { +- qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, +- vcon); ++ qemu_chr_add_handlers(vcon->chr, &chr_handlers, vcon); + info->have_data = flush_buf; + info->guest_open = guest_open; + info->guest_close = guest_close; +@@ -126,7 +131,7 @@ static int virtconsole_exitfn(VirtIOSerialPort *port) + * Instead of closing the chardev, free it so it can be used + * for other purposes. + */ +- qemu_chr_add_handlers(vcon->chr, NULL, NULL, NULL, NULL); ++ qemu_chr_add_handlers(vcon->chr, NULL, NULL); + } + + return 0; +diff --git a/hw/xen_console.c b/hw/xen_console.c +index edcb31c..2ba74f0 100644 +--- a/hw/xen_console.c ++++ b/hw/xen_console.c +@@ -212,6 +212,11 @@ out: + return ret; + } + ++static const QemuChrHandlers xencons_handlers = { ++ .fd_can_read = xencons_can_receive, ++ .fd_read = xencons_receive, ++}; ++ + static int con_initialise(struct XenDevice *xendev) + { + struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); +@@ -232,9 +237,9 @@ static int con_initialise(struct XenDevice *xendev) + return -1; + + xen_be_bind_evtchn(&con->xendev); +- if (con->chr) +- qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive, +- NULL, con); ++ if (con->chr) { ++ qemu_chr_add_handlers(con->chr, &xencons_handlers, con); ++ } + + xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n", + con->ring_ref, +@@ -248,8 +253,9 @@ static void con_disconnect(struct XenDevice *xendev) + { + struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); + +- if (con->chr) +- qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL); ++ if (con->chr) { ++ qemu_chr_add_handlers(con->chr, NULL, NULL); ++ } + xen_be_unbind_evtchn(&con->xendev); + + if (con->sring) { +diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c +index ceb7b4d..69f7191 100644 +--- a/hw/xilinx_uartlite.c ++++ b/hw/xilinx_uartlite.c +@@ -195,6 +195,12 @@ static void uart_event(void *opaque, int event) + + } + ++static const QemuChrHandlers uart_handlers = { ++ .fd_can_read = uart_can_rx, ++ .fd_read = uart_rx, ++ .fd_event = uart_event, ++}; ++ + static int xilinx_uartlite_init(SysBusDevice *dev) + { + struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev); +@@ -206,8 +212,9 @@ static int xilinx_uartlite_init(SysBusDevice *dev) + sysbus_init_mmio_region(dev, &s->mmio); + + s->chr = qdev_init_chardev(&dev->qdev); +- if (s->chr) +- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); ++ if (s->chr) { ++ qemu_chr_add_handlers(s->chr, &uart_handlers, s); ++ } + return 0; + } + +diff --git a/monitor.c b/monitor.c +index f956eb7..a82fda3 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -4882,6 +4882,18 @@ static void sortcmdlist(void) + * End: + */ + ++static const QemuChrHandlers monitor_handlers = { ++ .fd_can_read = monitor_can_read, ++ .fd_read = monitor_read, ++ .fd_event = monitor_event, ++}; ++ ++static const QemuChrHandlers monitor_control_handlers = { ++ .fd_can_read = monitor_can_read, ++ .fd_read = monitor_control_read, ++ .fd_event = monitor_control_event, ++}; ++ + void monitor_init(CharDriverState *chr, int flags) + { + static int is_first_init = 1; +@@ -4904,12 +4916,10 @@ void monitor_init(CharDriverState *chr, int flags) + if (monitor_ctrl_mode(mon)) { + mon->mc = g_malloc0(sizeof(MonitorControl)); + /* Control mode requires special handlers */ +- qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read, +- monitor_control_event, mon); ++ qemu_chr_add_handlers(chr, &monitor_control_handlers, mon); + qemu_chr_fe_set_echo(chr, true); + } else { +- qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, +- monitor_event, mon); ++ qemu_chr_add_handlers(chr, &monitor_handlers, mon); + } + + QLIST_INSERT_HEAD(&mon_list, mon, entry); +diff --git a/net/slirp.c b/net/slirp.c +index 6646ecb..05405ff 100644 +--- a/net/slirp.c ++++ b/net/slirp.c +@@ -576,6 +576,11 @@ static void guestfwd_read(void *opaque, const uint8_t *buf, int size) + slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); + } + ++static const QemuChrHandlers guestfwd_handlers = { ++ .fd_can_read = guestfwd_can_read, ++ .fd_read = guestfwd_read, ++}; ++ + static int slirp_guestfwd(SlirpState *s, const char *config_str, + int legacy_format) + { +@@ -632,8 +637,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, + fwd->port = port; + fwd->slirp = s->slirp; + +- qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, +- NULL, fwd); ++ qemu_chr_add_handlers(fwd->hd, &guestfwd_handlers, fwd); + return 0; + + fail_syntax: +diff --git a/qemu-char.c b/qemu-char.c +index a5ca611..d2a99a6 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -189,19 +189,26 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) + va_end(ap); + } + ++static const QemuChrHandlers null_handlers = { ++ /* All handlers are initialised to NULL */ ++}; ++ + void qemu_chr_add_handlers(CharDriverState *s, +- IOCanReadHandler *fd_can_read, +- IOReadHandler *fd_read, +- IOEventHandler *fd_event, +- void *opaque) ++ const QemuChrHandlers *handlers, void *opaque) + { +- if (!opaque && !fd_can_read && !fd_read && !fd_event) { ++ if (!s) { ++ return; ++ } ++ if (!opaque && !handlers) { + /* chr driver being released. */ + ++s->avail_connections; + } +- s->chr_can_read = fd_can_read; +- s->chr_read = fd_read; +- s->chr_event = fd_event; ++ if (!handlers) { ++ handlers = &null_handlers; ++ } ++ s->chr_can_read = handlers->fd_can_read; ++ s->chr_read = handlers->fd_read; ++ s->chr_event = handlers->fd_event; + s->handler_opaque = opaque; + if (s->chr_update_read_handler) + s->chr_update_read_handler(s); +@@ -441,6 +448,12 @@ static void mux_chr_event(void *opaque, int event) + mux_chr_send_event(d, i, event); + } + ++static const QemuChrHandlers mux_chr_handlers = { ++ .fd_can_read = mux_chr_can_read, ++ .fd_read = mux_chr_read, ++ .fd_event = mux_chr_event, ++}; ++ + static void mux_chr_update_read_handler(CharDriverState *chr) + { + MuxDriver *d = chr->opaque; +@@ -455,8 +468,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr) + 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); ++ qemu_chr_add_handlers(d->drv, &mux_chr_handlers, chr); + } + if (d->focus != -1) { + mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); +diff --git a/qemu-char.h b/qemu-char.h +index 8ca1e2d..564e688 100644 +--- a/qemu-char.h ++++ b/qemu-char.h +@@ -222,10 +222,15 @@ void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len); + */ + void qemu_chr_be_event(CharDriverState *s, int event); + +-void qemu_chr_add_handlers(CharDriverState *s, +- IOCanReadHandler *fd_can_read, +- IOReadHandler *fd_read, +- IOEventHandler *fd_event, ++ ++typedef struct QemuChrHandlers { ++ IOCanReadHandler *fd_can_read; ++ IOReadHandler *fd_read; ++ IOHandler *fd_write_unblocked; ++ IOEventHandler *fd_event; ++} QemuChrHandlers; ++ ++void qemu_chr_add_handlers(CharDriverState *s, const QemuChrHandlers *handlers, + void *opaque); + + void qemu_chr_generic_open(CharDriverState *s); +diff --git a/usb-redir.c b/usb-redir.c +index 86bccf8..e421cff 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -865,6 +865,12 @@ static void usbredir_chardev_event(void *opaque, int event) + } + } + ++static const QemuChrHandlers usbredir_chr_handlers = { ++ .fd_can_read = usbredir_chardev_can_read, ++ .fd_read = usbredir_chardev_read, ++ .fd_event = usbredir_chardev_event, ++}; ++ + /* + * init + destroy + */ +@@ -892,8 +898,7 @@ static int usbredir_initfn(USBDevice *udev) + + /* Let the backend know we are ready */ + qemu_chr_fe_open(dev->cs); +- qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read, +- usbredir_chardev_read, usbredir_chardev_event, dev); ++ qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); + + return 0; + } diff --git a/0008-iohandlers-Add-enable-disable_write_fd_handler-funct.patch b/0008-iohandlers-Add-enable-disable_write_fd_handler-funct.patch new file mode 100644 index 0000000..2b68aaf --- /dev/null +++ b/0008-iohandlers-Add-enable-disable_write_fd_handler-funct.patch @@ -0,0 +1,73 @@ +From 216176f588f4a4616bc129ccf5255734c8b1fe93 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 20:32:58 +0100 +Subject: [PATCH] iohandlers: Add enable/disable_write_fd_handler() functions + +These will be used to provide a cleaner API for the nonblocking case. + +Signed-off-by: Amit Shah +--- + iohandler.c | 35 +++++++++++++++++++++++++++++++++++ + main-loop.h | 3 +++ + 2 files changed, 38 insertions(+) + +diff --git a/iohandler.c b/iohandler.c +index 5640d49..a9a62cb 100644 +--- a/iohandler.c ++++ b/iohandler.c +@@ -45,6 +45,41 @@ typedef struct IOHandlerRecord { + static QLIST_HEAD(, IOHandlerRecord) io_handlers = + QLIST_HEAD_INITIALIZER(io_handlers); + ++static IOHandlerRecord *find_iohandler(int fd) ++{ ++ IOHandlerRecord *ioh; ++ ++ QLIST_FOREACH(ioh, &io_handlers, next) { ++ if (ioh->fd == fd) { ++ return ioh; ++ } ++ } ++ return NULL; ++} ++ ++void enable_write_fd_handler(int fd, IOHandler *fd_write) ++{ ++ IOHandlerRecord *ioh; ++ ++ ioh = find_iohandler(fd); ++ if (!ioh) { ++ return; ++ } ++ ++ ioh->fd_write = fd_write; ++} ++ ++void disable_write_fd_handler(int fd) ++{ ++ IOHandlerRecord *ioh; ++ ++ ioh = find_iohandler(fd); ++ if (!ioh) { ++ return; ++ } ++ ++ ioh->fd_write = NULL; ++} + + /* XXX: fd_read_poll should be suppressed, but an API change is + necessary in the character devices to suppress fd_can_read(). */ +diff --git a/main-loop.h b/main-loop.h +index 8a716b1..c5a96cd 100644 +--- a/main-loop.h ++++ b/main-loop.h +@@ -167,6 +167,9 @@ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); + typedef int IOCanReadHandler(void *opaque); + typedef void IOHandler(void *opaque); + ++void enable_write_fd_handler(int fd, IOHandler *fd_write); ++void disable_write_fd_handler(int fd); ++ + /** + * qemu_set_fd_handler2: Register a file descriptor with the main loop + * diff --git a/0009-char-Add-framework-for-a-write-unblocked-callback.patch b/0009-char-Add-framework-for-a-write-unblocked-callback.patch new file mode 100644 index 0000000..a8271ad --- /dev/null +++ b/0009-char-Add-framework-for-a-write-unblocked-callback.patch @@ -0,0 +1,58 @@ +From 17b20a10fec462c5906047b25d4eda83a1fa71dd Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 21:41:42 +0100 +Subject: [PATCH] char: Add framework for a 'write unblocked' callback + +The char layer can let users know that the driver will block on further +input. For users interested in not blocking, they can assign a function +pointer that will be called back when the driver becomes writable. This +patch just adds the function pointers to the CharDriverState structure, +future patches will enable the nonblocking and callback functionality. + +Signed-off-by: Amit Shah +--- + qemu-char.c | 3 +++ + qemu-char.h | 4 ++++ + 2 files changed, 7 insertions(+) + +diff --git a/qemu-char.c b/qemu-char.c +index d2a99a6..66b5887 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -208,11 +208,14 @@ void qemu_chr_add_handlers(CharDriverState *s, + } + s->chr_can_read = handlers->fd_can_read; + s->chr_read = handlers->fd_read; ++ s->chr_write_unblocked = handlers->fd_write_unblocked; + s->chr_event = handlers->fd_event; + s->handler_opaque = opaque; + if (s->chr_update_read_handler) + s->chr_update_read_handler(s); + ++ s->write_blocked = false; ++ + /* We're connecting to an already opened device, so let's make sure we + also get the open event */ + if (s->opened) { +diff --git a/qemu-char.h b/qemu-char.h +index 564e688..2628bee 100644 +--- a/qemu-char.h ++++ b/qemu-char.h +@@ -62,6 +62,9 @@ struct CharDriverState { + IOEventHandler *chr_event; + IOCanReadHandler *chr_can_read; + IOReadHandler *chr_read; ++ IOHandler *chr_write_unblocked; ++ void (*chr_enable_write_fd_handler)(struct CharDriverState *chr); ++ void (*chr_disable_write_fd_handler)(struct CharDriverState *chr); + void *handler_opaque; + void (*chr_close)(struct CharDriverState *chr); + void (*chr_accept_input)(struct CharDriverState *chr); +@@ -74,6 +77,7 @@ struct CharDriverState { + char *filename; + int opened; + int avail_connections; ++ bool write_blocked; /* Are we in a blocked state? */ + QTAILQ_ENTRY(CharDriverState) next; + }; + diff --git a/0010-char-Update-send_all-to-handle-nonblocking-chardev-w.patch b/0010-char-Update-send_all-to-handle-nonblocking-chardev-w.patch new file mode 100644 index 0000000..97971c8 --- /dev/null +++ b/0010-char-Update-send_all-to-handle-nonblocking-chardev-w.patch @@ -0,0 +1,185 @@ +From b9288d382e249663acf99e5d66b75685ec7cb123 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 22:00:27 +0100 +Subject: [PATCH] char: Update send_all() to handle nonblocking chardev write + requests + +The send_all function is modified to return to the caller in case the +driver cannot handle any more data. It returns -EAGAIN or +WSAEWOULDBLOCK on non-Windows and Windows platforms respectively. This +is only done when the caller sets a callback function handler indicating +it's not interested in blocking till the driver has written out all the +data. + +Currently there's no driver or caller that supports this. Future +commits will add such capability. + +Signed-off-by: Amit Shah +--- + net/socket.c | 4 ++-- + qemu-char.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ + qemu_socket.h | 2 +- + 3 files changed, 66 insertions(+), 9 deletions(-) + +diff --git a/net/socket.c b/net/socket.c +index e9ef128..0d53dce 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -56,8 +56,8 @@ static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_ + uint32_t len; + len = htonl(size); + +- send_all(s->fd, (const uint8_t *)&len, sizeof(len)); +- return send_all(s->fd, buf, size); ++ send_all(NULL, s->fd, (const uint8_t *)&len, sizeof(len)); ++ return send_all(NULL, s->fd, buf, size); + } + + static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size) +diff --git a/qemu-char.c b/qemu-char.c +index 66b5887..5e7f68e 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -507,7 +507,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) + + + #ifdef _WIN32 +-int send_all(int fd, const void *buf, int len1) ++static int do_send(int fd, const void *buf, int len1, bool nonblock) + { + int ret, len; + +@@ -515,9 +515,14 @@ int send_all(int fd, const void *buf, int len1) + while (len > 0) { + ret = send(fd, buf, len, 0); + if (ret < 0) { ++ if (nonblock && len1 - len) { ++ return len1 - len; ++ } + errno = WSAGetLastError(); + if (errno != WSAEWOULDBLOCK) { + return -1; ++ } else if (errno == WSAEWOULDBLOCK && nonblock) { ++ return WSAEWOULDBLOCK; + } + } else if (ret == 0) { + break; +@@ -531,7 +536,7 @@ int send_all(int fd, const void *buf, int len1) + + #else + +-int send_all(int fd, const void *_buf, int len1) ++static int do_send(int fd, const void *_buf, int len1, bool nonblock) + { + int ret, len; + const uint8_t *buf = _buf; +@@ -540,8 +545,15 @@ int send_all(int fd, const void *_buf, int len1) + while (len > 0) { + ret = write(fd, buf, len); + if (ret < 0) { +- if (errno != EINTR && errno != EAGAIN) ++ if (nonblock && len1 - len) { ++ return len1 - len; ++ } ++ if (errno == EAGAIN && nonblock) { ++ return -EAGAIN; ++ } ++ if (errno != EINTR && errno != EAGAIN) { + return -1; ++ } + } else if (ret == 0) { + break; + } else { +@@ -556,6 +568,44 @@ int send_all(int fd, const void *_buf, int len1) + #define STDIO_MAX_CLIENTS 1 + static int stdio_nb_clients; + ++int send_all(CharDriverState *chr, int fd, const void *_buf, int len1) ++{ ++ int ret, eagain_errno; ++ bool nonblock; ++ ++ if (chr && chr->write_blocked) { ++ /* ++ * The caller should not send us data while we're blocked, ++ * but this can happen when multiple writers are woken at once, ++ * so simply return -EAGAIN. ++ */ ++ return -EAGAIN; ++ } ++ ++ nonblock = false; ++ /* ++ * Ensure the char backend is able to receive and handle the ++ * 'write unblocked' event before we turn on nonblock support. ++ */ ++ if (chr && chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) { ++ nonblock = true; ++ } ++ ret = do_send(fd, _buf, len1, nonblock); ++ ++#ifdef _WIN32 ++ eagain_errno = WSAEWOULDBLOCK; ++#else ++ eagain_errno = -EAGAIN; ++#endif ++ ++ if (nonblock && (ret == eagain_errno || (ret >= 0 && ret < len1))) { ++ /* Update fd handler to wake up when chr becomes writable */ ++ chr->chr_enable_write_fd_handler(chr); ++ chr->write_blocked = true; ++ } ++ return ret; ++} ++ + #ifndef _WIN32 + + typedef struct { +@@ -567,7 +617,7 @@ typedef struct { + static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + { + FDCharDriver *s = chr->opaque; +- return send_all(s->fd_out, buf, len); ++ return send_all(chr, s->fd_out, buf, len); + } + + static int fd_chr_read_poll(void *opaque) +@@ -892,7 +942,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + pty_chr_update_read_handler(chr); + return 0; + } +- return send_all(s->fd, buf, len); ++ return send_all(chr, s->fd, buf, len); + } + + static int pty_chr_read_poll(void *opaque) +@@ -2196,8 +2246,15 @@ static void tcp_closed(void *opaque) + static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + { + TCPCharDriver *s = chr->opaque; ++ + if (s->connected) { +- return send_all(s->fd, buf, len); ++ int ret; ++ ++ ret = send_all(chr, s->fd, buf, len); ++ if (ret == -1 && errno == EPIPE) { ++ tcp_closed(chr); ++ } ++ return ret; + } else { + /* XXX: indicate an error ? */ + return len; +diff --git a/qemu_socket.h b/qemu_socket.h +index 9e32fac..9ea33fe 100644 +--- a/qemu_socket.h ++++ b/qemu_socket.h +@@ -37,7 +37,7 @@ int qemu_socket(int domain, int type, int protocol); + int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); + void socket_set_block(int fd); + void socket_set_nonblock(int fd); +-int send_all(int fd, const void *buf, int len1); ++int send_all(CharDriverState *chr, int fd, const void *buf, int len1); + + /* New, ipv6-ready socket helper functions, see qemu-sockets.c */ + int inet_listen_opts(QemuOpts *opts, int port_offset); diff --git a/0011-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch b/0011-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch new file mode 100644 index 0000000..75c8753 --- /dev/null +++ b/0011-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch @@ -0,0 +1,78 @@ +From 9add4194da962d50a7452d8097369c7e6f945961 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 22:02:47 +0100 +Subject: [PATCH] char: Equip the unix/tcp backend to handle nonblocking + writes# + +Now that the infrastructure is in place to return -EAGAIN to callers, +individual char drivers can set their update_fd_handlers() function to +set or remove an fd's write handler. This handler checks if the driver +became writable. + +A generic callback routine is used for unblocking writes and letting +users of chardevs know that a driver became writable again. + +Signed-off-by: Amit Shah +--- + qemu-char.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/qemu-char.c b/qemu-char.c +index 5e7f68e..f98b240 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -106,6 +106,19 @@ + static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = + QTAILQ_HEAD_INITIALIZER(chardevs); + ++/* ++ * Generic routine that gets called when chardev becomes writable. ++ * Lets chardev user know it's OK to send more data. ++ */ ++static void char_write_unblocked(void *opaque) ++{ ++ CharDriverState *chr = opaque; ++ ++ chr->write_blocked = false; ++ chr->chr_disable_write_fd_handler(chr); ++ chr->chr_write_unblocked(chr->handler_opaque); ++} ++ + void qemu_chr_be_event(CharDriverState *s, int event) + { + /* Keep track if the char device is open */ +@@ -2515,6 +2528,25 @@ static void tcp_chr_close(CharDriverState *chr) + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); + } + ++static void tcp_enable_write_fd_handler(CharDriverState *chr) ++{ ++ TCPCharDriver *s = chr->opaque; ++ ++ /* ++ * This function is called only after tcp_chr_connect() is called ++ * (either in 'server' mode or client mode. So we're sure of ++ * s->fd being initialised. ++ */ ++ enable_write_fd_handler(s->fd, char_write_unblocked); ++} ++ ++static void tcp_disable_write_fd_handler(CharDriverState *chr) ++{ ++ TCPCharDriver *s = chr->opaque; ++ ++ disable_write_fd_handler(s->fd); ++} ++ + static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr) + { + CharDriverState *chr = NULL; +@@ -2571,6 +2603,8 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr) + chr->chr_close = tcp_chr_close; + chr->get_msgfd = tcp_get_msgfd; + chr->chr_add_client = tcp_chr_add_client; ++ chr->chr_enable_write_fd_handler = tcp_enable_write_fd_handler; ++ chr->chr_disable_write_fd_handler = tcp_disable_write_fd_handler; + + if (is_listen) { + s->listen_fd = fd; diff --git a/0012-char-Throttle-when-host-connection-is-down.patch b/0012-char-Throttle-when-host-connection-is-down.patch new file mode 100644 index 0000000..6465902 --- /dev/null +++ b/0012-char-Throttle-when-host-connection-is-down.patch @@ -0,0 +1,53 @@ +From 7b5e576053c420ee067d754c8c5172928e699f05 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 22:05:10 +0100 +Subject: [PATCH] char: Throttle when host connection is down# + +When the host-side connection goes down, throttle the virtio-serial bus +and later unthrottle when a connection gets established. This helps +prevent any lost IO (guest->host) while the host connection was down. + +Bugzilla: 621484 + +This commit actually helps the bug mentioned above as no writes will now +get lost because of the throttling done here. With just the patches +sent earlier for that bug, one write will end up getting lost in the +worst case (host d/c, guest write, host connect). + +Signed-off-by: Amit Shah +--- + qemu-char.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/qemu-char.c b/qemu-char.c +index f98b240..5f67652 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -140,6 +140,9 @@ static void qemu_chr_generic_open_bh(void *opaque) + { + CharDriverState *s = opaque; + qemu_chr_be_event(s, CHR_EVENT_OPENED); ++ if (s->write_blocked) { ++ char_write_unblocked(s); ++ } + qemu_bh_delete(s->bh); + s->bh = NULL; + } +@@ -2266,6 +2269,17 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + ret = send_all(chr, s->fd, buf, len); + if (ret == -1 && errno == EPIPE) { + tcp_closed(chr); ++ ++ if (chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) { ++ /* ++ * Since we haven't written out anything, let's say ++ * we're throttled. This will prevent any output from ++ * the guest getting lost if host-side chardev goes ++ * down. Unthrottle when we re-connect. ++ */ ++ chr->write_blocked = true; ++ return 0; ++ } + } + return ret; + } else { diff --git a/0013-virtio-console-Enable-port-throttling-when-chardev-i.patch b/0013-virtio-console-Enable-port-throttling-when-chardev-i.patch new file mode 100644 index 0000000..fc1725e --- /dev/null +++ b/0013-virtio-console-Enable-port-throttling-when-chardev-i.patch @@ -0,0 +1,46 @@ +From e41d88487e07341ea2c1ff5f26bb8186dcaeb806 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 22:06:41 +0100 +Subject: [PATCH] virtio-console: Enable port throttling when chardev is slow + to consume data + +When a chardev indicates it can't accept more data, we tell the +virtio-serial code to stop sending us any more data till we tell +otherwise. This helps in guests continuing to run normally while the vq +keeps getting full and eventually the guest stops queueing more data. +As soon as the chardev indicates it can accept more data, start pushing! + +Signed-off-by: Amit Shah +--- + hw/virtio-console.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/virtio-console.c b/hw/virtio-console.c +index 6d6f3ef..da68211 100644 +--- a/hw/virtio-console.c ++++ b/hw/virtio-console.c +@@ -20,6 +20,16 @@ typedef struct VirtConsole { + CharDriverState *chr; + } VirtConsole; + ++/* ++ * Callback function that's called from chardevs when backend becomes ++ * writable. ++ */ ++static void chr_write_unblocked(void *opaque) ++{ ++ VirtConsole *vcon = opaque; ++ ++ virtio_serial_throttle_port(&vcon->port, false); ++} + + /* Callback function that's called when the guest sends us data */ + static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) +@@ -99,6 +109,7 @@ static const QemuChrHandlers chr_handlers = { + .fd_can_read = chr_can_read, + .fd_read = chr_read, + .fd_event = chr_event, ++ .fd_write_unblocked = chr_write_unblocked, + }; + + static int virtconsole_initfn(VirtIOSerialPort *port) diff --git a/0014-spice-qemu-char.c-add-throttling.patch b/0014-spice-qemu-char.c-add-throttling.patch new file mode 100644 index 0000000..85d4977 --- /dev/null +++ b/0014-spice-qemu-char.c-add-throttling.patch @@ -0,0 +1,130 @@ +From 9d324aabba1e20b6f3ed8a673d03f2c8bc0ad8d8 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Tue, 22 Mar 2011 12:27:59 +0200 +Subject: [PATCH] spice-qemu-char.c: add throttling + +BZ: 672191 + +upstream: not submitted (explained below) + +Adds throttling support to spicevmc chardev. Uses a timer to avoid recursing: +1. spice-server: reds.c: read_from_vdi_port +2. qemu: spice-qemu-char.c: vmc_read +3. chr_write_unblocked + (calls virtio_serial_throttle_port(port, false)) +4. qemu: virtio ... +5. qemu: spice-qemu-char.c: spice_chr_write +6. qemu: spice-qemu-char.c: wakeup (calls into spice-server) +7. spice-server: ... +8. qemu: spice-qemu-char.c: vmc_read + +Instead, in vmc_read if we were throttled and we are just about to return +all the bytes we will set a timer to be triggered immediately to call +chr_write_unblocked. Then we return after 2 above, and 3 is called from the +timer callback. This also means we can later remove some ugly recursion protection +from spice-server. + +The other tricky point in this patch is not returning the leftover chunk twice. +When we throttle, by definition we have data that spice server didn't consume. +It is being kept by virtio-serial, and by us. The next vmc_read callback needs +to not return it, but just do unthrottling. Then virtio will give us the remaining +chunk as usual in spice_chr_write, and we will pass it to spice server in the +next vmc_read. + +This patch relies on Amit's series to expose throttling to chardev's, which +was not accepted upstream, and will not be accepted upstream until the mainloop +is reworked to use glib. +--- + spice-qemu-char.c | 39 +++++++++++++++++++++++++++++++++++---- + 1 file changed, 35 insertions(+), 4 deletions(-) + +diff --git a/spice-qemu-char.c b/spice-qemu-char.c +index 7e8eaa9..eeeb32e 100644 +--- a/spice-qemu-char.c ++++ b/spice-qemu-char.c +@@ -1,4 +1,6 @@ + #include "config-host.h" ++#include "qemu-common.h" ++#include "qemu-timer.h" + #include "trace.h" + #include "ui/qemu-spice.h" + #include +@@ -25,6 +27,7 @@ typedef struct SpiceCharDriver { + uint8_t *datapos; + ssize_t bufsize, datalen; + uint32_t debug; ++ QEMUTimer *unblock_timer; + } SpiceCharDriver; + + static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) +@@ -50,6 +53,17 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) + return out; + } + ++static void spice_chr_unblock(void *opaque) ++{ ++ SpiceCharDriver *scd = opaque; ++ ++ if (scd->chr->chr_write_unblocked == NULL) { ++ dprintf(scd, 1, "%s: backend doesn't support unthrottling.\n", __func__); ++ return; ++ } ++ scd->chr->chr_write_unblocked(scd->chr->handler_opaque); ++} ++ + static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) + { + SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); +@@ -61,9 +75,16 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) + scd->datapos += bytes; + scd->datalen -= bytes; + assert(scd->datalen >= 0); +- if (scd->datalen == 0) { +- scd->datapos = 0; +- } ++ } ++ if (scd->datalen == 0 && scd->chr->write_blocked) { ++ dprintf(scd, 1, "%s: unthrottling (%d)\n", __func__, bytes); ++ scd->chr->write_blocked = false; ++ /* ++ * set a timer instead of calling scd->chr->chr_write_unblocked directly, ++ * because that will call back into spice_chr_write (see ++ * virtio-console.c:chr_write_unblocked), which is unwanted. ++ */ ++ qemu_mod_timer(scd->unblock_timer, 0); + } + trace_spice_vmc_read(bytes, len); + return bytes; +@@ -135,6 +156,7 @@ static void vmc_unregister_interface(SpiceCharDriver *scd) + static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + { + SpiceCharDriver *s = chr->opaque; ++ int read_bytes; + + dprintf(s, 2, "%s: %d\n", __func__, len); + vmc_register_interface(s); +@@ -147,7 +169,15 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + s->datapos = s->buffer; + s->datalen = len; + spice_server_char_device_wakeup(&s->sin); +- return len; ++ read_bytes = len - s->datalen; ++ if (read_bytes != len) { ++ dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__, ++ read_bytes, len, s->bufsize); ++ s->chr->write_blocked = true; ++ /* We'll get passed in the unconsumed data with the next call */ ++ s->datalen = 0; ++ } ++ return read_bytes; + } + + static void spice_chr_close(struct CharDriverState *chr) +@@ -225,6 +255,7 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr) + chr->chr_close = spice_chr_close; + chr->chr_guest_open = spice_chr_guest_open; + chr->chr_guest_close = spice_chr_guest_close; ++ s->unblock_timer = qemu_new_timer_ms(vm_clock, spice_chr_unblock, s); + + #if SPICE_SERVER_VERSION < 0x000901 + /* See comment in vmc_state() */ diff --git a/0015-spice-qemu-char.c-remove-intermediate-buffer.patch b/0015-spice-qemu-char.c-remove-intermediate-buffer.patch new file mode 100644 index 0000000..7703d6a --- /dev/null +++ b/0015-spice-qemu-char.c-remove-intermediate-buffer.patch @@ -0,0 +1,68 @@ +From 3ffa1aa2d06a70c0db4a7cafd98948ee157bc68e Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Tue, 22 Mar 2011 12:28:00 +0200 +Subject: [PATCH] spice-qemu-char.c: remove intermediate buffer + +BZ: 672191 +upstream: not submitted (explained below) + +virtio-serial's buffer is valid when it calls us, and we don't +access it otherwise: vmc_read is only called in response to wakeup, +or else we set datalen=0 and throttle. Then vmc_read is called back, +we return 0 (not accessing the buffer) and set the timer to unthrottle. + +Also make datalen int and not ssize_t (to fit spice_chr_write signature). + +This relied on the previous patch that introduces throttling, which +can't go upstream right now as explained in that patch. +--- + spice-qemu-char.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +diff --git a/spice-qemu-char.c b/spice-qemu-char.c +index eeeb32e..70a83bf 100644 +--- a/spice-qemu-char.c ++++ b/spice-qemu-char.c +@@ -23,9 +23,8 @@ typedef struct SpiceCharDriver { + SpiceCharDeviceInstance sin; + char *subtype; + bool active; +- uint8_t *buffer; +- uint8_t *datapos; +- ssize_t bufsize, datalen; ++ const uint8_t *datapos; ++ int datalen; + uint32_t debug; + QEMUTimer *unblock_timer; + } SpiceCharDriver; +@@ -69,7 +68,7 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) + SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); + int bytes = MIN(len, scd->datalen); + +- dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen); ++ dprintf(scd, 2, "%s: %p %d/%d/%d\n", __func__, scd->datapos, len, bytes, scd->datalen); + if (bytes > 0) { + memcpy(buf, scd->datapos, bytes); + scd->datapos += bytes; +@@ -161,18 +160,13 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + dprintf(s, 2, "%s: %d\n", __func__, len); + vmc_register_interface(s); + assert(s->datalen == 0); +- if (s->bufsize < len) { +- s->bufsize = len; +- s->buffer = g_realloc(s->buffer, s->bufsize); +- } +- memcpy(s->buffer, buf, len); +- s->datapos = s->buffer; ++ s->datapos = buf; + s->datalen = len; + spice_server_char_device_wakeup(&s->sin); + read_bytes = len - s->datalen; + if (read_bytes != len) { +- dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__, +- read_bytes, len, s->bufsize); ++ dprintf(s, 1, "%s: throttling: %d < %d\n", __func__, ++ read_bytes, len); + s->chr->write_blocked = true; + /* We'll get passed in the unconsumed data with the next call */ + s->datalen = 0; diff --git a/0016-usb-redir-Add-flow-control-support.patch b/0016-usb-redir-Add-flow-control-support.patch new file mode 100644 index 0000000..a15a69b --- /dev/null +++ b/0016-usb-redir-Add-flow-control-support.patch @@ -0,0 +1,62 @@ +From eae4c4930ff644eee757888bbd43466f9b15d056 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 19 Jul 2011 10:56:19 +0200 +Subject: [PATCH] usb-redir: Add flow control support + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 26 ++++++++++++++++++++++++-- + 1 file changed, 24 insertions(+), 2 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index e421cff..1289506 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -228,12 +228,22 @@ static int usbredir_read(void *priv, uint8_t *data, int count) + static int usbredir_write(void *priv, uint8_t *data, int count) + { + USBRedirDevice *dev = priv; ++ int r; + +- if (!dev->cs->opened) { ++ if (!dev->cs->opened || dev->cs->write_blocked) { + return 0; + } + +- return qemu_chr_fe_write(dev->cs, data, count); ++ r = qemu_chr_fe_write(dev->cs, data, count); ++ ++ if (r < 0) { ++ if (dev->cs->write_blocked) { ++ return 0; ++ } ++ return -1; ++ } ++ ++ return r; + } + + /* +@@ -865,10 +875,22 @@ static void usbredir_chardev_event(void *opaque, int event) + } + } + ++static void usbredir_chardev_write_unblocked(void *opaque) ++{ ++ USBRedirDevice *dev = opaque; ++ ++ if (dev->parser == NULL) { ++ /* usbredir_open_close_bh hasn't handled the open event yet */ ++ return; ++ } ++ usbredirparser_do_write(dev->parser); ++} ++ + static const QemuChrHandlers usbredir_chr_handlers = { + .fd_can_read = usbredir_chardev_can_read, + .fd_read = usbredir_chardev_read, + .fd_event = usbredir_chardev_event, ++ .fd_write_unblocked = usbredir_chardev_write_unblocked, + }; + + /* diff --git a/0017-virtio-serial-bus-replay-guest_open-on-migration.patch b/0017-virtio-serial-bus-replay-guest_open-on-migration.patch new file mode 100644 index 0000000..6f68af8 --- /dev/null +++ b/0017-virtio-serial-bus-replay-guest_open-on-migration.patch @@ -0,0 +1,47 @@ +From 16bd0559ba4870cf2f8c62654bcf1ee523e89afd Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Thu, 28 Jul 2011 15:08:48 +0300 +Subject: [PATCH] virtio-serial-bus: replay guest_open on migration + +When migrating a host with with a spice agent running the mouse becomes +non operational after the migration. This is rhbz #725965. + +The problem is that after migration spice doesn't know the guest agent is open. +Spice is just a char dev here. And a chardev cannot query it's device, the +device has to let the chardev know when it is open. Right now after migration +the chardev which is recreated is in it's default state, which assumes the +guest is disconnected. + +Char devices carry no information across migration, but the virtio-serial does +already carry the guest_connected state. This patch passes that bit to the +chardev. + +Signed-off-by: Alon Levy +--- + hw/virtio-serial-bus.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c +index a4825b9..e5f343f 100644 +--- a/hw/virtio-serial-bus.c ++++ b/hw/virtio-serial-bus.c +@@ -618,6 +618,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) + for (i = 0; i < nr_active_ports; i++) { + uint32_t id; + bool host_connected; ++ VirtIOSerialPortInfo *info; + + id = qemu_get_be32(f); + port = find_port_by_id(s, id); +@@ -626,6 +627,11 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) + } + + port->guest_connected = qemu_get_byte(f); ++ info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info); ++ if (port->guest_connected && info->guest_open) { ++ /* replay guest open */ ++ info->guest_open(port); ++ } + host_connected = qemu_get_byte(f); + if (host_connected != port->host_connected) { + /* diff --git a/0018-char-Disable-write-callback-if-throttled-chardev-is-.patch b/0018-char-Disable-write-callback-if-throttled-chardev-is-.patch new file mode 100644 index 0000000..46c226f --- /dev/null +++ b/0018-char-Disable-write-callback-if-throttled-chardev-is-.patch @@ -0,0 +1,32 @@ +From 774cd5d0718a65bed7032c9306128e79718bb72a Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Fri, 2 Dec 2011 15:42:55 +0530 +Subject: [PATCH] char: Disable write callback if throttled chardev is detached + +If a throttled chardev is detached from the frontend device, all future +callbacks should be suppressed. Not doing this results in a segfault. + +Bugzilla: 745758 +Upstream: Not applicable, since throttling is a RHEL6-only feature. + +Signed-off-by: Amit Shah +--- + qemu-char.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/qemu-char.c b/qemu-char.c +index 5f67652..5a94919 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -220,6 +220,11 @@ void qemu_chr_add_handlers(CharDriverState *s, + ++s->avail_connections; + } + if (!handlers) { ++ if (s->write_blocked) { ++ /* Ensure we disable the callback if we were throttled */ ++ s->chr_disable_write_fd_handler(s); ++ /* s->write_blocked is cleared below */ ++ } + handlers = &null_handlers; + } + s->chr_can_read = handlers->fd_can_read; diff --git a/0019-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch b/0019-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch new file mode 100644 index 0000000..d3ead51 --- /dev/null +++ b/0019-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch @@ -0,0 +1,32 @@ +From 18d2eb3e4dd3d3ecd3ce4dc9ad789403b9e2611a Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 13 Jan 2012 14:26:26 +0100 +Subject: [PATCH] usb-ehci: Clear the portstatus powner bit on device + disconnect + +According to the EHCI spec port ownerhsip should revert to the EHCI controller +on device disconnect. This fixes the problem of a port getting stuck on USB 1 +when using redirection and plugging in a USB 2 device after a USB 1 device +has been redirected. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index a946e1d..69bcc4b 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -764,6 +764,11 @@ static void ehci_detach(USBPort *port) + USBPort *companion = s->companion_ports[port->index]; + companion->ops->detach(companion); + companion->dev = NULL; ++ /* ++ * EHCI spec 4.2.2: "When a disconnect occurs... On the event, ++ * the port ownership is returned immediately to the EHCI controller." ++ */ ++ *portsc &= ~PORTSC_POWNER; + return; + } + diff --git a/0020-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch b/0020-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch new file mode 100644 index 0000000..828f5da --- /dev/null +++ b/0020-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch @@ -0,0 +1,260 @@ +From 74f7edc6c72bf654fbb100895cee3f529706f1be Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 12 Jan 2012 16:54:04 +0100 +Subject: [PATCH] usb-redir: Add the posibility to filter out certain devices + from redirecion + +This patch adds the posibility to filter out certain devices from redirecion. +To use this pass the filter property to -device usb-redir. The filter +property takes a string consisting of filter rules, the format for a rule is: +:::: + +-1 can be used to allow any value for a field. + +Muliple rules can be concatonated using | as a separator. Note that if +a device matches none of the passed in rules, redirecting it will not be +allowed! + +Example: +-device usb-redir,filter='-1:0x0781:0x5567:-1:0|0x08:-1:-1:-1:1' + +This example will deny the Sandisk Cruzer Blade being redirected, as it +has a usb id of 0781:5567, it will allow any other usb mass storage devices, +and it will deny any other devices (the default for devices not matching any +of the rules. + +Signed-off-by: Hans de Goede +--- + configure | 2 +- + usb-redir.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ + 2 files changed, 106 insertions(+), 11 deletions(-) + +diff --git a/configure b/configure +index 4b7faec..bae379c 100755 +--- a/configure ++++ b/configure +@@ -2541,7 +2541,7 @@ fi + + # check for usbredirparser for usb network redirection support + if test "$usb_redir" != "no" ; then +- if $pkg_config libusbredirparser >/dev/null 2>&1 ; then ++ if $pkg_config --atleast-version=0.3.3 libusbredirparser >/dev/null 2>&1 ; then + usb_redir="yes" + usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) + usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) +diff --git a/usb-redir.c b/usb-redir.c +index 1289506..b5f8081 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -34,6 +34,7 @@ + #include + #include + #include ++#include + + #include "hw/usb.h" + +@@ -72,6 +73,7 @@ struct USBRedirDevice { + /* Properties */ + CharDriverState *cs; + uint8_t debug; ++ char *filter_str; + /* Data passed from chardev the fd_read cb to the usbredirparser read cb */ + const uint8_t *read_buf; + int read_buf_size; +@@ -84,6 +86,11 @@ struct USBRedirDevice { + struct endp_data endpoint[MAX_ENDPOINTS]; + uint32_t packet_id; + QTAILQ_HEAD(, AsyncURB) asyncq; ++ /* Data for device filtering */ ++ struct usb_redir_device_connect_header device_info; ++ struct usb_redir_interface_info_header interface_info; ++ struct usbredirfilter_rule *filter_rules; ++ int filter_rules_count; + }; + + struct AsyncURB { +@@ -789,6 +796,7 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, + static void usbredir_open_close_bh(void *opaque) + { + USBRedirDevice *dev = opaque; ++ uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; + + usbredir_device_disconnect(dev); + +@@ -819,7 +827,9 @@ static void usbredir_open_close_bh(void *opaque) + dev->parser->interrupt_packet_func = usbredir_interrupt_packet; + dev->read_buf = NULL; + dev->read_buf_size = 0; +- usbredirparser_init(dev->parser, VERSION, NULL, 0, 0); ++ ++ usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); ++ usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0); + usbredirparser_do_write(dev->parser); + } + } +@@ -907,6 +917,17 @@ static int usbredir_initfn(USBDevice *udev) + return -1; + } + ++ if (dev->filter_str) { ++ i = usbredirfilter_string_to_rules(dev->filter_str, ":", "|", ++ &dev->filter_rules, ++ &dev->filter_rules_count); ++ if (i) { ++ qerror_report(QERR_INVALID_PARAMETER_VALUE, "filter", ++ "a usb device filter string"); ++ return -1; ++ } ++ } ++ + dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev); + dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); + +@@ -955,6 +976,44 @@ static void usbredir_handle_destroy(USBDevice *udev) + if (dev->parser) { + usbredirparser_destroy(dev->parser); + } ++ ++ free(dev->filter_rules); ++} ++ ++static int usbredir_check_filter(USBRedirDevice *dev) ++{ ++ if (dev->interface_info.interface_count == 0) { ++ ERROR("No interface info for device\n"); ++ return -1; ++ } ++ ++ if (dev->filter_rules) { ++ if (!usbredirparser_peer_has_cap(dev->parser, ++ usb_redir_cap_connect_device_version)) { ++ ERROR("Device filter specified and peer does not have the " ++ "connect_device_version capability\n"); ++ return -1; ++ } ++ ++ if (usbredirfilter_check( ++ dev->filter_rules, ++ dev->filter_rules_count, ++ dev->device_info.device_class, ++ dev->device_info.device_subclass, ++ dev->device_info.device_protocol, ++ dev->interface_info.interface_class, ++ dev->interface_info.interface_subclass, ++ dev->interface_info.interface_protocol, ++ dev->interface_info.interface_count, ++ dev->device_info.vendor_id, ++ dev->device_info.product_id, ++ dev->device_info.device_version_bcd, ++ 0) != 0) { ++ return -1; ++ } ++ } ++ ++ return 0; + } + + /* +@@ -983,6 +1042,7 @@ static void usbredir_device_connect(void *priv, + struct usb_redir_device_connect_header *device_connect) + { + USBRedirDevice *dev = priv; ++ const char *speed; + + if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { + ERROR("Received device connect while already connected\n"); +@@ -991,26 +1051,48 @@ static void usbredir_device_connect(void *priv, + + switch (device_connect->speed) { + case usb_redir_speed_low: +- DPRINTF("attaching low speed device\n"); ++ speed = "low speed"; + dev->dev.speed = USB_SPEED_LOW; + break; + case usb_redir_speed_full: +- DPRINTF("attaching full speed device\n"); ++ speed = "full speed"; + dev->dev.speed = USB_SPEED_FULL; + break; + case usb_redir_speed_high: +- DPRINTF("attaching high speed device\n"); ++ speed = "high speed"; + dev->dev.speed = USB_SPEED_HIGH; + break; + case usb_redir_speed_super: +- DPRINTF("attaching super speed device\n"); ++ speed = "super speed"; + dev->dev.speed = USB_SPEED_SUPER; + break; + default: +- DPRINTF("attaching unknown speed device, assuming full speed\n"); ++ speed = "unknown speed"; + dev->dev.speed = USB_SPEED_FULL; + } ++ ++ if (usbredirparser_peer_has_cap(dev->parser, ++ usb_redir_cap_connect_device_version)) { ++ INFO("attaching %s device %04x:%04x version %d.%d class %02x\n", ++ speed, device_connect->vendor_id, device_connect->product_id, ++ device_connect->device_version_bcd >> 8, ++ device_connect->device_version_bcd & 0xff, ++ device_connect->device_class); ++ } else { ++ INFO("attaching %s device %04x:%04x class %02x\n", speed, ++ device_connect->vendor_id, device_connect->product_id, ++ device_connect->device_class); ++ } ++ + dev->dev.speedmask = (1 << dev->dev.speed); ++ dev->device_info = *device_connect; ++ ++ if (usbredir_check_filter(dev)) { ++ WARNING("Device %04x:%04x rejected by device filter, not attaching\n", ++ device_connect->vendor_id, device_connect->product_id); ++ return; ++ } ++ + qemu_mod_timer(dev->attach_timer, dev->next_attach_time); + } + +@@ -1037,15 +1119,27 @@ static void usbredir_device_disconnect(void *priv) + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } ++ dev->interface_info.interface_count = 0; + } + + static void usbredir_interface_info(void *priv, + struct usb_redir_interface_info_header *interface_info) + { +- /* The intention is to allow specifying acceptable interface classes +- for redirection on the cmdline and in the future verify this here, +- and disconnect (or never connect) the device if a not accepted +- interface class is detected */ ++ USBRedirDevice *dev = priv; ++ ++ dev->interface_info = *interface_info; ++ ++ /* ++ * If we receive interface info after the device has already been ++ * connected (ie on a set_config), re-check the filter. ++ */ ++ if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { ++ if (usbredir_check_filter(dev)) { ++ ERROR("Device no longer matches filter after interface info " ++ "change, disconnecting!\n"); ++ usbredir_device_disconnect(dev); ++ } ++ } + } + + static void usbredir_ep_info(void *priv, +@@ -1355,6 +1449,7 @@ static struct USBDeviceInfo usbredir_dev_info = { + .qdev.props = (Property[]) { + DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), + DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), ++ DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str), + DEFINE_PROP_END_OF_LIST(), + }, + }; diff --git a/0021-usb-redir-Fix-printing-of-device-version.patch b/0021-usb-redir-Fix-printing-of-device-version.patch new file mode 100644 index 0000000..0f9cc77 --- /dev/null +++ b/0021-usb-redir-Fix-printing-of-device-version.patch @@ -0,0 +1,30 @@ +From 0bfba65fd1a9495f159d0a1824517d7b05999ca8 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sat, 18 Feb 2012 09:12:14 +0100 +Subject: [PATCH] usb-redir: Fix printing of device version + +The device version is in bcd format, which requires some special handling to +print. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index b5f8081..d64182b 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -1075,8 +1075,10 @@ static void usbredir_device_connect(void *priv, + usb_redir_cap_connect_device_version)) { + INFO("attaching %s device %04x:%04x version %d.%d class %02x\n", + speed, device_connect->vendor_id, device_connect->product_id, +- device_connect->device_version_bcd >> 8, +- device_connect->device_version_bcd & 0xff, ++ ((device_connect->device_version_bcd & 0xf000) >> 12) * 10 + ++ ((device_connect->device_version_bcd & 0x0f00) >> 8), ++ ((device_connect->device_version_bcd & 0x00f0) >> 4) * 10 + ++ ((device_connect->device_version_bcd & 0x000f) >> 0), + device_connect->device_class); + } else { + INFO("attaching %s device %04x:%04x class %02x\n", speed, diff --git a/0022-usb-redir-Always-clear-device-state-on-filter-reject.patch b/0022-usb-redir-Always-clear-device-state-on-filter-reject.patch new file mode 100644 index 0000000..f46bef4 --- /dev/null +++ b/0022-usb-redir-Always-clear-device-state-on-filter-reject.patch @@ -0,0 +1,60 @@ +From dbd558869cab190a75e33a267d22a7fb7ef78a5f Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sat, 18 Feb 2012 09:18:57 +0100 +Subject: [PATCH] usb-redir: Always clear device state on filter reject + +Always call usbredir_device_disconnect() when usbredir_check_filter() fails +to clean up all the device state (ie received endpoint info). + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index d64182b..eb174f0 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -984,7 +984,7 @@ static int usbredir_check_filter(USBRedirDevice *dev) + { + if (dev->interface_info.interface_count == 0) { + ERROR("No interface info for device\n"); +- return -1; ++ goto error; + } + + if (dev->filter_rules) { +@@ -992,7 +992,7 @@ static int usbredir_check_filter(USBRedirDevice *dev) + usb_redir_cap_connect_device_version)) { + ERROR("Device filter specified and peer does not have the " + "connect_device_version capability\n"); +- return -1; ++ goto error; + } + + if (usbredirfilter_check( +@@ -1009,11 +1009,15 @@ static int usbredir_check_filter(USBRedirDevice *dev) + dev->device_info.product_id, + dev->device_info.device_version_bcd, + 0) != 0) { +- return -1; ++ goto error; + } + } + + return 0; ++ ++error: ++ usbredir_device_disconnect(dev); ++ return -1; + } + + /* +@@ -1139,7 +1143,6 @@ static void usbredir_interface_info(void *priv, + if (usbredir_check_filter(dev)) { + ERROR("Device no longer matches filter after interface info " + "change, disconnecting!\n"); +- usbredir_device_disconnect(dev); + } + } + } diff --git a/0023-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch b/0023-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch new file mode 100644 index 0000000..dca4a8a --- /dev/null +++ b/0023-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch @@ -0,0 +1,89 @@ +From 61d885a42da0c504c8455f24cc0b4cbe82ecfbaa Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 19 Feb 2012 09:58:03 +0100 +Subject: [PATCH] usb-redir: Let the usb-host know about our device filtering + +libusbredirparser-0.3.4 adds 2 new packets which allows us to notify +the usb-host: +-about the usb device filter we have (if any), so that it knows not the even + try to redirect certain devices +-when we reject a device based on filtering (in case it tries anyways) + +Signed-off-by: Hans de Goede +--- + configure | 2 +- + usb-redir.c | 20 ++++++++++++++++++++ + 2 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/configure b/configure +index bae379c..59f91d0 100755 +--- a/configure ++++ b/configure +@@ -2541,7 +2541,7 @@ fi + + # check for usbredirparser for usb network redirection support + if test "$usb_redir" != "no" ; then +- if $pkg_config --atleast-version=0.3.3 libusbredirparser >/dev/null 2>&1 ; then ++ if $pkg_config --atleast-version=0.3.4 libusbredirparser >/dev/null 2>&1 ; then + usb_redir="yes" + usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) + usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) +diff --git a/usb-redir.c b/usb-redir.c +index eb174f0..3484479 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -106,6 +106,7 @@ struct AsyncURB { + QTAILQ_ENTRY(AsyncURB)next; + }; + ++static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); + static void usbredir_device_connect(void *priv, + struct usb_redir_device_connect_header *device_connect); + static void usbredir_device_disconnect(void *priv); +@@ -811,6 +812,7 @@ static void usbredir_open_close_bh(void *opaque) + dev->parser->log_func = usbredir_log; + dev->parser->read_func = usbredir_read; + dev->parser->write_func = usbredir_write; ++ dev->parser->hello_func = usbredir_hello; + dev->parser->device_connect_func = usbredir_device_connect; + dev->parser->device_disconnect_func = usbredir_device_disconnect; + dev->parser->interface_info_func = usbredir_interface_info; +@@ -829,6 +831,7 @@ static void usbredir_open_close_bh(void *opaque) + dev->read_buf_size = 0; + + usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); ++ usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); + usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0); + usbredirparser_do_write(dev->parser); + } +@@ -1017,6 +1020,10 @@ static int usbredir_check_filter(USBRedirDevice *dev) + + error: + usbredir_device_disconnect(dev); ++ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { ++ usbredirparser_send_filter_reject(dev->parser); ++ usbredirparser_do_write(dev->parser); ++ } + return -1; + } + +@@ -1042,6 +1049,19 @@ static int usbredir_handle_status(USBRedirDevice *dev, + } + } + ++static void usbredir_hello(void *priv, struct usb_redir_hello_header *h) ++{ ++ USBRedirDevice *dev = priv; ++ ++ /* Try to send the filter info now that we've the usb-host's caps */ ++ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter) && ++ dev->filter_rules) { ++ usbredirparser_send_filter_filter(dev->parser, dev->filter_rules, ++ dev->filter_rules_count); ++ usbredirparser_do_write(dev->parser); ++ } ++} ++ + static void usbredir_device_connect(void *priv, + struct usb_redir_device_connect_header *device_connect) + { diff --git a/0024-usb-redir-Limit-return-values-returned-by-iso-packet.patch b/0024-usb-redir-Limit-return-values-returned-by-iso-packet.patch new file mode 100644 index 0000000..f2d0a38 --- /dev/null +++ b/0024-usb-redir-Limit-return-values-returned-by-iso-packet.patch @@ -0,0 +1,38 @@ +From 2740733386ffa8208f64a8e8e8988724f0ca1dde Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 26 Feb 2012 15:28:51 +0100 +Subject: [PATCH] usb-redir: Limit return values returned by iso packets + +The usbredir protocol uses a status of usb_redir_stall to indicate that +an iso data stream has stopped (ie because the urbs failed on resubmit), +but iso packets should never return a result of USB_RET_STALL, since iso +endpoints cannot stall. So instead simply always return USB_RET_NAK on +iso stream errors. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index 3484479..c0ac7be 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -440,7 +440,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + /* Check iso_error for stream errors, otherwise its an underrun */ + status = dev->endpoint[EP2I(ep)].iso_error; + dev->endpoint[EP2I(ep)].iso_error = 0; +- return usbredir_handle_status(dev, status, 0); ++ return status ? USB_RET_NAK : 0; + } + DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep, + isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); +@@ -448,7 +448,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + status = isop->status; + if (status != usb_redir_success) { + bufp_free(dev, isop, ep); +- return usbredir_handle_status(dev, status, 0); ++ return USB_RET_NAK; + } + + len = isop->len; diff --git a/0025-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch b/0025-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch new file mode 100644 index 0000000..c6de01a --- /dev/null +++ b/0025-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch @@ -0,0 +1,30 @@ +From 3e69c5cc77c4e2e2b9c07d0d30e399705e3cbf09 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sun, 26 Feb 2012 15:51:50 +0100 +Subject: [PATCH] usb-redir: Return USB_RET_NAK when we've no data for an + interrupt endpoint + +We should return USB_RET_NAK, rather then a 0 sized packet, when we've no data +for an interrupt IN endpoint. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/usb-redir.c b/usb-redir.c +index c0ac7be..d10be6f 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -557,7 +557,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, + /* Check interrupt_error for stream errors */ + status = dev->endpoint[EP2I(ep)].interrupt_error; + dev->endpoint[EP2I(ep)].interrupt_error = 0; +- return usbredir_handle_status(dev, status, 0); ++ if (status) { ++ return usbredir_handle_status(dev, status, 0); ++ } ++ return USB_RET_NAK; + } + DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep, + intp->status, intp->len); diff --git a/0026-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch b/0026-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch new file mode 100644 index 0000000..45eae5c --- /dev/null +++ b/0026-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch @@ -0,0 +1,61 @@ +From 7de8a8e7db3f75e5f8fc5edadfcc973e965ef2c3 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 20 Feb 2012 16:27:47 +0100 +Subject: [PATCH] usb-ehci: Handle ISO packets failing with an error other then + NAK + +Before this patch the ehci code was not checking for any other errors other +then USB_RET_NAK. This causes 2 problems: +1) Other errors are not reported to the guest. +2) When transactions with the ITD_XACT_IOC bit set completing with another + error would not result in USBSTS_INT getting set. + +I hit this problem when unplugging devices while iso data was streaming from +the device to the guest. When this happens it takes a while for the guest to +process the unplugging and remove ISO transactions from the ehci schedule, in +the mean time these transactions would complete with a result of USB_RET_NODEV, +which was not handled. This lead to the Linux guest's usb subsystem "hanging", +that is it would no longer see new usb devices getting plugged in and running +for example lsusb would lead to a stuck (D state) lsusb process. This patch +fixes this. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 22 +++++++++++++++++++--- + 1 file changed, 19 insertions(+), 3 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index 69bcc4b..a6b6ae5 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1512,11 +1512,27 @@ static int ehci_process_itd(EHCIState *ehci, + /* IN */ + set_field(&itd->transact[i], ret, ITD_XACT_LENGTH); + } +- +- if (itd->transact[i] & ITD_XACT_IOC) { +- ehci_record_interrupt(ehci, USBSTS_INT); ++ } else { ++ switch (ret) { ++ default: ++ fprintf(stderr, "Unexpected iso usb result: %d\n", ret); ++ /* Fall through */ ++ case USB_RET_NODEV: ++ /* 3.3.2: XACTERR is only allowed on IN transactions */ ++ if (dir) { ++ itd->transact[i] |= ITD_XACT_XACTERR; ++ ehci_record_interrupt(ehci, USBSTS_ERRINT); ++ } ++ break; ++ case USB_RET_BABBLE: ++ itd->transact[i] |= ITD_XACT_BABBLE; ++ ehci_record_interrupt(ehci, USBSTS_ERRINT); ++ break; + } + } ++ if (itd->transact[i] & ITD_XACT_IOC) { ++ ehci_record_interrupt(ehci, USBSTS_INT); ++ } + itd->transact[i] &= ~ITD_XACT_ACTIVE; + } + } diff --git a/0027-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch b/0027-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch new file mode 100644 index 0000000..bd544a4 --- /dev/null +++ b/0027-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch @@ -0,0 +1,57 @@ +From 4d4fb021905e8d6bf382daa247a1a8da58fef8b7 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 27 Feb 2012 11:44:52 +0100 +Subject: [PATCH] usb-ehci: Never follow table entries with the T-bit set + +Before this patch the T-bit was not checked in 2 places, while it should be. + +Once we properly check the T-bit everywhere we no longer need the weird +entry < 0x1000 and entry > 0x1000 checks, so this patch removes them. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index a6b6ae5..37076a9 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1596,8 +1596,7 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async) + int again = 0; + uint32_t entry = ehci_get_fetch_addr(ehci, async); + +- if (entry < 0x1000) { +- DPRINTF("fetchentry: entry invalid (0x%08x)\n", entry); ++ if (NLPTR_TBIT(entry)) { + ehci_set_state(ehci, async, EST_ACTIVE); + goto out; + } +@@ -1705,7 +1704,8 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + if (q->qh.token & QTD_TOKEN_HALT) { + ehci_set_state(ehci, async, EST_HORIZONTALQH); + +- } else if ((q->qh.token & QTD_TOKEN_ACTIVE) && (q->qh.current_qtd > 0x1000)) { ++ } else if ((q->qh.token & QTD_TOKEN_ACTIVE) && ++ (NLPTR_TBIT(q->qh.current_qtd) == 0)) { + q->qtdaddr = q->qh.current_qtd; + ehci_set_state(ehci, async, EST_FETCHQTD); + +@@ -1784,7 +1784,6 @@ static int ehci_state_advqueue(EHCIQueue *q, int async) + * want data and alt-next qTD is valid + */ + if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) && +- (q->qh.altnext_qtd > 0x1000) && + (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) { + q->qtdaddr = q->qh.altnext_qtd; + ehci_set_state(q->ehci, async, EST_FETCHQTD); +@@ -1792,8 +1791,7 @@ static int ehci_state_advqueue(EHCIQueue *q, int async) + /* + * next qTD is valid + */ +- } else if ((q->qh.next_qtd > 0x1000) && +- (NLPTR_TBIT(q->qh.next_qtd) == 0)) { ++ } else if (NLPTR_TBIT(q->qh.next_qtd) == 0) { + q->qtdaddr = q->qh.next_qtd; + ehci_set_state(q->ehci, async, EST_FETCHQTD); + diff --git a/0028-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch b/0028-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch new file mode 100644 index 0000000..fac12ca --- /dev/null +++ b/0028-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch @@ -0,0 +1,215 @@ +From 69ac2b074d687e0143da70c528515563b1c742c5 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 28 Feb 2012 16:34:38 +0100 +Subject: [PATCH] usb-ehci: split our qh queue into async and periodic queues + +qhs can be part of both the async and the periodic schedule, as is shown +in later patches in this series it is useful to keep track of the qhs on +a per schedule basis. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 62 +++++++++++++++++++++++++++++++++++------------------------ + 1 file changed, 37 insertions(+), 25 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index 37076a9..980cce3 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -347,7 +347,6 @@ enum async_state { + struct EHCIQueue { + EHCIState *ehci; + QTAILQ_ENTRY(EHCIQueue) next; +- bool async_schedule; + uint32_t seen; + uint64_t ts; + +@@ -367,6 +366,8 @@ struct EHCIQueue { + int usb_status; + }; + ++typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead; ++ + struct EHCIState { + PCIDevice dev; + USBBus bus; +@@ -410,7 +411,8 @@ struct EHCIState { + USBPort ports[NB_PORTS]; + USBPort *companion_ports[NB_PORTS]; + uint32_t usbsts_pending; +- QTAILQ_HEAD(, EHCIQueue) queues; ++ EHCIQueueHead aqueues; ++ EHCIQueueHead pqueues; + + uint32_t a_fetch_addr; // which address to look at next + uint32_t p_fetch_addr; // which address to look at next +@@ -660,31 +662,34 @@ static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr, + + static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async) + { ++ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + EHCIQueue *q; + + q = g_malloc0(sizeof(*q)); + q->ehci = ehci; +- q->async_schedule = async; +- QTAILQ_INSERT_HEAD(&ehci->queues, q, next); ++ QTAILQ_INSERT_HEAD(head, q, next); + trace_usb_ehci_queue_action(q, "alloc"); + return q; + } + +-static void ehci_free_queue(EHCIQueue *q) ++static void ehci_free_queue(EHCIQueue *q, int async) + { ++ EHCIQueueHead *head = async ? &q->ehci->aqueues : &q->ehci->pqueues; + trace_usb_ehci_queue_action(q, "free"); + if (q->async == EHCI_ASYNC_INFLIGHT) { + usb_cancel_packet(&q->packet); + } +- QTAILQ_REMOVE(&q->ehci->queues, q, next); ++ QTAILQ_REMOVE(head, q, next); + g_free(q); + } + +-static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr) ++static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, ++ int async) + { ++ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + EHCIQueue *q; + +- QTAILQ_FOREACH(q, &ehci->queues, next) { ++ QTAILQ_FOREACH(q, head, next) { + if (addr == q->qhaddr) { + return q; + } +@@ -692,11 +697,12 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr) + return NULL; + } + +-static void ehci_queues_rip_unused(EHCIState *ehci) ++static void ehci_queues_rip_unused(EHCIState *ehci, int async) + { ++ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + EHCIQueue *q, *tmp; + +- QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { ++ QTAILQ_FOREACH_SAFE(q, head, next, tmp) { + if (q->seen) { + q->seen = 0; + q->ts = ehci->last_run_ns; +@@ -706,28 +712,30 @@ static void ehci_queues_rip_unused(EHCIState *ehci) + /* allow 0.25 sec idle */ + continue; + } +- ehci_free_queue(q); ++ ehci_free_queue(q, async); + } + } + +-static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev) ++static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) + { ++ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + EHCIQueue *q, *tmp; + +- QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { ++ QTAILQ_FOREACH_SAFE(q, head, next, tmp) { + if (q->packet.owner != dev) { + continue; + } +- ehci_free_queue(q); ++ ehci_free_queue(q, async); + } + } + +-static void ehci_queues_rip_all(EHCIState *ehci) ++static void ehci_queues_rip_all(EHCIState *ehci, int async) + { ++ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + EHCIQueue *q, *tmp; + +- QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { +- ehci_free_queue(q); ++ QTAILQ_FOREACH_SAFE(q, head, next, tmp) { ++ ehci_free_queue(q, async); + } + } + +@@ -772,7 +780,8 @@ static void ehci_detach(USBPort *port) + return; + } + +- ehci_queues_rip_device(s, port->dev); ++ ehci_queues_rip_device(s, port->dev, 0); ++ ehci_queues_rip_device(s, port->dev, 1); + + *portsc &= ~(PORTSC_CONNECT|PORTSC_PED); + *portsc |= PORTSC_CSC; +@@ -792,7 +801,8 @@ static void ehci_child_detach(USBPort *port, USBDevice *child) + return; + } + +- ehci_queues_rip_device(s, child); ++ ehci_queues_rip_device(s, child, 0); ++ ehci_queues_rip_device(s, child, 1); + } + + static void ehci_wakeup(USBPort *port) +@@ -890,7 +900,8 @@ static void ehci_reset(void *opaque) + usb_send_msg(devs[i], USB_MSG_RESET); + } + } +- ehci_queues_rip_all(s); ++ ehci_queues_rip_all(s, 0); ++ ehci_queues_rip_all(s, 1); + } + + static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) +@@ -1554,7 +1565,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) + ehci_set_usbsts(ehci, USBSTS_REC); + } + +- ehci_queues_rip_unused(ehci); ++ ehci_queues_rip_unused(ehci, async); + + /* Find the head of the list (4.9.1.1) */ + for(i = 0; i < MAX_QH; i++) { +@@ -1641,7 +1652,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + int reload; + + entry = ehci_get_fetch_addr(ehci, async); +- q = ehci_find_queue_by_qh(ehci, entry); ++ q = ehci_find_queue_by_qh(ehci, entry, async); + if (NULL == q) { + q = ehci_alloc_queue(ehci, async); + } +@@ -2092,7 +2103,7 @@ static void ehci_advance_state(EHCIState *ehci, + + static void ehci_advance_async_state(EHCIState *ehci) + { +- int async = 1; ++ const int async = 1; + + switch(ehci_get_state(ehci, async)) { + case EST_INACTIVE: +@@ -2149,7 +2160,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) + { + uint32_t entry; + uint32_t list; +- int async = 0; ++ const int async = 0; + + // 4.6 + +@@ -2366,7 +2377,8 @@ static int usb_ehci_initfn(PCIDevice *dev) + } + + s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s); +- QTAILQ_INIT(&s->queues); ++ QTAILQ_INIT(&s->aqueues); ++ QTAILQ_INIT(&s->pqueues); + + qemu_register_reset(ehci_reset, s); + diff --git a/0029-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch b/0029-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch new file mode 100644 index 0000000..bdaf33a --- /dev/null +++ b/0029-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch @@ -0,0 +1,39 @@ +From 11fd62d6fd2bea9537fb7915b19043bbad88c410 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 2 Mar 2012 13:52:44 +0100 +Subject: [PATCH] usb-ehci: always call ehci_queues_rip_unused for period + queues + +Before this patch USB 2 devices with interrupt endpoints were not working +properly. The problem is that to avoid loops we stop processing as soon +as we encounter a queue-head (qh) we've already seen since qhs can be linked +in a circular fashion, this is tracked by the seen flag in our qh struct. + +The resetting of the seen flag is done from ehci_queues_rip_unused which +before this patch was only called when executing the statemachine for the +async schedule. + +But packets for interrupt endpoints are part of the periodic schedule! So what +would happen is that when there were no ctrl or bulk packets for a USB 2 +device with an interrupt endpoint, the async schedule would become non +active, then ehci_queues_rip_unused would no longer get called and when +processing the qhs for the interrupt endpoints from the periodic schedule +their seen bit would still be 1 and they would be skipped. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index 980cce3..422afc8 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -2195,6 +2195,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) + ehci_set_fetch_addr(ehci, async,entry); + ehci_set_state(ehci, async, EST_FETCHENTRY); + ehci_advance_state(ehci, async); ++ ehci_queues_rip_unused(ehci, async, 0); + break; + + default: diff --git a/0030-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch b/0030-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch new file mode 100644 index 0000000..4faa5de --- /dev/null +++ b/0030-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch @@ -0,0 +1,111 @@ +From 27a9a7c516996ae28d635edaaec956be0e919d76 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 1 Mar 2012 15:20:17 +0100 +Subject: [PATCH] usb-ehci: Drop cached qhs when the doorbell gets rung + +The purpose of the IAAD bit / the doorbell is to make the ehci controller +forget about cached qhs, this is mainly used when cancelling transactions, +the qh is unlinked from the async schedule and then the doorbell gets rung, +once the doorbell is acked by the controller the hcd knows that the qh is +no longer in use and that it can do something else with the memory, such +as re-use it for a new qh! But we keep our struct representing this qh around +for circa 250 ms. This allows for a (mightily large) race window where the +following could happen: +-hcd submits a qh at address 0xdeadbeef +-our ehci code sees the qh, sends a request to a usb-device, gets a result + of USB_RET_ASYNC, sets the async_state of the qh to EHCI_ASYNC_INFLIGHT +-hcd unlinks the qh at address 0xdeadbeef +-hcd rings the doorbell, wait for us to ack it +-hcd re-uses the qh at address 0xdeadbeef +-our ehci code sees the qh, looks in the async_queue, sees there already is + a qh at address 0xdeadbeef there with async_state of EHCI_ASYNC_INFLIGHT, + does nothing +-the *original* (which the hcd thinks it has cancelled) transaction finishes +-our ehci code sees the qh on yet another pass through the async list, + looks in the async_queue, sees there already is a qh at address 0xdeadbeef + there with async_state of EHCI_ASYNC_COMPLETED, and finished the transaction + with the results of the *original* transaction. + +Not good (tm), this patch fixes this race by removing all qhs which have not +been seen during the last cycle through the async list immidiately when the +doorbell is rung. + +Note this patch does not fix any actually observed problem, but upon +reading of the EHCI spec it became apparent to me that the above race could +happen and the usb-ehci behavior from before this patch is not good. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 31 ++++++++++++++++--------------- + 1 file changed, 16 insertions(+), 15 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index 422afc8..b8ba483 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -697,7 +697,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, + return NULL; + } + +-static void ehci_queues_rip_unused(EHCIState *ehci, int async) ++static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) + { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + EHCIQueue *q, *tmp; +@@ -708,7 +708,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async) + q->ts = ehci->last_run_ns; + continue; + } +- if (ehci->last_run_ns < q->ts + 250000000) { ++ if (!flush && ehci->last_run_ns < q->ts + 250000000) { + /* allow 0.25 sec idle */ + continue; + } +@@ -1565,7 +1565,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) + ehci_set_usbsts(ehci, USBSTS_REC); + } + +- ehci_queues_rip_unused(ehci, async); ++ ehci_queues_rip_unused(ehci, async, 0); + + /* Find the head of the list (4.9.1.1) */ + for(i = 0; i < MAX_QH; i++) { +@@ -2121,18 +2121,7 @@ static void ehci_advance_async_state(EHCIState *ehci) + break; + } + +- /* If the doorbell is set, the guest wants to make a change to the +- * schedule. The host controller needs to release cached data. +- * (section 4.8.2) +- */ +- if (ehci->usbcmd & USBCMD_IAAD) { +- DPRINTF("ASYNC: doorbell request acknowledged\n"); +- ehci->usbcmd &= ~USBCMD_IAAD; +- ehci_set_interrupt(ehci, USBSTS_IAA); +- break; +- } +- +- /* make sure guest has acknowledged */ ++ /* make sure guest has acknowledged the doorbell interrupt */ + /* TO-DO: is this really needed? */ + if (ehci->usbsts & USBSTS_IAA) { + DPRINTF("IAA status bit still set.\n"); +@@ -2146,6 +2135,18 @@ static void ehci_advance_async_state(EHCIState *ehci) + + ehci_set_state(ehci, async, EST_WAITLISTHEAD); + ehci_advance_state(ehci, async); ++ ++ /* If the doorbell is set, the guest wants to make a change to the ++ * schedule. The host controller needs to release cached data. ++ * (section 4.8.2) ++ */ ++ if (ehci->usbcmd & USBCMD_IAAD) { ++ /* Remove all unseen qhs from the async qhs queue */ ++ ehci_queues_rip_unused(ehci, async, 1); ++ DPRINTF("ASYNC: doorbell request acknowledged\n"); ++ ehci->usbcmd &= ~USBCMD_IAAD; ++ ehci_set_interrupt(ehci, USBSTS_IAA); ++ } + break; + + default: diff --git a/0031-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch b/0031-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch new file mode 100644 index 0000000..fb93ff4 --- /dev/null +++ b/0031-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch @@ -0,0 +1,41 @@ +From ea210d9cf81169777f1bfd0f4cb6e9c86fb1fbe6 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 2 Mar 2012 11:02:04 +0100 +Subject: [PATCH] usb-ehci: Rip the queues when the async or period schedule is + halted + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index b8ba483..11eded7 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1054,7 +1054,8 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) + + if (!(val & USBCMD_RUNSTOP) && (s->usbcmd & USBCMD_RUNSTOP)) { + qemu_del_timer(s->frame_timer); +- // TODO - should finish out some stuff before setting halt ++ ehci_queues_rip_all(s, 0); ++ ehci_queues_rip_all(s, 1); + ehci_set_usbsts(s, USBSTS_HALT); + } + +@@ -2116,6 +2117,7 @@ static void ehci_advance_async_state(EHCIState *ehci) + + case EST_ACTIVE: + if ( !(ehci->usbcmd & USBCMD_ASE)) { ++ ehci_queues_rip_all(ehci, async); + ehci_clear_usbsts(ehci, USBSTS_ASS); + ehci_set_state(ehci, async, EST_INACTIVE); + break; +@@ -2176,6 +2178,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) + + case EST_ACTIVE: + if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) { ++ ehci_queues_rip_all(ehci, async); + ehci_clear_usbsts(ehci, USBSTS_PSS); + ehci_set_state(ehci, async, EST_INACTIVE); + break; diff --git a/0032-usb-ehci-Any-packet-completion-except-for-NAK-should.patch b/0032-usb-ehci-Any-packet-completion-except-for-NAK-should.patch new file mode 100644 index 0000000..20d12c9 --- /dev/null +++ b/0032-usb-ehci-Any-packet-completion-except-for-NAK-should.patch @@ -0,0 +1,30 @@ +From 15e1636b0c32a0b4c0b85bc8b52ada681eb36a00 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 1 Mar 2012 16:34:56 +0100 +Subject: [PATCH] usb-ehci: Any packet completion except for NAK should set the + interrupt + +As clearly stated in the 2.3.2 of the EHCI spec, any time USBERRINT get +sets then if the td has its IOC bit set USBINT should be set as well. + +This means that for any status except for USB_RET_NAK we should set +USBINT if the IOC bit is set. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index 11eded7..bc5f591 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1338,7 +1338,7 @@ err: + q->qh.token ^= QTD_TOKEN_DTOGGLE; + q->qh.token &= ~QTD_TOKEN_ACTIVE; + +- if ((q->usb_status >= 0) && (q->qh.token & QTD_TOKEN_IOC)) { ++ if ((q->usb_status != USB_RET_NAK) && (q->qh.token & QTD_TOKEN_IOC)) { + ehci_record_interrupt(q->ehci, USBSTS_INT); + } + } diff --git a/0033-usb-ehci-Fix-cerr-tracking.patch b/0033-usb-ehci-Fix-cerr-tracking.patch new file mode 100644 index 0000000..30b181d --- /dev/null +++ b/0033-usb-ehci-Fix-cerr-tracking.patch @@ -0,0 +1,69 @@ +From c65a584d05b2e2d5fa1f997981ce6c055a089b3f Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 1 Mar 2012 21:43:56 +0100 +Subject: [PATCH] usb-ehci: Fix cerr tracking + +cerr should only be decremented on errors which cause XactErr to be set, and +when that happens the failing transaction should be retried until cerr reaches +0 and only then should USBSTS_ERRINT be set (and inactive cleared and +USBSTS_INT set if requested). + +Since we don't have any hardware level errors (and in case of redirection +the real hardware has already retried), re-trying makes no sense, so +immediately set cerr to 0 on errors which set XactErr. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 19 ++++++------------- + 1 file changed, 6 insertions(+), 13 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index bc5f591..a3d5c11 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1269,7 +1269,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) + + static void ehci_execute_complete(EHCIQueue *q) + { +- int c_err, reload; ++ int reload; + + assert(q->async != EHCI_ASYNC_INFLIGHT); + q->async = EHCI_ASYNC_NONE; +@@ -1278,15 +1278,10 @@ static void ehci_execute_complete(EHCIQueue *q) + q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status); + + if (q->usb_status < 0) { +-err: +- /* TO-DO: put this is in a function that can be invoked below as well */ +- c_err = get_field(q->qh.token, QTD_TOKEN_CERR); +- c_err--; +- set_field(&q->qh.token, c_err, QTD_TOKEN_CERR); +- + switch(q->usb_status) { + case USB_RET_NODEV: + q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); ++ set_field(&q->qh.token, 0, QTD_TOKEN_CERR); + ehci_record_interrupt(q->ehci, USBSTS_ERRINT); + break; + case USB_RET_STALL: +@@ -1314,15 +1309,13 @@ err: + assert(0); + break; + } ++ } else if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) { ++ q->usb_status = USB_RET_BABBLE; ++ q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); ++ ehci_record_interrupt(q->ehci, USBSTS_ERRINT); + } else { +- // DPRINTF("Short packet condition\n"); + // TODO check 4.12 for splits + +- if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) { +- q->usb_status = USB_RET_BABBLE; +- goto err; +- } +- + if (q->tbytes && q->pid == USB_TOKEN_IN) { + q->tbytes -= q->usb_status; + } else { diff --git a/0034-usb-ehci-Remove-dead-nakcnt-code.patch b/0034-usb-ehci-Remove-dead-nakcnt-code.patch new file mode 100644 index 0000000..6705335 --- /dev/null +++ b/0034-usb-ehci-Remove-dead-nakcnt-code.patch @@ -0,0 +1,75 @@ +From 5fd12d0e21807ff6f61794840ed4212ec45c4be4 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 1 Mar 2012 23:11:13 +0100 +Subject: [PATCH] usb-ehci: Remove dead nakcnt code + +This patch removes 2 bits of dead nakcnt code: + +1) usb_ehci_execute calls ehci_qh_do_overlay which does: +nakcnt = reload; +and then has a block of code which is conditional on: +if (reload && !nakcnt) { +which ofcourse is never true now as nakcnt == reload. + +2) ehci_state_fetchqh does: +nakcnt = reload; +but before nakcnt is ever used ehci_state_fetchqh is always followed +by a ehci_qh_do_overlay call which also does: +nakcnt = reload; +So doing this from ehci_state_fetchqh is redundant. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 20 -------------------- + 1 file changed, 20 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index a3d5c11..92cdf2a 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1643,7 +1643,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + { + uint32_t entry; + EHCIQueue *q; +- int reload; + + entry = ehci_get_fetch_addr(ehci, async); + q = ehci_find_queue_by_qh(ehci, entry, async); +@@ -1701,11 +1700,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + } + #endif + +- reload = get_field(q->qh.epchar, QH_EPCHAR_RL); +- if (reload) { +- set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT); +- } +- + if (q->qh.token & QTD_TOKEN_HALT) { + ehci_set_state(ehci, async, EST_HORIZONTALQH); + +@@ -1865,25 +1859,11 @@ static void ehci_flush_qh(EHCIQueue *q) + static int ehci_state_execute(EHCIQueue *q, int async) + { + int again = 0; +- int reload, nakcnt; +- int smask; + + if (ehci_qh_do_overlay(q) != 0) { + return -1; + } + +- smask = get_field(q->qh.epcap, QH_EPCAP_SMASK); +- +- if (!smask) { +- reload = get_field(q->qh.epchar, QH_EPCHAR_RL); +- nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT); +- if (reload && !nakcnt) { +- ehci_set_state(q->ehci, async, EST_HORIZONTALQH); +- again = 1; +- goto out; +- } +- } +- + // TODO verify enough time remains in the uframe as in 4.4.1.1 + // TODO write back ptr to async list when done or out of time + // TODO Windows does not seem to ever set the MULT field diff --git a/0035-usb-ehci-Fix-and-simplify-nakcnt-handling.patch b/0035-usb-ehci-Fix-and-simplify-nakcnt-handling.patch new file mode 100644 index 0000000..203acc5 --- /dev/null +++ b/0035-usb-ehci-Fix-and-simplify-nakcnt-handling.patch @@ -0,0 +1,117 @@ +From 35f2ecb66299e63a76e51e6758c517cf1394c8f9 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 1 Mar 2012 23:55:11 +0100 +Subject: [PATCH] usb-ehci: Fix and simplify nakcnt handling + +The nakcnt code in ehci_execute_complete() marked transactions as finished +when a packet completed with a result of USB_RET_NAK, but USB_RET_NAK +means that the device cannot receive / send data at that time and that +the transaction should be retried later, which is also what the usb-uhci +and usb-ohci code does. + +Note that there already was some special code in place to handle this +for interrupt endpoints in the form of doing a return from +ehci_execute_complete() when reload == 0, but that for bulk transactions +this was not handled correctly (where as for example the usb-ccid device does +return USB_RET_NAK for bulk packets). + +Besides that the code in ehci_execute_complete() decrement nakcnt by 1 +on a packet result of USB_RET_NAK, but +-since the transaction got marked as finished, + nakcnt would never be decremented again +-there is no code checking for nakcnt becoming 0 +-there is no use in re-trying the transaction within the same usb frame / + usb-ehci frame-timer call, since the status of emulated devices won't change + as long as the usb-ehci frame-timer is running +So we should simply set the nakcnt to 0 when we get a USB_RET_NAK, thus +claiming that we've tried reload times (or as many times as possible if +reload is 0). + +Besides the code in ehci_execute_complete() handling USB_RET_NAK there +was also code handling it in ehci_state_executing(), which calls +ehci_execute_complete(), and then does its own handling on top of the handling +in ehci_execute_complete(), this code would decrement nakcnt *again* (if not +already 0), or restore the reload value (which was never changed) on success. + +Since the double decrement was wrong to begin with, and is no longer needed +now that we set nakcnt directly to 0 on USB_RET_NAK, and the restore of reload +is not needed either, this patch simply removes all nakcnt handling from +ehci_state_executing(). + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 32 ++++---------------------------- + 1 file changed, 4 insertions(+), 28 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index 92cdf2a..aa6fae5 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1269,8 +1269,6 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) + + static void ehci_execute_complete(EHCIQueue *q) + { +- int reload; +- + assert(q->async != EHCI_ASYNC_INFLIGHT); + q->async = EHCI_ASYNC_NONE; + +@@ -1289,16 +1287,8 @@ static void ehci_execute_complete(EHCIQueue *q) + ehci_record_interrupt(q->ehci, USBSTS_ERRINT); + break; + case USB_RET_NAK: +- /* 4.10.3 */ +- reload = get_field(q->qh.epchar, QH_EPCHAR_RL); +- if ((q->pid == USB_TOKEN_IN) && reload) { +- int nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT); +- nakcnt--; +- set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT); +- } else if (!reload) { +- return; +- } +- break; ++ set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT); ++ return; /* We're not done yet with this transaction */ + case USB_RET_BABBLE: + q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); + ehci_record_interrupt(q->ehci, USBSTS_ERRINT); +@@ -1331,7 +1321,7 @@ static void ehci_execute_complete(EHCIQueue *q) + q->qh.token ^= QTD_TOKEN_DTOGGLE; + q->qh.token &= ~QTD_TOKEN_ACTIVE; + +- if ((q->usb_status != USB_RET_NAK) && (q->qh.token & QTD_TOKEN_IOC)) { ++ if (q->qh.token & QTD_TOKEN_IOC) { + ehci_record_interrupt(q->ehci, USBSTS_INT); + } + } +@@ -1905,7 +1895,6 @@ out: + static int ehci_state_executing(EHCIQueue *q, int async) + { + int again = 0; +- int reload, nakcnt; + + ehci_execute_complete(q); + if (q->usb_status == USB_RET_ASYNC) { +@@ -1925,21 +1914,8 @@ static int ehci_state_executing(EHCIQueue *q, int async) + // counter decrements to 0 + } + +- reload = get_field(q->qh.epchar, QH_EPCHAR_RL); +- if (reload) { +- nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT); +- if (q->usb_status == USB_RET_NAK) { +- if (nakcnt) { +- nakcnt--; +- } +- } else { +- nakcnt = reload; +- } +- set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT); +- } +- + /* 4.10.5 */ +- if ((q->usb_status == USB_RET_NAK) || (q->qh.token & QTD_TOKEN_ACTIVE)) { ++ if (q->usb_status == USB_RET_NAK) { + ehci_set_state(q->ehci, async, EST_HORIZONTALQH); + } else { + ehci_set_state(q->ehci, async, EST_WRITEBACK); diff --git a/0036-usb-ehci-Remove-dead-isoch_pause-code.patch b/0036-usb-ehci-Remove-dead-isoch_pause-code.patch new file mode 100644 index 0000000..f9cfe27 --- /dev/null +++ b/0036-usb-ehci-Remove-dead-isoch_pause-code.patch @@ -0,0 +1,111 @@ +From 8b7a0e0ea17192bd7db60a2211b0ffe04b2bac18 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 2 Mar 2012 00:36:50 +0100 +Subject: [PATCH] usb-ehci: Remove dead isoch_pause code + +I see no value in keeping this around, so lets delete it. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 60 +++++++++++++++-------------------------------------------- + 1 file changed, 15 insertions(+), 45 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index aa6fae5..72c3f2a 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -419,7 +419,6 @@ struct EHCIState { + + USBPacket ipacket; + QEMUSGList isgl; +- int isoch_pause; + + uint64_t last_run_ns; + }; +@@ -886,7 +885,6 @@ static void ehci_reset(void *opaque) + + s->astate = EST_INACTIVE; + s->pstate = EST_INACTIVE; +- s->isoch_pause = -1; + s->attach_poll_counter = 0; + + for(i = 0; i < NB_PORTS; i++) { +@@ -1468,46 +1466,7 @@ static int ehci_process_itd(EHCIState *ehci, + usb_packet_unmap(&ehci->ipacket); + qemu_sglist_destroy(&ehci->isgl); + +-#if 0 +- /* In isoch, there is no facility to indicate a NAK so let's +- * instead just complete a zero-byte transaction. Setting +- * DBERR seems too draconian. +- */ +- +- if (ret == USB_RET_NAK) { +- if (ehci->isoch_pause > 0) { +- DPRINTF("ISOCH: received a NAK but paused so returning\n"); +- ehci->isoch_pause--; +- return 0; +- } else if (ehci->isoch_pause == -1) { +- DPRINTF("ISOCH: recv NAK & isoch pause inactive, setting\n"); +- // Pause frindex for up to 50 msec waiting for data from +- // remote +- ehci->isoch_pause = 50; +- return 0; +- } else { +- DPRINTF("ISOCH: isoch pause timeout! return 0\n"); +- ret = 0; +- } +- } else { +- DPRINTF("ISOCH: received ACK, clearing pause\n"); +- ehci->isoch_pause = -1; +- } +-#else +- if (ret == USB_RET_NAK) { +- ret = 0; +- } +-#endif +- +- if (ret >= 0) { +- if (!dir) { +- /* OUT */ +- set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH); +- } else { +- /* IN */ +- set_field(&itd->transact[i], ret, ITD_XACT_LENGTH); +- } +- } else { ++ if (ret < 0) { + switch (ret) { + default: + fprintf(stderr, "Unexpected iso usb result: %d\n", ret); +@@ -1523,6 +1482,19 @@ static int ehci_process_itd(EHCIState *ehci, + itd->transact[i] |= ITD_XACT_BABBLE; + ehci_record_interrupt(ehci, USBSTS_ERRINT); + break; ++ case USB_RET_NAK: ++ /* no data for us, so do a zero-length transfer */ ++ ret = 0; ++ break; ++ } ++ } ++ if (ret >= 0) { ++ if (!dir) { ++ /* OUT */ ++ set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH); ++ } else { ++ /* IN */ ++ set_field(&itd->transact[i], ret, ITD_XACT_LENGTH); + } + } + if (itd->transact[i] & ITD_XACT_IOC) { +@@ -2176,9 +2148,7 @@ static void ehci_frame_timer(void *opaque) + + for (i = 0; i < frames; i++) { + if ( !(ehci->usbsts & USBSTS_HALT)) { +- if (ehci->isoch_pause <= 0) { +- ehci->frindex += 8; +- } ++ ehci->frindex += 8; + + if (ehci->frindex > 0x00001fff) { + ehci->frindex = 0; diff --git a/0037-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch b/0037-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch new file mode 100644 index 0000000..263875f --- /dev/null +++ b/0037-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch @@ -0,0 +1,67 @@ +From c767c83ab8061664dcd6ea05b692c2acf0efb27f Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 1 Mar 2012 17:22:14 +0100 +Subject: [PATCH] usb: return BABBLE rather then NAK when we receive too much + data + +Signed-off-by: Hans de Goede +--- + usb-linux.c | 8 +++++++- + usb-redir.c | 4 ++-- + 2 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/usb-linux.c b/usb-linux.c +index 749ce71..9987a2c 100644 +--- a/usb-linux.c ++++ b/usb-linux.c +@@ -391,6 +391,10 @@ static void async_complete(void *opaque) + p->result = USB_RET_STALL; + break; + ++ case -EOVERFLOW: ++ p->result = USB_RET_BABBLE; ++ break; ++ + default: + p->result = USB_RET_NAK; + break; +@@ -729,6 +733,8 @@ static int urb_status_to_usb_ret(int status) + switch (status) { + case -EPIPE: + return USB_RET_STALL; ++ case -EOVERFLOW: ++ return USB_RET_BABBLE; + default: + return USB_RET_NAK; + } +@@ -766,7 +772,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) + } else if (aurb[i].urb.iso_frame_desc[j].actual_length + > p->iov.size) { + printf("husb: received iso data is larger then packet\n"); +- len = USB_RET_NAK; ++ len = USB_RET_BABBLE; + /* All good copy data over */ + } else { + len = aurb[i].urb.iso_frame_desc[j].actual_length; +diff --git a/usb-redir.c b/usb-redir.c +index d10be6f..7313140 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -456,7 +456,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + ERROR("received iso data is larger then packet ep %02X (%d > %d)\n", + ep, len, (int)p->iov.size); + bufp_free(dev, isop, ep); +- return USB_RET_NAK; ++ return USB_RET_BABBLE; + } + usb_packet_copy(p, isop->data, len); + bufp_free(dev, isop, ep); +@@ -575,7 +575,7 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, + if (len > p->iov.size) { + ERROR("received int data is larger then packet ep %02X\n", ep); + bufp_free(dev, intp, ep); +- return USB_RET_NAK; ++ return USB_RET_BABBLE; + } + usb_packet_copy(p, intp->data, len); + bufp_free(dev, intp, ep); diff --git a/0038-usb-add-USB_RET_IOERROR.patch b/0038-usb-add-USB_RET_IOERROR.patch new file mode 100644 index 0000000..0f214ed --- /dev/null +++ b/0038-usb-add-USB_RET_IOERROR.patch @@ -0,0 +1,164 @@ +From 65969230e04e8a3d80d4ca0aef29dbae735f3f13 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 2 Mar 2012 00:26:23 +0100 +Subject: [PATCH] usb: add USB_RET_IOERROR + +We already have USB_RET_NAK, but that means that a device does not want +to send/receive right now. But with host / network redirection we can +actually have a transaction fail due to some io error, rather then ie +the device just not having any data atm. + +This patch adds a new error code named USB_RET_IOERROR for this, and uses +it were appropriate. + +Notes: +-Currently all usb-controllers handle this the same as NODEV, but that + may change in the future, OHCI could indicate a CRC error instead for example. +-This patch does not touch hw/usb-musb.c, that is because the code in there + handles STALL and NAK specially and has a if status < 0 generic catch all + for all other errors + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 2 ++ + hw/usb-ohci.c | 2 ++ + hw/usb-uhci.c | 1 + + hw/usb.h | 11 ++++++----- + usb-linux.c | 4 ++-- + usb-redir.c | 9 ++++++--- + 6 files changed, 19 insertions(+), 10 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index 72c3f2a..ba1b9da 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1275,6 +1275,7 @@ static void ehci_execute_complete(EHCIQueue *q) + + if (q->usb_status < 0) { + switch(q->usb_status) { ++ case USB_RET_IOERROR: + case USB_RET_NODEV: + q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); + set_field(&q->qh.token, 0, QTD_TOKEN_CERR); +@@ -1471,6 +1472,7 @@ static int ehci_process_itd(EHCIState *ehci, + default: + fprintf(stderr, "Unexpected iso usb result: %d\n", ret); + /* Fall through */ ++ case USB_RET_IOERROR: + case USB_RET_NODEV: + /* 3.3.2: XACTERR is only allowed on IN transactions */ + if (dir) { +diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c +index c27014a..f374cad 100644 +--- a/hw/usb-ohci.c ++++ b/hw/usb-ohci.c +@@ -828,6 +828,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, + OHCI_CC_DATAUNDERRUN); + } else { + switch (ret) { ++ case USB_RET_IOERROR: + case USB_RET_NODEV: + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, + OHCI_CC_DEVICENOTRESPONDING); +@@ -1051,6 +1052,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); + } else { + switch (ret) { ++ case USB_RET_IOERROR: + case USB_RET_NODEV: + OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); + case USB_RET_NAK: +diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c +index f9e3ea5..a994943 100644 +--- a/hw/usb-uhci.c ++++ b/hw/usb-uhci.c +@@ -751,6 +751,7 @@ out: + break; + return 1; + ++ case USB_RET_IOERROR: + case USB_RET_NODEV: + default: + break; +diff --git a/hw/usb.h b/hw/usb.h +index c6e1870..4010e12 100644 +--- a/hw/usb.h ++++ b/hw/usb.h +@@ -41,11 +41,12 @@ + #define USB_MSG_DETACH 0x101 + #define USB_MSG_RESET 0x102 + +-#define USB_RET_NODEV (-1) +-#define USB_RET_NAK (-2) +-#define USB_RET_STALL (-3) +-#define USB_RET_BABBLE (-4) +-#define USB_RET_ASYNC (-5) ++#define USB_RET_NODEV (-1) ++#define USB_RET_NAK (-2) ++#define USB_RET_STALL (-3) ++#define USB_RET_BABBLE (-4) ++#define USB_RET_IOERROR (-5) ++#define USB_RET_ASYNC (-6) + + #define USB_SPEED_LOW 0 + #define USB_SPEED_FULL 1 +diff --git a/usb-linux.c b/usb-linux.c +index 9987a2c..c56a74e 100644 +--- a/usb-linux.c ++++ b/usb-linux.c +@@ -396,7 +396,7 @@ static void async_complete(void *opaque) + break; + + default: +- p->result = USB_RET_NAK; ++ p->result = USB_RET_IOERROR; + break; + } + +@@ -736,7 +736,7 @@ static int urb_status_to_usb_ret(int status) + case -EOVERFLOW: + return USB_RET_BABBLE; + default: +- return USB_RET_NAK; ++ return USB_RET_IOERROR; + } + } + +diff --git a/usb-redir.c b/usb-redir.c +index 7313140..b044dc5 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -440,7 +440,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + /* Check iso_error for stream errors, otherwise its an underrun */ + status = dev->endpoint[EP2I(ep)].iso_error; + dev->endpoint[EP2I(ep)].iso_error = 0; +- return status ? USB_RET_NAK : 0; ++ return status ? USB_RET_IOERROR : 0; + } + DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep, + isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); +@@ -448,7 +448,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, + status = isop->status; + if (status != usb_redir_success) { + bufp_free(dev, isop, ep); +- return USB_RET_NAK; ++ return USB_RET_IOERROR; + } + + len = isop->len; +@@ -1044,11 +1044,14 @@ static int usbredir_handle_status(USBRedirDevice *dev, + return USB_RET_STALL; + case usb_redir_cancelled: + WARNING("returning cancelled packet to HC?\n"); ++ return USB_RET_NAK; + case usb_redir_inval: ++ WARNING("got invalid param error from usb-host?\n"); ++ return USB_RET_NAK; + case usb_redir_ioerror: + case usb_redir_timeout: + default: +- return USB_RET_NAK; ++ return USB_RET_IOERROR; + } + } + diff --git a/0039-usb-ehci-fix-reset.patch b/0039-usb-ehci-fix-reset.patch new file mode 100644 index 0000000..e57d1b3 --- /dev/null +++ b/0039-usb-ehci-fix-reset.patch @@ -0,0 +1,37 @@ +From d6f515f1df543d17242cff93dc4fc44bb7c89ef9 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 23 Feb 2012 13:24:00 +0000 +Subject: [PATCH] usb-ehci: fix reset + +Two reset fixes: + * pick up s->usbcmd value after ehci_reset call to make sure it + keeps the reset value and doesn't get rubbish filled in when + val is written back to the mmio register array later on. + * make sure the frame timer is zapped on reset. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb-ehci.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index ba1b9da..ad0f6e1 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -900,6 +900,7 @@ static void ehci_reset(void *opaque) + } + ehci_queues_rip_all(s, 0); + ehci_queues_rip_all(s, 1); ++ qemu_del_timer(s->frame_timer); + } + + static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) +@@ -1059,7 +1060,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) + + if (val & USBCMD_HCRESET) { + ehci_reset(s); +- val &= ~USBCMD_HCRESET; ++ val = s->usbcmd; + } + + /* not supporting dynamic frame list size at the moment */ diff --git a/0040-usb-ehci-sanity-check-iso-xfers.patch b/0040-usb-ehci-sanity-check-iso-xfers.patch new file mode 100644 index 0000000..e42cd12 --- /dev/null +++ b/0040-usb-ehci-sanity-check-iso-xfers.patch @@ -0,0 +1,39 @@ +From 18fd6695ac06a6f63e75d8a390be3247e234d2cc Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Sun, 4 Mar 2012 12:41:11 +0100 +Subject: [PATCH] usb-ehci: sanity-check iso xfers + +This patch adds a sanity check to itd processing to make sure the +endpoint addressed by the guest is actually an iso endpoint. Also +verify that usb drivers don't return USB_RET_ASYNC which is illegal for +iso xfers. + +Signed-off-by: Gerd Hoffmann +(Cherry picked from: aa0568ff2559d7717f4684af6a83d0bd1a125f56) + +[qemu-kvm-1.0: we don't track ep types on RHEL-6 like we do upstream, so we +cannot check if an itd is pointing to a non iso ep in advance, but we do still +need to make sure that we never handle an iso xfer async. So check if the +device does want to handle it async, and if so cancel the xfer and treat it as +a NAK, like upstream does when the ep type check fails.] + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index ad0f6e1..b5d7037 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1485,6 +1485,10 @@ static int ehci_process_itd(EHCIState *ehci, + itd->transact[i] |= ITD_XACT_BABBLE; + ehci_record_interrupt(ehci, USBSTS_ERRINT); + break; ++ case USB_RET_ASYNC: ++ /* ISO endpoints are never ASYNC, not an iso endpoint? */ ++ usb_cancel_packet(&ehci->ipacket); ++ /* Treat this as a NAK (fall through) */ + case USB_RET_NAK: + /* no data for us, so do a zero-length transfer */ + ret = 0; diff --git a/0041-usb-ehci-frindex-always-is-a-14-bits-counter.patch b/0041-usb-ehci-frindex-always-is-a-14-bits-counter.patch new file mode 100644 index 0000000..78562b9 --- /dev/null +++ b/0041-usb-ehci-frindex-always-is-a-14-bits-counter.patch @@ -0,0 +1,71 @@ +From f57640353c847f6d7bf5a2d115caa2ea49d316b8 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 28 Mar 2012 20:31:32 +0200 +Subject: [PATCH] usb-ehci: frindex always is a 14 bits counter + +frindex always is a 14 bits counter, and not a 13 bits one as we were +emulating. There are some subtle hints to this in the spec, first of all +"Table 2-12. FRINDEX - Frame Index Register" says: +"Bit 13:0 Frame Index. The value in this register increments at the end of +each time frame (e.g. micro-frame). Bits [N:3] are used for the Frame List +current index. This means that each location of the frame list is accessed +8 times (frames or micro-frames) before moving to the next index. The +following illustrates values of N based on the value of the Frame List +Size field in the USBCMD register. + +USBCMD[Frame List Size] Number Elements N +00b 1024 12 +01b 512 11 +10b 256 10 +11b Reserved" + +Notice how the text talks about "Bits [N:3]" are used ..., it does +NOT say that when N == 12 (our case) the counter will wrap from 8191 to 0, +or in otherwords that it is a 13 bits counter (bits 0 - 12). + +The other hint is in "Table 2-10. USBSTS USB Status Register Bit Definitions": + +"Bit 3 Frame List Rollover - R/WC. The Host Controller sets this bit to a one +when the Frame List Index (see Section 2.3.4) rolls over from its maximum value +to zero. The exact value at which the rollover occurs depends on the frame +list size. For example, if the frame list size (as programmed in the Frame +List Size field of the USBCMD register) is 1024, the Frame Index Register +rolls over every time FRINDEX[13] toggles. Similarly, if the size is 512, +the Host Controller sets this bit to a one every time FRINDEX[12] toggles." + +Notice how this text talks about setting bit 3 when bit 13 of frindex toggles +(when there are 1024 entries, so our case), so this indicates that frindex +has a bit 13 making it a 14 bit counter. + +Besides these clear hints the real proof is in the pudding. Before this +patch I could not stream data from a USB2 webcam under Windows XP, after +this cam using a USB2 webcam under Windows XP works fine, and no regressions +with other operating systems were seen. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index b5d7037..3934bf0 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -2157,11 +2157,15 @@ static void ehci_frame_timer(void *opaque) + if ( !(ehci->usbsts & USBSTS_HALT)) { + ehci->frindex += 8; + +- if (ehci->frindex > 0x00001fff) { +- ehci->frindex = 0; ++ if (ehci->frindex == 0x00002000) { + ehci_set_interrupt(ehci, USBSTS_FLR); + } + ++ if (ehci->frindex == 0x00004000) { ++ ehci_set_interrupt(ehci, USBSTS_FLR); ++ ehci->frindex = 0; ++ } ++ + ehci->sofv = (ehci->frindex - 1) >> 3; + ehci->sofv &= 0x000003ff; + } diff --git a/0042-usb-ehci-Drop-unused-sofv-value.patch b/0042-usb-ehci-Drop-unused-sofv-value.patch new file mode 100644 index 0000000..53ba765 --- /dev/null +++ b/0042-usb-ehci-Drop-unused-sofv-value.patch @@ -0,0 +1,46 @@ +From de57c42da930470e62fb520f6c0de5d87da67385 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 29 Mar 2012 16:37:34 +0200 +Subject: [PATCH] usb-ehci: Drop unused sofv value + +The sofv value only ever gets a value assigned and is never used (read) +anywhere, so we can just drop it. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 8 -------- + 1 file changed, 8 deletions(-) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index 3934bf0..ff69587 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -403,7 +403,6 @@ struct EHCIState { + /* + * Internal states, shadow registers, etc + */ +- uint32_t sofv; + QEMUTimer *frame_timer; + int attach_poll_counter; + int astate; // Current state in asynchronous schedule +@@ -1082,10 +1081,6 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) + val &= USBINTR_MASK; + break; + +- case FRINDEX: +- s->sofv = val >> 3; +- break; +- + case CONFIGFLAG: + val &= 0x1; + if (val) { +@@ -2165,9 +2160,6 @@ static void ehci_frame_timer(void *opaque) + ehci_set_interrupt(ehci, USBSTS_FLR); + ehci->frindex = 0; + } +- +- ehci->sofv = (ehci->frindex - 1) >> 3; +- ehci->sofv &= 0x000003ff; + } + + if (frames - i > ehci->maxframes) { diff --git a/0043-usb-redir-Notify-our-peer-when-we-reject-a-device-du.patch b/0043-usb-redir-Notify-our-peer-when-we-reject-a-device-du.patch new file mode 100644 index 0000000..df4d5a4 --- /dev/null +++ b/0043-usb-redir-Notify-our-peer-when-we-reject-a-device-du.patch @@ -0,0 +1,33 @@ +From 1aa49526aebe5461a5c61c686a2ea83d6c7e9e7d Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 29 Mar 2012 16:41:23 +0200 +Subject: [PATCH] usb-redir: Notify our peer when we reject a device due to a + speed mismatch + +Also cleanup (reset) our device state when we reject a device due to a +speed mismatch. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/usb-redir.c b/usb-redir.c +index b044dc5..93e892d 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -844,7 +844,13 @@ static void usbredir_do_attach(void *opaque) + { + USBRedirDevice *dev = opaque; + +- usb_device_attach(&dev->dev); ++ if (usb_device_attach(&dev->dev) != 0) { ++ usbredir_device_disconnect(dev); ++ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { ++ usbredirparser_send_filter_reject(dev->parser); ++ usbredirparser_do_write(dev->parser); ++ } ++ } + } + + /* diff --git a/0044-usb-redir-An-interface-count-of-0-is-a-valid-value.patch b/0044-usb-redir-An-interface-count-of-0-is-a-valid-value.patch new file mode 100644 index 0000000..0c7b7f4 --- /dev/null +++ b/0044-usb-redir-An-interface-count-of-0-is-a-valid-value.patch @@ -0,0 +1,44 @@ +From 5d5dff2fb85390c00a7b7e555b34a82ccca7c89b Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sat, 31 Mar 2012 13:07:24 +0200 +Subject: [PATCH] usb-redir: An interface count of 0 is a valid value + +An interface-count of 0 happens when a device is in unconfigured state when +it gets redirected. So we should not use 0 to detect not having received +interface info from our peer. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/usb-redir.c b/usb-redir.c +index 93e892d..e0eb393 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -39,6 +39,7 @@ + #include "hw/usb.h" + + #define MAX_ENDPOINTS 32 ++#define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */ + #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) + #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) + +@@ -994,7 +995,7 @@ static void usbredir_handle_destroy(USBDevice *udev) + + static int usbredir_check_filter(USBRedirDevice *dev) + { +- if (dev->interface_info.interface_count == 0) { ++ if (dev->interface_info.interface_count == NO_INTERFACE_INFO) { + ERROR("No interface info for device\n"); + goto error; + } +@@ -1157,7 +1158,7 @@ static void usbredir_device_disconnect(void *priv) + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +- dev->interface_info.interface_count = 0; ++ dev->interface_info.interface_count = NO_INTERFACE_INFO; + } + + static void usbredir_interface_info(void *priv, diff --git a/0045-usb-redir-Reset-device-address-and-speed-on-disconne.patch b/0045-usb-redir-Reset-device-address-and-speed-on-disconne.patch new file mode 100644 index 0000000..56e87fc --- /dev/null +++ b/0045-usb-redir-Reset-device-address-and-speed-on-disconne.patch @@ -0,0 +1,26 @@ +From 28aa326b7d0068c78359f8bce00bef60e6c59d36 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sat, 31 Mar 2012 13:12:09 +0200 +Subject: [PATCH] usb-redir: Reset device address and speed on disconnect + +Without this disconnected devices look like the last redirected device +in the monitor in "info usb". + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/usb-redir.c b/usb-redir.c +index e0eb393..a424826 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -1159,6 +1159,8 @@ static void usbredir_device_disconnect(void *priv) + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } + dev->interface_info.interface_count = NO_INTERFACE_INFO; ++ dev->dev.addr = 0; ++ dev->dev.speed = 0; + } + + static void usbredir_interface_info(void *priv, diff --git a/0046-usb-redir-Not-finding-an-async-urb-id-is-not-an-erro.patch b/0046-usb-redir-Not-finding-an-async-urb-id-is-not-an-erro.patch new file mode 100644 index 0000000..5664a22 --- /dev/null +++ b/0046-usb-redir-Not-finding-an-async-urb-id-is-not-an-erro.patch @@ -0,0 +1,27 @@ +From 54a8b5462e71abbbf4a4c3c444f70abfc6659877 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Sat, 31 Mar 2012 13:17:13 +0200 +Subject: [PATCH] usb-redir: Not finding an async urb id is not an error + +We clear our pending async urb list on device disconnect and we may still +receive "packet complete" packets from our peer after this, which will then +refer to packet ids no longer in our list. + +Signed-off-by: Hans de Goede +--- + usb-redir.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/usb-redir.c b/usb-redir.c +index a424826..ec9170a 100644 +--- a/usb-redir.c ++++ b/usb-redir.c +@@ -286,7 +286,7 @@ static AsyncURB *async_find(USBRedirDevice *dev, uint32_t packet_id) + return aurb; + } + } +- ERROR("could not find async urb for packet_id %u\n", packet_id); ++ DPRINTF("could not find async urb for packet_id %u\n", packet_id); + return NULL; + } + diff --git a/0047-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch b/0047-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch new file mode 100644 index 0000000..8311cef --- /dev/null +++ b/0047-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch @@ -0,0 +1,32 @@ +From ede6c50c5236dd0cdbcef242320ad3c8bc2bbfd3 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 3 Apr 2012 14:04:31 +0200 +Subject: [PATCH] usb-ehci: Ensure frindex writes leave a valid frindex value + +frindex is a 14 bits counter, so bits 31-14 should always be 0, and +after the commit titled "usb-ehci: frindex always is a 14 bits counter" +we rely on frindex always being a multiple of 8. I've not seen this in +practice, but theoretically a guest can write a value >= 0x4000 or a value +which is not a multiple of 8 value to frindex, this patch ensures that +things will still work when that happens. + +Signed-off-by: Hans de Goede +--- + hw/usb-ehci.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c +index ff69587..16e6053 100644 +--- a/hw/usb-ehci.c ++++ b/hw/usb-ehci.c +@@ -1081,6 +1081,10 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) + val &= USBINTR_MASK; + break; + ++ case FRINDEX: ++ val &= 0x00003ff8; /* frindex is 14bits and always a multiple of 8 */ ++ break; ++ + case CONFIGFLAG: + val &= 0x1; + if (val) { diff --git a/0101-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch b/0101-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch new file mode 100644 index 0000000..b29006f --- /dev/null +++ b/0101-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch @@ -0,0 +1,26 @@ +From d9621f01291e00340f1e9947d1d13bbda9288056 Mon Sep 17 00:00:00 2001 +From: Markus Armbruster +Date: Fri, 4 Nov 2011 10:34:24 +0100 +Subject: [PATCH] qxl: Slot sanity check in qxl_phys2virt() is off by one, fix + +Spotted by Coverity. + +Signed-off-by: Markus Armbruster +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 41500e9..e0f9d4a 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1020,7 +1020,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) + case MEMSLOT_GROUP_HOST: + return (void*)offset; + case MEMSLOT_GROUP_GUEST: +- PANIC_ON(slot > NUM_MEMSLOTS); ++ PANIC_ON(slot >= NUM_MEMSLOTS); + PANIC_ON(!qxl->guest_slots[slot].active); + PANIC_ON(offset < qxl->guest_slots[slot].delta); + offset -= qxl->guest_slots[slot].delta; diff --git a/0101-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch b/0101-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch deleted file mode 100644 index 324f9e4..0000000 --- a/0101-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 01936dfd5b9fa8117fc1d63ce92198dd28422773 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 19 Dec 2011 14:59:45 +0100 -Subject: [PATCH 101/118] usb-redir: Clear iso / irq error when stopping the - stream - -And ignore status messages from the client which arrive after stream -stop (the stream stop send to the client and an error status reported by -the client my cross each other due to network latency). - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 6 ++++-- - 1 files changed, 4 insertions(+), 2 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index fb91c92..7678f1a 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -410,6 +410,7 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep) - DPRINTF("iso stream stopped ep %02X\n", ep); - dev->endpoint[EP2I(ep)].iso_started = 0; - } -+ dev->endpoint[EP2I(ep)].iso_error = 0; - usbredir_free_bufpq(dev, ep); - } - -@@ -522,6 +523,7 @@ static void usbredir_stop_interrupt_receiving(USBRedirDevice *dev, - DPRINTF("interrupt recv stopped ep %02X\n", ep); - dev->endpoint[EP2I(ep)].interrupt_started = 0; - } -+ dev->endpoint[EP2I(ep)].interrupt_error = 0; - usbredir_free_bufpq(dev, ep); - } - -@@ -1029,7 +1031,7 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id, - DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status, - ep, id); - -- if (!dev->dev.attached) { -+ if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) { - return; - } - -@@ -1050,7 +1052,7 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, - DPRINTF("interrupt recv status %d ep %02X id %u\n", - interrupt_receiving_status->status, ep, id); - -- if (!dev->dev.attached) { -+ if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) { - return; - } - --- -1.7.7.5 - diff --git a/0102-input-send-kbd-mouse-events-only-to-running-guests.patch b/0102-input-send-kbd-mouse-events-only-to-running-guests.patch new file mode 100644 index 0000000..cd2ae92 --- /dev/null +++ b/0102-input-send-kbd-mouse-events-only-to-running-guests.patch @@ -0,0 +1,42 @@ +From 626044aeb50b2bc521cb279296fae83986ede8fa Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 15 Feb 2012 09:15:37 +0100 +Subject: [PATCH] input: send kbd+mouse events only to running guests. + +Trying to interact with a stopped guest will queue up the events, +then send them all at once when the guest continues running, with +a high chance to have them cause unwanted actions. + +Avoid that by only injecting the input events only when the guest +is in running state. + +Signed-off-by: Gerd Hoffmann +Signed-off-by: Anthony Liguori +--- + input.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/input.c b/input.c +index 9ade63f..b48408d 100644 +--- a/input.c ++++ b/input.c +@@ -130,6 +130,9 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry) + + void kbd_put_keycode(int keycode) + { ++ if (!runstate_is_running()) { ++ return; ++ } + if (qemu_put_kbd_event) { + qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode); + } +@@ -151,6 +154,9 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) + void *mouse_event_opaque; + int width, height; + ++ if (!runstate_is_running()) { ++ return; ++ } + if (QTAILQ_EMPTY(&mouse_handlers)) { + return; + } diff --git a/0102-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch b/0102-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch deleted file mode 100644 index 297fa9b..0000000 --- a/0102-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch +++ /dev/null @@ -1,102 +0,0 @@ -From cc5740ae8aa68dbbdc690f694b0e55d70f9c49ee Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 19 Dec 2011 13:42:40 +0100 -Subject: [PATCH 102/118] usb-redir: Dynamically adjust iso buffering size - based on ep interval - -Note the bufpq_target_size id stored in the endpoint info struct, -even though it only used once. This is done because it will be -referenced from other code in a follow up patch. - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++----- - 1 files changed, 47 insertions(+), 5 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index 7678f1a..ab2c8fa 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -61,6 +61,7 @@ struct endp_data { - uint8_t interrupt_started; - uint8_t interrupt_error; - QTAILQ_HEAD(, buf_packet) bufpq; -+ int bufpq_target_size; - }; - - struct USBRedirDevice { -@@ -332,15 +333,41 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - uint8_t ep) - { - int status, len; -- - if (!dev->endpoint[EP2I(ep)].iso_started && - !dev->endpoint[EP2I(ep)].iso_error) { - struct usb_redir_start_iso_stream_header start_iso = { - .endpoint = ep, -- /* TODO maybe do something with these depending on ep interval? */ -- .pkts_per_urb = 32, -- .no_urbs = 3, - }; -+ int pkts_per_sec; -+ -+ if (dev->dev.speed == USB_SPEED_HIGH) -+ pkts_per_sec = 8000 / dev->endpoint[EP2I(ep)].interval; -+ else -+ pkts_per_sec = 1000 / dev->endpoint[EP2I(ep)].interval; -+ /* Testing has shown that we need circa 60 ms buffer */ -+ dev->endpoint[EP2I(ep)].bufpq_target_size = (pkts_per_sec * 60) / 1000; -+ -+ /* Aim for approx 100 interrupts / second on the client to -+ balance latency and interrupt load */ -+ start_iso.pkts_per_urb = pkts_per_sec / 100; -+ if (start_iso.pkts_per_urb < 1) { -+ start_iso.pkts_per_urb = 1; -+ } else if (start_iso.pkts_per_urb > 32) { -+ start_iso.pkts_per_urb = 32; -+ } -+ -+ start_iso.no_urbs = (dev->endpoint[EP2I(ep)].bufpq_target_size + -+ start_iso.pkts_per_urb - 1) / -+ start_iso.pkts_per_urb; -+ /* Output endpoints pre-fill only 1/2 of the packets, keeping the rest -+ as overflow buffer. Also see the usbredir protocol documentation */ -+ if (!(ep & USB_DIR_IN)) { -+ start_iso.no_urbs *= 2; -+ } -+ if (start_iso.no_urbs > 16) { -+ start_iso.no_urbs = 16; -+ } -+ - /* No id, we look at the ep when receiving a status back */ - usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso); - usbredirparser_do_write(dev->parser); -@@ -961,9 +988,24 @@ static void usbredir_ep_info(void *priv, - dev->endpoint[i].type = ep_info->type[i]; - dev->endpoint[i].interval = ep_info->interval[i]; - dev->endpoint[i].interface = ep_info->interface[i]; -- if (dev->endpoint[i].type != usb_redir_type_invalid) { -+ switch (dev->endpoint[i].type) { -+ case usb_redir_type_invalid: -+ break; -+ case usb_redir_type_iso: -+ case usb_redir_type_interrupt: -+ if (dev->endpoint[i].interval == 0) { -+ ERROR("Received 0 interval for isoc or irq endpoint\n"); -+ usbredir_device_disconnect(dev); -+ } -+ /* Fall through */ -+ case usb_redir_type_control: -+ case usb_redir_type_bulk: - DPRINTF("ep: %02X type: %d interface: %d\n", I2EP(i), - dev->endpoint[i].type, dev->endpoint[i].interface); -+ break; -+ default: -+ ERROR("Received invalid endpoint type\n"); -+ usbredir_device_disconnect(dev); - } - } - } --- -1.7.7.5 - diff --git a/0103-qxl-fix-warnings-on-32bit.patch b/0103-qxl-fix-warnings-on-32bit.patch new file mode 100644 index 0000000..1890449 --- /dev/null +++ b/0103-qxl-fix-warnings-on-32bit.patch @@ -0,0 +1,42 @@ +From 0c2a62bf28f82dd4112dfb76f9b5a5062e22ea99 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 8 Feb 2012 15:58:35 +0100 +Subject: [PATCH] qxl: fix warnings on 32bit + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index e0f9d4a..4fd5e4e 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -628,7 +628,7 @@ static void interface_release_resource(QXLInstance *sin, + + if (ext.group_id == MEMSLOT_GROUP_HOST) { + /* host group -> vga mode update request */ +- qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id); ++ qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id); + return; + } + +@@ -751,7 +751,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) + qxl->current_async = QXL_UNDEFINED_IO; + qemu_mutex_unlock(&qxl->async_lock); + +- dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie); ++ dprint(qxl, 2, "async_complete: %d (%" PRId64 ") done\n", ++ current_async, cookie); + switch (current_async) { + case QXL_IO_CREATE_PRIMARY_ASYNC: + qxl_create_guest_primary_complete(qxl); +@@ -1018,7 +1019,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) + + switch (group_id) { + case MEMSLOT_GROUP_HOST: +- return (void*)offset; ++ return (void *)(intptr_t)offset; + case MEMSLOT_GROUP_GUEST: + PANIC_ON(slot >= NUM_MEMSLOTS); + PANIC_ON(!qxl->guest_slots[slot].active); diff --git a/0103-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch b/0103-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch deleted file mode 100644 index 56daa98..0000000 --- a/0103-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 577aff1f1df0a41fd5e21f5ff2b470c36565211b Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 19 Dec 2011 14:55:15 +0100 -Subject: [PATCH 103/118] usb-redir: Pre-fill our isoc input buffer before - sending pkts to the host - -This is something which should have been done from the first version of -usb-redir, but wasn't. - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 16 ++++++++++++++++ - 1 files changed, 16 insertions(+), 0 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index ab2c8fa..17ea7a7 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -60,7 +60,9 @@ struct endp_data { - uint8_t iso_error; /* For reporting iso errors to the HC */ - uint8_t interrupt_started; - uint8_t interrupt_error; -+ uint8_t bufpq_prefilled; - QTAILQ_HEAD(, buf_packet) bufpq; -+ int bufpq_size; - int bufpq_target_size; - }; - -@@ -296,6 +298,7 @@ static struct buf_packet *bufp_alloc(USBRedirDevice *dev, - bufp->len = len; - bufp->status = status; - QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); -+ dev->endpoint[EP2I(ep)].bufpq_size++; - return bufp; - } - -@@ -303,6 +306,7 @@ static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp, - uint8_t ep) - { - QTAILQ_REMOVE(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); -+ dev->endpoint[EP2I(ep)].bufpq_size--; - free(bufp->data); - g_free(bufp); - } -@@ -373,14 +377,26 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - usbredirparser_do_write(dev->parser); - DPRINTF("iso stream started ep %02X\n", ep); - dev->endpoint[EP2I(ep)].iso_started = 1; -+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0; - } - - if (ep & USB_DIR_IN) { - struct buf_packet *isop; - -+ if (dev->endpoint[EP2I(ep)].iso_started && -+ !dev->endpoint[EP2I(ep)].bufpq_prefilled) { -+ if (dev->endpoint[EP2I(ep)].bufpq_size < -+ dev->endpoint[EP2I(ep)].bufpq_target_size) { -+ return usbredir_handle_status(dev, 0, 0); -+ } -+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 1; -+ } -+ - isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); - if (isop == NULL) { - DPRINTF2("iso-token-in ep %02X, no isop\n", ep); -+ /* Re-fill the buffer */ -+ dev->endpoint[EP2I(ep)].bufpq_prefilled = 0; - /* Check iso_error for stream errors, otherwise its an underrun */ - status = dev->endpoint[EP2I(ep)].iso_error; - dev->endpoint[EP2I(ep)].iso_error = 0; --- -1.7.7.5 - diff --git a/0104-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch b/0104-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch new file mode 100644 index 0000000..7e0065c --- /dev/null +++ b/0104-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch @@ -0,0 +1,53 @@ +From ffbbf5a2455cd5c840a298a983e986c6ec46d38b Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 15 Feb 2012 14:04:44 +0100 +Subject: [PATCH] qxl: don't render stuff when the vm is stopped. + +This patch fixes the local qxl renderer to not kick spice-server +in case the vm is stopped. First it is largely pointless because +we ask spice-server to process all not-yet processed commands when +the vm is stopped, so there isn't much do do anyway. Second we +avoid triggering an assert in spice-server. + +The patch makes sure we still honor redraw requests, even if we don't +ask spice-server for updates. This is needed to handle displaysurface +changes with a stopped vm correctly. + +With this patch applied it is possible to take screen shots (via +screendump monitor command) from a qxl gpu even in case the guest +is stopped. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 2c51ba9..a7891b2 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -121,19 +121,17 @@ void qxl_render_update(PCIQXLDevice *qxl) + dpy_resize(vga->ds); + } + +- if (!qxl->guest_primary.commands) { +- return; +- } +- qxl->guest_primary.commands = 0; +- + update.left = 0; + update.right = qxl->guest_primary.surface.width; + update.top = 0; + update.bottom = qxl->guest_primary.surface.height; + + memset(dirty, 0, sizeof(dirty)); +- qxl_spice_update_area(qxl, 0, &update, +- dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); ++ if (runstate_is_running() && qxl->guest_primary.commands) { ++ qxl->guest_primary.commands = 0; ++ qxl_spice_update_area(qxl, 0, &update, ++ dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); ++ } + if (redraw) { + memset(dirty, 0, sizeof(dirty)); + dirty[0] = update; diff --git a/0104-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch b/0104-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch deleted file mode 100644 index 0f826d3..0000000 --- a/0104-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch +++ /dev/null @@ -1,87 +0,0 @@ -From b8e632d175063770655e75507de85ae873fa6c2d Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 20 Dec 2011 16:54:25 +0100 -Subject: [PATCH 104/118] usb-redir: Try to keep our buffer size near the - target size - -Before this patch we would allow the (iso) buffer to grow unlimited -(and it would under certain circumstances) leading to way too high -latencies for iso data streams. - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 30 +++++++++++++++++++++++++++--- - 1 files changed, 27 insertions(+), 3 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index 17ea7a7..88d941a 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -61,6 +61,7 @@ struct endp_data { - uint8_t interrupt_started; - uint8_t interrupt_error; - uint8_t bufpq_prefilled; -+ uint8_t bufpq_dropping_packets; - QTAILQ_HEAD(, buf_packet) bufpq; - int bufpq_size; - int bufpq_target_size; -@@ -290,16 +291,34 @@ static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) - } - } - --static struct buf_packet *bufp_alloc(USBRedirDevice *dev, -+static void bufp_alloc(USBRedirDevice *dev, - uint8_t *data, int len, int status, uint8_t ep) - { -- struct buf_packet *bufp = g_malloc(sizeof(struct buf_packet)); -+ struct buf_packet *bufp; -+ -+ if (!dev->endpoint[EP2I(ep)].bufpq_dropping_packets && -+ dev->endpoint[EP2I(ep)].bufpq_size > -+ 2 * dev->endpoint[EP2I(ep)].bufpq_target_size) { -+ DPRINTF("bufpq overflow, dropping packets ep %02X\n", ep); -+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 1; -+ } -+ /* Since we're interupting the stream anyways, drop enough packets to get -+ back to our target buffer size */ -+ if (dev->endpoint[EP2I(ep)].bufpq_dropping_packets) { -+ if (dev->endpoint[EP2I(ep)].bufpq_size > -+ dev->endpoint[EP2I(ep)].bufpq_target_size) { -+ free(data); -+ return; -+ } -+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; -+ } -+ -+ bufp = g_malloc(sizeof(struct buf_packet)); - bufp->data = data; - bufp->len = len; - bufp->status = status; - QTAILQ_INSERT_TAIL(&dev->endpoint[EP2I(ep)].bufpq, bufp, next); - dev->endpoint[EP2I(ep)].bufpq_size++; -- return bufp; - } - - static void bufp_free(USBRedirDevice *dev, struct buf_packet *bufp, -@@ -378,6 +397,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - DPRINTF("iso stream started ep %02X\n", ep); - dev->endpoint[EP2I(ep)].iso_started = 1; - dev->endpoint[EP2I(ep)].bufpq_prefilled = 0; -+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; - } - - if (ep & USB_DIR_IN) { -@@ -504,6 +524,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, - usbredirparser_do_write(dev->parser); - DPRINTF("interrupt recv started ep %02X\n", ep); - dev->endpoint[EP2I(ep)].interrupt_started = 1; -+ /* We don't really want to drop interrupt packets ever, but -+ having some upper limit to how much we buffer is good. */ -+ dev->endpoint[EP2I(ep)].bufpq_target_size = 1000; -+ dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; - } - - intp = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); --- -1.7.7.5 - diff --git a/0105-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch b/0105-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch new file mode 100644 index 0000000..2423095 --- /dev/null +++ b/0105-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch @@ -0,0 +1,94 @@ +From c84b4be013e683978e2d55d996c3dc6d7bace2aa Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 15 Feb 2012 11:22:15 +0200 +Subject: [PATCH] qxl: set only off-screen surfaces dirty instead of the whole + vram + +We used to assure the guest surfaces were saved before migration by +setting the whole vram dirty. This patch sets dirty only the areas +that are actually used in the vram. + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 53 ++++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 44 insertions(+), 9 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 4fd5e4e..3d9b1b3 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1010,7 +1010,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) + qxl_spice_destroy_surfaces(d, QXL_SYNC); + } + +-/* called from spice server thread context only */ ++/* can be also called from spice server thread context */ + void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) + { + uint64_t phys = le64_to_cpu(pqxl); +@@ -1469,6 +1469,46 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) + } + } + ++static void qxl_dirty_surfaces(PCIQXLDevice *qxl) ++{ ++ intptr_t vram_start; ++ int i; ++ ++ if (qxl->mode != QXL_MODE_NATIVE) { ++ return; ++ } ++ ++ /* dirty the primary surface */ ++ qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, ++ qxl->shadow_rom.surface0_area_size); ++ ++ vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); ++ ++ /* dirty the off-screen surfaces */ ++ for (i = 0; i < NUM_SURFACES; i++) { ++ QXLSurfaceCmd *cmd; ++ intptr_t surface_offset; ++ int surface_size; ++ ++ if (qxl->guest_surfaces.cmds[i] == 0) { ++ continue; ++ } ++ ++ cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], ++ MEMSLOT_GROUP_GUEST); ++ assert(cmd->type == QXL_SURFACE_CMD_CREATE); ++ surface_offset = (intptr_t)qxl_phys2virt(qxl, ++ cmd->u.surface_create.data, ++ MEMSLOT_GROUP_GUEST); ++ surface_offset -= vram_start; ++ surface_size = cmd->u.surface_create.height * ++ abs(cmd->u.surface_create.stride); ++ dprint(qxl, 3, "%s: dirty surface %d, offset %d, size %d\n", __func__, ++ i, (int)surface_offset, surface_size); ++ qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size); ++ } ++} ++ + static void qxl_vm_change_state_handler(void *opaque, int running, + RunState state) + { +@@ -1482,14 +1522,9 @@ static void qxl_vm_change_state_handler(void *opaque, int running, + * called + */ + qxl_update_irq(qxl); +- } else if (qxl->mode == QXL_MODE_NATIVE) { +- /* dirty all vram (which holds surfaces) and devram (primary surface) +- * to make sure they are saved */ +- /* FIXME #1: should go out during "live" stage */ +- /* FIXME #2: we only need to save the areas which are actually used */ +- qxl_set_dirty(&qxl->vram_bar, 0, qxl->vram_size); +- qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, +- qxl->shadow_rom.surface0_area_size); ++ } else { ++ /* make sure surfaces are saved before migration */ ++ qxl_dirty_surfaces(qxl); + } + } + diff --git a/0105-usb-redir-Improve-some-debugging-messages.patch b/0105-usb-redir-Improve-some-debugging-messages.patch deleted file mode 100644 index 8c5bda6..0000000 --- a/0105-usb-redir-Improve-some-debugging-messages.patch +++ /dev/null @@ -1,58 +0,0 @@ -From ba411ef969f3dcd8e82929e5577c0e06a60a5707 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 20 Dec 2011 16:21:34 +0100 -Subject: [PATCH 105/118] usb-redir: Improve some debugging messages - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 13 ++++++++----- - 1 files changed, 8 insertions(+), 5 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index 88d941a..86bccf8 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -394,7 +394,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - /* No id, we look at the ep when receiving a status back */ - usbredirparser_send_start_iso_stream(dev->parser, 0, &start_iso); - usbredirparser_do_write(dev->parser); -- DPRINTF("iso stream started ep %02X\n", ep); -+ DPRINTF("iso stream started pkts/sec %d pkts/urb %d urbs %d ep %02X\n", -+ pkts_per_sec, start_iso.pkts_per_urb, start_iso.no_urbs, ep); - dev->endpoint[EP2I(ep)].iso_started = 1; - dev->endpoint[EP2I(ep)].bufpq_prefilled = 0; - dev->endpoint[EP2I(ep)].bufpq_dropping_packets = 0; -@@ -414,7 +415,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - - isop = QTAILQ_FIRST(&dev->endpoint[EP2I(ep)].bufpq); - if (isop == NULL) { -- DPRINTF2("iso-token-in ep %02X, no isop\n", ep); -+ DPRINTF("iso-token-in ep %02X, no isop, iso_error: %d\n", -+ ep, dev->endpoint[EP2I(ep)].iso_error); - /* Re-fill the buffer */ - dev->endpoint[EP2I(ep)].bufpq_prefilled = 0; - /* Check iso_error for stream errors, otherwise its an underrun */ -@@ -422,8 +424,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - dev->endpoint[EP2I(ep)].iso_error = 0; - return usbredir_handle_status(dev, status, 0); - } -- DPRINTF2("iso-token-in ep %02X status %d len %d\n", ep, isop->status, -- isop->len); -+ DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep, -+ isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); - - status = isop->status; - if (status != usb_redir_success) { -@@ -433,7 +435,8 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - - len = isop->len; - if (len > p->iov.size) { -- ERROR("received iso data is larger then packet ep %02X\n", ep); -+ ERROR("received iso data is larger then packet ep %02X (%d > %d)\n", -+ ep, len, (int)p->iov.size); - bufp_free(dev, isop, ep); - return USB_RET_NAK; - } --- -1.7.7.5 - diff --git a/0106-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch b/0106-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch deleted file mode 100644 index bb37bd7..0000000 --- a/0106-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch +++ /dev/null @@ -1,57 +0,0 @@ -From 34736b9b6690054152ae2b9b37f75f7ed720590a Mon Sep 17 00:00:00 2001 -From: Amit Shah -Date: Mon, 21 Mar 2011 21:57:47 +0100 -Subject: [PATCH 106/118] char: Split out tcp socket close code in a separate - function - -Signed-off-by: Amit Shah ---- - qemu-char.c | 25 ++++++++++++++++--------- - 1 files changed, 16 insertions(+), 9 deletions(-) - -diff --git a/qemu-char.c b/qemu-char.c -index 27abcb9..a5ca611 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -2163,6 +2163,21 @@ typedef struct { - - static void tcp_chr_accept(void *opaque); - -+static void tcp_closed(void *opaque) -+{ -+ CharDriverState *chr = opaque; -+ TCPCharDriver *s = chr->opaque; -+ -+ s->connected = 0; -+ if (s->listen_fd >= 0) { -+ qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); -+ } -+ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); -+ closesocket(s->fd); -+ s->fd = -1; -+ qemu_chr_be_event(chr, CHR_EVENT_CLOSED); -+} -+ - static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - { - TCPCharDriver *s = chr->opaque; -@@ -2313,15 +2328,7 @@ static void tcp_chr_read(void *opaque) - len = s->max_size; - size = tcp_chr_recv(chr, (void *)buf, len); - if (size == 0) { -- /* connection closed */ -- s->connected = 0; -- if (s->listen_fd >= 0) { -- qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); -- } -- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); -- closesocket(s->fd); -- s->fd = -1; -- qemu_chr_be_event(chr, CHR_EVENT_CLOSED); -+ tcp_closed(chr); - } else if (size > 0) { - if (s->do_telnetopt) - tcp_chr_process_IAC_bytes(chr, s, buf, &size); --- -1.7.7.5 - diff --git a/0106-qxl-make-sure-primary-surface-is-saved-on-migration-.patch b/0106-qxl-make-sure-primary-surface-is-saved-on-migration-.patch new file mode 100644 index 0000000..dfa436e --- /dev/null +++ b/0106-qxl-make-sure-primary-surface-is-saved-on-migration-.patch @@ -0,0 +1,27 @@ +From 73dd6f6a1e6cf8da34efff7b1e30a2d0855ed582 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 15 Feb 2012 11:22:16 +0200 +Subject: [PATCH] qxl: make sure primary surface is saved on migration also in + compat mode + +RHBZ #790083 + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 3d9b1b3..b910337 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1474,7 +1474,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) + intptr_t vram_start; + int i; + +- if (qxl->mode != QXL_MODE_NATIVE) { ++ if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) { + return; + } + diff --git a/0107-Add-SPICE-support-to-add_client-monitor-command.patch b/0107-Add-SPICE-support-to-add_client-monitor-command.patch new file mode 100644 index 0000000..2a8c90b --- /dev/null +++ b/0107-Add-SPICE-support-to-add_client-monitor-command.patch @@ -0,0 +1,136 @@ +From 8824f88121cc0d07fec40828bf4c02824e21c52f Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Mon, 13 Feb 2012 13:43:08 +0000 +Subject: [PATCH] Add SPICE support to add_client monitor command + +With the acceptance of some new APIs to libspice-server.so it +is possible to add support for SPICE to the 'add_client' +monitor command, bringing parity with VNC. Since SPICE can +use TLS or plain connections, the command also gains a new +'tls' parameter to specify whether TLS should be attempted +on the injected client sockets. + +This new feature is only enabled if building against a +libspice-server >= 0.10.1 + +* qmp-commands.hx: Add 'tls' parameter & missing doc for + 'skipauth' parameter +* monitor.c: Wire up SPICE for 'add_client' command +* ui/qemu-spice.h, ui/spice-core.c: Add qemu_spice_display_add_client + API to wire up from monitor + +[1] http://cgit.freedesktop.org/spice/spice/commit/server/spice.h?id=d55b68b6b44f2499278fa860fb47ff22f5011faa + http://cgit.freedesktop.org/spice/spice/commit/server/spice.h?id=bd07dde530d9504e1cfe7ed5837fc00c26f36716 + +Changes in v3: + - Added 'optional' flag to new parameters documented + - Added no-op impl of qemu_spice_display_add_client when + SPICE is disabled during build + +Signed-off-by: Daniel P. Berrange +Signed-off-by: Gerd Hoffmann +--- + monitor.c | 9 +++++++-- + qmp-commands.hx | 6 ++++-- + ui/qemu-spice.h | 7 +++++++ + ui/spice-core.c | 13 +++++++++++++ + 4 files changed, 31 insertions(+), 4 deletions(-) + +diff --git a/monitor.c b/monitor.c +index a82fda3..3c23aa4 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -998,13 +998,18 @@ static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_d + CharDriverState *s; + + if (strcmp(protocol, "spice") == 0) { ++ int fd = monitor_get_fd(mon, fdname); ++ int skipauth = qdict_get_try_bool(qdict, "skipauth", 0); ++ int tls = qdict_get_try_bool(qdict, "tls", 0); + if (!using_spice) { + /* correct one? spice isn't a device ,,, */ + qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); + return -1; + } +- qerror_report(QERR_ADD_CLIENT_FAILED); +- return -1; ++ if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) { ++ close(fd); ++ } ++ return 0; + #ifdef CONFIG_VNC + } else if (strcmp(protocol, "vnc") == 0) { + int fd = monitor_get_fd(mon, fdname); +diff --git a/qmp-commands.hx b/qmp-commands.hx +index 97975a5..122b10d 100644 +--- a/qmp-commands.hx ++++ b/qmp-commands.hx +@@ -909,8 +909,8 @@ EQMP + + { + .name = "add_client", +- .args_type = "protocol:s,fdname:s,skipauth:b?", +- .params = "protocol fdname skipauth", ++ .args_type = "protocol:s,fdname:s,skipauth:b?,tls:b?", ++ .params = "protocol fdname skipauth tls", + .help = "add a graphics client", + .user_print = monitor_user_noop, + .mhandler.cmd_new = add_graphics_client, +@@ -926,6 +926,8 @@ Arguments: + + - "protocol": protocol name (json-string) + - "fdname": file descriptor name (json-string) ++- "skipauth": whether to skip authentication (json-bool, optional) ++- "tls": whether to perform TLS (json-bool, optional) + + Example: + +diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h +index c35b29c..680206a 100644 +--- a/ui/qemu-spice.h ++++ b/ui/qemu-spice.h +@@ -33,6 +33,7 @@ void qemu_spice_init(void); + void qemu_spice_input_init(void); + void qemu_spice_audio_init(void); + void qemu_spice_display_init(DisplayState *ds); ++int qemu_spice_display_add_client(int csock, int skipauth, int tls); + int qemu_spice_add_interface(SpiceBaseInstance *sin); + int qemu_spice_set_passwd(const char *passwd, + bool fail_if_connected, bool disconnect_if_connected); +@@ -68,6 +69,12 @@ static inline int qemu_spice_migrate_info(const char *h, int p, int t, + return -1; + } + ++static inline int qemu_spice_display_add_client(int csock, int skipauth, ++ int tls) ++{ ++ return -1; ++} ++ + #endif /* CONFIG_SPICE */ + + #endif /* QEMU_SPICE_H */ +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 5639c6f..d98863e 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -747,6 +747,19 @@ int qemu_spice_set_pw_expire(time_t expires) + return qemu_spice_set_ticket(false, false); + } + ++int qemu_spice_display_add_client(int csock, int skipauth, int tls) ++{ ++#if SPICE_SERVER_VERSION >= 0x000a01 ++ if (tls) { ++ return spice_server_add_ssl_client(spice_server, csock, skipauth); ++ } else { ++ return spice_server_add_client(spice_server, csock, skipauth); ++ } ++#else ++ return -1; ++#endif ++} ++ + static void spice_register_config(void) + { + qemu_add_opts(&qemu_spice_opts); diff --git a/0107-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch b/0107-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch deleted file mode 100644 index 48acb6a..0000000 --- a/0107-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch +++ /dev/null @@ -1,871 +0,0 @@ -From 61efa48e1973eaac16615c85198d9d74e36a3124 Mon Sep 17 00:00:00 2001 -From: Amit Shah -Date: Mon, 21 Mar 2011 20:31:45 +0100 -Subject: [PATCH 107/118] char: Add a QemuChrHandlers struct to initialise - chardev handlers - -Instead of passing each handler in the qemu_add_handlers() function, -create a struct of handlers that can be passed to the function instead. - -Signed-off-by: Amit Shah ---- - gdbstub.c | 9 +++++++-- - hw/ccid-card-passthru.c | 11 +++++++---- - hw/debugcon.c | 2 +- - hw/escc.c | 9 +++++++-- - hw/etraxfs_ser.c | 13 +++++++++---- - hw/grlib_apbuart.c | 12 +++++++----- - hw/ivshmem.c | 28 ++++++++++++++++++++++------ - hw/lm32_juart.c | 8 +++++++- - hw/lm32_uart.c | 8 +++++++- - hw/mcf_uart.c | 9 +++++++-- - hw/milkymist-uart.c | 8 +++++++- - hw/pl011.c | 9 +++++++-- - hw/pxa2xx.c | 13 +++++++++---- - hw/serial.c | 9 +++++++-- - hw/sh_serial.c | 12 +++++++++--- - hw/spapr_vty.c | 8 ++++++-- - hw/strongarm.c | 12 +++++++----- - hw/syborg_serial.c | 9 +++++++-- - hw/usb-serial.c | 9 +++++++-- - hw/virtio-console.c | 11 ++++++++--- - hw/xen_console.c | 16 +++++++++++----- - hw/xilinx_uartlite.c | 11 +++++++++-- - monitor.c | 18 ++++++++++++++---- - net/slirp.c | 8 ++++++-- - qemu-char.c | 32 ++++++++++++++++++++++---------- - qemu-char.h | 13 +++++++++---- - usb-redir.c | 9 +++++++-- - 27 files changed, 233 insertions(+), 83 deletions(-) - -diff --git a/gdbstub.c b/gdbstub.c -index 640cf4e..b984e12 100644 ---- a/gdbstub.c -+++ b/gdbstub.c -@@ -2860,6 +2860,12 @@ static void gdb_sigterm_handler(int signal) - } - #endif - -+static const QemuChrHandlers gdb_handlers = { -+ .fd_can_read = gdb_chr_can_receive, -+ .fd_read = gdb_chr_receive, -+ .fd_event = gdb_chr_event, -+}; -+ - int gdbserver_start(const char *device) - { - GDBState *s; -@@ -2889,8 +2895,7 @@ int gdbserver_start(const char *device) - if (!chr) - return -1; - -- qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive, -- gdb_chr_event, NULL); -+ qemu_chr_add_handlers(chr, &gdb_handlers, NULL); - } - - s = gdbserver_state; -diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c -index 9f51c6c..c5bff01 100644 ---- a/hw/ccid-card-passthru.c -+++ b/hw/ccid-card-passthru.c -@@ -274,6 +274,12 @@ static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len) - return card->atr; - } - -+static const QemuChrHandlers passthru_handlers = { -+ .fd_can_read = ccid_card_vscard_can_read, -+ .fd_read = ccid_card_vscard_read, -+ .fd_event = ccid_card_vscard_event, -+}; -+ - static int passthru_initfn(CCIDCardState *base) - { - PassthruState *card = DO_UPCAST(PassthruState, base, base); -@@ -282,10 +288,7 @@ static int passthru_initfn(CCIDCardState *base) - card->vscard_in_hdr = 0; - if (card->cs) { - DPRINTF(card, D_INFO, "initing chardev\n"); -- qemu_chr_add_handlers(card->cs, -- ccid_card_vscard_can_read, -- ccid_card_vscard_read, -- ccid_card_vscard_event, card); -+ qemu_chr_add_handlers(card->cs, &passthru_handlers, card); - ccid_card_vscard_send_init(card); - } else { - error_report("missing chardev"); -diff --git a/hw/debugcon.c b/hw/debugcon.c -index c9ee6d9..1d3c3ca 100644 ---- a/hw/debugcon.c -+++ b/hw/debugcon.c -@@ -73,7 +73,7 @@ static void debugcon_init_core(DebugconState *s) - exit(1); - } - -- qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s); -+ qemu_chr_add_handlers(s->chr, NULL, s); - } - - static int debugcon_isa_initfn(ISADevice *dev) -diff --git a/hw/escc.c b/hw/escc.c -index 13c7e66..997377e 100644 ---- a/hw/escc.c -+++ b/hw/escc.c -@@ -867,6 +867,12 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, - sysbus_mmio_map(s, 0, base); - } - -+static const QemuChrHandlers serial_handlers = { -+ .fd_can_read = serial_can_receive, -+ .fd_read = serial_receive1, -+ .fd_event = serial_event, -+}; -+ - static int escc_init1(SysBusDevice *dev) - { - SerialState *s = FROM_SYSBUS(SerialState, dev); -@@ -879,8 +885,7 @@ static int escc_init1(SysBusDevice *dev) - s->chn[i].chn = 1 - i; - s->chn[i].clock = s->frequency / 2; - if (s->chn[i].chr) { -- qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, -- serial_receive1, serial_event, &s->chn[i]); -+ qemu_chr_add_handlers(s->chn[i].chr, &serial_handlers, &s->chn[i]); - } - } - s->chn[0].otherchn = &s->chn[1]; -diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c -index 298b985..29d486e 100644 ---- a/hw/etraxfs_ser.c -+++ b/hw/etraxfs_ser.c -@@ -208,6 +208,12 @@ static void etraxfs_ser_reset(DeviceState *d) - - } - -+static const QemuChrHandlers serial_handlers = { -+ .fd_can_read = serial_can_receive, -+ .fd_read = serial_receive, -+ .fd_event = serial_event, -+}; -+ - static int etraxfs_ser_init(SysBusDevice *dev) - { - struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev); -@@ -217,10 +223,9 @@ static int etraxfs_ser_init(SysBusDevice *dev) - sysbus_init_mmio_region(dev, &s->mmio); - - s->chr = qdev_init_chardev(&dev->qdev); -- if (s->chr) -- qemu_chr_add_handlers(s->chr, -- serial_can_receive, serial_receive, -- serial_event, s); -+ if (s->chr) { -+ qemu_chr_add_handlers(s->chr, &serial_handlers, s); -+ } - return 0; - } - -diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c -index c90b810..ac6c33b 100644 ---- a/hw/grlib_apbuart.c -+++ b/hw/grlib_apbuart.c -@@ -144,16 +144,18 @@ static CPUWriteMemoryFunc * const grlib_apbuart_write[] = { - NULL, NULL, grlib_apbuart_writel, - }; - -+static const QemuChrHandlers grlib_handlers = { -+ .fd_can_read = grlib_apbuart_can_receive, -+ .fd_read = grlib_apbuart_receive, -+ .fd_event = grlib_apbuart_event, -+}; -+ - static int grlib_apbuart_init(SysBusDevice *dev) - { - UART *uart = FROM_SYSBUS(typeof(*uart), dev); - int uart_regs = 0; - -- qemu_chr_add_handlers(uart->chr, -- grlib_apbuart_can_receive, -- grlib_apbuart_receive, -- grlib_apbuart_event, -- uart); -+ qemu_chr_add_handlers(uart->chr, &grlib_handlers, uart); - - sysbus_init_irq(dev, &uart->irq); - -diff --git a/hw/ivshmem.c b/hw/ivshmem.c -index 7b4dbf6..ee78576 100644 ---- a/hw/ivshmem.c -+++ b/hw/ivshmem.c -@@ -276,6 +276,18 @@ static void fake_irqfd(void *opaque, const uint8_t *buf, int size) { - msix_notify(pdev, entry->vector); - } - -+static const QemuChrHandlers ivshmem_handlers = { -+ .fd_can_read = ivshmem_can_receive, -+ .fd_read = ivshmem_receive, -+ .fd_event = ivshmem_event, -+}; -+ -+static const QemuChrHandlers ivshmem_msi_handlers = { -+ .fd_can_read = ivshmem_can_receive, -+ .fd_read = fake_irqfd, -+ .fd_event = ivshmem_event, -+}; -+ - static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd, - int vector) - { -@@ -295,11 +307,10 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, int eventfd, - s->eventfd_table[vector].pdev = &s->dev; - s->eventfd_table[vector].vector = vector; - -- qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd, -- ivshmem_event, &s->eventfd_table[vector]); -+ qemu_chr_add_handlers(chr, &ivshmem_msi_handlers, -+ &s->eventfd_table[vector]); - } else { -- qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive, -- ivshmem_event, s); -+ qemu_chr_add_handlers(chr, &ivshmem_handlers, s); - } - - return chr; -@@ -614,6 +625,12 @@ static int ivshmem_load(QEMUFile* f, void *opaque, int version_id) - return 0; - } - -+static const QemuChrHandlers ivshmem_server_handlers = { -+ .fd_can_read = ivshmem_can_receive, -+ .fd_read = ivshmem_read, -+ .fd_event = ivshmem_event, -+}; -+ - static int pci_ivshmem_init(PCIDevice *dev) - { - IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev); -@@ -703,8 +720,7 @@ static int pci_ivshmem_init(PCIDevice *dev) - - s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *)); - -- qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read, -- ivshmem_event, s); -+ qemu_chr_add_handlers(s->server_chr, &ivshmem_server_handlers, s); - } else { - /* just map the file immediately, we're not using a server */ - int fd; -diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c -index 5454aa4..1b9fa07 100644 ---- a/hw/lm32_juart.c -+++ b/hw/lm32_juart.c -@@ -110,13 +110,19 @@ static void juart_reset(DeviceState *d) - s->jrx = 0; - } - -+static const QemuChrHandlers juart_handlers = { -+ .fd_can_read = juart_can_rx, -+ .fd_read = juart_rx, -+ .fd_event = juart_event, -+}; -+ - static int lm32_juart_init(SysBusDevice *dev) - { - LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev); - - s->chr = qdev_init_chardev(&dev->qdev); - if (s->chr) { -- qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s); -+ qemu_chr_add_handlers(s->chr, juart_handlers, s); - } - - return 0; -diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c -index 3678545..ccaf88c 100644 ---- a/hw/lm32_uart.c -+++ b/hw/lm32_uart.c -@@ -242,6 +242,12 @@ static void uart_reset(DeviceState *d) - s->regs[R_LSR] = LSR_THRE | LSR_TEMT; - } - -+static const QemuChrHandlers uart_handlers = { -+ .fd_can_read = uart_can_rx, -+ .fd_read = uart_rx, -+ .fd_event = uart_event, -+}; -+ - static int lm32_uart_init(SysBusDevice *dev) - { - LM32UartState *s = FROM_SYSBUS(typeof(*s), dev); -@@ -255,7 +261,7 @@ static int lm32_uart_init(SysBusDevice *dev) - - s->chr = qdev_init_chardev(&dev->qdev); - if (s->chr) { -- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); -+ qemu_chr_add_handlers(s->chr, uart_handlers, s); - } - - return 0; -diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c -index e6b2ab0..2870683 100644 ---- a/hw/mcf_uart.c -+++ b/hw/mcf_uart.c -@@ -268,6 +268,12 @@ static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) - mcf_uart_push_byte(s, buf[0]); - } - -+static const QemuChrHandlers mcf_uart_handlers = { -+ .fd_can_read = mcf_uart_can_receive, -+ .fd_read = mcf_uart_receive, -+ .fd_event = mcf_uart_event, -+}; -+ - void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) - { - mcf_uart_state *s; -@@ -276,8 +282,7 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) - s->chr = chr; - s->irq = irq; - if (chr) { -- qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive, -- mcf_uart_event, s); -+ qemu_chr_add_handlers(chr, &mcf_uart_handlers, s); - } - mcf_uart_reset(s); - return s; -diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c -index 5404ca9..fd10e12 100644 ---- a/hw/milkymist-uart.c -+++ b/hw/milkymist-uart.c -@@ -189,6 +189,12 @@ static void milkymist_uart_reset(DeviceState *d) - s->regs[R_STAT] = STAT_THRE; - } - -+static const QemuChrHandlers uart_handlers = { -+ .fd_can_read = uart_can_rx, -+ .fd_read = uart_rx, -+ .fd_event = uart_event, -+}; -+ - static int milkymist_uart_init(SysBusDevice *dev) - { - MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev); -@@ -201,7 +207,7 @@ static int milkymist_uart_init(SysBusDevice *dev) - - s->chr = qdev_init_chardev(&dev->qdev); - if (s->chr) { -- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); -+ qemu_chr_add_handlers(s->chr, uart_handlers, s); - } - - return 0; -diff --git a/hw/pl011.c b/hw/pl011.c -index 707a161..7482246 100644 ---- a/hw/pl011.c -+++ b/hw/pl011.c -@@ -260,6 +260,12 @@ static const VMStateDescription vmstate_pl011 = { - } - }; - -+static const QemuChrHandlers pl011_handlers = { -+ .fd_can_read = pl011_can_receive, -+ .fd_read = pl011_receive, -+ .fd_event = pl011_event, -+}; -+ - static int pl011_init(SysBusDevice *dev, const unsigned char *id) - { - int iomemtype; -@@ -278,8 +284,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id) - s->cr = 0x300; - s->flags = 0x90; - if (s->chr) { -- qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, -- pl011_event, s); -+ qemu_chr_add_handlers(s->chr, &pl011_handlers, s); - } - vmstate_register(&dev->qdev, -1, &vmstate_pl011, s); - return 0; -diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c -index e9a507e..24925b6 100644 ---- a/hw/pxa2xx.c -+++ b/hw/pxa2xx.c -@@ -1984,6 +1984,12 @@ static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) - return 0; - } - -+static const QemuChrHandlers pxa2xx_handlers = { -+ .fd_can_read = pxa2xx_fir_is_empty, -+ .fd_read = pxa2xx_fir_rx, -+ .fd_event = pxa2xx_fir_event, -+}; -+ - static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, - target_phys_addr_t base, - qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma, -@@ -2002,10 +2008,9 @@ static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, - memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000); - memory_region_add_subregion(sysmem, base, &s->iomem); - -- if (chr) -- qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, -- pxa2xx_fir_rx, pxa2xx_fir_event, s); -- -+ if (chr) { -+ qemu_chr_add_handlers(chr, &pxa2xx_handlers, s); -+ } - register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save, - pxa2xx_fir_load, s); - -diff --git a/hw/serial.c b/hw/serial.c -index d35c7a9..6499d4a 100644 ---- a/hw/serial.c -+++ b/hw/serial.c -@@ -728,6 +728,12 @@ static void serial_reset(void *opaque) - qemu_irq_lower(s->irq); - } - -+static const QemuChrHandlers serial_handlers = { -+ .fd_can_read = serial_can_receive1, -+ .fd_read = serial_receive1, -+ .fd_event = serial_event, -+}; -+ - static void serial_init_core(SerialState *s) - { - if (!s->chr) { -@@ -742,8 +748,7 @@ static void serial_init_core(SerialState *s) - - qemu_register_reset(serial_reset, s); - -- qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, -- serial_event, s); -+ qemu_chr_add_handlers(s->chr, &serial_handlers, s); - } - - /* Change the main reference oscillator frequency. */ -diff --git a/hw/sh_serial.c b/hw/sh_serial.c -index a20c59e..470ce7a 100644 ---- a/hw/sh_serial.c -+++ b/hw/sh_serial.c -@@ -350,6 +350,12 @@ static CPUWriteMemoryFunc * const sh_serial_writefn[] = { - &sh_serial_write, - }; - -+static const QemuChrHandlers sh_serial_handlers = { -+ .fd_can_read = sh_serial_can_receive1, -+ .fd_read = sh_serial_receive1, -+ .fd_event = sh_serial_event, -+}; -+ - void sh_serial_init (target_phys_addr_t base, int feat, - uint32_t freq, CharDriverState *chr, - qemu_irq eri_source, -@@ -389,9 +395,9 @@ void sh_serial_init (target_phys_addr_t base, int feat, - - s->chr = chr; - -- if (chr) -- qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1, -- sh_serial_event, s); -+ if (chr) { -+ qemu_chr_add_handlers(chr, &sh_serial_handlers, s); -+ } - - s->eri = eri_source; - s->rxi = rxi_source; -diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c -index f23cc36..0d9cd59 100644 ---- a/hw/spapr_vty.c -+++ b/hw/spapr_vty.c -@@ -54,6 +54,11 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) - qemu_chr_fe_write(dev->chardev, buf, len); - } - -+static const QemuChrHandlers vty_handlers = { -+ .fd_can_read = vty_can_receive, -+ .fd_read = vty_receive, -+}; -+ - static int spapr_vty_init(VIOsPAPRDevice *sdev) - { - VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; -@@ -63,8 +68,7 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev) - exit(1); - } - -- qemu_chr_add_handlers(dev->chardev, vty_can_receive, -- vty_receive, NULL, dev); -+ qemu_chr_add_handlers(dev->chardev, vty_handlers, dev); - - return 0; - } -diff --git a/hw/strongarm.c b/hw/strongarm.c -index a3d9080..8a8a219 100644 ---- a/hw/strongarm.c -+++ b/hw/strongarm.c -@@ -1160,6 +1160,12 @@ static const MemoryRegionOps strongarm_uart_ops = { - .endianness = DEVICE_NATIVE_ENDIAN, - }; - -+static const QemuChrHandlers strongarm_uart_handlers = { -+ .fd_can_read = strongarm_uart_can_receive, -+ .fd_read = strongarm_uart_receive, -+ .fd_event = strongarm_uart_event, -+}; -+ - static int strongarm_uart_init(SysBusDevice *dev) - { - StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev); -@@ -1172,11 +1178,7 @@ static int strongarm_uart_init(SysBusDevice *dev) - s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s); - - if (s->chr) { -- qemu_chr_add_handlers(s->chr, -- strongarm_uart_can_receive, -- strongarm_uart_receive, -- strongarm_uart_event, -- s); -+ qemu_chr_add_handlers(s->chr, &strongarm_uart_handlers, s); - } - - return 0; -diff --git a/hw/syborg_serial.c b/hw/syborg_serial.c -index c83f82c..fff76da 100644 ---- a/hw/syborg_serial.c -+++ b/hw/syborg_serial.c -@@ -292,6 +292,12 @@ static const VMStateDescription vmstate_syborg_serial = { - } - }; - -+static const QemuChrHandlers syborg_serial_handlers = { -+ .fd_can_read = syborg_serial_can_receive, -+ .fd_read = syborg_serial_receive, -+ .fd_event = syborg_serial_event, -+}; -+ - static int syborg_serial_init(SysBusDevice *dev) - { - SyborgSerialState *s = FROM_SYSBUS(SyborgSerialState, dev); -@@ -304,8 +310,7 @@ static int syborg_serial_init(SysBusDevice *dev) - sysbus_init_mmio(dev, 0x1000, iomemtype); - s->chr = qdev_init_chardev(&dev->qdev); - if (s->chr) { -- qemu_chr_add_handlers(s->chr, syborg_serial_can_receive, -- syborg_serial_receive, syborg_serial_event, s); -+ qemu_chr_add_handlers(s->chr, &syborg_serial_handlers, s); - } - if (s->fifo_size <= 0) { - fprintf(stderr, "syborg_serial: fifo too small\n"); -diff --git a/hw/usb-serial.c b/hw/usb-serial.c -index 7dbf6df..bcf6622 100644 ---- a/hw/usb-serial.c -+++ b/hw/usb-serial.c -@@ -482,6 +482,12 @@ static void usb_serial_event(void *opaque, int event) - } - } - -+static const QemuChrHandlers usb_serial_handlers = { -+ .fd_can_read = usb_serial_can_read, -+ .fd_read = usb_serial_read, -+ .fd_event = usb_serial_event, -+}; -+ - static int usb_serial_initfn(USBDevice *dev) - { - USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev); -@@ -493,8 +499,7 @@ static int usb_serial_initfn(USBDevice *dev) - return -1; - } - -- qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read, -- usb_serial_event, s); -+ qemu_chr_add_handlers(s->cs, &usb_serial_handlers, s); - usb_serial_handle_reset(dev); - return 0; - } -diff --git a/hw/virtio-console.c b/hw/virtio-console.c -index d3351c8..6d6f3ef 100644 ---- a/hw/virtio-console.c -+++ b/hw/virtio-console.c -@@ -95,6 +95,12 @@ static void chr_event(void *opaque, int event) - } - } - -+static const QemuChrHandlers chr_handlers = { -+ .fd_can_read = chr_can_read, -+ .fd_read = chr_read, -+ .fd_event = chr_event, -+}; -+ - static int virtconsole_initfn(VirtIOSerialPort *port) - { - VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); -@@ -107,8 +113,7 @@ static int virtconsole_initfn(VirtIOSerialPort *port) - } - - if (vcon->chr) { -- qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, -- vcon); -+ qemu_chr_add_handlers(vcon->chr, &chr_handlers, vcon); - info->have_data = flush_buf; - info->guest_open = guest_open; - info->guest_close = guest_close; -@@ -126,7 +131,7 @@ static int virtconsole_exitfn(VirtIOSerialPort *port) - * Instead of closing the chardev, free it so it can be used - * for other purposes. - */ -- qemu_chr_add_handlers(vcon->chr, NULL, NULL, NULL, NULL); -+ qemu_chr_add_handlers(vcon->chr, NULL, NULL); - } - - return 0; -diff --git a/hw/xen_console.c b/hw/xen_console.c -index edcb31c..2ba74f0 100644 ---- a/hw/xen_console.c -+++ b/hw/xen_console.c -@@ -212,6 +212,11 @@ out: - return ret; - } - -+static const QemuChrHandlers xencons_handlers = { -+ .fd_can_read = xencons_can_receive, -+ .fd_read = xencons_receive, -+}; -+ - static int con_initialise(struct XenDevice *xendev) - { - struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); -@@ -232,9 +237,9 @@ static int con_initialise(struct XenDevice *xendev) - return -1; - - xen_be_bind_evtchn(&con->xendev); -- if (con->chr) -- qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive, -- NULL, con); -+ if (con->chr) { -+ qemu_chr_add_handlers(con->chr, &xencons_handlers, con); -+ } - - xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n", - con->ring_ref, -@@ -248,8 +253,9 @@ static void con_disconnect(struct XenDevice *xendev) - { - struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); - -- if (con->chr) -- qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL); -+ if (con->chr) { -+ qemu_chr_add_handlers(con->chr, NULL, NULL); -+ } - xen_be_unbind_evtchn(&con->xendev); - - if (con->sring) { -diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c -index ceb7b4d..69f7191 100644 ---- a/hw/xilinx_uartlite.c -+++ b/hw/xilinx_uartlite.c -@@ -195,6 +195,12 @@ static void uart_event(void *opaque, int event) - - } - -+static const QemuChrHandlers uart_handlers = { -+ .fd_can_read = uart_can_rx, -+ .fd_read = uart_rx, -+ .fd_event = uart_event, -+}; -+ - static int xilinx_uartlite_init(SysBusDevice *dev) - { - struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev); -@@ -206,8 +212,9 @@ static int xilinx_uartlite_init(SysBusDevice *dev) - sysbus_init_mmio_region(dev, &s->mmio); - - s->chr = qdev_init_chardev(&dev->qdev); -- if (s->chr) -- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); -+ if (s->chr) { -+ qemu_chr_add_handlers(s->chr, &uart_handlers, s); -+ } - return 0; - } - -diff --git a/monitor.c b/monitor.c -index f956eb7..a82fda3 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -4882,6 +4882,18 @@ static void sortcmdlist(void) - * End: - */ - -+static const QemuChrHandlers monitor_handlers = { -+ .fd_can_read = monitor_can_read, -+ .fd_read = monitor_read, -+ .fd_event = monitor_event, -+}; -+ -+static const QemuChrHandlers monitor_control_handlers = { -+ .fd_can_read = monitor_can_read, -+ .fd_read = monitor_control_read, -+ .fd_event = monitor_control_event, -+}; -+ - void monitor_init(CharDriverState *chr, int flags) - { - static int is_first_init = 1; -@@ -4904,12 +4916,10 @@ void monitor_init(CharDriverState *chr, int flags) - if (monitor_ctrl_mode(mon)) { - mon->mc = g_malloc0(sizeof(MonitorControl)); - /* Control mode requires special handlers */ -- qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read, -- monitor_control_event, mon); -+ qemu_chr_add_handlers(chr, &monitor_control_handlers, mon); - qemu_chr_fe_set_echo(chr, true); - } else { -- qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, -- monitor_event, mon); -+ qemu_chr_add_handlers(chr, &monitor_handlers, mon); - } - - QLIST_INSERT_HEAD(&mon_list, mon, entry); -diff --git a/net/slirp.c b/net/slirp.c -index 6646ecb..05405ff 100644 ---- a/net/slirp.c -+++ b/net/slirp.c -@@ -576,6 +576,11 @@ static void guestfwd_read(void *opaque, const uint8_t *buf, int size) - slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); - } - -+static const QemuChrHandlers guestfwd_handlers = { -+ .fd_can_read = guestfwd_can_read, -+ .fd_read = guestfwd_read, -+}; -+ - static int slirp_guestfwd(SlirpState *s, const char *config_str, - int legacy_format) - { -@@ -632,8 +637,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, - fwd->port = port; - fwd->slirp = s->slirp; - -- qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, -- NULL, fwd); -+ qemu_chr_add_handlers(fwd->hd, &guestfwd_handlers, fwd); - return 0; - - fail_syntax: -diff --git a/qemu-char.c b/qemu-char.c -index a5ca611..d2a99a6 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -189,19 +189,26 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) - va_end(ap); - } - -+static const QemuChrHandlers null_handlers = { -+ /* All handlers are initialised to NULL */ -+}; -+ - void qemu_chr_add_handlers(CharDriverState *s, -- IOCanReadHandler *fd_can_read, -- IOReadHandler *fd_read, -- IOEventHandler *fd_event, -- void *opaque) -+ const QemuChrHandlers *handlers, void *opaque) - { -- if (!opaque && !fd_can_read && !fd_read && !fd_event) { -+ if (!s) { -+ return; -+ } -+ if (!opaque && !handlers) { - /* chr driver being released. */ - ++s->avail_connections; - } -- s->chr_can_read = fd_can_read; -- s->chr_read = fd_read; -- s->chr_event = fd_event; -+ if (!handlers) { -+ handlers = &null_handlers; -+ } -+ s->chr_can_read = handlers->fd_can_read; -+ s->chr_read = handlers->fd_read; -+ s->chr_event = handlers->fd_event; - s->handler_opaque = opaque; - if (s->chr_update_read_handler) - s->chr_update_read_handler(s); -@@ -441,6 +448,12 @@ static void mux_chr_event(void *opaque, int event) - mux_chr_send_event(d, i, event); - } - -+static const QemuChrHandlers mux_chr_handlers = { -+ .fd_can_read = mux_chr_can_read, -+ .fd_read = mux_chr_read, -+ .fd_event = mux_chr_event, -+}; -+ - static void mux_chr_update_read_handler(CharDriverState *chr) - { - MuxDriver *d = chr->opaque; -@@ -455,8 +468,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr) - 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); -+ qemu_chr_add_handlers(d->drv, &mux_chr_handlers, chr); - } - if (d->focus != -1) { - mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); -diff --git a/qemu-char.h b/qemu-char.h -index 8ca1e2d..564e688 100644 ---- a/qemu-char.h -+++ b/qemu-char.h -@@ -222,10 +222,15 @@ void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len); - */ - void qemu_chr_be_event(CharDriverState *s, int event); - --void qemu_chr_add_handlers(CharDriverState *s, -- IOCanReadHandler *fd_can_read, -- IOReadHandler *fd_read, -- IOEventHandler *fd_event, -+ -+typedef struct QemuChrHandlers { -+ IOCanReadHandler *fd_can_read; -+ IOReadHandler *fd_read; -+ IOHandler *fd_write_unblocked; -+ IOEventHandler *fd_event; -+} QemuChrHandlers; -+ -+void qemu_chr_add_handlers(CharDriverState *s, const QemuChrHandlers *handlers, - void *opaque); - - void qemu_chr_generic_open(CharDriverState *s); -diff --git a/usb-redir.c b/usb-redir.c -index 86bccf8..e421cff 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -865,6 +865,12 @@ static void usbredir_chardev_event(void *opaque, int event) - } - } - -+static const QemuChrHandlers usbredir_chr_handlers = { -+ .fd_can_read = usbredir_chardev_can_read, -+ .fd_read = usbredir_chardev_read, -+ .fd_event = usbredir_chardev_event, -+}; -+ - /* - * init + destroy - */ -@@ -892,8 +898,7 @@ static int usbredir_initfn(USBDevice *udev) - - /* Let the backend know we are ready */ - qemu_chr_fe_open(dev->cs); -- qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read, -- usbredir_chardev_read, usbredir_chardev_event, dev); -+ qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); - - return 0; - } --- -1.7.7.5 - diff --git a/0108-iohandlers-Add-enable-disable_write_fd_handler-funct.patch b/0108-iohandlers-Add-enable-disable_write_fd_handler-funct.patch deleted file mode 100644 index a02a798..0000000 --- a/0108-iohandlers-Add-enable-disable_write_fd_handler-funct.patch +++ /dev/null @@ -1,77 +0,0 @@ -From f896c023201863927853c5d97e62916e0753fede Mon Sep 17 00:00:00 2001 -From: Amit Shah -Date: Mon, 21 Mar 2011 20:32:58 +0100 -Subject: [PATCH 108/118] iohandlers: Add enable/disable_write_fd_handler() - functions - -These will be used to provide a cleaner API for the nonblocking case. - -Signed-off-by: Amit Shah ---- - iohandler.c | 35 +++++++++++++++++++++++++++++++++++ - main-loop.h | 3 +++ - 2 files changed, 38 insertions(+), 0 deletions(-) - -diff --git a/iohandler.c b/iohandler.c -index 5640d49..a9a62cb 100644 ---- a/iohandler.c -+++ b/iohandler.c -@@ -45,6 +45,41 @@ typedef struct IOHandlerRecord { - static QLIST_HEAD(, IOHandlerRecord) io_handlers = - QLIST_HEAD_INITIALIZER(io_handlers); - -+static IOHandlerRecord *find_iohandler(int fd) -+{ -+ IOHandlerRecord *ioh; -+ -+ QLIST_FOREACH(ioh, &io_handlers, next) { -+ if (ioh->fd == fd) { -+ return ioh; -+ } -+ } -+ return NULL; -+} -+ -+void enable_write_fd_handler(int fd, IOHandler *fd_write) -+{ -+ IOHandlerRecord *ioh; -+ -+ ioh = find_iohandler(fd); -+ if (!ioh) { -+ return; -+ } -+ -+ ioh->fd_write = fd_write; -+} -+ -+void disable_write_fd_handler(int fd) -+{ -+ IOHandlerRecord *ioh; -+ -+ ioh = find_iohandler(fd); -+ if (!ioh) { -+ return; -+ } -+ -+ ioh->fd_write = NULL; -+} - - /* XXX: fd_read_poll should be suppressed, but an API change is - necessary in the character devices to suppress fd_can_read(). */ -diff --git a/main-loop.h b/main-loop.h -index 8a716b1..c5a96cd 100644 ---- a/main-loop.h -+++ b/main-loop.h -@@ -167,6 +167,9 @@ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); - typedef int IOCanReadHandler(void *opaque); - typedef void IOHandler(void *opaque); - -+void enable_write_fd_handler(int fd, IOHandler *fd_write); -+void disable_write_fd_handler(int fd); -+ - /** - * qemu_set_fd_handler2: Register a file descriptor with the main loop - * --- -1.7.7.5 - diff --git a/0108-spice-support-ipv6-channel-address-in-monitor-events.patch b/0108-spice-support-ipv6-channel-address-in-monitor-events.patch new file mode 100644 index 0000000..a9ed92b --- /dev/null +++ b/0108-spice-support-ipv6-channel-address-in-monitor-events.patch @@ -0,0 +1,80 @@ +From b54dc2a6c0a6b38a2fac5db290624e904a21fe99 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Wed, 8 Feb 2012 15:40:15 +0200 +Subject: [PATCH] spice: support ipv6 channel address in monitor events and in + spice info + +RHBZ #788444 + +CC: Gerd Hoffmann + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +--- + ui/spice-core.c | 37 ++++++++++++++++++++++++++++++++----- + 1 file changed, 32 insertions(+), 5 deletions(-) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index d98863e..27216e9 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -220,10 +220,23 @@ static void channel_event(int event, SpiceChannelEventInfo *info) + } + + client = qdict_new(); +- add_addr_info(client, &info->paddr, info->plen); +- + server = qdict_new(); +- add_addr_info(server, &info->laddr, info->llen); ++ ++#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT ++ if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { ++ add_addr_info(client, (struct sockaddr *)&info->paddr_ext, ++ info->plen_ext); ++ add_addr_info(server, (struct sockaddr *)&info->laddr_ext, ++ info->llen_ext); ++ } else { ++ fprintf(stderr, "spice: %s, extended address is expected\n", ++ __func__); ++#endif ++ add_addr_info(client, &info->paddr, info->plen); ++ add_addr_info(server, &info->laddr, info->llen); ++#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT ++ } ++#endif + + if (event == SPICE_CHANNEL_EVENT_INITIALIZED) { + qdict_put(server, "auth", qstring_from_str(auth)); +@@ -376,16 +389,30 @@ static SpiceChannelList *qmp_query_spice_channels(void) + QTAILQ_FOREACH(item, &channel_list, link) { + SpiceChannelList *chan; + char host[NI_MAXHOST], port[NI_MAXSERV]; ++ struct sockaddr *paddr; ++ socklen_t plen; + + chan = g_malloc0(sizeof(*chan)); + chan->value = g_malloc0(sizeof(*chan->value)); + +- getnameinfo(&item->info->paddr, item->info->plen, ++#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT ++ if (item->info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { ++ paddr = (struct sockaddr *)&item->info->paddr_ext; ++ plen = item->info->plen_ext; ++ } else { ++#endif ++ paddr = &item->info->paddr; ++ plen = item->info->plen; ++#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT ++ } ++#endif ++ ++ getnameinfo(paddr, plen, + host, sizeof(host), port, sizeof(port), + NI_NUMERICHOST | NI_NUMERICSERV); + chan->value->host = g_strdup(host); + chan->value->port = g_strdup(port); +- chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family)); ++ chan->value->family = g_strdup(inet_strfamily(paddr->sa_family)); + + chan->value->connection_id = item->info->connection_id; + chan->value->channel_type = item->info->type; diff --git a/0109-char-Add-framework-for-a-write-unblocked-callback.patch b/0109-char-Add-framework-for-a-write-unblocked-callback.patch deleted file mode 100644 index 2599187..0000000 --- a/0109-char-Add-framework-for-a-write-unblocked-callback.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 6d5337e1dc8d926f9183e2f5eb5e97c438203527 Mon Sep 17 00:00:00 2001 -From: Amit Shah -Date: Mon, 21 Mar 2011 21:41:42 +0100 -Subject: [PATCH 109/118] char: Add framework for a 'write unblocked' callback - -The char layer can let users know that the driver will block on further -input. For users interested in not blocking, they can assign a function -pointer that will be called back when the driver becomes writable. This -patch just adds the function pointers to the CharDriverState structure, -future patches will enable the nonblocking and callback functionality. - -Signed-off-by: Amit Shah ---- - qemu-char.c | 3 +++ - qemu-char.h | 4 ++++ - 2 files changed, 7 insertions(+), 0 deletions(-) - -diff --git a/qemu-char.c b/qemu-char.c -index d2a99a6..66b5887 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -208,11 +208,14 @@ void qemu_chr_add_handlers(CharDriverState *s, - } - s->chr_can_read = handlers->fd_can_read; - s->chr_read = handlers->fd_read; -+ s->chr_write_unblocked = handlers->fd_write_unblocked; - s->chr_event = handlers->fd_event; - s->handler_opaque = opaque; - if (s->chr_update_read_handler) - s->chr_update_read_handler(s); - -+ s->write_blocked = false; -+ - /* We're connecting to an already opened device, so let's make sure we - also get the open event */ - if (s->opened) { -diff --git a/qemu-char.h b/qemu-char.h -index 564e688..2628bee 100644 ---- a/qemu-char.h -+++ b/qemu-char.h -@@ -62,6 +62,9 @@ struct CharDriverState { - IOEventHandler *chr_event; - IOCanReadHandler *chr_can_read; - IOReadHandler *chr_read; -+ IOHandler *chr_write_unblocked; -+ void (*chr_enable_write_fd_handler)(struct CharDriverState *chr); -+ void (*chr_disable_write_fd_handler)(struct CharDriverState *chr); - void *handler_opaque; - void (*chr_close)(struct CharDriverState *chr); - void (*chr_accept_input)(struct CharDriverState *chr); -@@ -74,6 +77,7 @@ struct CharDriverState { - char *filename; - int opened; - int avail_connections; -+ bool write_blocked; /* Are we in a blocked state? */ - QTAILQ_ENTRY(CharDriverState) next; - }; - --- -1.7.7.5 - diff --git a/0109-qxl-drop-vram-bar-minimum-size.patch b/0109-qxl-drop-vram-bar-minimum-size.patch new file mode 100644 index 0000000..5360c99 --- /dev/null +++ b/0109-qxl-drop-vram-bar-minimum-size.patch @@ -0,0 +1,27 @@ +From ba6e610d1e7eeb5f2f06e7321c8153f827a6634b Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 17 Feb 2012 14:40:01 +0100 +Subject: [PATCH] qxl: drop vram bar minimum size + +There is no reason to require a minimum size of 16 MB for the vram. +Lower the limit to 4096 (one page). Make it disapper completely would +break guests. +--- + hw/qxl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index b910337..d71c94d 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1595,8 +1595,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) + init_qxl_rom(qxl); + init_qxl_ram(qxl); + +- if (qxl->vram_size < 16 * 1024 * 1024) { +- qxl->vram_size = 16 * 1024 * 1024; ++ if (qxl->vram_size < 4096) { ++ qxl->vram_size = 4096; + } + if (qxl->revision == 1) { + qxl->vram_size = 4096; diff --git a/0110-char-Update-send_all-to-handle-nonblocking-chardev-w.patch b/0110-char-Update-send_all-to-handle-nonblocking-chardev-w.patch deleted file mode 100644 index c694ebf..0000000 --- a/0110-char-Update-send_all-to-handle-nonblocking-chardev-w.patch +++ /dev/null @@ -1,188 +0,0 @@ -From 9ca6b87b877fa46c81ce8e5b5a97dca4f522a727 Mon Sep 17 00:00:00 2001 -From: Amit Shah -Date: Mon, 21 Mar 2011 22:00:27 +0100 -Subject: [PATCH 110/118] char: Update send_all() to handle nonblocking - chardev write requests - -The send_all function is modified to return to the caller in case the -driver cannot handle any more data. It returns -EAGAIN or -WSAEWOULDBLOCK on non-Windows and Windows platforms respectively. This -is only done when the caller sets a callback function handler indicating -it's not interested in blocking till the driver has written out all the -data. - -Currently there's no driver or caller that supports this. Future -commits will add such capability. - -Signed-off-by: Amit Shah ---- - net/socket.c | 4 +- - qemu-char.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++----- - qemu_socket.h | 2 +- - 3 files changed, 66 insertions(+), 9 deletions(-) - -diff --git a/net/socket.c b/net/socket.c -index e9ef128..0d53dce 100644 ---- a/net/socket.c -+++ b/net/socket.c -@@ -56,8 +56,8 @@ static ssize_t net_socket_receive(VLANClientState *nc, const uint8_t *buf, size_ - uint32_t len; - len = htonl(size); - -- send_all(s->fd, (const uint8_t *)&len, sizeof(len)); -- return send_all(s->fd, buf, size); -+ send_all(NULL, s->fd, (const uint8_t *)&len, sizeof(len)); -+ return send_all(NULL, s->fd, buf, size); - } - - static ssize_t net_socket_receive_dgram(VLANClientState *nc, const uint8_t *buf, size_t size) -diff --git a/qemu-char.c b/qemu-char.c -index 66b5887..5e7f68e 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -507,7 +507,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) - - - #ifdef _WIN32 --int send_all(int fd, const void *buf, int len1) -+static int do_send(int fd, const void *buf, int len1, bool nonblock) - { - int ret, len; - -@@ -515,9 +515,14 @@ int send_all(int fd, const void *buf, int len1) - while (len > 0) { - ret = send(fd, buf, len, 0); - if (ret < 0) { -+ if (nonblock && len1 - len) { -+ return len1 - len; -+ } - errno = WSAGetLastError(); - if (errno != WSAEWOULDBLOCK) { - return -1; -+ } else if (errno == WSAEWOULDBLOCK && nonblock) { -+ return WSAEWOULDBLOCK; - } - } else if (ret == 0) { - break; -@@ -531,7 +536,7 @@ int send_all(int fd, const void *buf, int len1) - - #else - --int send_all(int fd, const void *_buf, int len1) -+static int do_send(int fd, const void *_buf, int len1, bool nonblock) - { - int ret, len; - const uint8_t *buf = _buf; -@@ -540,8 +545,15 @@ int send_all(int fd, const void *_buf, int len1) - while (len > 0) { - ret = write(fd, buf, len); - if (ret < 0) { -- if (errno != EINTR && errno != EAGAIN) -+ if (nonblock && len1 - len) { -+ return len1 - len; -+ } -+ if (errno == EAGAIN && nonblock) { -+ return -EAGAIN; -+ } -+ if (errno != EINTR && errno != EAGAIN) { - return -1; -+ } - } else if (ret == 0) { - break; - } else { -@@ -556,6 +568,44 @@ int send_all(int fd, const void *_buf, int len1) - #define STDIO_MAX_CLIENTS 1 - static int stdio_nb_clients; - -+int send_all(CharDriverState *chr, int fd, const void *_buf, int len1) -+{ -+ int ret, eagain_errno; -+ bool nonblock; -+ -+ if (chr && chr->write_blocked) { -+ /* -+ * The caller should not send us data while we're blocked, -+ * but this can happen when multiple writers are woken at once, -+ * so simply return -EAGAIN. -+ */ -+ return -EAGAIN; -+ } -+ -+ nonblock = false; -+ /* -+ * Ensure the char backend is able to receive and handle the -+ * 'write unblocked' event before we turn on nonblock support. -+ */ -+ if (chr && chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) { -+ nonblock = true; -+ } -+ ret = do_send(fd, _buf, len1, nonblock); -+ -+#ifdef _WIN32 -+ eagain_errno = WSAEWOULDBLOCK; -+#else -+ eagain_errno = -EAGAIN; -+#endif -+ -+ if (nonblock && (ret == eagain_errno || (ret >= 0 && ret < len1))) { -+ /* Update fd handler to wake up when chr becomes writable */ -+ chr->chr_enable_write_fd_handler(chr); -+ chr->write_blocked = true; -+ } -+ return ret; -+} -+ - #ifndef _WIN32 - - typedef struct { -@@ -567,7 +617,7 @@ typedef struct { - static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - { - FDCharDriver *s = chr->opaque; -- return send_all(s->fd_out, buf, len); -+ return send_all(chr, s->fd_out, buf, len); - } - - static int fd_chr_read_poll(void *opaque) -@@ -892,7 +942,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - pty_chr_update_read_handler(chr); - return 0; - } -- return send_all(s->fd, buf, len); -+ return send_all(chr, s->fd, buf, len); - } - - static int pty_chr_read_poll(void *opaque) -@@ -2196,8 +2246,15 @@ static void tcp_closed(void *opaque) - static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - { - TCPCharDriver *s = chr->opaque; -+ - if (s->connected) { -- return send_all(s->fd, buf, len); -+ int ret; -+ -+ ret = send_all(chr, s->fd, buf, len); -+ if (ret == -1 && errno == EPIPE) { -+ tcp_closed(chr); -+ } -+ return ret; - } else { - /* XXX: indicate an error ? */ - return len; -diff --git a/qemu_socket.h b/qemu_socket.h -index 9e32fac..9ea33fe 100644 ---- a/qemu_socket.h -+++ b/qemu_socket.h -@@ -37,7 +37,7 @@ int qemu_socket(int domain, int type, int protocol); - int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); - void socket_set_block(int fd); - void socket_set_nonblock(int fd); --int send_all(int fd, const void *buf, int len1); -+int send_all(CharDriverState *chr, int fd, const void *buf, int len1); - - /* New, ipv6-ready socket helper functions, see qemu-sockets.c */ - int inet_listen_opts(QemuOpts *opts, int port_offset); --- -1.7.7.5 - diff --git a/0110-qxl-move-ram-size-init-to-new-function.patch b/0110-qxl-move-ram-size-init-to-new-function.patch new file mode 100644 index 0000000..88f3d51 --- /dev/null +++ b/0110-qxl-move-ram-size-init-to-new-function.patch @@ -0,0 +1,94 @@ +From 86b1736c4105ec6073c969dc9f0aaaf899e00be1 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 17 Feb 2012 15:02:40 +0100 +Subject: [PATCH] qxl: move ram size init to new function + +Factor memory bar sizing bits out to a separate function. + +Signed-off-by: Gerd Hoffmann + +Conflicts: + + hw/qxl.c +--- + hw/qxl.c | 41 ++++++++++++++++++++++------------------- + 1 file changed, 22 insertions(+), 19 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index d71c94d..df8efbc 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1557,6 +1557,25 @@ static DisplayChangeListener display_listener = { + .dpy_refresh = display_refresh, + }; + ++static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) ++{ ++ /* vga ram (bar 0) */ ++ if (qxl->vga.vram_size < ram_min_mb * 1024 * 1024) { ++ qxl->vga.vram_size = ram_min_mb * 1024 * 1024; ++ } ++ ++ /* vram (surfaces, bar 1) */ ++ if (qxl->vram_size < 4096) { ++ qxl->vram_size = 4096; ++ } ++ if (qxl->revision == 1) { ++ qxl->vram_size = 4096; ++ } ++ ++ qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1); ++ qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); ++} ++ + static int qxl_init_common(PCIQXLDevice *qxl) + { + uint8_t* config = qxl->pci.config; +@@ -1595,13 +1614,6 @@ static int qxl_init_common(PCIQXLDevice *qxl) + init_qxl_rom(qxl); + init_qxl_ram(qxl); + +- if (qxl->vram_size < 4096) { +- qxl->vram_size = 4096; +- } +- if (qxl->revision == 1) { +- qxl->vram_size = 4096; +- } +- qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); + memory_region_init_ram(&qxl->vram_bar, &qxl->pci.qdev, "qxl.vram", + qxl->vram_size); + +@@ -1644,15 +1656,11 @@ static int qxl_init_primary(PCIDevice *dev) + { + PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); + VGACommonState *vga = &qxl->vga; +- ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); + PortioList *qxl_vga_port_list = g_new(PortioList, 1); + + qxl->id = 0; +- +- if (ram_size < 32 * 1024 * 1024) { +- ram_size = 32 * 1024 * 1024; +- } +- vga_common_init(vga, ram_size); ++ qxl_init_ramsize(qxl, 32); ++ vga_common_init(vga, qxl->vga.vram_size); + vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false); + portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga"); + portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); +@@ -1671,14 +1679,9 @@ static int qxl_init_secondary(PCIDevice *dev) + { + static int device_id = 1; + PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); +- ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); + + qxl->id = device_id++; +- +- if (ram_size < 16 * 1024 * 1024) { +- ram_size = 16 * 1024 * 1024; +- } +- qxl->vga.vram_size = ram_size; ++ qxl_init_ramsize(qxl, 16); + memory_region_init_ram(&qxl->vga.vram, &qxl->pci.qdev, "qxl.vgavram", + qxl->vga.vram_size); + qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram); diff --git a/0111-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch b/0111-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch deleted file mode 100644 index 10ccf75..0000000 --- a/0111-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch +++ /dev/null @@ -1,81 +0,0 @@ -From b235c039fbab104ab582922f0083625564e177b1 Mon Sep 17 00:00:00 2001 -From: Amit Shah -Date: Mon, 21 Mar 2011 22:02:47 +0100 -Subject: [PATCH 111/118] char: Equip the unix/tcp backend to handle - nonblocking writes# - -Now that the infrastructure is in place to return -EAGAIN to callers, -individual char drivers can set their update_fd_handlers() function to -set or remove an fd's write handler. This handler checks if the driver -became writable. - -A generic callback routine is used for unblocking writes and letting -users of chardevs know that a driver became writable again. - -Signed-off-by: Amit Shah ---- - qemu-char.c | 34 ++++++++++++++++++++++++++++++++++ - 1 files changed, 34 insertions(+), 0 deletions(-) - -diff --git a/qemu-char.c b/qemu-char.c -index 5e7f68e..f98b240 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -106,6 +106,19 @@ - static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = - QTAILQ_HEAD_INITIALIZER(chardevs); - -+/* -+ * Generic routine that gets called when chardev becomes writable. -+ * Lets chardev user know it's OK to send more data. -+ */ -+static void char_write_unblocked(void *opaque) -+{ -+ CharDriverState *chr = opaque; -+ -+ chr->write_blocked = false; -+ chr->chr_disable_write_fd_handler(chr); -+ chr->chr_write_unblocked(chr->handler_opaque); -+} -+ - void qemu_chr_be_event(CharDriverState *s, int event) - { - /* Keep track if the char device is open */ -@@ -2515,6 +2528,25 @@ static void tcp_chr_close(CharDriverState *chr) - qemu_chr_be_event(chr, CHR_EVENT_CLOSED); - } - -+static void tcp_enable_write_fd_handler(CharDriverState *chr) -+{ -+ TCPCharDriver *s = chr->opaque; -+ -+ /* -+ * This function is called only after tcp_chr_connect() is called -+ * (either in 'server' mode or client mode. So we're sure of -+ * s->fd being initialised. -+ */ -+ enable_write_fd_handler(s->fd, char_write_unblocked); -+} -+ -+static void tcp_disable_write_fd_handler(CharDriverState *chr) -+{ -+ TCPCharDriver *s = chr->opaque; -+ -+ disable_write_fd_handler(s->fd); -+} -+ - static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr) - { - CharDriverState *chr = NULL; -@@ -2571,6 +2603,8 @@ static int qemu_chr_open_socket(QemuOpts *opts, CharDriverState **_chr) - chr->chr_close = tcp_chr_close; - chr->get_msgfd = tcp_get_msgfd; - chr->chr_add_client = tcp_chr_add_client; -+ chr->chr_enable_write_fd_handler = tcp_enable_write_fd_handler; -+ chr->chr_disable_write_fd_handler = tcp_disable_write_fd_handler; - - if (is_listen) { - s->listen_fd = fd; --- -1.7.7.5 - diff --git a/0111-qxl-add-user-friendly-bar-size-properties.patch b/0111-qxl-add-user-friendly-bar-size-properties.patch new file mode 100644 index 0000000..b799af0 --- /dev/null +++ b/0111-qxl-add-user-friendly-bar-size-properties.patch @@ -0,0 +1,60 @@ +From b9209105173154ae0d6821e9c548011c7d04179d Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 17 Feb 2012 15:03:24 +0100 +Subject: [PATCH] qxl: add user-friendly bar size properties + +Add two properties to specify bar sizes in megabytes instead of bytes, +which is alot more user-friendly. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 8 ++++++++ + hw/qxl.h | 4 ++++ + 2 files changed, 12 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index df8efbc..c8839c3 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1560,11 +1560,17 @@ static DisplayChangeListener display_listener = { + static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) + { + /* vga ram (bar 0) */ ++ if (qxl->ram_size_mb != -1) { ++ qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024; ++ } + if (qxl->vga.vram_size < ram_min_mb * 1024 * 1024) { + qxl->vga.vram_size = ram_min_mb * 1024 * 1024; + } + + /* vram (surfaces, bar 1) */ ++ if (qxl->vram_size_mb != -1) { ++ qxl->vram_size = qxl->vram_size_mb * 1024 * 1024; ++ } + if (qxl->vram_size < 4096) { + qxl->vram_size = 4096; + } +@@ -1863,6 +1869,8 @@ static Property qxl_properties[] = { + DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), + DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), + DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), ++ DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), ++ DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram_size_mb, -1), + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/hw/qxl.h b/hw/qxl.h +index 766aa6d..d062991 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -89,6 +89,10 @@ typedef struct PCIQXLDevice { + + /* io bar */ + MemoryRegion io_bar; ++ ++ /* user-friendly properties (in megabytes) */ ++ uint32_t ram_size_mb; ++ uint32_t vram_size_mb; + } PCIQXLDevice; + + #define PANIC_ON(x) if ((x)) { \ diff --git a/0112-char-Throttle-when-host-connection-is-down.patch b/0112-char-Throttle-when-host-connection-is-down.patch deleted file mode 100644 index f8d29af..0000000 --- a/0112-char-Throttle-when-host-connection-is-down.patch +++ /dev/null @@ -1,56 +0,0 @@ -From e5eb5b185d39942a2011b21114bb7f0b8e11427a Mon Sep 17 00:00:00 2001 -From: Amit Shah -Date: Mon, 21 Mar 2011 22:05:10 +0100 -Subject: [PATCH 112/118] char: Throttle when host connection is down# - -When the host-side connection goes down, throttle the virtio-serial bus -and later unthrottle when a connection gets established. This helps -prevent any lost IO (guest->host) while the host connection was down. - -Bugzilla: 621484 - -This commit actually helps the bug mentioned above as no writes will now -get lost because of the throttling done here. With just the patches -sent earlier for that bug, one write will end up getting lost in the -worst case (host d/c, guest write, host connect). - -Signed-off-by: Amit Shah ---- - qemu-char.c | 14 ++++++++++++++ - 1 files changed, 14 insertions(+), 0 deletions(-) - -diff --git a/qemu-char.c b/qemu-char.c -index f98b240..5f67652 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -140,6 +140,9 @@ static void qemu_chr_generic_open_bh(void *opaque) - { - CharDriverState *s = opaque; - qemu_chr_be_event(s, CHR_EVENT_OPENED); -+ if (s->write_blocked) { -+ char_write_unblocked(s); -+ } - qemu_bh_delete(s->bh); - s->bh = NULL; - } -@@ -2266,6 +2269,17 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - ret = send_all(chr, s->fd, buf, len); - if (ret == -1 && errno == EPIPE) { - tcp_closed(chr); -+ -+ if (chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) { -+ /* -+ * Since we haven't written out anything, let's say -+ * we're throttled. This will prevent any output from -+ * the guest getting lost if host-side chardev goes -+ * down. Unthrottle when we re-connect. -+ */ -+ chr->write_blocked = true; -+ return 0; -+ } - } - return ret; - } else { --- -1.7.7.5 - diff --git a/0112-qxl-fix-spice-sdl-no-cursor-regression.patch b/0112-qxl-fix-spice-sdl-no-cursor-regression.patch new file mode 100644 index 0000000..33760f4 --- /dev/null +++ b/0112-qxl-fix-spice-sdl-no-cursor-regression.patch @@ -0,0 +1,90 @@ +From e40909ec7cb1160ad269c1c207d218850e727eaf Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:25 +0200 +Subject: [PATCH] qxl: fix spice+sdl no cursor regression +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +regression introduced by 075360945860ad9bdd491921954b383bf762b0e5, + +v2: lock around qemu_spice_cursor_refresh_unlocked + +Reported-by: Fabiano Fidêncio +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 4 ++++ + ui/spice-display.c | 23 ++++++++++++++--------- + ui/spice-display.h | 1 + + 3 files changed, 19 insertions(+), 9 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index c8839c3..17f2576 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1548,6 +1548,10 @@ static void display_refresh(struct DisplayState *ds) + { + if (qxl0->mode == QXL_MODE_VGA) { + qemu_spice_display_refresh(&qxl0->ssd); ++ } else { ++ qemu_mutex_lock(&qxl0->ssd.lock); ++ qemu_spice_cursor_refresh_unlocked(&qxl0->ssd); ++ qemu_mutex_unlock(&qxl0->ssd.lock); + } + } + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 6c302a3..c6e61d8 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -317,16 +317,8 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) + ssd->notify++; + } + +-void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) ++void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) + { +- dprint(3, "%s:\n", __FUNCTION__); +- vga_hw_update(); +- +- qemu_mutex_lock(&ssd->lock); +- if (ssd->update == NULL) { +- ssd->update = qemu_spice_create_update(ssd); +- ssd->notify++; +- } + if (ssd->cursor) { + ssd->ds->cursor_define(ssd->cursor); + cursor_put(ssd->cursor); +@@ -337,6 +329,19 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) + ssd->mouse_x = -1; + ssd->mouse_y = -1; + } ++} ++ ++void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) ++{ ++ dprint(3, "%s:\n", __func__); ++ vga_hw_update(); ++ ++ qemu_mutex_lock(&ssd->lock); ++ if (ssd->update == NULL) { ++ ssd->update = qemu_spice_create_update(ssd); ++ ssd->notify++; ++ } ++ qemu_spice_cursor_refresh_unlocked(ssd); + qemu_mutex_unlock(&ssd->lock); + + if (ssd->notify) { +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 5e52df9..a23bfc8 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -97,6 +97,7 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + int x, int y, int w, int h); + void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); + void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); ++void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd); + + void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + qxl_async_io async); diff --git a/0113-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch b/0113-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch new file mode 100644 index 0000000..c10bb9f --- /dev/null +++ b/0113-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch @@ -0,0 +1,26 @@ +From 319a228b634930e2822579f85522eb6afdd3ebbe Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:26 +0200 +Subject: [PATCH] sdl: remove NULL check, g_malloc0 can't fail + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + ui/sdl.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/ui/sdl.c b/ui/sdl.c +index 8cafc44..6844c83 100644 +--- a/ui/sdl.c ++++ b/ui/sdl.c +@@ -167,10 +167,6 @@ static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf) + static DisplaySurface* sdl_create_displaysurface(int width, int height) + { + DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface)); +- if (surface == NULL) { +- fprintf(stderr, "sdl_create_displaysurface: malloc failed\n"); +- exit(1); +- } + + surface->width = width; + surface->height = height; diff --git a/0113-virtio-console-Enable-port-throttling-when-chardev-i.patch b/0113-virtio-console-Enable-port-throttling-when-chardev-i.patch deleted file mode 100644 index 73dfcb6..0000000 --- a/0113-virtio-console-Enable-port-throttling-when-chardev-i.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 71108acb189f5fda923013ed72270642199ab50d Mon Sep 17 00:00:00 2001 -From: Amit Shah -Date: Mon, 21 Mar 2011 22:06:41 +0100 -Subject: [PATCH 113/118] virtio-console: Enable port throttling when chardev - is slow to consume data - -When a chardev indicates it can't accept more data, we tell the -virtio-serial code to stop sending us any more data till we tell -otherwise. This helps in guests continuing to run normally while the vq -keeps getting full and eventually the guest stops queueing more data. -As soon as the chardev indicates it can accept more data, start pushing! - -Signed-off-by: Amit Shah ---- - hw/virtio-console.c | 11 +++++++++++ - 1 files changed, 11 insertions(+), 0 deletions(-) - -diff --git a/hw/virtio-console.c b/hw/virtio-console.c -index 6d6f3ef..da68211 100644 ---- a/hw/virtio-console.c -+++ b/hw/virtio-console.c -@@ -20,6 +20,16 @@ typedef struct VirtConsole { - CharDriverState *chr; - } VirtConsole; - -+/* -+ * Callback function that's called from chardevs when backend becomes -+ * writable. -+ */ -+static void chr_write_unblocked(void *opaque) -+{ -+ VirtConsole *vcon = opaque; -+ -+ virtio_serial_throttle_port(&vcon->port, false); -+} - - /* Callback function that's called when the guest sends us data */ - static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) -@@ -99,6 +109,7 @@ static const QemuChrHandlers chr_handlers = { - .fd_can_read = chr_can_read, - .fd_read = chr_read, - .fd_event = chr_event, -+ .fd_write_unblocked = chr_write_unblocked, - }; - - static int virtconsole_initfn(VirtIOSerialPort *port) --- -1.7.7.5 - diff --git a/0114-qxl-drop-qxl_spice_update_area_async-definition.patch b/0114-qxl-drop-qxl_spice_update_area_async-definition.patch new file mode 100644 index 0000000..801f9d1 --- /dev/null +++ b/0114-qxl-drop-qxl_spice_update_area_async-definition.patch @@ -0,0 +1,31 @@ +From d3ca92da49658c29441ff3e1a4fdec2d1cb94baa Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:27 +0200 +Subject: [PATCH] qxl: drop qxl_spice_update_area_async definition + +It was never used. Introduced in +5ff4e36c804157bd84af43c139f8cd3a59722db9 +qxl: async io support using new spice api + +But not used even then. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.h | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/hw/qxl.h b/hw/qxl.h +index d062991..a615eca 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -138,9 +138,3 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); + void qxl_render_resize(PCIQXLDevice *qxl); + void qxl_render_update(PCIQXLDevice *qxl); + void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); +-#if SPICE_INTERFACE_QXL_MINOR >= 1 +-void qxl_spice_update_area_async(PCIQXLDevice *qxl, uint32_t surface_id, +- struct QXLRect *area, +- uint32_t clear_dirty_region, +- int is_vga); +-#endif diff --git a/0114-spice-qemu-char.c-add-throttling.patch b/0114-spice-qemu-char.c-add-throttling.patch deleted file mode 100644 index 00c7580..0000000 --- a/0114-spice-qemu-char.c-add-throttling.patch +++ /dev/null @@ -1,133 +0,0 @@ -From d4066655fc866ac0e57420b32dec3b37277b374c Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Tue, 22 Mar 2011 12:27:59 +0200 -Subject: [PATCH 114/118] spice-qemu-char.c: add throttling - -BZ: 672191 - -upstream: not submitted (explained below) - -Adds throttling support to spicevmc chardev. Uses a timer to avoid recursing: -1. spice-server: reds.c: read_from_vdi_port -2. qemu: spice-qemu-char.c: vmc_read -3. chr_write_unblocked - (calls virtio_serial_throttle_port(port, false)) -4. qemu: virtio ... -5. qemu: spice-qemu-char.c: spice_chr_write -6. qemu: spice-qemu-char.c: wakeup (calls into spice-server) -7. spice-server: ... -8. qemu: spice-qemu-char.c: vmc_read - -Instead, in vmc_read if we were throttled and we are just about to return -all the bytes we will set a timer to be triggered immediately to call -chr_write_unblocked. Then we return after 2 above, and 3 is called from the -timer callback. This also means we can later remove some ugly recursion protection -from spice-server. - -The other tricky point in this patch is not returning the leftover chunk twice. -When we throttle, by definition we have data that spice server didn't consume. -It is being kept by virtio-serial, and by us. The next vmc_read callback needs -to not return it, but just do unthrottling. Then virtio will give us the remaining -chunk as usual in spice_chr_write, and we will pass it to spice server in the -next vmc_read. - -This patch relies on Amit's series to expose throttling to chardev's, which -was not accepted upstream, and will not be accepted upstream until the mainloop -is reworked to use glib. ---- - spice-qemu-char.c | 39 +++++++++++++++++++++++++++++++++++---- - 1 files changed, 35 insertions(+), 4 deletions(-) - -diff --git a/spice-qemu-char.c b/spice-qemu-char.c -index 7e8eaa9..eeeb32e 100644 ---- a/spice-qemu-char.c -+++ b/spice-qemu-char.c -@@ -1,4 +1,6 @@ - #include "config-host.h" -+#include "qemu-common.h" -+#include "qemu-timer.h" - #include "trace.h" - #include "ui/qemu-spice.h" - #include -@@ -25,6 +27,7 @@ typedef struct SpiceCharDriver { - uint8_t *datapos; - ssize_t bufsize, datalen; - uint32_t debug; -+ QEMUTimer *unblock_timer; - } SpiceCharDriver; - - static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) -@@ -50,6 +53,17 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) - return out; - } - -+static void spice_chr_unblock(void *opaque) -+{ -+ SpiceCharDriver *scd = opaque; -+ -+ if (scd->chr->chr_write_unblocked == NULL) { -+ dprintf(scd, 1, "%s: backend doesn't support unthrottling.\n", __func__); -+ return; -+ } -+ scd->chr->chr_write_unblocked(scd->chr->handler_opaque); -+} -+ - static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) - { - SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); -@@ -61,9 +75,16 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) - scd->datapos += bytes; - scd->datalen -= bytes; - assert(scd->datalen >= 0); -- if (scd->datalen == 0) { -- scd->datapos = 0; -- } -+ } -+ if (scd->datalen == 0 && scd->chr->write_blocked) { -+ dprintf(scd, 1, "%s: unthrottling (%d)\n", __func__, bytes); -+ scd->chr->write_blocked = false; -+ /* -+ * set a timer instead of calling scd->chr->chr_write_unblocked directly, -+ * because that will call back into spice_chr_write (see -+ * virtio-console.c:chr_write_unblocked), which is unwanted. -+ */ -+ qemu_mod_timer(scd->unblock_timer, 0); - } - trace_spice_vmc_read(bytes, len); - return bytes; -@@ -135,6 +156,7 @@ static void vmc_unregister_interface(SpiceCharDriver *scd) - static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - { - SpiceCharDriver *s = chr->opaque; -+ int read_bytes; - - dprintf(s, 2, "%s: %d\n", __func__, len); - vmc_register_interface(s); -@@ -147,7 +169,15 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - s->datapos = s->buffer; - s->datalen = len; - spice_server_char_device_wakeup(&s->sin); -- return len; -+ read_bytes = len - s->datalen; -+ if (read_bytes != len) { -+ dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__, -+ read_bytes, len, s->bufsize); -+ s->chr->write_blocked = true; -+ /* We'll get passed in the unconsumed data with the next call */ -+ s->datalen = 0; -+ } -+ return read_bytes; - } - - static void spice_chr_close(struct CharDriverState *chr) -@@ -225,6 +255,7 @@ int qemu_chr_open_spice(QemuOpts *opts, CharDriverState **_chr) - chr->chr_close = spice_chr_close; - chr->chr_guest_open = spice_chr_guest_open; - chr->chr_guest_close = spice_chr_guest_close; -+ s->unblock_timer = qemu_new_timer_ms(vm_clock, spice_chr_unblock, s); - - #if SPICE_SERVER_VERSION < 0x000901 - /* See comment in vmc_state() */ --- -1.7.7.5 - diff --git a/0115-qxl-require-spice-0.8.2.patch b/0115-qxl-require-spice-0.8.2.patch new file mode 100644 index 0000000..97f8960 --- /dev/null +++ b/0115-qxl-require-spice-0.8.2.patch @@ -0,0 +1,355 @@ +From 824fc1518acc3c50aff5a23807a35cf3dbc753f4 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:28 +0200 +Subject: [PATCH] qxl: require spice >= 0.8.2 + +drop all ifdefs on SPICE_INTERFACE_QXL_MINOR >= 1 as a result, +any check for SPICE_SERVER_VERSION that is now always satisfied, +and SPICE_INTERFACE_CORE_MINOR >= 3 tests, because +0.8.2 has SPICE_INTERFACE_QXL_MINOR == 1 and +SPICE_INTERFACE_CORE_MINOR == 3. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + configure | 2 +- + hw/qxl.c | 40 ---------------------------------------- + hw/qxl.h | 4 ---- + ui/spice-core.c | 17 ----------------- + ui/spice-display.c | 12 ------------ + 5 files changed, 1 insertion(+), 74 deletions(-) + +diff --git a/configure b/configure +index 59f91d0..9bdeea7 100755 +--- a/configure ++++ b/configure +@@ -2501,7 +2501,7 @@ int main(void) { spice_server_new(); return 0; } + EOF + spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null) + spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null) +- if $pkg_config --atleast-version=0.6.0 spice-server >/dev/null 2>&1 && \ ++ if $pkg_config --atleast-version=0.8.2 spice-server >/dev/null 2>&1 && \ + compile_prog "$spice_cflags" "$spice_libs" ; then + spice="yes" + libs_softmmu="$libs_softmmu $spice_libs" +diff --git a/hw/qxl.c b/hw/qxl.c +index 17f2576..0be9859 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -125,9 +125,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl); + + void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) + { +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + qxl_send_events(qxl, QXL_INTERRUPT_ERROR); +-#endif + if (qxl->guestdebug) { + va_list ap; + va_start(ap, msg); +@@ -149,12 +147,8 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, + dirty_rects, num_dirty_rects, clear_dirty_region); + } else { +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, + clear_dirty_region, 0); +-#else +- abort(); +-#endif + } + } + +@@ -171,24 +165,18 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + qxl_async_io async) + { + if (async) { +-#if SPICE_INTERFACE_QXL_MINOR < 1 +- abort(); +-#else + spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, + (uint64_t)id); +-#endif + } else { + qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); + qxl_spice_destroy_surface_wait_complete(qxl, id); + } + } + +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) + { + spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0); + } +-#endif + + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, + uint32_t count) +@@ -217,11 +205,7 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) + static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) + { + if (async) { +-#if SPICE_INTERFACE_QXL_MINOR < 1 +- abort(); +-#else + spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0); +-#endif + } else { + qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); + qxl_spice_destroy_surfaces_complete(qxl); +@@ -493,7 +477,6 @@ static const char *io_port_to_string(uint32_t io_port) + [QXL_IO_DESTROY_PRIMARY] = "QXL_IO_DESTROY_PRIMARY", + [QXL_IO_DESTROY_SURFACE_WAIT] = "QXL_IO_DESTROY_SURFACE_WAIT", + [QXL_IO_DESTROY_ALL_SURFACES] = "QXL_IO_DESTROY_ALL_SURFACES", +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + [QXL_IO_UPDATE_AREA_ASYNC] = "QXL_IO_UPDATE_AREA_ASYNC", + [QXL_IO_MEMSLOT_ADD_ASYNC] = "QXL_IO_MEMSLOT_ADD_ASYNC", + [QXL_IO_CREATE_PRIMARY_ASYNC] = "QXL_IO_CREATE_PRIMARY_ASYNC", +@@ -503,7 +486,6 @@ static const char *io_port_to_string(uint32_t io_port) + = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC", + [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC", + [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE", +-#endif + }; + return io_port_to_string[io_port]; + } +@@ -738,8 +720,6 @@ static int interface_flush_resources(QXLInstance *sin) + + static void qxl_create_guest_primary_complete(PCIQXLDevice *d); + +-#if SPICE_INTERFACE_QXL_MINOR >= 1 +- + /* called from spice server thread context only */ + static void interface_async_complete(QXLInstance *sin, uint64_t cookie) + { +@@ -767,8 +747,6 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) + qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); + } + +-#endif +- + static const QXLInterface qxl_interface = { + .base.type = SPICE_INTERFACE_QXL, + .base.description = "qxl gpu", +@@ -788,9 +766,7 @@ static const QXLInterface qxl_interface = { + .req_cursor_notification = interface_req_cursor_notification, + .notify_update = interface_notify_update, + .flush_resources = interface_flush_resources, +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + .async_complete = interface_async_complete, +-#endif + }; + + static void qxl_enter_vga_mode(PCIQXLDevice *d) +@@ -1140,9 +1116,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + PCIQXLDevice *d = opaque; + uint32_t io_port = addr; + qxl_async_io async = QXL_SYNC; +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + uint32_t orig_io_port = io_port; +-#endif + + switch (io_port) { + case QXL_IO_RESET: +@@ -1152,10 +1126,8 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + case QXL_IO_CREATE_PRIMARY: + case QXL_IO_UPDATE_IRQ: + case QXL_IO_LOG: +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + case QXL_IO_MEMSLOT_ADD_ASYNC: + case QXL_IO_CREATE_PRIMARY_ASYNC: +-#endif + break; + default: + if (d->mode != QXL_MODE_VGA) { +@@ -1163,17 +1135,14 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + } + dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", + __func__, io_port, io_port_to_string(io_port)); +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + /* be nice to buggy guest drivers */ + if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && + io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) { + qxl_send_events(d, QXL_INTERRUPT_IO_CMD); + } +-#endif + return; + } + +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + /* we change the io_port to avoid ifdeffery in the main switch */ + orig_io_port = io_port; + switch (io_port) { +@@ -1212,7 +1181,6 @@ async_common: + default: + break; + } +-#endif + + switch (io_port) { + case QXL_IO_UPDATE_AREA: +@@ -1304,7 +1272,6 @@ async_common: + } + qxl_spice_destroy_surface_wait(d, val, async); + break; +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + case QXL_IO_FLUSH_RELEASE: { + QXLReleaseRing *ring = &d->ram->release_ring; + if (ring->prod - ring->cons + 1 == ring->num_items) { +@@ -1325,7 +1292,6 @@ async_common: + d->num_free_res); + qxl_spice_flush_surfaces_async(d); + break; +-#endif + case QXL_IO_DESTROY_ALL_SURFACES: + d->mode = QXL_MODE_UNDEFINED; + qxl_spice_destroy_surfaces(d, async); +@@ -1336,16 +1302,12 @@ async_common: + } + return; + cancel_async: +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + if (async) { + qxl_send_events(d, QXL_INTERRUPT_IO_CMD); + qemu_mutex_lock(&d->async_lock); + d->current_async = QXL_UNDEFINED_IO; + qemu_mutex_unlock(&d->async_lock); + } +-#else +- return; +-#endif + } + + static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, +@@ -1607,9 +1569,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) + case 2: /* spice 0.6 -- qxl-2 */ + pci_device_rev = QXL_REVISION_STABLE_V06; + break; +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + case 3: /* qxl-3 */ +-#endif + default: + pci_device_rev = QXL_DEFAULT_REVISION; + break; +diff --git a/hw/qxl.h b/hw/qxl.h +index a615eca..9288e46 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -108,11 +108,7 @@ typedef struct PCIQXLDevice { + } \ + } while (0) + +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10 +-#else +-#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V06 +-#endif + + /* qxl.c */ + void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 27216e9..2c815f1 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -139,8 +139,6 @@ static void watch_remove(SpiceWatch *watch) + g_free(watch); + } + +-#if SPICE_INTERFACE_CORE_MINOR >= 3 +- + typedef struct ChannelList ChannelList; + struct ChannelList { + SpiceChannelEventInfo *info; +@@ -257,15 +255,6 @@ static void channel_event(int event, SpiceChannelEventInfo *info) + } + } + +-#else /* SPICE_INTERFACE_CORE_MINOR >= 3 */ +- +-static QList *channel_list_get(void) +-{ +- return NULL; +-} +- +-#endif /* SPICE_INTERFACE_CORE_MINOR >= 3 */ +- + static SpiceCoreInterface core_interface = { + .base.type = SPICE_INTERFACE_CORE, + .base.description = "qemu core services", +@@ -281,9 +270,7 @@ static SpiceCoreInterface core_interface = { + .watch_update_mask = watch_update_mask, + .watch_remove = watch_remove, + +-#if SPICE_INTERFACE_CORE_MINOR >= 3 + .channel_event = channel_event, +-#endif + }; + + #ifdef SPICE_INTERFACE_MIGRATION +@@ -490,7 +477,6 @@ static void migration_state_notifier(Notifier *notifier, void *data) + spice_server_migrate_start(spice_server); + #endif + } else if (migration_has_finished(s)) { +-#if SPICE_SERVER_VERSION >= 0x000701 /* 0.7.1 */ + #ifndef SPICE_INTERFACE_MIGRATION + spice_server_migrate_switch(spice_server); + #else +@@ -498,7 +484,6 @@ static void migration_state_notifier(Notifier *notifier, void *data) + } else if (migration_has_failed(s)) { + spice_server_migrate_end(spice_server, false); + #endif +-#endif + } + } + +@@ -659,11 +644,9 @@ void qemu_spice_init(void) + spice_server_set_noauth(spice_server); + } + +-#if SPICE_SERVER_VERSION >= 0x000801 + if (qemu_opt_get_bool(opts, "disable-copy-paste", 0)) { + spice_server_set_agent_copypaste(spice_server, false); + } +-#endif + + compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ; + str = qemu_opt_get(opts, "image-compression"); +diff --git a/ui/spice-display.c b/ui/spice-display.c +index c6e61d8..ad76bae 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -64,11 +64,7 @@ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + qxl_async_io async) + { + if (async != QXL_SYNC) { +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0); +-#else +- abort(); +-#endif + } else { + ssd->worker->add_memslot(ssd->worker, memslot); + } +@@ -84,11 +80,7 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + qxl_async_io async) + { + if (async != QXL_SYNC) { +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0); +-#else +- abort(); +-#endif + } else { + ssd->worker->create_primary_surface(ssd->worker, id, surface); + } +@@ -99,11 +91,7 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + uint32_t id, qxl_async_io async) + { + if (async != QXL_SYNC) { +-#if SPICE_INTERFACE_QXL_MINOR >= 1 + spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0); +-#else +- abort(); +-#endif + } else { + ssd->worker->destroy_primary_surface(ssd->worker, id); + } diff --git a/0115-spice-qemu-char.c-remove-intermediate-buffer.patch b/0115-spice-qemu-char.c-remove-intermediate-buffer.patch deleted file mode 100644 index 2ec2e2f..0000000 --- a/0115-spice-qemu-char.c-remove-intermediate-buffer.patch +++ /dev/null @@ -1,71 +0,0 @@ -From 9d965c99311c6f3d5c7ba9b66a72398814175865 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Tue, 22 Mar 2011 12:28:00 +0200 -Subject: [PATCH 115/118] spice-qemu-char.c: remove intermediate buffer - -BZ: 672191 -upstream: not submitted (explained below) - -virtio-serial's buffer is valid when it calls us, and we don't -access it otherwise: vmc_read is only called in response to wakeup, -or else we set datalen=0 and throttle. Then vmc_read is called back, -we return 0 (not accessing the buffer) and set the timer to unthrottle. - -Also make datalen int and not ssize_t (to fit spice_chr_write signature). - -This relied on the previous patch that introduces throttling, which -can't go upstream right now as explained in that patch. ---- - spice-qemu-char.c | 18 ++++++------------ - 1 files changed, 6 insertions(+), 12 deletions(-) - -diff --git a/spice-qemu-char.c b/spice-qemu-char.c -index eeeb32e..70a83bf 100644 ---- a/spice-qemu-char.c -+++ b/spice-qemu-char.c -@@ -23,9 +23,8 @@ typedef struct SpiceCharDriver { - SpiceCharDeviceInstance sin; - char *subtype; - bool active; -- uint8_t *buffer; -- uint8_t *datapos; -- ssize_t bufsize, datalen; -+ const uint8_t *datapos; -+ int datalen; - uint32_t debug; - QEMUTimer *unblock_timer; - } SpiceCharDriver; -@@ -69,7 +68,7 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) - SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); - int bytes = MIN(len, scd->datalen); - -- dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen); -+ dprintf(scd, 2, "%s: %p %d/%d/%d\n", __func__, scd->datapos, len, bytes, scd->datalen); - if (bytes > 0) { - memcpy(buf, scd->datapos, bytes); - scd->datapos += bytes; -@@ -161,18 +160,13 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - dprintf(s, 2, "%s: %d\n", __func__, len); - vmc_register_interface(s); - assert(s->datalen == 0); -- if (s->bufsize < len) { -- s->bufsize = len; -- s->buffer = g_realloc(s->buffer, s->bufsize); -- } -- memcpy(s->buffer, buf, len); -- s->datapos = s->buffer; -+ s->datapos = buf; - s->datalen = len; - spice_server_char_device_wakeup(&s->sin); - read_bytes = len - s->datalen; - if (read_bytes != len) { -- dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__, -- read_bytes, len, s->bufsize); -+ dprintf(s, 1, "%s: throttling: %d < %d\n", __func__, -+ read_bytes, len); - s->chr->write_blocked = true; - /* We'll get passed in the unconsumed data with the next call */ - s->datalen = 0; --- -1.7.7.5 - diff --git a/0116-qxl-remove-flipped.patch b/0116-qxl-remove-flipped.patch new file mode 100644 index 0000000..9ba2e27 --- /dev/null +++ b/0116-qxl-remove-flipped.patch @@ -0,0 +1,142 @@ +From 5c858288c296f040a07311b6a754d2d79f933eb5 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:29 +0200 +Subject: [PATCH] qxl: remove flipped + +Tested on linux and windows guests. For negative stride, qxl_flip copies +directly to vga->ds->surface->data, for positive it's reallocated to +share qxl->guest_primary.data + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 66 ++++++++++++++++++++++++++------------------------------- + hw/qxl.h | 2 +- + 2 files changed, 31 insertions(+), 37 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index a7891b2..5811d74 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -23,10 +23,21 @@ + + static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) + { +- uint8_t *src = qxl->guest_primary.data; +- uint8_t *dst = qxl->guest_primary.flipped; ++ uint8_t *src; ++ uint8_t *dst = qxl->vga.ds->surface->data; + int len, i; + ++ if (qxl->guest_primary.qxl_stride > 0) { ++ return; ++ } ++ if (!qxl->guest_primary.data) { ++ dprint(qxl, 1, "%s: initializing guest_primary.data\n", __func__); ++ qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); ++ } ++ dprint(qxl, 1, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, ++ qxl->guest_primary.qxl_stride, ++ rect->left, rect->right, rect->top, rect->bottom); ++ src = qxl->guest_primary.data; + src += (qxl->guest_primary.surface.height - rect->top - 1) * + qxl->guest_primary.abs_stride; + dst += rect->top * qxl->guest_primary.abs_stride; +@@ -75,52 +86,38 @@ void qxl_render_update(PCIQXLDevice *qxl) + { + VGACommonState *vga = &qxl->vga; + QXLRect dirty[32], update; +- void *ptr; + int i, redraw = 0; +- +- if (!is_buffer_shared(vga->ds->surface)) { +- dprint(qxl, 1, "%s: restoring shared displaysurface\n", __func__); +- qxl->guest_primary.resized++; +- qxl->guest_primary.commands++; +- redraw = 1; +- } ++ DisplaySurface *surface = vga->ds->surface; + + if (qxl->guest_primary.resized) { + qxl->guest_primary.resized = 0; + +- if (qxl->guest_primary.flipped) { +- g_free(qxl->guest_primary.flipped); +- qxl->guest_primary.flipped = NULL; +- } +- qemu_free_displaysurface(vga->ds); +- + qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); +- if (qxl->guest_primary.qxl_stride < 0) { +- /* spice surface is upside down -> need extra buffer to flip */ +- qxl->guest_primary.flipped = +- g_malloc(qxl->guest_primary.surface.width * +- qxl->guest_primary.abs_stride); +- ptr = qxl->guest_primary.flipped; +- } else { +- ptr = qxl->guest_primary.data; +- } +- dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n", ++ dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d\n", + __FUNCTION__, + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, + qxl->guest_primary.qxl_stride, + qxl->guest_primary.bytes_pp, +- qxl->guest_primary.bits_pp, +- qxl->guest_primary.flipped ? "yes" : "no"); +- vga->ds->surface = ++ qxl->guest_primary.bits_pp); ++ } ++ if (surface->width != qxl->guest_primary.surface.width || ++ surface->height != qxl->guest_primary.surface.height) { ++ dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", ++ __func__); ++ if (qxl->guest_primary.qxl_stride > 0) { ++ qemu_free_displaysurface(vga->ds); + qemu_create_displaysurface_from(qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, + qxl->guest_primary.bits_pp, + qxl->guest_primary.abs_stride, +- ptr); +- dpy_resize(vga->ds); ++ qxl->guest_primary.data); ++ } else { ++ qemu_resize_displaysurface(vga->ds, ++ qxl->guest_primary.surface.width, ++ qxl->guest_primary.surface.height); ++ } + } +- + update.left = 0; + update.right = qxl->guest_primary.surface.width; + update.top = 0; +@@ -136,14 +133,11 @@ void qxl_render_update(PCIQXLDevice *qxl) + memset(dirty, 0, sizeof(dirty)); + dirty[0] = update; + } +- + for (i = 0; i < ARRAY_SIZE(dirty); i++) { + if (qemu_spice_rect_is_empty(dirty+i)) { + break; + } +- if (qxl->guest_primary.flipped) { +- qxl_flip(qxl, dirty+i); +- } ++ qxl_flip(qxl, dirty+i); + dpy_update(vga->ds, + dirty[i].left, dirty[i].top, + dirty[i].right - dirty[i].left, +diff --git a/hw/qxl.h b/hw/qxl.h +index 9288e46..53a3ace 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -52,7 +52,7 @@ typedef struct PCIQXLDevice { + uint32_t abs_stride; + uint32_t bits_pp; + uint32_t bytes_pp; +- uint8_t *data, *flipped; ++ uint8_t *data; + } guest_primary; + + struct surfaces { diff --git a/0116-usb-redir-Add-flow-control-support.patch b/0116-usb-redir-Add-flow-control-support.patch deleted file mode 100644 index 94d10ef..0000000 --- a/0116-usb-redir-Add-flow-control-support.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 80aafc63c842ee902cc9e32d692efed8952a1e14 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 19 Jul 2011 10:56:19 +0200 -Subject: [PATCH 116/118] usb-redir: Add flow control support - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 26 ++++++++++++++++++++++++-- - 1 files changed, 24 insertions(+), 2 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index e421cff..1289506 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -228,12 +228,22 @@ static int usbredir_read(void *priv, uint8_t *data, int count) - static int usbredir_write(void *priv, uint8_t *data, int count) - { - USBRedirDevice *dev = priv; -+ int r; - -- if (!dev->cs->opened) { -+ if (!dev->cs->opened || dev->cs->write_blocked) { - return 0; - } - -- return qemu_chr_fe_write(dev->cs, data, count); -+ r = qemu_chr_fe_write(dev->cs, data, count); -+ -+ if (r < 0) { -+ if (dev->cs->write_blocked) { -+ return 0; -+ } -+ return -1; -+ } -+ -+ return r; - } - - /* -@@ -865,10 +875,22 @@ static void usbredir_chardev_event(void *opaque, int event) - } - } - -+static void usbredir_chardev_write_unblocked(void *opaque) -+{ -+ USBRedirDevice *dev = opaque; -+ -+ if (dev->parser == NULL) { -+ /* usbredir_open_close_bh hasn't handled the open event yet */ -+ return; -+ } -+ usbredirparser_do_write(dev->parser); -+} -+ - static const QemuChrHandlers usbredir_chr_handlers = { - .fd_can_read = usbredir_chardev_can_read, - .fd_read = usbredir_chardev_read, - .fd_event = usbredir_chardev_event, -+ .fd_write_unblocked = usbredir_chardev_write_unblocked, - }; - - /* --- -1.7.7.5 - diff --git a/0117-qxl-introduce-QXLCookie.patch b/0117-qxl-introduce-QXLCookie.patch new file mode 100644 index 0000000..d83cd3b --- /dev/null +++ b/0117-qxl-introduce-QXLCookie.patch @@ -0,0 +1,261 @@ +From c9180962530868341a4ecdb5a99d942b9ce05139 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:30 +0200 +Subject: [PATCH] qxl: introduce QXLCookie + +Will be used in the next patch. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 2 +- + hw/qxl.c | 61 +++++++++++++++++++++++++++++++++++++++++------------- + hw/qxl.h | 2 +- + ui/spice-display.c | 22 +++++++++++++++++--- + ui/spice-display.h | 14 +++++++++++++ + 5 files changed, 82 insertions(+), 19 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 5811d74..4c22166 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -127,7 +127,7 @@ void qxl_render_update(PCIQXLDevice *qxl) + if (runstate_is_running() && qxl->guest_primary.commands) { + qxl->guest_primary.commands = 0; + qxl_spice_update_area(qxl, 0, &update, +- dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); ++ dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL); + } + if (redraw) { + memset(dirty, 0, sizeof(dirty)); +diff --git a/hw/qxl.c b/hw/qxl.c +index 0be9859..e6e65d9 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -141,14 +141,15 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + struct QXLRect *area, struct QXLRect *dirty_rects, + uint32_t num_dirty_rects, + uint32_t clear_dirty_region, +- qxl_async_io async) ++ qxl_async_io async, struct QXLCookie *cookie) + { + if (async == QXL_SYNC) { + qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, + dirty_rects, num_dirty_rects, clear_dirty_region); + } else { ++ assert(cookie != NULL); + spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, +- clear_dirty_region, 0); ++ clear_dirty_region, (uint64_t)cookie); + } + } + +@@ -164,9 +165,13 @@ static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl, + static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + qxl_async_io async) + { ++ QXLCookie *cookie; ++ + if (async) { +- spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, +- (uint64_t)id); ++ cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_DESTROY_SURFACE_ASYNC); ++ cookie->u.surface_id = id; ++ spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uint64_t)cookie); + } else { + qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); + qxl_spice_destroy_surface_wait_complete(qxl, id); +@@ -175,7 +180,9 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + + static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) + { +- spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0); ++ spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, ++ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_FLUSH_SURFACES_ASYNC)); + } + + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, +@@ -205,7 +212,9 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) + static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) + { + if (async) { +- spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0); ++ spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, ++ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_DESTROY_ALL_SURFACES_ASYNC)); + } else { + qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); + qxl_spice_destroy_surfaces_complete(qxl); +@@ -721,9 +730,8 @@ static int interface_flush_resources(QXLInstance *sin) + static void qxl_create_guest_primary_complete(PCIQXLDevice *d); + + /* called from spice server thread context only */ +-static void interface_async_complete(QXLInstance *sin, uint64_t cookie) ++static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + { +- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + uint32_t current_async; + + qemu_mutex_lock(&qxl->async_lock); +@@ -731,8 +739,16 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) + qxl->current_async = QXL_UNDEFINED_IO; + qemu_mutex_unlock(&qxl->async_lock); + +- dprint(qxl, 2, "async_complete: %d (%" PRId64 ") done\n", +- current_async, cookie); ++ dprint(qxl, 2, "async_complete: %d (%p) done\n", current_async, cookie); ++ if (!cookie) { ++ fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__); ++ return; ++ } ++ if (cookie && current_async != cookie->io) { ++ fprintf(stderr, ++ "qxl: %s: error: current_async = %d != %ld = cookie->io\n", ++ __func__, current_async, cookie->io); ++ } + switch (current_async) { + case QXL_IO_CREATE_PRIMARY_ASYNC: + qxl_create_guest_primary_complete(qxl); +@@ -741,12 +757,29 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) + qxl_spice_destroy_surfaces_complete(qxl); + break; + case QXL_IO_DESTROY_SURFACE_ASYNC: +- qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie); ++ qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id); + break; + } + qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); + } + ++/* called from spice server thread context only */ ++static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ QXLCookie *cookie = (QXLCookie *)cookie_token; ++ ++ switch (cookie->type) { ++ case QXL_COOKIE_TYPE_IO: ++ interface_async_complete_io(qxl, cookie); ++ break; ++ default: ++ fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", ++ __func__, cookie->type); ++ } ++ g_free(cookie); ++} ++ + static const QXLInterface qxl_interface = { + .base.type = SPICE_INTERFACE_QXL, + .base.description = "qxl gpu", +@@ -1057,9 +1090,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) + if (d->mode == QXL_MODE_UNDEFINED) { + return 0; + } +- + dprint(d, 1, "%s\n", __FUNCTION__); +- + d->mode = QXL_MODE_UNDEFINED; + qemu_spice_destroy_primary_surface(&d->ssd, 0, async); + qxl_spice_reset_cursor(d); +@@ -1187,7 +1218,9 @@ async_common: + { + QXLRect update = d->ram->update_area; + qxl_spice_update_area(d, d->ram->update_surface, +- &update, NULL, 0, 0, async); ++ &update, NULL, 0, 0, async, ++ qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_UPDATE_AREA_ASYNC)); + break; + } + case QXL_IO_NOTIFY_CMD: +diff --git a/hw/qxl.h b/hw/qxl.h +index 53a3ace..1443925 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -118,7 +118,7 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + struct QXLRect *area, struct QXLRect *dirty_rects, + uint32_t num_dirty_rects, + uint32_t clear_dirty_region, +- qxl_async_io async); ++ qxl_async_io async, QXLCookie *cookie); + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, + uint32_t count); + void qxl_spice_oom(PCIQXLDevice *qxl); +diff --git a/ui/spice-display.c b/ui/spice-display.c +index ad76bae..ab266ae 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -60,11 +60,23 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) + dest->right = MAX(dest->right, r->right); + } + ++QXLCookie *qxl_cookie_new(int type, uint64_t io) ++{ ++ QXLCookie *cookie; ++ ++ cookie = g_malloc0(sizeof(*cookie)); ++ cookie->type = type; ++ cookie->io = io; ++ return cookie; ++} ++ + void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + qxl_async_io async) + { + if (async != QXL_SYNC) { +- spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0); ++ spice_qxl_add_memslot_async(&ssd->qxl, memslot, ++ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_MEMSLOT_ADD_ASYNC)); + } else { + ssd->worker->add_memslot(ssd->worker, memslot); + } +@@ -80,7 +92,9 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + qxl_async_io async) + { + if (async != QXL_SYNC) { +- spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0); ++ spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, ++ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_CREATE_PRIMARY_ASYNC)); + } else { + ssd->worker->create_primary_surface(ssd->worker, id, surface); + } +@@ -91,7 +105,9 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + uint32_t id, qxl_async_io async) + { + if (async != QXL_SYNC) { +- spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0); ++ spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, ++ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_DESTROY_PRIMARY_ASYNC)); + } else { + ssd->worker->destroy_primary_surface(ssd->worker, id); + } +diff --git a/ui/spice-display.h b/ui/spice-display.h +index a23bfc8..8a010cb 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -48,6 +48,20 @@ typedef enum qxl_async_io { + QXL_ASYNC, + } qxl_async_io; + ++enum { ++ QXL_COOKIE_TYPE_IO, ++}; ++ ++typedef struct QXLCookie { ++ int type; ++ uint64_t io; ++ union { ++ uint32_t surface_id; ++ } u; ++} QXLCookie; ++ ++QXLCookie *qxl_cookie_new(int type, uint64_t io); ++ + typedef struct SimpleSpiceDisplay SimpleSpiceDisplay; + typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; + diff --git a/0117-virtio-serial-bus-replay-guest_open-on-migration.patch b/0117-virtio-serial-bus-replay-guest_open-on-migration.patch deleted file mode 100644 index 2e76feb..0000000 --- a/0117-virtio-serial-bus-replay-guest_open-on-migration.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 8e92fe9feebc319c019feb8c28941e322524932f Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Thu, 28 Jul 2011 15:08:48 +0300 -Subject: [PATCH 117/118] virtio-serial-bus: replay guest_open on migration - -When migrating a host with with a spice agent running the mouse becomes -non operational after the migration. This is rhbz #725965. - -The problem is that after migration spice doesn't know the guest agent is open. -Spice is just a char dev here. And a chardev cannot query it's device, the -device has to let the chardev know when it is open. Right now after migration -the chardev which is recreated is in it's default state, which assumes the -guest is disconnected. - -Char devices carry no information across migration, but the virtio-serial does -already carry the guest_connected state. This patch passes that bit to the -chardev. - -Signed-off-by: Alon Levy ---- - hw/virtio-serial-bus.c | 6 ++++++ - 1 files changed, 6 insertions(+), 0 deletions(-) - -diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c -index a4825b9..e5f343f 100644 ---- a/hw/virtio-serial-bus.c -+++ b/hw/virtio-serial-bus.c -@@ -618,6 +618,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) - for (i = 0; i < nr_active_ports; i++) { - uint32_t id; - bool host_connected; -+ VirtIOSerialPortInfo *info; - - id = qemu_get_be32(f); - port = find_port_by_id(s, id); -@@ -626,6 +627,11 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) - } - - port->guest_connected = qemu_get_byte(f); -+ info = DO_UPCAST(VirtIOSerialPortInfo, qdev, port->dev.info); -+ if (port->guest_connected && info->guest_open) { -+ /* replay guest open */ -+ info->guest_open(port); -+ } - host_connected = qemu_get_byte(f); - if (host_connected != port->host_connected) { - /* --- -1.7.7.5 - diff --git a/0118-char-Disable-write-callback-if-throttled-chardev-is-.patch b/0118-char-Disable-write-callback-if-throttled-chardev-is-.patch deleted file mode 100644 index 757fb21..0000000 --- a/0118-char-Disable-write-callback-if-throttled-chardev-is-.patch +++ /dev/null @@ -1,36 +0,0 @@ -From fad276489cbc04f228d52b7019bee9e7a88c8a86 Mon Sep 17 00:00:00 2001 -From: Amit Shah -Date: Fri, 2 Dec 2011 15:42:55 +0530 -Subject: [PATCH 118/118] char: Disable write callback if throttled chardev is - detached - -If a throttled chardev is detached from the frontend device, all future -callbacks should be suppressed. Not doing this results in a segfault. - -Bugzilla: 745758 -Upstream: Not applicable, since throttling is a RHEL6-only feature. - -Signed-off-by: Amit Shah ---- - qemu-char.c | 5 +++++ - 1 files changed, 5 insertions(+), 0 deletions(-) - -diff --git a/qemu-char.c b/qemu-char.c -index 5f67652..5a94919 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -220,6 +220,11 @@ void qemu_chr_add_handlers(CharDriverState *s, - ++s->avail_connections; - } - if (!handlers) { -+ if (s->write_blocked) { -+ /* Ensure we disable the callback if we were throttled */ -+ s->chr_disable_write_fd_handler(s); -+ /* s->write_blocked is cleared below */ -+ } - handlers = &null_handlers; - } - s->chr_can_read = handlers->fd_can_read; --- -1.7.7.5 - diff --git a/0118-qxl-make-qxl_render_update-async.patch b/0118-qxl-make-qxl_render_update-async.patch new file mode 100644 index 0000000..034242b --- /dev/null +++ b/0118-qxl-make-qxl_render_update-async.patch @@ -0,0 +1,357 @@ +From f229e9b26f1606e21cd5c2d5bb984d0af012c579 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Fri, 24 Feb 2012 23:19:31 +0200 +Subject: [PATCH] qxl: make qxl_render_update async + +RHBZ# 747011 + +Removes the last user of QXL_SYNC when using update drivers that use the +_ASYNC io ports. + +The last user is qxl_render_update, it is called both by qxl_hw_update +which is the vga_hw_update_ptr passed to graphic_console_init, and by +qxl_hw_screen_dump. + +At the same time the QXLRect area being passed to the red_worker thread +is passed as a copy, as part of the QXLCookie. + +The implementation uses interface_update_area_complete with a bh to make +sure dpy_update and qxl_flip are called from the io thread, otherwise +the vga->ds->surface.data can change under our feet. + +With this patch sdl+spice works fine. But spice by itself doesn't +produce the expected screendumps unless repeated a few times, due to +ppm_save being called before update_area (rendering done in spice server +thread) having a chance to complete. Fixed by next patch, but see commit +message for problem introduced by it. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 96 +++++++++++++++++++++++++++++++++++++++--------------- + hw/qxl.c | 69 ++++++++++++++++++++++++++++++++++++--- + hw/qxl.h | 10 ++++++ + ui/spice-display.h | 6 ++++ + 4 files changed, 150 insertions(+), 31 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 4c22166..4857838 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -82,17 +82,25 @@ void qxl_render_resize(PCIQXLDevice *qxl) + } + } + +-void qxl_render_update(PCIQXLDevice *qxl) ++static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area) ++{ ++ area->left = 0; ++ area->right = qxl->guest_primary.surface.width; ++ area->top = 0; ++ area->bottom = qxl->guest_primary.surface.height; ++} ++ ++static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + { + VGACommonState *vga = &qxl->vga; +- QXLRect dirty[32], update; +- int i, redraw = 0; ++ int i; + DisplaySurface *surface = vga->ds->surface; + + if (qxl->guest_primary.resized) { + qxl->guest_primary.resized = 0; +- + qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); ++ qxl_set_rect_to_surface(qxl, &qxl->dirty[0]); ++ qxl->num_dirty_rects = 1; + dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d\n", + __FUNCTION__, + qxl->guest_primary.surface.width, +@@ -103,9 +111,9 @@ void qxl_render_update(PCIQXLDevice *qxl) + } + if (surface->width != qxl->guest_primary.surface.width || + surface->height != qxl->guest_primary.surface.height) { +- dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", +- __func__); + if (qxl->guest_primary.qxl_stride > 0) { ++ dprint(qxl, 1, "%s: using guest_primary for displaysurface\n", ++ __func__); + qemu_free_displaysurface(vga->ds); + qemu_create_displaysurface_from(qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, +@@ -113,36 +121,70 @@ void qxl_render_update(PCIQXLDevice *qxl) + qxl->guest_primary.abs_stride, + qxl->guest_primary.data); + } else { ++ dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", ++ __func__); + qemu_resize_displaysurface(vga->ds, + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height); + } + } +- update.left = 0; +- update.right = qxl->guest_primary.surface.width; +- update.top = 0; +- update.bottom = qxl->guest_primary.surface.height; +- +- memset(dirty, 0, sizeof(dirty)); +- if (runstate_is_running() && qxl->guest_primary.commands) { +- qxl->guest_primary.commands = 0; +- qxl_spice_update_area(qxl, 0, &update, +- dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL); +- } +- if (redraw) { +- memset(dirty, 0, sizeof(dirty)); +- dirty[0] = update; +- } +- for (i = 0; i < ARRAY_SIZE(dirty); i++) { +- if (qemu_spice_rect_is_empty(dirty+i)) { ++ for (i = 0; i < qxl->num_dirty_rects; i++) { ++ if (qemu_spice_rect_is_empty(qxl->dirty+i)) { + break; + } +- qxl_flip(qxl, dirty+i); ++ qxl_flip(qxl, qxl->dirty+i); + dpy_update(vga->ds, +- dirty[i].left, dirty[i].top, +- dirty[i].right - dirty[i].left, +- dirty[i].bottom - dirty[i].top); ++ qxl->dirty[i].left, qxl->dirty[i].top, ++ qxl->dirty[i].right - qxl->dirty[i].left, ++ qxl->dirty[i].bottom - qxl->dirty[i].top); ++ } ++ qxl->num_dirty_rects = 0; ++} ++ ++/* ++ * use ssd.lock to protect render_update_cookie_num. ++ * qxl_render_update is called by io thread or vcpu thread, and the completion ++ * callbacks are called by spice_server thread, defering to bh called from the ++ * io thread. ++ */ ++void qxl_render_update(PCIQXLDevice *qxl) ++{ ++ QXLCookie *cookie; ++ ++ qemu_mutex_lock(&qxl->ssd.lock); ++ ++ if (!runstate_is_running() || !qxl->guest_primary.commands) { ++ qxl_render_update_area_unlocked(qxl); ++ qemu_mutex_unlock(&qxl->ssd.lock); ++ return; + } ++ ++ qxl->guest_primary.commands = 0; ++ qxl->render_update_cookie_num++; ++ qemu_mutex_unlock(&qxl->ssd.lock); ++ cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, ++ 0); ++ qxl_set_rect_to_surface(qxl, &cookie->u.render.area); ++ qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL, ++ 0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie); ++} ++ ++void qxl_render_update_area_bh(void *opaque) ++{ ++ PCIQXLDevice *qxl = opaque; ++ ++ qemu_mutex_lock(&qxl->ssd.lock); ++ qxl_render_update_area_unlocked(qxl); ++ qemu_mutex_unlock(&qxl->ssd.lock); ++} ++ ++void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie) ++{ ++ qemu_mutex_lock(&qxl->ssd.lock); ++ qemu_bh_schedule(qxl->update_area_bh); ++ qxl->render_update_cookie_num--; ++ qemu_mutex_unlock(&qxl->ssd.lock); ++ g_free(cookie); + } + + static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor) +diff --git a/hw/qxl.c b/hw/qxl.c +index e6e65d9..73be115 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -750,6 +750,11 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + __func__, current_async, cookie->io); + } + switch (current_async) { ++ case QXL_IO_MEMSLOT_ADD_ASYNC: ++ case QXL_IO_DESTROY_PRIMARY_ASYNC: ++ case QXL_IO_UPDATE_AREA_ASYNC: ++ case QXL_IO_FLUSH_SURFACES_ASYNC: ++ break; + case QXL_IO_CREATE_PRIMARY_ASYNC: + qxl_create_guest_primary_complete(qxl); + break; +@@ -759,11 +764,54 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + case QXL_IO_DESTROY_SURFACE_ASYNC: + qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id); + break; ++ default: ++ fprintf(stderr, "qxl: %s: unexpected current_async %d\n", __func__, ++ current_async); + } + qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); + } + + /* called from spice server thread context only */ ++static void interface_update_area_complete(QXLInstance *sin, ++ uint32_t surface_id, ++ QXLRect *dirty, uint32_t num_updated_rects) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ int i; ++ int qxl_i; ++ ++ qemu_mutex_lock(&qxl->ssd.lock); ++ if (surface_id != 0 || !qxl->render_update_cookie_num) { ++ qemu_mutex_unlock(&qxl->ssd.lock); ++ return; ++ } ++ if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) { ++ /* ++ * overflow - treat this as a full update. Not expected to be common. ++ */ ++ dprint(qxl, 1, "%s: overflow of dirty rects\n", __func__); ++ qxl->guest_primary.resized = 1; ++ } ++ if (qxl->guest_primary.resized) { ++ /* ++ * Don't bother copying or scheduling the bh since we will flip ++ * the whole area anyway on completion of the update_area async call ++ */ ++ qemu_mutex_unlock(&qxl->ssd.lock); ++ return; ++ } ++ qxl_i = qxl->num_dirty_rects; ++ for (i = 0; i < num_updated_rects; i++) { ++ qxl->dirty[qxl_i++] = dirty[i]; ++ } ++ qxl->num_dirty_rects += num_updated_rects; ++ dprint(qxl, 1, "%s: scheduling update_area_bh, #dirty %d\n", ++ __func__, qxl->num_dirty_rects); ++ qemu_bh_schedule(qxl->update_area_bh); ++ qemu_mutex_unlock(&qxl->ssd.lock); ++} ++ ++/* called from spice server thread context only */ + static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); +@@ -772,12 +820,16 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) + switch (cookie->type) { + case QXL_COOKIE_TYPE_IO: + interface_async_complete_io(qxl, cookie); ++ g_free(cookie); ++ break; ++ case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA: ++ qxl_render_update_area_done(qxl, cookie); + break; + default: + fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", + __func__, cookie->type); ++ g_free(cookie); + } +- g_free(cookie); + } + + static const QXLInterface qxl_interface = { +@@ -800,6 +852,7 @@ static const QXLInterface qxl_interface = { + .notify_update = interface_notify_update, + .flush_resources = interface_flush_resources, + .async_complete = interface_async_complete, ++ .update_area_complete = interface_update_area_complete, + }; + + static void qxl_enter_vga_mode(PCIQXLDevice *d) +@@ -1216,11 +1269,17 @@ async_common: + switch (io_port) { + case QXL_IO_UPDATE_AREA: + { ++ QXLCookie *cookie = NULL; + QXLRect update = d->ram->update_area; ++ ++ if (async == QXL_ASYNC) { ++ cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_UPDATE_AREA_ASYNC); ++ cookie->u.area = update; ++ } + qxl_spice_update_area(d, d->ram->update_surface, +- &update, NULL, 0, 0, async, +- qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_UPDATE_AREA_ASYNC)); ++ cookie ? &cookie->u.area : &update, ++ NULL, 0, 0, async, cookie); + break; + } + case QXL_IO_NOTIFY_CMD: +@@ -1652,6 +1711,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) + init_pipe_signaling(qxl); + qxl_reset_state(qxl); + ++ qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl); ++ + return 0; + } + +diff --git a/hw/qxl.h b/hw/qxl.h +index 1443925..86e415b 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -18,6 +18,8 @@ enum qxl_mode { + + #define QXL_UNDEFINED_IO UINT32_MAX + ++#define QXL_NUM_DIRTY_RECTS 64 ++ + typedef struct PCIQXLDevice { + PCIDevice pci; + SimpleSpiceDisplay ssd; +@@ -93,6 +95,12 @@ typedef struct PCIQXLDevice { + /* user-friendly properties (in megabytes) */ + uint32_t ram_size_mb; + uint32_t vram_size_mb; ++ ++ /* qxl_render_update state */ ++ int render_update_cookie_num; ++ int num_dirty_rects; ++ QXLRect dirty[QXL_NUM_DIRTY_RECTS]; ++ QEMUBH *update_area_bh; + } PCIQXLDevice; + + #define PANIC_ON(x) if ((x)) { \ +@@ -134,3 +142,5 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); + void qxl_render_resize(PCIQXLDevice *qxl); + void qxl_render_update(PCIQXLDevice *qxl); + void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); ++void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie); ++void qxl_render_update_area_bh(void *opaque); +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 8a010cb..12e50b6 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -50,6 +50,7 @@ typedef enum qxl_async_io { + + enum { + QXL_COOKIE_TYPE_IO, ++ QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, + }; + + typedef struct QXLCookie { +@@ -57,6 +58,11 @@ typedef struct QXLCookie { + uint64_t io; + union { + uint32_t surface_id; ++ QXLRect area; ++ struct { ++ QXLRect area; ++ int redraw; ++ } render; + } u; + } QXLCookie; + diff --git a/0119-spice-use-error_report-to-report-errors.patch b/0119-spice-use-error_report-to-report-errors.patch new file mode 100644 index 0000000..9b86d31 --- /dev/null +++ b/0119-spice-use-error_report-to-report-errors.patch @@ -0,0 +1,99 @@ +From 13a3ec7847529b74584cec7da2377a755b65eb13 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Fri, 24 Feb 2012 18:13:12 +0100 +Subject: [PATCH] spice: use error_report to report errors + +Error message reporting during spice startup wasn't consistent, it was done +with fprintf(stderr, "") but sometimes the message didn't have a trailing +\n. Using error_report make the intent of the message clearer and deal +with the final \n for us. + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-core.c | 22 +++++++++++----------- + 1 file changed, 11 insertions(+), 11 deletions(-) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 2c815f1..8503f03 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -227,8 +227,8 @@ static void channel_event(int event, SpiceChannelEventInfo *info) + add_addr_info(server, (struct sockaddr *)&info->laddr_ext, + info->llen_ext); + } else { +- fprintf(stderr, "spice: %s, extended address is expected\n", +- __func__); ++ error_report("spice: %s, extended address is expected", ++ __func__); + #endif + add_addr_info(client, &info->paddr, info->plen); + add_addr_info(server, &info->laddr, info->llen); +@@ -333,7 +333,7 @@ static int parse_name(const char *string, const char *optname, + if (value != -1) { + return value; + } +- fprintf(stderr, "spice: invalid %s: %s\n", optname, string); ++ error_report("spice: invalid %s: %s", optname, string); + exit(1); + } + +@@ -525,7 +525,7 @@ static int add_channel(const char *name, const char *value, void *opaque) + rc = spice_server_set_channel_security(spice_server, value, security); + } + if (rc != 0) { +- fprintf(stderr, "spice: failed to set channel security for %s\n", value); ++ error_report("spice: failed to set channel security for %s", value); + exit(1); + } + return 0; +@@ -553,15 +553,15 @@ void qemu_spice_init(void) + port = qemu_opt_get_number(opts, "port", 0); + tls_port = qemu_opt_get_number(opts, "tls-port", 0); + if (!port && !tls_port) { +- fprintf(stderr, "neither port nor tls-port specified for spice."); ++ error_report("neither port nor tls-port specified for spice"); + exit(1); + } + if (port < 0 || port > 65535) { +- fprintf(stderr, "spice port is out of range"); ++ error_report("spice port is out of range"); + exit(1); + } + if (tls_port < 0 || tls_port > 65535) { +- fprintf(stderr, "spice tls-port is out of range"); ++ error_report("spice tls-port is out of range"); + exit(1); + } + password = qemu_opt_get(opts, "password"); +@@ -631,11 +631,11 @@ void qemu_spice_init(void) + #if SPICE_SERVER_VERSION >= 0x000900 /* 0.9.0 */ + if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 || + spice_server_set_sasl(spice_server, 1) == -1) { +- fprintf(stderr, "spice: failed to enable sasl\n"); ++ error_report("spice: failed to enable sasl"); + exit(1); + } + #else +- fprintf(stderr, "spice: sasl is not available (spice >= 0.9 required)\n"); ++ error_report("spice: sasl is not available (spice >= 0.9 required)"); + exit(1); + #endif + } +@@ -683,7 +683,7 @@ void qemu_spice_init(void) + qemu_opt_foreach(opts, add_channel, NULL, 0); + + if (0 != spice_server_init(spice_server, &core_interface)) { +- fprintf(stderr, "failed to initialize spice server"); ++ error_report("failed to initialize spice server"); + exit(1); + }; + using_spice = 1; +@@ -708,7 +708,7 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin) + { + if (!spice_server) { + if (QTAILQ_FIRST(&qemu_spice_opts.head) != NULL) { +- fprintf(stderr, "Oops: spice configured but not active\n"); ++ error_report("Oops: spice configured but not active"); + exit(1); + } + /* diff --git a/0119-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch b/0119-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch deleted file mode 100644 index cb41dc0..0000000 --- a/0119-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 959f57d34f11daf0da6f73541243934f39dfb2b2 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 13 Jan 2012 14:26:26 +0100 -Subject: [PATCH 119/140] usb-ehci: Clear the portstatus powner bit on device - disconnect - -According to the EHCI spec port ownerhsip should revert to the EHCI controller -on device disconnect. This fixes the problem of a port getting stuck on USB 1 -when using redirection and plugging in a USB 2 device after a USB 1 device -has been redirected. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index a946e1d..69bcc4b 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -764,6 +764,11 @@ static void ehci_detach(USBPort *port) - USBPort *companion = s->companion_ports[port->index]; - companion->ops->detach(companion); - companion->dev = NULL; -+ /* -+ * EHCI spec 4.2.2: "When a disconnect occurs... On the event, -+ * the port ownership is returned immediately to the EHCI controller." -+ */ -+ *portsc &= ~PORTSC_POWNER; - return; - } - --- -1.7.9.3 - diff --git a/0120-Error-out-when-tls-channel-option-is-used-without-TL.patch b/0120-Error-out-when-tls-channel-option-is-used-without-TL.patch new file mode 100644 index 0000000..f23dbe5 --- /dev/null +++ b/0120-Error-out-when-tls-channel-option-is-used-without-TL.patch @@ -0,0 +1,40 @@ +From b3520ff11022b03f90255b5596aaa498cbea2d75 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Fri, 24 Feb 2012 18:28:32 +0100 +Subject: [PATCH] Error out when tls-channel option is used without TLS + +It's currently possible to setup spice channels using TLS when +no TLS port has been specified (ie TLS is disabled). This cannot +work, so better to error out in such a situation. + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-core.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 8503f03..98356b0 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -511,6 +511,12 @@ static int add_channel(const char *name, const char *value, void *opaque) + int rc; + + if (strcmp(name, "tls-channel") == 0) { ++ int *tls_port = opaque; ++ if (!*tls_port) { ++ error_report("spice: tried to setup tls-channel" ++ " without specifying a TLS port"); ++ exit(1); ++ } + security = SPICE_CHANNEL_SECURITY_SSL; + } + if (strcmp(name, "plaintext-channel") == 0) { +@@ -680,7 +686,7 @@ void qemu_spice_init(void) + spice_server_set_playback_compression + (spice_server, qemu_opt_get_bool(opts, "playback-compression", 1)); + +- qemu_opt_foreach(opts, add_channel, NULL, 0); ++ qemu_opt_foreach(opts, add_channel, &tls_port, 0); + + if (0 != spice_server_init(spice_server, &core_interface)) { + error_report("failed to initialize spice server"); diff --git a/0120-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch b/0120-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch deleted file mode 100644 index c0d0e9f..0000000 --- a/0120-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch +++ /dev/null @@ -1,263 +0,0 @@ -From bcc4748db3e991fbaa032fe9c0726288a8f1008d Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 12 Jan 2012 16:54:04 +0100 -Subject: [PATCH 120/140] usb-redir: Add the posibility to filter out certain - devices from redirecion - -This patch adds the posibility to filter out certain devices from redirecion. -To use this pass the filter property to -device usb-redir. The filter -property takes a string consisting of filter rules, the format for a rule is: -:::: - --1 can be used to allow any value for a field. - -Muliple rules can be concatonated using | as a separator. Note that if -a device matches none of the passed in rules, redirecting it will not be -allowed! - -Example: --device usb-redir,filter='-1:0x0781:0x5567:-1:0|0x08:-1:-1:-1:1' - -This example will deny the Sandisk Cruzer Blade being redirected, as it -has a usb id of 0781:5567, it will allow any other usb mass storage devices, -and it will deny any other devices (the default for devices not matching any -of the rules. - -Signed-off-by: Hans de Goede ---- - configure | 2 +- - usb-redir.c | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ - 2 files changed, 106 insertions(+), 11 deletions(-) - -diff --git a/configure b/configure -index 7ecf44e..c7e37df 100755 ---- a/configure -+++ b/configure -@@ -2541,7 +2541,7 @@ fi - - # check for usbredirparser for usb network redirection support - if test "$usb_redir" != "no" ; then -- if $pkg_config libusbredirparser >/dev/null 2>&1 ; then -+ if $pkg_config --atleast-version=0.3.3 libusbredirparser >/dev/null 2>&1 ; then - usb_redir="yes" - usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) - usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) -diff --git a/usb-redir.c b/usb-redir.c -index 6e92f14..85f40d6 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -34,6 +34,7 @@ - #include - #include - #include -+#include - - #include "hw/usb.h" - -@@ -72,6 +73,7 @@ struct USBRedirDevice { - /* Properties */ - CharDriverState *cs; - uint8_t debug; -+ char *filter_str; - /* Data passed from chardev the fd_read cb to the usbredirparser read cb */ - const uint8_t *read_buf; - int read_buf_size; -@@ -84,6 +86,11 @@ struct USBRedirDevice { - struct endp_data endpoint[MAX_ENDPOINTS]; - uint32_t packet_id; - QTAILQ_HEAD(, AsyncURB) asyncq; -+ /* Data for device filtering */ -+ struct usb_redir_device_connect_header device_info; -+ struct usb_redir_interface_info_header interface_info; -+ struct usbredirfilter_rule *filter_rules; -+ int filter_rules_count; - }; - - struct AsyncURB { -@@ -790,6 +797,7 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, - static void usbredir_open_close_bh(void *opaque) - { - USBRedirDevice *dev = opaque; -+ uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; - - usbredir_device_disconnect(dev); - -@@ -820,7 +828,9 @@ static void usbredir_open_close_bh(void *opaque) - dev->parser->interrupt_packet_func = usbredir_interrupt_packet; - dev->read_buf = NULL; - dev->read_buf_size = 0; -- usbredirparser_init(dev->parser, VERSION, NULL, 0, 0); -+ -+ usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); -+ usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0); - usbredirparser_do_write(dev->parser); - } - } -@@ -908,6 +918,17 @@ static int usbredir_initfn(USBDevice *udev) - return -1; - } - -+ if (dev->filter_str) { -+ i = usbredirfilter_string_to_rules(dev->filter_str, ":", "|", -+ &dev->filter_rules, -+ &dev->filter_rules_count); -+ if (i) { -+ qerror_report(QERR_INVALID_PARAMETER_VALUE, "filter", -+ "a usb device filter string"); -+ return -1; -+ } -+ } -+ - dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev); - dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - -@@ -956,6 +977,44 @@ static void usbredir_handle_destroy(USBDevice *udev) - if (dev->parser) { - usbredirparser_destroy(dev->parser); - } -+ -+ free(dev->filter_rules); -+} -+ -+static int usbredir_check_filter(USBRedirDevice *dev) -+{ -+ if (dev->interface_info.interface_count == 0) { -+ ERROR("No interface info for device\n"); -+ return -1; -+ } -+ -+ if (dev->filter_rules) { -+ if (!usbredirparser_peer_has_cap(dev->parser, -+ usb_redir_cap_connect_device_version)) { -+ ERROR("Device filter specified and peer does not have the " -+ "connect_device_version capability\n"); -+ return -1; -+ } -+ -+ if (usbredirfilter_check( -+ dev->filter_rules, -+ dev->filter_rules_count, -+ dev->device_info.device_class, -+ dev->device_info.device_subclass, -+ dev->device_info.device_protocol, -+ dev->interface_info.interface_class, -+ dev->interface_info.interface_subclass, -+ dev->interface_info.interface_protocol, -+ dev->interface_info.interface_count, -+ dev->device_info.vendor_id, -+ dev->device_info.product_id, -+ dev->device_info.device_version_bcd, -+ 0) != 0) { -+ return -1; -+ } -+ } -+ -+ return 0; - } - - /* -@@ -984,6 +1043,7 @@ static void usbredir_device_connect(void *priv, - struct usb_redir_device_connect_header *device_connect) - { - USBRedirDevice *dev = priv; -+ const char *speed; - - if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { - ERROR("Received device connect while already connected\n"); -@@ -992,26 +1052,48 @@ static void usbredir_device_connect(void *priv, - - switch (device_connect->speed) { - case usb_redir_speed_low: -- DPRINTF("attaching low speed device\n"); -+ speed = "low speed"; - dev->dev.speed = USB_SPEED_LOW; - break; - case usb_redir_speed_full: -- DPRINTF("attaching full speed device\n"); -+ speed = "full speed"; - dev->dev.speed = USB_SPEED_FULL; - break; - case usb_redir_speed_high: -- DPRINTF("attaching high speed device\n"); -+ speed = "high speed"; - dev->dev.speed = USB_SPEED_HIGH; - break; - case usb_redir_speed_super: -- DPRINTF("attaching super speed device\n"); -+ speed = "super speed"; - dev->dev.speed = USB_SPEED_SUPER; - break; - default: -- DPRINTF("attaching unknown speed device, assuming full speed\n"); -+ speed = "unknown speed"; - dev->dev.speed = USB_SPEED_FULL; - } -+ -+ if (usbredirparser_peer_has_cap(dev->parser, -+ usb_redir_cap_connect_device_version)) { -+ INFO("attaching %s device %04x:%04x version %d.%d class %02x\n", -+ speed, device_connect->vendor_id, device_connect->product_id, -+ device_connect->device_version_bcd >> 8, -+ device_connect->device_version_bcd & 0xff, -+ device_connect->device_class); -+ } else { -+ INFO("attaching %s device %04x:%04x class %02x\n", speed, -+ device_connect->vendor_id, device_connect->product_id, -+ device_connect->device_class); -+ } -+ - dev->dev.speedmask = (1 << dev->dev.speed); -+ dev->device_info = *device_connect; -+ -+ if (usbredir_check_filter(dev)) { -+ WARNING("Device %04x:%04x rejected by device filter, not attaching\n", -+ device_connect->vendor_id, device_connect->product_id); -+ return; -+ } -+ - qemu_mod_timer(dev->attach_timer, dev->next_attach_time); - } - -@@ -1038,15 +1120,27 @@ static void usbredir_device_disconnect(void *priv) - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } -+ dev->interface_info.interface_count = 0; - } - - static void usbredir_interface_info(void *priv, - struct usb_redir_interface_info_header *interface_info) - { -- /* The intention is to allow specifying acceptable interface classes -- for redirection on the cmdline and in the future verify this here, -- and disconnect (or never connect) the device if a not accepted -- interface class is detected */ -+ USBRedirDevice *dev = priv; -+ -+ dev->interface_info = *interface_info; -+ -+ /* -+ * If we receive interface info after the device has already been -+ * connected (ie on a set_config), re-check the filter. -+ */ -+ if (qemu_timer_pending(dev->attach_timer) || dev->dev.attached) { -+ if (usbredir_check_filter(dev)) { -+ ERROR("Device no longer matches filter after interface info " -+ "change, disconnecting!\n"); -+ usbredir_device_disconnect(dev); -+ } -+ } - } - - static void usbredir_ep_info(void *priv, -@@ -1356,6 +1450,7 @@ static struct USBDeviceInfo usbredir_dev_info = { - .qdev.props = (Property[]) { - DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), - DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), -+ DEFINE_PROP_STRING("filter", USBRedirDevice, filter_str), - DEFINE_PROP_END_OF_LIST(), - }, - }; --- -1.7.9.3 - diff --git a/0121-qxl-properly-handle-upright-and-non-shared-surfaces.patch b/0121-qxl-properly-handle-upright-and-non-shared-surfaces.patch new file mode 100644 index 0000000..15d4137 --- /dev/null +++ b/0121-qxl-properly-handle-upright-and-non-shared-surfaces.patch @@ -0,0 +1,74 @@ +From 38803225a25d8194cbe8d372579e0bc28ae35abc Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 27 Feb 2012 11:05:09 +0100 +Subject: [PATCH] qxl: properly handle upright and non-shared surfaces + +Although qxl creates a shared displaysurface when the qxl surface is +upright and doesn't need to be flipped there is no guarantee that the +surface doesn't become unshared for some reason. Rename qxl_flip to +qxl_blit and fix it to handle both flip and non-flip cases. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 20 +++++++++++++------- + 1 file changed, 13 insertions(+), 7 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 4857838..2e10e93 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -21,25 +21,31 @@ + + #include "qxl.h" + +-static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) ++static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) + { + uint8_t *src; + uint8_t *dst = qxl->vga.ds->surface->data; + int len, i; + +- if (qxl->guest_primary.qxl_stride > 0) { ++ if (is_buffer_shared(qxl->vga.ds->surface)) { + return; + } + if (!qxl->guest_primary.data) { + dprint(qxl, 1, "%s: initializing guest_primary.data\n", __func__); + qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); + } +- dprint(qxl, 1, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, ++ dprint(qxl, 2, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, + qxl->guest_primary.qxl_stride, + rect->left, rect->right, rect->top, rect->bottom); + src = qxl->guest_primary.data; +- src += (qxl->guest_primary.surface.height - rect->top - 1) * +- qxl->guest_primary.abs_stride; ++ if (qxl->guest_primary.qxl_stride < 0) { ++ /* qxl surface is upside down, walk src scanlines ++ * in reverse order to flip it */ ++ src += (qxl->guest_primary.surface.height - rect->top - 1) * ++ qxl->guest_primary.abs_stride; ++ } else { ++ src += rect->top * qxl->guest_primary.abs_stride; ++ } + dst += rect->top * qxl->guest_primary.abs_stride; + src += rect->left * qxl->guest_primary.bytes_pp; + dst += rect->left * qxl->guest_primary.bytes_pp; +@@ -48,7 +54,7 @@ static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) + for (i = rect->top; i < rect->bottom; i++) { + memcpy(dst, src, len); + dst += qxl->guest_primary.abs_stride; +- src -= qxl->guest_primary.abs_stride; ++ src += qxl->guest_primary.qxl_stride; + } + } + +@@ -132,7 +138,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + if (qemu_spice_rect_is_empty(qxl->dirty+i)) { + break; + } +- qxl_flip(qxl, qxl->dirty+i); ++ qxl_blit(qxl, qxl->dirty+i); + dpy_update(vga->ds, + qxl->dirty[i].left, qxl->dirty[i].top, + qxl->dirty[i].right - qxl->dirty[i].left, diff --git a/0121-usb-redir-Fix-printing-of-device-version.patch b/0121-usb-redir-Fix-printing-of-device-version.patch deleted file mode 100644 index 854641c..0000000 --- a/0121-usb-redir-Fix-printing-of-device-version.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 6c13e7b9448b10d966bb99c00c5120678ccd2a3f Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sat, 18 Feb 2012 09:12:14 +0100 -Subject: [PATCH 121/140] usb-redir: Fix printing of device version - -The device version is in bcd format, which requires some special handling to -print. - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index 85f40d6..9b804e9 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -1076,8 +1076,10 @@ static void usbredir_device_connect(void *priv, - usb_redir_cap_connect_device_version)) { - INFO("attaching %s device %04x:%04x version %d.%d class %02x\n", - speed, device_connect->vendor_id, device_connect->product_id, -- device_connect->device_version_bcd >> 8, -- device_connect->device_version_bcd & 0xff, -+ ((device_connect->device_version_bcd & 0xf000) >> 12) * 10 + -+ ((device_connect->device_version_bcd & 0x0f00) >> 8), -+ ((device_connect->device_version_bcd & 0x00f0) >> 4) * 10 + -+ ((device_connect->device_version_bcd & 0x000f) >> 0), - device_connect->device_class); - } else { - INFO("attaching %s device %04x:%04x class %02x\n", speed, --- -1.7.9.3 - diff --git a/0122-spice-set-spice-uuid-and-name.patch b/0122-spice-set-spice-uuid-and-name.patch new file mode 100644 index 0000000..1599553 --- /dev/null +++ b/0122-spice-set-spice-uuid-and-name.patch @@ -0,0 +1,36 @@ +From a149ead57ceb131ff2e859549e835c8499c6ba47 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Mon, 5 Mar 2012 18:22:26 +0100 +Subject: [PATCH] spice: set spice uuid and name + +This allows a Spice client to identify a VM + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-core.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 98356b0..4ad0a67 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -19,6 +19,7 @@ + #include + + #include ++#include "sysemu.h" + + #include "qemu-common.h" + #include "qemu-spice.h" +@@ -688,6 +689,11 @@ void qemu_spice_init(void) + + qemu_opt_foreach(opts, add_channel, &tls_port, 0); + ++#if SPICE_SERVER_VERSION >= 0x000a02 /* 0.10.2 */ ++ spice_server_set_name(spice_server, qemu_name); ++ spice_server_set_uuid(spice_server, qemu_uuid); ++#endif ++ + if (0 != spice_server_init(spice_server, &core_interface)) { + error_report("failed to initialize spice server"); + exit(1); diff --git a/0122-usb-redir-Always-clear-device-state-on-filter-reject.patch b/0122-usb-redir-Always-clear-device-state-on-filter-reject.patch deleted file mode 100644 index 66ccf68..0000000 --- a/0122-usb-redir-Always-clear-device-state-on-filter-reject.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 49a01afb24b925de97074d093fb072bb7de470f9 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sat, 18 Feb 2012 09:18:57 +0100 -Subject: [PATCH 122/140] usb-redir: Always clear device state on filter - reject - -Always call usbredir_device_disconnect() when usbredir_check_filter() fails -to clean up all the device state (ie received endpoint info). - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 11 +++++++---- - 1 file changed, 7 insertions(+), 4 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index 9b804e9..fe3b0a3 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -985,7 +985,7 @@ static int usbredir_check_filter(USBRedirDevice *dev) - { - if (dev->interface_info.interface_count == 0) { - ERROR("No interface info for device\n"); -- return -1; -+ goto error; - } - - if (dev->filter_rules) { -@@ -993,7 +993,7 @@ static int usbredir_check_filter(USBRedirDevice *dev) - usb_redir_cap_connect_device_version)) { - ERROR("Device filter specified and peer does not have the " - "connect_device_version capability\n"); -- return -1; -+ goto error; - } - - if (usbredirfilter_check( -@@ -1010,11 +1010,15 @@ static int usbredir_check_filter(USBRedirDevice *dev) - dev->device_info.product_id, - dev->device_info.device_version_bcd, - 0) != 0) { -- return -1; -+ goto error; - } - } - - return 0; -+ -+error: -+ usbredir_device_disconnect(dev); -+ return -1; - } - - /* -@@ -1140,7 +1144,6 @@ static void usbredir_interface_info(void *priv, - if (usbredir_check_filter(dev)) { - ERROR("Device no longer matches filter after interface info " - "change, disconnecting!\n"); -- usbredir_device_disconnect(dev); - } - } - } --- -1.7.9.3 - diff --git a/0123-monitor-fix-client_migrate_info-error-handling.patch b/0123-monitor-fix-client_migrate_info-error-handling.patch new file mode 100644 index 0000000..99d02d7 --- /dev/null +++ b/0123-monitor-fix-client_migrate_info-error-handling.patch @@ -0,0 +1,32 @@ +From 26e9af01cb047fcd1eeb8fe8e9397266afc4df72 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Sun, 18 Mar 2012 09:42:39 +0200 +Subject: [PATCH] monitor: fix client_migrate_info error handling + +Report QERR_MISSING_PARAMETER when port is missing. Otherwise +QERR_UNDEFINED_ERROR will occur. + +rhbz #795652 + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +--- + monitor.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/monitor.c b/monitor.c +index 3c23aa4..76739d7 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -1046,6 +1046,11 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict, + return -1; + } + ++ if (port == -1 && tls_port == -1) { ++ qerror_report(QERR_MISSING_PARAMETER, "port/tls-port"); ++ return -1; ++ } ++ + ret = qemu_spice_migrate_info(hostname, port, tls_port, subject, + cb, opaque); + if (ret != 0) { diff --git a/0123-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch b/0123-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch deleted file mode 100644 index 9a166bf..0000000 --- a/0123-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch +++ /dev/null @@ -1,93 +0,0 @@ -From f04315d9210f22e5d7317f1cfb3c076fb93b3c08 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sun, 19 Feb 2012 09:58:03 +0100 -Subject: [PATCH 123/140] usb-redir: Let the usb-host know about our device - filtering - -libusbredirparser-0.3.4 adds 2 new packets which allows us to notify -the usb-host: --about the usb device filter we have (if any), so that it knows not the even - try to redirect certain devices --when we reject a device based on filtering (in case it tries anyways) - -Signed-off-by: Hans de Goede ---- - configure | 2 +- - usb-redir.c | 20 ++++++++++++++++++++ - 2 files changed, 21 insertions(+), 1 deletion(-) - -diff --git a/configure b/configure -index c7e37df..a4848a4 100755 ---- a/configure -+++ b/configure -@@ -2541,7 +2541,7 @@ fi - - # check for usbredirparser for usb network redirection support - if test "$usb_redir" != "no" ; then -- if $pkg_config --atleast-version=0.3.3 libusbredirparser >/dev/null 2>&1 ; then -+ if $pkg_config --atleast-version=0.3.4 libusbredirparser >/dev/null 2>&1 ; then - usb_redir="yes" - usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) - usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) -diff --git a/usb-redir.c b/usb-redir.c -index fe3b0a3..d10d8de 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -106,6 +106,7 @@ struct AsyncURB { - QTAILQ_ENTRY(AsyncURB)next; - }; - -+static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); - static void usbredir_device_connect(void *priv, - struct usb_redir_device_connect_header *device_connect); - static void usbredir_device_disconnect(void *priv); -@@ -812,6 +813,7 @@ static void usbredir_open_close_bh(void *opaque) - dev->parser->log_func = usbredir_log; - dev->parser->read_func = usbredir_read; - dev->parser->write_func = usbredir_write; -+ dev->parser->hello_func = usbredir_hello; - dev->parser->device_connect_func = usbredir_device_connect; - dev->parser->device_disconnect_func = usbredir_device_disconnect; - dev->parser->interface_info_func = usbredir_interface_info; -@@ -830,6 +832,7 @@ static void usbredir_open_close_bh(void *opaque) - dev->read_buf_size = 0; - - usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); -+ usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); - usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0); - usbredirparser_do_write(dev->parser); - } -@@ -1018,6 +1021,10 @@ static int usbredir_check_filter(USBRedirDevice *dev) - - error: - usbredir_device_disconnect(dev); -+ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { -+ usbredirparser_send_filter_reject(dev->parser); -+ usbredirparser_do_write(dev->parser); -+ } - return -1; - } - -@@ -1043,6 +1050,19 @@ static int usbredir_handle_status(USBRedirDevice *dev, - } - } - -+static void usbredir_hello(void *priv, struct usb_redir_hello_header *h) -+{ -+ USBRedirDevice *dev = priv; -+ -+ /* Try to send the filter info now that we've the usb-host's caps */ -+ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter) && -+ dev->filter_rules) { -+ usbredirparser_send_filter_filter(dev->parser, dev->filter_rules, -+ dev->filter_rules_count); -+ usbredirparser_do_write(dev->parser); -+ } -+} -+ - static void usbredir_device_connect(void *priv, - struct usb_redir_device_connect_header *device_connect) - { --- -1.7.9.3 - diff --git a/0124-qxl-init_pipe_signaling-exit-on-failure.patch b/0124-qxl-init_pipe_signaling-exit-on-failure.patch new file mode 100644 index 0000000..747797c --- /dev/null +++ b/0124-qxl-init_pipe_signaling-exit-on-failure.patch @@ -0,0 +1,46 @@ +From f520591e875e79ef5965d5a82d43af2fc2334241 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Sun, 18 Mar 2012 13:46:13 +0100 +Subject: [PATCH] qxl: init_pipe_signaling: exit on failure + +If pipe creation fails, exit, don't log and continue. Fix indentation at +the same time. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 73be115..9ad5807 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1453,16 +1453,17 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) + + static void init_pipe_signaling(PCIQXLDevice *d) + { +- if (pipe(d->pipe) < 0) { +- dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__); +- return; +- } +- fcntl(d->pipe[0], F_SETFL, O_NONBLOCK); +- fcntl(d->pipe[1], F_SETFL, O_NONBLOCK); +- fcntl(d->pipe[0], F_SETOWN, getpid()); +- +- qemu_thread_get_self(&d->main); +- qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d); ++ if (pipe(d->pipe) < 0) { ++ fprintf(stderr, "%s:%s: qxl pipe creation failed\n", ++ __FILE__, __func__); ++ exit(1); ++ } ++ fcntl(d->pipe[0], F_SETFL, O_NONBLOCK); ++ fcntl(d->pipe[1], F_SETFL, O_NONBLOCK); ++ fcntl(d->pipe[0], F_SETOWN, getpid()); ++ ++ qemu_thread_get_self(&d->main); ++ qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d); + } + + /* graphics console */ diff --git a/0124-usb-redir-Limit-return-values-returned-by-iso-packet.patch b/0124-usb-redir-Limit-return-values-returned-by-iso-packet.patch deleted file mode 100644 index d35ae08..0000000 --- a/0124-usb-redir-Limit-return-values-returned-by-iso-packet.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 91338d1b4df14f7454d1b52200d2ae4eb957fa72 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sun, 26 Feb 2012 15:28:51 +0100 -Subject: [PATCH 124/140] usb-redir: Limit return values returned by iso - packets - -The usbredir protocol uses a status of usb_redir_stall to indicate that -an iso data stream has stopped (ie because the urbs failed on resubmit), -but iso packets should never return a result of USB_RET_STALL, since iso -endpoints cannot stall. So instead simply always return USB_RET_NAK on -iso stream errors. - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index d10d8de..c76e55d 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -441,7 +441,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - /* Check iso_error for stream errors, otherwise its an underrun */ - status = dev->endpoint[EP2I(ep)].iso_error; - dev->endpoint[EP2I(ep)].iso_error = 0; -- return usbredir_handle_status(dev, status, 0); -+ return status ? USB_RET_NAK : 0; - } - DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep, - isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); -@@ -449,7 +449,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - status = isop->status; - if (status != usb_redir_success) { - bufp_free(dev, isop, ep); -- return usbredir_handle_status(dev, status, 0); -+ return USB_RET_NAK; - } - - len = isop->len; --- -1.7.9.3 - diff --git a/0125-qxl-switch-qxl.c-to-trace-events.patch b/0125-qxl-switch-qxl.c-to-trace-events.patch new file mode 100644 index 0000000..8b6ea0b --- /dev/null +++ b/0125-qxl-switch-qxl.c-to-trace-events.patch @@ -0,0 +1,750 @@ +From 1e2fc2f3699fc61f2eaba0f292649edd4327b2d1 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Sun, 18 Mar 2012 13:46:14 +0100 +Subject: [PATCH] qxl: switch qxl.c to trace-events + +dprint is still used for qxl_init_common one time prints. + +also switched parts of spice-display.c over, mainly all the callbacks to +spice server. + +All qxl device trace events start with the qxl device id. + +Signed-off-by: Alon Levy +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Gerd Hoffmann + +Conflicts: + + trace-events +--- + hw/qxl.c | 141 ++++++++++++++++++++++++++--------------------------- + trace-events | 59 ++++++++++++++++++++++ + ui/spice-display.c | 14 +++++- + 3 files changed, 140 insertions(+), 74 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 9ad5807..813873a 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -23,6 +23,7 @@ + #include "qemu-queue.h" + #include "monitor.h" + #include "sysemu.h" ++#include "trace.h" + + #include "qxl.h" + +@@ -143,6 +144,10 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + uint32_t clear_dirty_region, + qxl_async_io async, struct QXLCookie *cookie) + { ++ trace_qxl_spice_update_area(qxl->id, surface_id, area->left, area->right, ++ area->top, area->bottom); ++ trace_qxl_spice_update_area_rest(qxl->id, num_dirty_rects, ++ clear_dirty_region); + if (async == QXL_SYNC) { + qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, + dirty_rects, num_dirty_rects, clear_dirty_region); +@@ -156,6 +161,7 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl, + uint32_t id) + { ++ trace_qxl_spice_destroy_surface_wait_complete(qxl->id, id); + qemu_mutex_lock(&qxl->track_lock); + qxl->guest_surfaces.cmds[id] = 0; + qxl->guest_surfaces.count--; +@@ -167,6 +173,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + { + QXLCookie *cookie; + ++ trace_qxl_spice_destroy_surface_wait(qxl->id, id, async); + if (async) { + cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_DESTROY_SURFACE_ASYNC); +@@ -174,12 +181,13 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uint64_t)cookie); + } else { + qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); +- qxl_spice_destroy_surface_wait_complete(qxl, id); + } + } + + static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count, ++ qxl->num_free_res); + spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_FLUSH_SURFACES_ASYNC)); +@@ -188,21 +196,25 @@ static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, + uint32_t count) + { ++ trace_qxl_spice_loadvm_commands(qxl->id, ext, count); + qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count); + } + + void qxl_spice_oom(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_oom(qxl->id); + qxl->ssd.worker->oom(qxl->ssd.worker); + } + + void qxl_spice_reset_memslots(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_reset_memslots(qxl->id); + qxl->ssd.worker->reset_memslots(qxl->ssd.worker); + } + + static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_destroy_surfaces_complete(qxl->id); + qemu_mutex_lock(&qxl->track_lock); + memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); + qxl->guest_surfaces.count = 0; +@@ -211,6 +223,7 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) + + static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) + { ++ trace_qxl_spice_destroy_surfaces(qxl->id, async); + if (async) { + spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +@@ -223,11 +236,13 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) + + void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_reset_image_cache(qxl->id); + qxl->ssd.worker->reset_image_cache(qxl->ssd.worker); + } + + void qxl_spice_reset_cursor(PCIQXLDevice *qxl) + { ++ trace_qxl_spice_reset_cursor(qxl->id); + qxl->ssd.worker->reset_cursor(qxl->ssd.worker); + qemu_mutex_lock(&qxl->track_lock); + qxl->guest_cursor = 0; +@@ -412,7 +427,7 @@ static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + +- dprint(qxl, 1, "%s:\n", __FUNCTION__); ++ trace_qxl_interface_attach_worker(qxl->id); + qxl->ssd.worker = qxl_worker; + } + +@@ -420,7 +435,7 @@ static void interface_set_compression_level(QXLInstance *sin, int level) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + +- dprint(qxl, 1, "%s: %d\n", __FUNCTION__, level); ++ trace_qxl_interface_set_compression_level(qxl->id, level); + qxl->shadow_rom.compression_level = cpu_to_le32(level); + qxl->rom->compression_level = cpu_to_le32(level); + qxl_rom_set_dirty(qxl); +@@ -430,6 +445,7 @@ static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + ++ trace_qxl_interface_set_mm_time(qxl->id, mm_time); + qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time); + qxl->rom->mm_clock = cpu_to_le32(mm_time); + qxl_rom_set_dirty(qxl); +@@ -439,7 +455,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + +- dprint(qxl, 1, "%s:\n", __FUNCTION__); ++ trace_qxl_interface_get_init_info(qxl->id); + info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; + info->memslot_id_bits = MEMSLOT_SLOT_BITS; + info->num_memslots = NUM_MEMSLOTS; +@@ -508,9 +524,10 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + QXLCommand *cmd; + int notify, ret; + ++ trace_qxl_ring_command_check(qxl->id, qxl_mode_to_string(qxl->mode)); ++ + switch (qxl->mode) { + case QXL_MODE_VGA: +- dprint(qxl, 2, "%s: vga\n", __FUNCTION__); + ret = false; + qemu_mutex_lock(&qxl->ssd.lock); + if (qxl->ssd.update != NULL) { +@@ -521,19 +538,18 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + } + qemu_mutex_unlock(&qxl->ssd.lock); + if (ret) { +- dprint(qxl, 2, "%s %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); ++ trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); + qxl_log_command(qxl, "vga", ext); + } + return ret; + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: + case QXL_MODE_UNDEFINED: +- dprint(qxl, 4, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); + ring = &qxl->ram->cmd_ring; + if (SPICE_RING_IS_EMPTY(ring)) { + return false; + } +- dprint(qxl, 2, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); ++ trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); + SPICE_RING_CONS_ITEM(ring, cmd); + ext->cmd = *cmd; + ext->group_id = MEMSLOT_GROUP_GUEST; +@@ -558,6 +574,7 @@ static int interface_req_cmd_notification(QXLInstance *sin) + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + int wait = 1; + ++ trace_qxl_ring_command_req_notification(qxl->id); + switch (qxl->mode) { + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: +@@ -595,10 +612,11 @@ static inline void qxl_push_free_res(PCIQXLDevice *d, int flush) + } + + SPICE_RING_PUSH(ring, notify); +- dprint(d, 2, "free: push %d items, notify %s, ring %d/%d [%d,%d]\n", +- d->num_free_res, notify ? "yes" : "no", +- ring->prod - ring->cons, ring->num_items, +- ring->prod, ring->cons); ++ trace_qxl_ring_res_push(d->id, qxl_mode_to_string(d->mode), ++ d->guest_surfaces.count, d->num_free_res, ++ d->last_release, notify ? "yes" : "no"); ++ trace_qxl_ring_res_push_rest(d->id, ring->prod - ring->cons, ++ ring->num_items, ring->prod, ring->cons); + if (notify) { + qxl_send_events(d, QXL_INTERRUPT_DISPLAY); + } +@@ -645,7 +663,7 @@ static void interface_release_resource(QXLInstance *sin, + } + qxl->last_release = ext.info; + qxl->num_free_res++; +- dprint(qxl, 3, "%4d\r", qxl->num_free_res); ++ trace_qxl_ring_res_put(qxl->id, qxl->num_free_res); + qxl_push_free_res(qxl, 0); + } + +@@ -657,6 +675,8 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * + QXLCommand *cmd; + int notify; + ++ trace_qxl_ring_cursor_check(qxl->id, qxl_mode_to_string(qxl->mode)); ++ + switch (qxl->mode) { + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: +@@ -680,6 +700,7 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * + if (qxl->id == 0) { + qxl_render_cursor(qxl, ext); + } ++ trace_qxl_ring_cursor_get(qxl->id, qxl_mode_to_string(qxl->mode)); + return true; + default: + return false; +@@ -692,6 +713,7 @@ static int interface_req_cursor_notification(QXLInstance *sin) + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + int wait = 1; + ++ trace_qxl_ring_cursor_req_notification(qxl->id); + switch (qxl->mode) { + case QXL_MODE_COMPAT: + case QXL_MODE_NATIVE: +@@ -719,7 +741,6 @@ static int interface_flush_resources(QXLInstance *sin) + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + int ret; + +- dprint(qxl, 1, "free: guest flush (have %d)\n", qxl->num_free_res); + ret = qxl->num_free_res; + if (ret) { + qxl_push_free_res(qxl, 1); +@@ -739,7 +760,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + qxl->current_async = QXL_UNDEFINED_IO; + qemu_mutex_unlock(&qxl->async_lock); + +- dprint(qxl, 2, "async_complete: %d (%p) done\n", current_async, cookie); ++ trace_qxl_interface_async_complete_io(qxl->id, current_async, cookie); + if (!cookie) { + fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__); + return; +@@ -785,11 +806,15 @@ static void interface_update_area_complete(QXLInstance *sin, + qemu_mutex_unlock(&qxl->ssd.lock); + return; + } ++ trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left, ++ dirty->right, dirty->top, dirty->bottom); ++ trace_qxl_interface_update_area_complete_rest(qxl->id, num_updated_rects); + if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) { + /* + * overflow - treat this as a full update. Not expected to be common. + */ +- dprint(qxl, 1, "%s: overflow of dirty rects\n", __func__); ++ trace_qxl_interface_update_area_complete_overflow(qxl->id, ++ QXL_NUM_DIRTY_RECTS); + qxl->guest_primary.resized = 1; + } + if (qxl->guest_primary.resized) { +@@ -805,8 +830,8 @@ static void interface_update_area_complete(QXLInstance *sin, + qxl->dirty[qxl_i++] = dirty[i]; + } + qxl->num_dirty_rects += num_updated_rects; +- dprint(qxl, 1, "%s: scheduling update_area_bh, #dirty %d\n", +- __func__, qxl->num_dirty_rects); ++ trace_qxl_interface_update_area_complete_schedule_bh(qxl->id, ++ qxl->num_dirty_rects); + qemu_bh_schedule(qxl->update_area_bh); + qemu_mutex_unlock(&qxl->ssd.lock); + } +@@ -860,7 +885,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) + if (d->mode == QXL_MODE_VGA) { + return; + } +- dprint(d, 1, "%s\n", __FUNCTION__); ++ trace_qxl_enter_vga_mode(d->id); + qemu_spice_create_host_primary(&d->ssd); + d->mode = QXL_MODE_VGA; + memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); +@@ -871,7 +896,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d) + if (d->mode != QXL_MODE_VGA) { + return; + } +- dprint(d, 1, "%s\n", __FUNCTION__); ++ trace_qxl_exit_vga_mode(d->id); + qxl_destroy_primary(d, QXL_SYNC); + } + +@@ -908,7 +933,7 @@ static void qxl_reset_state(PCIQXLDevice *d) + + static void qxl_soft_reset(PCIQXLDevice *d) + { +- dprint(d, 1, "%s:\n", __FUNCTION__); ++ trace_qxl_soft_reset(d->id); + qxl_check_state(d); + + if (d->id == 0) { +@@ -920,8 +945,7 @@ static void qxl_soft_reset(PCIQXLDevice *d) + + static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) + { +- dprint(d, 1, "%s: start%s\n", __FUNCTION__, +- loadvm ? " (loadvm)" : ""); ++ trace_qxl_hard_reset(d->id, loadvm); + + qxl_spice_reset_cursor(d); + qxl_spice_reset_image_cache(d); +@@ -936,13 +960,12 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) + } + qemu_spice_create_host_memslot(&d->ssd); + qxl_soft_reset(d); +- +- dprint(d, 1, "%s: done\n", __FUNCTION__); + } + + static void qxl_reset_handler(DeviceState *dev) + { + PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev); ++ + qxl_hard_reset(d, 0); + } + +@@ -951,8 +974,8 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) + VGACommonState *vga = opaque; + PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga); + ++ trace_qxl_io_write_vga(qxl->id, qxl_mode_to_string(qxl->mode), addr, val); + if (qxl->mode != QXL_MODE_VGA) { +- dprint(qxl, 1, "%s\n", __FUNCTION__); + qxl_destroy_primary(qxl, QXL_SYNC); + qxl_soft_reset(qxl); + } +@@ -992,9 +1015,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start); + guest_end = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end); + +- dprint(d, 1, "%s: slot %d: guest phys 0x%" PRIx64 " - 0x%" PRIx64 "\n", +- __FUNCTION__, slot_id, +- guest_start, guest_end); ++ trace_qxl_memslot_add_guest(d->id, slot_id, guest_start, guest_end); + + PANIC_ON(slot_id >= NUM_MEMSLOTS); + PANIC_ON(guest_start > guest_end); +@@ -1040,10 +1061,6 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + memslot.generation = d->rom->slot_generation = 0; + qxl_rom_set_dirty(d); + +- dprint(d, 1, "%s: slot %d: host virt 0x%lx - 0x%lx\n", +- __FUNCTION__, memslot.slot_id, +- memslot.virt_start, memslot.virt_end); +- + qemu_spice_add_memslot(&d->ssd, &memslot, async); + d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; + d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; +@@ -1053,21 +1070,19 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + + static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) + { +- dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id); + qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id); + d->guest_slots[slot_id].active = 0; + } + + static void qxl_reset_memslots(PCIQXLDevice *d) + { +- dprint(d, 1, "%s:\n", __FUNCTION__); + qxl_spice_reset_memslots(d); + memset(&d->guest_slots, 0, sizeof(d->guest_slots)); + } + + static void qxl_reset_surfaces(PCIQXLDevice *d) + { +- dprint(d, 1, "%s:\n", __FUNCTION__); ++ trace_qxl_reset_surfaces(d->id); + d->mode = QXL_MODE_UNDEFINED; + qxl_spice_destroy_surfaces(d, QXL_SYNC); + } +@@ -1109,9 +1124,6 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, + assert(qxl->mode != QXL_MODE_NATIVE); + qxl_exit_vga_mode(qxl); + +- dprint(qxl, 1, "%s: %dx%d\n", __FUNCTION__, +- le32_to_cpu(sc->width), le32_to_cpu(sc->height)); +- + surface.format = le32_to_cpu(sc->format); + surface.height = le32_to_cpu(sc->height); + surface.mem = le64_to_cpu(sc->mem); +@@ -1120,6 +1132,10 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, + surface.width = le32_to_cpu(sc->width); + surface.type = le32_to_cpu(sc->type); + surface.flags = le32_to_cpu(sc->flags); ++ trace_qxl_create_guest_primary(qxl->id, sc->width, sc->height, sc->mem, ++ sc->format, sc->position); ++ trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type, ++ sc->flags); + + surface.mouse_mode = true; + surface.group_id = MEMSLOT_GROUP_GUEST; +@@ -1143,7 +1159,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) + if (d->mode == QXL_MODE_UNDEFINED) { + return 0; + } +- dprint(d, 1, "%s\n", __FUNCTION__); ++ trace_qxl_destroy_primary(d->id); + d->mode = QXL_MODE_UNDEFINED; + qemu_spice_destroy_primary_surface(&d->ssd, 0, async); + qxl_spice_reset_cursor(d); +@@ -1170,8 +1186,8 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) + .mem = devmem + d->shadow_rom.draw_area_offset, + }; + +- dprint(d, 1, "%s: mode %d [ %d x %d @ %d bpp devmem 0x%" PRIx64 " ]\n", +- __func__, modenr, mode->x_res, mode->y_res, mode->bits, devmem); ++ trace_qxl_set_mode(d->id, modenr, mode->x_res, mode->y_res, mode->bits, ++ devmem); + if (!loadvm) { + qxl_hard_reset(d, 0); + } +@@ -1217,8 +1233,8 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + if (d->mode != QXL_MODE_VGA) { + break; + } +- dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", +- __func__, io_port, io_port_to_string(io_port)); ++ trace_qxl_io_unexpected_vga_mode(d->id, ++ io_port, io_port_to_string(io_port)); + /* be nice to buggy guest drivers */ + if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && + io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) { +@@ -1260,11 +1276,12 @@ async_common: + } + d->current_async = orig_io_port; + qemu_mutex_unlock(&d->async_lock); +- dprint(d, 2, "start async %d (%"PRId64")\n", io_port, val); + break; + default: + break; + } ++ trace_qxl_io_write(d->id, qxl_mode_to_string(d->mode), addr, val, size, ++ async); + + switch (io_port) { + case QXL_IO_UPDATE_AREA: +@@ -1300,7 +1317,6 @@ async_common: + d->oom_running = 0; + break; + case QXL_IO_SET_MODE: +- dprint(d, 1, "QXL_SET_MODE %d\n", (int)val); + qxl_set_mode(d, val, 0); + break; + case QXL_IO_LOG: +@@ -1310,7 +1326,6 @@ async_common: + } + break; + case QXL_IO_RESET: +- dprint(d, 1, "QXL_IO_RESET\n"); + qxl_hard_reset(d, 0); + break; + case QXL_IO_MEMSLOT_ADD: +@@ -1338,7 +1353,6 @@ async_common: + async); + goto cancel_async; + } +- dprint(d, 1, "QXL_IO_CREATE_PRIMARY async=%d\n", async); + d->guest_primary.surface = d->ram->create_surface; + qxl_create_guest_primary(d, 0, async); + break; +@@ -1348,11 +1362,9 @@ async_common: + async); + goto cancel_async; + } +- dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (async=%d) (%s)\n", async, +- qxl_mode_to_string(d->mode)); + if (!qxl_destroy_primary(d, async)) { +- dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC in %s, ignored\n", +- qxl_mode_to_string(d->mode)); ++ trace_qxl_io_destroy_primary_ignored(d->id, ++ qxl_mode_to_string(d->mode)); + goto cancel_async; + } + break; +@@ -1372,16 +1384,9 @@ async_common: + ring->prod, ring->cons); + } + qxl_push_free_res(d, 1 /* flush */); +- dprint(d, 1, "QXL_IO_FLUSH_RELEASE exit (%s, s#=%d, res#=%d,%p)\n", +- qxl_mode_to_string(d->mode), d->guest_surfaces.count, +- d->num_free_res, d->last_release); + break; + } + case QXL_IO_FLUSH_SURFACES_ASYNC: +- dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC" +- " (%"PRId64") (%s, s#=%d, res#=%d)\n", +- val, qxl_mode_to_string(d->mode), d->guest_surfaces.count, +- d->num_free_res); + qxl_spice_flush_surfaces_async(d); + break; + case QXL_IO_DESTROY_ALL_SURFACES: +@@ -1407,7 +1412,7 @@ static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, + { + PCIQXLDevice *d = opaque; + +- dprint(d, 1, "%s: unexpected\n", __FUNCTION__); ++ trace_qxl_io_read_unexpected(d->id); + return 0xff; + } + +@@ -1558,8 +1563,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) + surface_offset -= vram_start; + surface_size = cmd->u.surface_create.height * + abs(cmd->u.surface_create.stride); +- dprint(qxl, 3, "%s: dirty surface %d, offset %d, size %d\n", __func__, +- i, (int)surface_offset, surface_size); ++ trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size); + qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size); + } + } +@@ -1759,7 +1763,7 @@ static void qxl_pre_save(void *opaque) + PCIQXLDevice* d = opaque; + uint8_t *ram_start = d->vga.vram_ptr; + +- dprint(d, 1, "%s:\n", __FUNCTION__); ++ trace_qxl_pre_save(d->id); + if (d->last_release == NULL) { + d->last_release_offset = 0; + } else { +@@ -1772,10 +1776,9 @@ static int qxl_pre_load(void *opaque) + { + PCIQXLDevice* d = opaque; + +- dprint(d, 1, "%s: start\n", __FUNCTION__); ++ trace_qxl_pre_load(d->id); + qxl_hard_reset(d, 1); + qxl_exit_vga_mode(d); +- dprint(d, 1, "%s: done\n", __FUNCTION__); + return 0; + } + +@@ -1787,7 +1790,6 @@ static void qxl_create_memslots(PCIQXLDevice *d) + if (!d->guest_slots[i].active) { + continue; + } +- dprint(d, 1, "%s: restoring guest slot %d\n", __func__, i); + qxl_add_memslot(d, i, 0, QXL_SYNC); + } + } +@@ -1799,8 +1801,6 @@ static int qxl_post_load(void *opaque, int version) + QXLCommandExt *cmds; + int in, out, newmode; + +- dprint(d, 1, "%s: start\n", __FUNCTION__); +- + assert(d->last_release_offset < d->vga.vram_size); + if (d->last_release_offset == 0) { + d->last_release = NULL; +@@ -1810,8 +1810,7 @@ static int qxl_post_load(void *opaque, int version) + + d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset); + +- dprint(d, 1, "%s: restore mode (%s)\n", __FUNCTION__, +- qxl_mode_to_string(d->mode)); ++ trace_qxl_post_load(d->id, qxl_mode_to_string(d->mode)); + newmode = d->mode; + d->mode = QXL_MODE_UNDEFINED; + +@@ -1853,8 +1852,6 @@ static int qxl_post_load(void *opaque, int version) + qxl_set_mode(d, d->shadow_rom.mode, 1); + break; + } +- dprint(d, 1, "%s: done\n", __FUNCTION__); +- + return 0; + } + +diff --git a/trace-events b/trace-events +index e417897..2c7d5a3 100644 +--- a/trace-events ++++ b/trace-events +@@ -631,3 +631,62 @@ win_helper_no_switch_pstate(uint32_t new_pstate_regs) "change_pstate: regs new=% + win_helper_wrpil(uint32_t psrpil, uint32_t new_pil) "old=%x new=%x" + win_helper_done(uint32_t tl) "tl=%d" + win_helper_retry(uint32_t tl) "tl=%d" ++ ++# hw/qxl.c ++disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d" ++disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u" ++qxl_create_guest_primary(int qid, uint32_t width, uint32_t height, uint64_t mem, uint32_t format, uint32_t position) "%d %dx%d mem=%lx %d,%d" ++qxl_create_guest_primary_rest(int qid, int32_t stride, uint32_t type, uint32_t flags) "%d %d,%d,%d" ++qxl_destroy_primary(int qid) "%d" ++qxl_enter_vga_mode(int qid) "%d" ++qxl_exit_vga_mode(int qid) "%d" ++qxl_hard_reset(int qid, int64_t loadvm) "%d loadvm=%"PRId64"" ++qxl_interface_async_complete_io(int qid, uint32_t current_async, void *cookie) "%d current=%d cookie=%p" ++qxl_interface_attach_worker(int qid) "%d" ++qxl_interface_get_init_info(int qid) "%d" ++qxl_interface_set_compression_level(int qid, int64_t level) "%d %"PRId64 ++qxl_interface_update_area_complete(int qid, uint32_t surface_id, uint32_t dirty_left, uint32_t dirty_right, uint32_t dirty_top, uint32_t dirty_bottom) "%d surface=%d [%d,%d,%d,%d]" ++qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d #=%d" ++qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" ++qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" ++qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" ++qxl_io_read_unexpected(int qid) "%d" ++qxl_io_unexpected_vga_mode(int qid, uint32_t io_port, const char *desc) "%d 0x%x (%s)" ++qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" ++qxl_memslot_add_guest(int qid, uint32_t slot_id, uint64_t guest_start, uint64_t guest_end) "%d %u: guest phys 0x%"PRIx64 " - 0x%" PRIx64 ++qxl_post_load(int qid, const char *mode) "%d %s" ++qxl_pre_load(int qid) "%d" ++qxl_pre_save(int qid) "%d" ++qxl_reset_surfaces(int qid) "%d" ++qxl_ring_command_check(int qid, const char *mode) "%d %s" ++qxl_ring_command_get(int qid, const char *mode) "%d %s" ++qxl_ring_command_req_notification(int qid) "%d" ++qxl_ring_cursor_check(int qid, const char *mode) "%d %s" ++qxl_ring_cursor_get(int qid, const char *mode) "%d %s" ++qxl_ring_cursor_req_notification(int qid) "%d" ++qxl_ring_res_push(int qid, const char *mode, uint32_t surface_count, uint32_t free_res, void *last_release, const char *notify) "%d %s s#=%d res#=%d last=%p notify=%s" ++qxl_ring_res_push_rest(int qid, uint32_t ring_has, uint32_t ring_size, uint32_t prod, uint32_t cons) "%d ring %d/%d [%d,%d]" ++qxl_ring_res_put(int qid, uint32_t free_res) "%d #res=%d" ++qxl_set_mode(int qid, int modenr, uint32_t x_res, uint32_t y_res, uint32_t bits, uint64_t devmem) "%d mode=%d [ x=%d y=%d @ bpp=%d devmem=0x%" PRIx64 " ]" ++qxl_soft_reset(int qid) "%d" ++qemu_spice_add_memslot(int qid, uint32_t slot_id, unsigned long virt_start, unsigned long virt_end, int async) "%d %u: host virt 0x%lx - 0x%lx async=%d" ++qemu_spice_del_memslot(int qid, uint32_t gid, uint32_t slot_id) "%d gid=%u sid=%u" ++qemu_spice_create_primary_surface(int qid, uint32_t sid, void *surface, int async) "%d sid=%u surface=%p async=%d" ++qemu_spice_destroy_primary_surface(int qid, uint32_t sid, int async) "%d sid=%u async=%d" ++qemu_spice_wakeup(uint32_t qid) "%d" ++qemu_spice_start(uint32_t qid) "%d" ++qemu_spice_stop(uint32_t qid) "%d" ++qemu_spice_create_update(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "lr %d -> %d, tb -> %d -> %d" ++qxl_spice_destroy_surfaces_complete(int qid) "%d" ++qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d" ++qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d" ++qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d" ++qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d" ++qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d" ++qxl_spice_oom(int qid) "%d" ++qxl_spice_reset_cursor(int qid) "%d" ++qxl_spice_reset_image_cache(int qid) "%d" ++qxl_spice_reset_memslots(int qid) "%d" ++qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" ++qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" ++qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" +diff --git a/ui/spice-display.c b/ui/spice-display.c +index ab266ae..28d6d4a 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -22,6 +22,7 @@ + #include "monitor.h" + #include "console.h" + #include "sysemu.h" ++#include "trace.h" + + #include "spice-display.h" + +@@ -73,6 +74,10 @@ QXLCookie *qxl_cookie_new(int type, uint64_t io) + void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + qxl_async_io async) + { ++ trace_qemu_spice_add_memslot(ssd->qxl.id, memslot->slot_id, ++ memslot->virt_start, memslot->virt_end, ++ async); ++ + if (async != QXL_SYNC) { + spice_qxl_add_memslot_async(&ssd->qxl, memslot, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +@@ -84,6 +89,7 @@ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + + void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) + { ++ trace_qemu_spice_del_memslot(ssd->qxl.id, gid, sid); + ssd->worker->del_memslot(ssd->worker, gid, sid); + } + +@@ -91,6 +97,7 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + QXLDevSurfaceCreate *surface, + qxl_async_io async) + { ++ trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async); + if (async != QXL_SYNC) { + spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +@@ -100,10 +107,10 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + } + } + +- + void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + uint32_t id, qxl_async_io async) + { ++ trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async); + if (async != QXL_SYNC) { + spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, + (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +@@ -115,16 +122,19 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + + void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) + { ++ trace_qemu_spice_wakeup(ssd->qxl.id); + ssd->worker->wakeup(ssd->worker); + } + + void qemu_spice_start(SimpleSpiceDisplay *ssd) + { ++ trace_qemu_spice_start(ssd->qxl.id); + ssd->worker->start(ssd->worker); + } + + void qemu_spice_stop(SimpleSpiceDisplay *ssd) + { ++ trace_qemu_spice_stop(ssd->qxl.id); + ssd->worker->stop(ssd->worker); + } + +@@ -142,7 +152,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + return NULL; + }; + +- dprint(2, "%s: lr %d -> %d, tb -> %d -> %d\n", __FUNCTION__, ++ trace_qemu_spice_create_update( + ssd->dirty.left, ssd->dirty.right, + ssd->dirty.top, ssd->dirty.bottom); + diff --git a/0125-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch b/0125-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch deleted file mode 100644 index 516b431..0000000 --- a/0125-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch +++ /dev/null @@ -1,33 +0,0 @@ -From ddb24b5063e3b4c90295bd4ddaab3bfc428ae79b Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sun, 26 Feb 2012 15:51:50 +0100 -Subject: [PATCH 125/140] usb-redir: Return USB_RET_NAK when we've no data for - an interrupt endpoint - -We should return USB_RET_NAK, rather then a 0 sized packet, when we've no data -for an interrupt IN endpoint. - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/usb-redir.c b/usb-redir.c -index c76e55d..629c87d 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -558,7 +558,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, - /* Check interrupt_error for stream errors */ - status = dev->endpoint[EP2I(ep)].interrupt_error; - dev->endpoint[EP2I(ep)].interrupt_error = 0; -- return usbredir_handle_status(dev, status, 0); -+ if (status) { -+ return usbredir_handle_status(dev, status, 0); -+ } -+ return USB_RET_NAK; - } - DPRINTF("interrupt-token-in ep %02X status %d len %d\n", ep, - intp->status, intp->len); --- -1.7.9.3 - diff --git a/0126-qxl-qxl_render.c-add-trace-events.patch b/0126-qxl-qxl_render.c-add-trace-events.patch new file mode 100644 index 0000000..bdf4425 --- /dev/null +++ b/0126-qxl-qxl_render.c-add-trace-events.patch @@ -0,0 +1,92 @@ +From d1ca7c3e651d40b5d3431806d1e47c524cf6ecb8 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Sun, 18 Mar 2012 13:46:15 +0100 +Subject: [PATCH] qxl/qxl_render.c: add trace events + +Signed-off-by: Alon Levy +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Gerd Hoffmann + +Cherry-pick: Added missing include "trace.h" +--- + hw/qxl-render.c | 14 +++++--------- + trace-events | 7 +++++++ + 2 files changed, 12 insertions(+), 9 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 2e10e93..835dc5e 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -20,6 +20,7 @@ + */ + + #include "qxl.h" ++#include "trace.h" + + static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) + { +@@ -31,11 +32,10 @@ static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) + return; + } + if (!qxl->guest_primary.data) { +- dprint(qxl, 1, "%s: initializing guest_primary.data\n", __func__); ++ trace_qxl_render_blit_guest_primary_initialized(); + qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); + } +- dprint(qxl, 2, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, +- qxl->guest_primary.qxl_stride, ++ trace_qxl_render_blit(qxl->guest_primary.qxl_stride, + rect->left, rect->right, rect->top, rect->bottom); + src = qxl->guest_primary.data; + if (qxl->guest_primary.qxl_stride < 0) { +@@ -107,8 +107,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); + qxl_set_rect_to_surface(qxl, &qxl->dirty[0]); + qxl->num_dirty_rects = 1; +- dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d\n", +- __FUNCTION__, ++ trace_qxl_render_guest_primary_resized( + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, + qxl->guest_primary.qxl_stride, +@@ -118,8 +117,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + if (surface->width != qxl->guest_primary.surface.width || + surface->height != qxl->guest_primary.surface.height) { + if (qxl->guest_primary.qxl_stride > 0) { +- dprint(qxl, 1, "%s: using guest_primary for displaysurface\n", +- __func__); + qemu_free_displaysurface(vga->ds); + qemu_create_displaysurface_from(qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height, +@@ -127,8 +124,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + qxl->guest_primary.abs_stride, + qxl->guest_primary.data); + } else { +- dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", +- __func__); + qemu_resize_displaysurface(vga->ds, + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height); +@@ -187,6 +182,7 @@ void qxl_render_update_area_bh(void *opaque) + void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie) + { + qemu_mutex_lock(&qxl->ssd.lock); ++ trace_qxl_render_update_area_done(cookie); + qemu_bh_schedule(qxl->update_area_bh); + qxl->render_update_cookie_num--; + qemu_mutex_unlock(&qxl->ssd.lock); +diff --git a/trace-events b/trace-events +index 2c7d5a3..d21e832 100644 +--- a/trace-events ++++ b/trace-events +@@ -690,3 +690,10 @@ qxl_spice_reset_memslots(int qid) "%d" + qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" + qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" + qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" ++qxl_vga_ioport_while_not_in_vga_mode(int qid) "%d (int qid, reset to VGA mode because of VGA io)" ++ ++# hw/qxl-render.c ++qxl_render_blit_guest_primary_initialized(void) "" ++qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]" ++qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d" ++qxl_render_update_area_done(void *cookie) "%p" diff --git a/0126-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch b/0126-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch deleted file mode 100644 index 7c3c59d..0000000 --- a/0126-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 7a3acb928b617b33605c779e7df05c2c896844b1 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 20 Feb 2012 16:27:47 +0100 -Subject: [PATCH 126/140] usb-ehci: Handle ISO packets failing with an error - other then NAK - -Before this patch the ehci code was not checking for any other errors other -then USB_RET_NAK. This causes 2 problems: -1) Other errors are not reported to the guest. -2) When transactions with the ITD_XACT_IOC bit set completing with another - error would not result in USBSTS_INT getting set. - -I hit this problem when unplugging devices while iso data was streaming from -the device to the guest. When this happens it takes a while for the guest to -process the unplugging and remove ISO transactions from the ehci schedule, in -the mean time these transactions would complete with a result of USB_RET_NODEV, -which was not handled. This lead to the Linux guest's usb subsystem "hanging", -that is it would no longer see new usb devices getting plugged in and running -for example lsusb would lead to a stuck (D state) lsusb process. This patch -fixes this. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 22 +++++++++++++++++++--- - 1 file changed, 19 insertions(+), 3 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index 69bcc4b..a6b6ae5 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -1512,11 +1512,27 @@ static int ehci_process_itd(EHCIState *ehci, - /* IN */ - set_field(&itd->transact[i], ret, ITD_XACT_LENGTH); - } -- -- if (itd->transact[i] & ITD_XACT_IOC) { -- ehci_record_interrupt(ehci, USBSTS_INT); -+ } else { -+ switch (ret) { -+ default: -+ fprintf(stderr, "Unexpected iso usb result: %d\n", ret); -+ /* Fall through */ -+ case USB_RET_NODEV: -+ /* 3.3.2: XACTERR is only allowed on IN transactions */ -+ if (dir) { -+ itd->transact[i] |= ITD_XACT_XACTERR; -+ ehci_record_interrupt(ehci, USBSTS_ERRINT); -+ } -+ break; -+ case USB_RET_BABBLE: -+ itd->transact[i] |= ITD_XACT_BABBLE; -+ ehci_record_interrupt(ehci, USBSTS_ERRINT); -+ break; - } - } -+ if (itd->transact[i] & ITD_XACT_IOC) { -+ ehci_record_interrupt(ehci, USBSTS_INT); -+ } - itd->transact[i] &= ~ITD_XACT_ACTIVE; - } - } --- -1.7.9.3 - diff --git a/0127-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch b/0127-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch new file mode 100644 index 0000000..d35a9d7 --- /dev/null +++ b/0127-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch @@ -0,0 +1,77 @@ +From 12d059c0284e5d5c0959209aeeac73a73d3e0469 Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 16 Mar 2012 13:50:04 +0000 +Subject: [PATCH] hw/qxl.c: Fix compilation failures on 32 bit hosts + +Fix compilation failures on 32 bit hosts (cast from pointer to +integer of different size; %ld expects 'long int' not uint64_t). + +Reported-by: Steve Langasek +Signed-off-by: Peter Maydell +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 813873a..bcdf274 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -154,7 +154,7 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, + } else { + assert(cookie != NULL); + spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, +- clear_dirty_region, (uint64_t)cookie); ++ clear_dirty_region, (uintptr_t)cookie); + } + } + +@@ -178,7 +178,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_DESTROY_SURFACE_ASYNC); + cookie->u.surface_id = id; +- spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uint64_t)cookie); ++ spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie); + } else { + qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); + } +@@ -189,8 +189,8 @@ static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) + trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count, + qxl->num_free_res); + spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, +- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_FLUSH_SURFACES_ASYNC)); ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_FLUSH_SURFACES_ASYNC)); + } + + void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, +@@ -226,8 +226,8 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) + trace_qxl_spice_destroy_surfaces(qxl->id, async); + if (async) { + spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, +- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_DESTROY_ALL_SURFACES_ASYNC)); ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_DESTROY_ALL_SURFACES_ASYNC)); + } else { + qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); + qxl_spice_destroy_surfaces_complete(qxl); +@@ -767,7 +767,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + } + if (cookie && current_async != cookie->io) { + fprintf(stderr, +- "qxl: %s: error: current_async = %d != %ld = cookie->io\n", ++ "qxl: %s: error: current_async = %d != %" PRId64 " = cookie->io\n", + __func__, current_async, cookie->io); + } + switch (current_async) { +@@ -840,7 +840,7 @@ static void interface_update_area_complete(QXLInstance *sin, + static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); +- QXLCookie *cookie = (QXLCookie *)cookie_token; ++ QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token; + + switch (cookie->type) { + case QXL_COOKIE_TYPE_IO: diff --git a/0127-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch b/0127-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch deleted file mode 100644 index e437048..0000000 --- a/0127-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch +++ /dev/null @@ -1,61 +0,0 @@ -From 82e500c24a026323e0b8b869e227cc68b179fb11 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 27 Feb 2012 11:44:52 +0100 -Subject: [PATCH 127/140] usb-ehci: Never follow table entries with the T-bit - set - -Before this patch the T-bit was not checked in 2 places, while it should be. - -Once we properly check the T-bit everywhere we no longer need the weird -entry < 0x1000 and entry > 0x1000 checks, so this patch removes them. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 10 ++++------ - 1 file changed, 4 insertions(+), 6 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index a6b6ae5..37076a9 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -1596,8 +1596,7 @@ static int ehci_state_fetchentry(EHCIState *ehci, int async) - int again = 0; - uint32_t entry = ehci_get_fetch_addr(ehci, async); - -- if (entry < 0x1000) { -- DPRINTF("fetchentry: entry invalid (0x%08x)\n", entry); -+ if (NLPTR_TBIT(entry)) { - ehci_set_state(ehci, async, EST_ACTIVE); - goto out; - } -@@ -1705,7 +1704,8 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) - if (q->qh.token & QTD_TOKEN_HALT) { - ehci_set_state(ehci, async, EST_HORIZONTALQH); - -- } else if ((q->qh.token & QTD_TOKEN_ACTIVE) && (q->qh.current_qtd > 0x1000)) { -+ } else if ((q->qh.token & QTD_TOKEN_ACTIVE) && -+ (NLPTR_TBIT(q->qh.current_qtd) == 0)) { - q->qtdaddr = q->qh.current_qtd; - ehci_set_state(ehci, async, EST_FETCHQTD); - -@@ -1784,7 +1784,6 @@ static int ehci_state_advqueue(EHCIQueue *q, int async) - * want data and alt-next qTD is valid - */ - if (((q->qh.token & QTD_TOKEN_TBYTES_MASK) != 0) && -- (q->qh.altnext_qtd > 0x1000) && - (NLPTR_TBIT(q->qh.altnext_qtd) == 0)) { - q->qtdaddr = q->qh.altnext_qtd; - ehci_set_state(q->ehci, async, EST_FETCHQTD); -@@ -1792,8 +1791,7 @@ static int ehci_state_advqueue(EHCIQueue *q, int async) - /* - * next qTD is valid - */ -- } else if ((q->qh.next_qtd > 0x1000) && -- (NLPTR_TBIT(q->qh.next_qtd) == 0)) { -+ } else if (NLPTR_TBIT(q->qh.next_qtd) == 0) { - q->qtdaddr = q->qh.next_qtd; - ehci_set_state(q->ehci, async, EST_FETCHQTD); - --- -1.7.9.3 - diff --git a/0128-spice-fix-broken-initialization.patch b/0128-spice-fix-broken-initialization.patch new file mode 100644 index 0000000..03e5f1e --- /dev/null +++ b/0128-spice-fix-broken-initialization.patch @@ -0,0 +1,64 @@ +From 3e9665b4c19038e4bbfe22ea140181daf7adf025 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 14 Mar 2012 20:33:37 +0200 +Subject: [PATCH] spice: fix broken initialization + +Commit 1b71f7c14fab6f00c2680d4489fbee7baf796e4f moved MODULE_INIT_QOM to +way before MODULE_INIT_MACHINE, thereby breaking assumptions made in +spice-core.c which registered both a type initializer and a machine +intializer. + +This fix removes the type registration, and replaces it with calling +qemu_spice_init in vl.c after command line parsing (second pass) is +done, and after timers are armed, required by spice server. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann + +Conflicts: + + ui/spice-core.c +--- + ui/spice-core.c | 8 +------- + vl.c | 5 +++++ + 2 files changed, 6 insertions(+), 7 deletions(-) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 4ad0a67..a468524 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -554,7 +554,7 @@ void qemu_spice_init(void) + + qemu_thread_get_self(&me); + +- if (!opts) { ++ if (!opts) { + return; + } + port = qemu_opt_get_number(opts, "port", 0); +@@ -787,9 +787,3 @@ static void spice_register_config(void) + qemu_add_opts(&qemu_spice_opts); + } + machine_init(spice_register_config); +- +-static void spice_initialize(void) +-{ +- qemu_spice_init(); +-} +-device_init(spice_initialize); +diff --git a/vl.c b/vl.c +index fdefa86..d33eb03 100644 +--- a/vl.c ++++ b/vl.c +@@ -3271,6 +3271,11 @@ int main(int argc, char **argv, char **envp) + exit(1); + } + ++#ifdef CONFIG_SPICE ++ /* spice needs the timers to be initialized by this point */ ++ qemu_spice_init(); ++#endif ++ + if (icount_option && (kvm_enabled() || xen_enabled())) { + fprintf(stderr, "-icount is not allowed with kvm or xen\n"); + exit(1); diff --git a/0128-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch b/0128-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch deleted file mode 100644 index 6272c84..0000000 --- a/0128-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch +++ /dev/null @@ -1,219 +0,0 @@ -From 0f1e5b8d4f36de8b6b1301740226c9858b5a0318 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 28 Feb 2012 16:34:38 +0100 -Subject: [PATCH 128/140] usb-ehci: split our qh queue into async and periodic - queues - -qhs can be part of both the async and the periodic schedule, as is shown -in later patches in this series it is useful to keep track of the qhs on -a per schedule basis. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 62 ++++++++++++++++++++++++++++++++++----------------------- - 1 file changed, 37 insertions(+), 25 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index 37076a9..980cce3 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -347,7 +347,6 @@ enum async_state { - struct EHCIQueue { - EHCIState *ehci; - QTAILQ_ENTRY(EHCIQueue) next; -- bool async_schedule; - uint32_t seen; - uint64_t ts; - -@@ -367,6 +366,8 @@ struct EHCIQueue { - int usb_status; - }; - -+typedef QTAILQ_HEAD(EHCIQueueHead, EHCIQueue) EHCIQueueHead; -+ - struct EHCIState { - PCIDevice dev; - USBBus bus; -@@ -410,7 +411,8 @@ struct EHCIState { - USBPort ports[NB_PORTS]; - USBPort *companion_ports[NB_PORTS]; - uint32_t usbsts_pending; -- QTAILQ_HEAD(, EHCIQueue) queues; -+ EHCIQueueHead aqueues; -+ EHCIQueueHead pqueues; - - uint32_t a_fetch_addr; // which address to look at next - uint32_t p_fetch_addr; // which address to look at next -@@ -660,31 +662,34 @@ static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr, - - static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, int async) - { -+ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; - EHCIQueue *q; - - q = g_malloc0(sizeof(*q)); - q->ehci = ehci; -- q->async_schedule = async; -- QTAILQ_INSERT_HEAD(&ehci->queues, q, next); -+ QTAILQ_INSERT_HEAD(head, q, next); - trace_usb_ehci_queue_action(q, "alloc"); - return q; - } - --static void ehci_free_queue(EHCIQueue *q) -+static void ehci_free_queue(EHCIQueue *q, int async) - { -+ EHCIQueueHead *head = async ? &q->ehci->aqueues : &q->ehci->pqueues; - trace_usb_ehci_queue_action(q, "free"); - if (q->async == EHCI_ASYNC_INFLIGHT) { - usb_cancel_packet(&q->packet); - } -- QTAILQ_REMOVE(&q->ehci->queues, q, next); -+ QTAILQ_REMOVE(head, q, next); - g_free(q); - } - --static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr) -+static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, -+ int async) - { -+ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; - EHCIQueue *q; - -- QTAILQ_FOREACH(q, &ehci->queues, next) { -+ QTAILQ_FOREACH(q, head, next) { - if (addr == q->qhaddr) { - return q; - } -@@ -692,11 +697,12 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr) - return NULL; - } - --static void ehci_queues_rip_unused(EHCIState *ehci) -+static void ehci_queues_rip_unused(EHCIState *ehci, int async) - { -+ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; - EHCIQueue *q, *tmp; - -- QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { -+ QTAILQ_FOREACH_SAFE(q, head, next, tmp) { - if (q->seen) { - q->seen = 0; - q->ts = ehci->last_run_ns; -@@ -706,28 +712,30 @@ static void ehci_queues_rip_unused(EHCIState *ehci) - /* allow 0.25 sec idle */ - continue; - } -- ehci_free_queue(q); -+ ehci_free_queue(q, async); - } - } - --static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev) -+static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) - { -+ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; - EHCIQueue *q, *tmp; - -- QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { -+ QTAILQ_FOREACH_SAFE(q, head, next, tmp) { - if (q->packet.owner != dev) { - continue; - } -- ehci_free_queue(q); -+ ehci_free_queue(q, async); - } - } - --static void ehci_queues_rip_all(EHCIState *ehci) -+static void ehci_queues_rip_all(EHCIState *ehci, int async) - { -+ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; - EHCIQueue *q, *tmp; - -- QTAILQ_FOREACH_SAFE(q, &ehci->queues, next, tmp) { -- ehci_free_queue(q); -+ QTAILQ_FOREACH_SAFE(q, head, next, tmp) { -+ ehci_free_queue(q, async); - } - } - -@@ -772,7 +780,8 @@ static void ehci_detach(USBPort *port) - return; - } - -- ehci_queues_rip_device(s, port->dev); -+ ehci_queues_rip_device(s, port->dev, 0); -+ ehci_queues_rip_device(s, port->dev, 1); - - *portsc &= ~(PORTSC_CONNECT|PORTSC_PED); - *portsc |= PORTSC_CSC; -@@ -792,7 +801,8 @@ static void ehci_child_detach(USBPort *port, USBDevice *child) - return; - } - -- ehci_queues_rip_device(s, child); -+ ehci_queues_rip_device(s, child, 0); -+ ehci_queues_rip_device(s, child, 1); - } - - static void ehci_wakeup(USBPort *port) -@@ -890,7 +900,8 @@ static void ehci_reset(void *opaque) - usb_send_msg(devs[i], USB_MSG_RESET); - } - } -- ehci_queues_rip_all(s); -+ ehci_queues_rip_all(s, 0); -+ ehci_queues_rip_all(s, 1); - } - - static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) -@@ -1554,7 +1565,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) - ehci_set_usbsts(ehci, USBSTS_REC); - } - -- ehci_queues_rip_unused(ehci); -+ ehci_queues_rip_unused(ehci, async); - - /* Find the head of the list (4.9.1.1) */ - for(i = 0; i < MAX_QH; i++) { -@@ -1641,7 +1652,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) - int reload; - - entry = ehci_get_fetch_addr(ehci, async); -- q = ehci_find_queue_by_qh(ehci, entry); -+ q = ehci_find_queue_by_qh(ehci, entry, async); - if (NULL == q) { - q = ehci_alloc_queue(ehci, async); - } -@@ -2092,7 +2103,7 @@ static void ehci_advance_state(EHCIState *ehci, - - static void ehci_advance_async_state(EHCIState *ehci) - { -- int async = 1; -+ const int async = 1; - - switch(ehci_get_state(ehci, async)) { - case EST_INACTIVE: -@@ -2149,7 +2160,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) - { - uint32_t entry; - uint32_t list; -- int async = 0; -+ const int async = 0; - - // 4.6 - -@@ -2366,7 +2377,8 @@ static int usb_ehci_initfn(PCIDevice *dev) - } - - s->frame_timer = qemu_new_timer_ns(vm_clock, ehci_frame_timer, s); -- QTAILQ_INIT(&s->queues); -+ QTAILQ_INIT(&s->aqueues); -+ QTAILQ_INIT(&s->pqueues); - - qemu_register_reset(ehci_reset, s); - --- -1.7.9.3 - diff --git a/0129-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch b/0129-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch new file mode 100644 index 0000000..a938678 --- /dev/null +++ b/0129-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch @@ -0,0 +1,52 @@ +From 32fc9bd666d17f62d331029b4b0bbb0bc21c9bab Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Wed, 7 Mar 2012 13:36:48 +0000 +Subject: [PATCH] ui/spice-display.c: Fix compilation warnings on 32 bit hosts + +Fix compilation failures ("cast from pointer to integer of +different size [-Werror=pointer-to-int-cast]") by using +uintptr_t instead. + +Signed-off-by: Peter Maydell +Signed-off-by: Gerd Hoffmann +--- + ui/spice-display.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 28d6d4a..6d7563f 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -80,8 +80,8 @@ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, + + if (async != QXL_SYNC) { + spice_qxl_add_memslot_async(&ssd->qxl, memslot, +- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_MEMSLOT_ADD_ASYNC)); ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_MEMSLOT_ADD_ASYNC)); + } else { + ssd->worker->add_memslot(ssd->worker, memslot); + } +@@ -100,8 +100,8 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async); + if (async != QXL_SYNC) { + spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, +- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_CREATE_PRIMARY_ASYNC)); ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_CREATE_PRIMARY_ASYNC)); + } else { + ssd->worker->create_primary_surface(ssd->worker, id, surface); + } +@@ -113,8 +113,8 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async); + if (async != QXL_SYNC) { + spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, +- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, +- QXL_IO_DESTROY_PRIMARY_ASYNC)); ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_DESTROY_PRIMARY_ASYNC)); + } else { + ssd->worker->destroy_primary_surface(ssd->worker, id); + } diff --git a/0129-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch b/0129-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch deleted file mode 100644 index 6305ec4..0000000 --- a/0129-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 320063f7165c5a5f9ddd5a09a4663bc1a81f5bd6 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 2 Mar 2012 13:52:44 +0100 -Subject: [PATCH 129/140] usb-ehci: always call ehci_queues_rip_unused for - period queues - -Before this patch USB 2 devices with interrupt endpoints were not working -properly. The problem is that to avoid loops we stop processing as soon -as we encounter a queue-head (qh) we've already seen since qhs can be linked -in a circular fashion, this is tracked by the seen flag in our qh struct. - -The resetting of the seen flag is done from ehci_queues_rip_unused which -before this patch was only called when executing the statemachine for the -async schedule. - -But packets for interrupt endpoints are part of the periodic schedule! So what -would happen is that when there were no ctrl or bulk packets for a USB 2 -device with an interrupt endpoint, the async schedule would become non -active, then ehci_queues_rip_unused would no longer get called and when -processing the qhs for the interrupt endpoints from the periodic schedule -their seen bit would still be 1 and they would be skipped. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index 980cce3..422afc8 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -2195,6 +2195,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) - ehci_set_fetch_addr(ehci, async,entry); - ehci_set_state(ehci, async, EST_FETCHENTRY); - ehci_advance_state(ehci, async); -+ ehci_queues_rip_unused(ehci, async, 0); - break; - - default: --- -1.7.9.3 - diff --git a/0130-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch b/0130-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch new file mode 100644 index 0000000..7ccd26e --- /dev/null +++ b/0130-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch @@ -0,0 +1,75 @@ +From 58f452225db16f00b368ad03ae689cb5dbd09940 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 21 Mar 2012 18:17:18 +0200 +Subject: [PATCH] ui/spice-display: use uintptr_t when casting qxl physical + addresses + +The current intptr_t casts are a problem when the address's highest +bit is 1, and it is cast to a intptr_t and then to uint64_t, such +as at: + surface.mem = (intptr_t)ssd->buf; + +This causes the sign bit to be extended which causes a wrong address to +be passed on to spice, which then complains when it gets the wrong +slot_id number, since the slot_id is taken from the higher bits. + +The assertion happens early - during the first primary surface creation. + +This fixes running "-vga qxl -spice" with 32 bit compiled +qemu-system-i386. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + ui/spice-display.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 6d7563f..cb8a7ad 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -168,7 +168,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + drawable->bbox = ssd->dirty; + drawable->clip.type = SPICE_CLIP_TYPE_NONE; + drawable->effect = QXL_EFFECT_OPAQUE; +- drawable->release_info.id = (intptr_t)update; ++ drawable->release_info.id = (uintptr_t)update; + drawable->type = QXL_DRAW_COPY; + drawable->surfaces_dest[0] = -1; + drawable->surfaces_dest[1] = -1; +@@ -179,7 +179,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + + time_space.tv_nsec / 1000 / 1000; + + drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; +- drawable->u.copy.src_bitmap = (intptr_t)image; ++ drawable->u.copy.src_bitmap = (uintptr_t)image; + drawable->u.copy.src_area.right = bw; + drawable->u.copy.src_area.bottom = bh; + +@@ -189,7 +189,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + image->bitmap.stride = bw * 4; + image->descriptor.width = image->bitmap.x = bw; + image->descriptor.height = image->bitmap.y = bh; +- image->bitmap.data = (intptr_t)(update->bitmap); ++ image->bitmap.data = (uintptr_t)(update->bitmap); + image->bitmap.palette = 0; + image->bitmap.format = SPICE_BITMAP_FMT_32BIT; + +@@ -210,7 +210,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + } + + cmd->type = QXL_CMD_DRAW; +- cmd->data = (intptr_t)drawable; ++ cmd->data = (uintptr_t)drawable; + + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + return update; +@@ -254,7 +254,7 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) + surface.mouse_mode = true; + surface.flags = 0; + surface.type = 0; +- surface.mem = (intptr_t)ssd->buf; ++ surface.mem = (uintptr_t)ssd->buf; + surface.group_id = MEMSLOT_GROUP_HOST; + + qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC); diff --git a/0130-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch b/0130-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch deleted file mode 100644 index fa1b20d..0000000 --- a/0130-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch +++ /dev/null @@ -1,115 +0,0 @@ -From 35562fb521547e081e732453a6395fc00d9ee9e4 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 1 Mar 2012 15:20:17 +0100 -Subject: [PATCH 130/140] usb-ehci: Drop cached qhs when the doorbell gets - rung - -The purpose of the IAAD bit / the doorbell is to make the ehci controller -forget about cached qhs, this is mainly used when cancelling transactions, -the qh is unlinked from the async schedule and then the doorbell gets rung, -once the doorbell is acked by the controller the hcd knows that the qh is -no longer in use and that it can do something else with the memory, such -as re-use it for a new qh! But we keep our struct representing this qh around -for circa 250 ms. This allows for a (mightily large) race window where the -following could happen: --hcd submits a qh at address 0xdeadbeef --our ehci code sees the qh, sends a request to a usb-device, gets a result - of USB_RET_ASYNC, sets the async_state of the qh to EHCI_ASYNC_INFLIGHT --hcd unlinks the qh at address 0xdeadbeef --hcd rings the doorbell, wait for us to ack it --hcd re-uses the qh at address 0xdeadbeef --our ehci code sees the qh, looks in the async_queue, sees there already is - a qh at address 0xdeadbeef there with async_state of EHCI_ASYNC_INFLIGHT, - does nothing --the *original* (which the hcd thinks it has cancelled) transaction finishes --our ehci code sees the qh on yet another pass through the async list, - looks in the async_queue, sees there already is a qh at address 0xdeadbeef - there with async_state of EHCI_ASYNC_COMPLETED, and finished the transaction - with the results of the *original* transaction. - -Not good (tm), this patch fixes this race by removing all qhs which have not -been seen during the last cycle through the async list immidiately when the -doorbell is rung. - -Note this patch does not fix any actually observed problem, but upon -reading of the EHCI spec it became apparent to me that the above race could -happen and the usb-ehci behavior from before this patch is not good. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 31 ++++++++++++++++--------------- - 1 file changed, 16 insertions(+), 15 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index 422afc8..b8ba483 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -697,7 +697,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, - return NULL; - } - --static void ehci_queues_rip_unused(EHCIState *ehci, int async) -+static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) - { - EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; - EHCIQueue *q, *tmp; -@@ -708,7 +708,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async) - q->ts = ehci->last_run_ns; - continue; - } -- if (ehci->last_run_ns < q->ts + 250000000) { -+ if (!flush && ehci->last_run_ns < q->ts + 250000000) { - /* allow 0.25 sec idle */ - continue; - } -@@ -1565,7 +1565,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) - ehci_set_usbsts(ehci, USBSTS_REC); - } - -- ehci_queues_rip_unused(ehci, async); -+ ehci_queues_rip_unused(ehci, async, 0); - - /* Find the head of the list (4.9.1.1) */ - for(i = 0; i < MAX_QH; i++) { -@@ -2121,18 +2121,7 @@ static void ehci_advance_async_state(EHCIState *ehci) - break; - } - -- /* If the doorbell is set, the guest wants to make a change to the -- * schedule. The host controller needs to release cached data. -- * (section 4.8.2) -- */ -- if (ehci->usbcmd & USBCMD_IAAD) { -- DPRINTF("ASYNC: doorbell request acknowledged\n"); -- ehci->usbcmd &= ~USBCMD_IAAD; -- ehci_set_interrupt(ehci, USBSTS_IAA); -- break; -- } -- -- /* make sure guest has acknowledged */ -+ /* make sure guest has acknowledged the doorbell interrupt */ - /* TO-DO: is this really needed? */ - if (ehci->usbsts & USBSTS_IAA) { - DPRINTF("IAA status bit still set.\n"); -@@ -2146,6 +2135,18 @@ static void ehci_advance_async_state(EHCIState *ehci) - - ehci_set_state(ehci, async, EST_WAITLISTHEAD); - ehci_advance_state(ehci, async); -+ -+ /* If the doorbell is set, the guest wants to make a change to the -+ * schedule. The host controller needs to release cached data. -+ * (section 4.8.2) -+ */ -+ if (ehci->usbcmd & USBCMD_IAAD) { -+ /* Remove all unseen qhs from the async qhs queue */ -+ ehci_queues_rip_unused(ehci, async, 1); -+ DPRINTF("ASYNC: doorbell request acknowledged\n"); -+ ehci->usbcmd &= ~USBCMD_IAAD; -+ ehci_set_interrupt(ehci, USBSTS_IAA); -+ } - break; - - default: --- -1.7.9.3 - diff --git a/0131-qxl-add-optinal-64bit-vram-bar.patch b/0131-qxl-add-optinal-64bit-vram-bar.patch new file mode 100644 index 0000000..2ec63e9 --- /dev/null +++ b/0131-qxl-add-optinal-64bit-vram-bar.patch @@ -0,0 +1,182 @@ +From c407d1fe045eaec796dcbd4058c54d0bbf71fd53 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 14 Oct 2011 18:05:48 +0200 +Subject: [PATCH] qxl: add optinal 64bit vram bar + +This patch adds an 64bit pci bar for vram. It is turned off by default. +It can be enabled by setting the size of the 64bit bar to be larger than +the 32bit bar. Both 32bit and 64bit bar refer to the same memory. Only +the first part of the memory is available via 32bit bar. + +The intention is to allow large vram sizes for 64bit guests, by allowing +the vram bar being mapped above 4G, so we don't have to squeeze it into +the pci I/O window below 4G. + +With vram_size_mb=16 and vram64_size_mb=256 it looks like this: + +00:02.0 VGA compatible controller: Red Hat, Inc. Device 0100 (rev 02) (prog-if 00 [VGA controller]) + Subsystem: Red Hat, Inc Device 1100 + Physical Slot: 2 + Flags: fast devsel, IRQ 10 + Memory at f8000000 (32-bit, non-prefetchable) [size=64M] + Memory at fc000000 (32-bit, non-prefetchable) [size=16M] + Memory at fd020000 (32-bit, non-prefetchable) [size=8K] + I/O ports at c5a0 [size=32] + Memory at ffe0000000 (64-bit, prefetchable) [size=256M] + Expansion ROM at fd000000 [disabled] [size=64K] + +[ mapping above 4G needs patched seabios: + http://www.kraxel.org/cgit/seabios/commit/?h=pci64 ] + +Conflicts: + + hw/qxl.c +--- + hw/qxl.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- + hw/qxl.h | 7 +++++++ + 2 files changed, 51 insertions(+), 7 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index bcdf274..18f3759 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1002,6 +1002,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + static const int regions[] = { + QXL_RAM_RANGE_INDEX, + QXL_VRAM_RANGE_INDEX, ++ QXL_VRAM64_RANGE_INDEX, + }; + uint64_t guest_start; + uint64_t guest_end; +@@ -1046,6 +1047,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, + virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram); + break; + case QXL_VRAM_RANGE_INDEX: ++ case 4 /* vram 64bit */: + virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar); + break; + default: +@@ -1630,18 +1632,28 @@ static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) + qxl->vga.vram_size = ram_min_mb * 1024 * 1024; + } + +- /* vram (surfaces, bar 1) */ ++ /* vram32 (surfaces, 32bit, bar 1) */ ++ if (qxl->vram32_size_mb != -1) { ++ qxl->vram32_size = qxl->vram32_size_mb * 1024 * 1024; ++ } ++ if (qxl->vram32_size < 4096) { ++ qxl->vram32_size = 4096; ++ } ++ ++ /* vram (surfaces, 64bit, bar 4+5) */ + if (qxl->vram_size_mb != -1) { + qxl->vram_size = qxl->vram_size_mb * 1024 * 1024; + } +- if (qxl->vram_size < 4096) { +- qxl->vram_size = 4096; ++ if (qxl->vram_size < qxl->vram32_size) { ++ qxl->vram_size = qxl->vram32_size; + } ++ + if (qxl->revision == 1) { ++ qxl->vram32_size = 4096; + qxl->vram_size = 4096; + } +- + qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1); ++ qxl->vram32_size = msb_mask(qxl->vram32_size * 2 - 1); + qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); + } + +@@ -1683,6 +1695,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) + + memory_region_init_ram(&qxl->vram_bar, &qxl->pci.qdev, "qxl.vram", + qxl->vram_size); ++ memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar, ++ 0, qxl->vram32_size); + + io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); + if (qxl->revision == 1) { +@@ -1706,7 +1720,29 @@ static int qxl_init_common(PCIQXLDevice *qxl) + PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram); + + pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, +- PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram_bar); ++ PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram32_bar); ++ ++ if (qxl->vram32_size < qxl->vram_size) { ++ /* ++ * Make the 64bit vram bar show up only in case it is ++ * configured to be larger than the 32bit vram bar. ++ */ ++ pci_register_bar(&qxl->pci, QXL_VRAM64_RANGE_INDEX, ++ PCI_BASE_ADDRESS_SPACE_MEMORY | ++ PCI_BASE_ADDRESS_MEM_TYPE_64 | ++ PCI_BASE_ADDRESS_MEM_PREFETCH, ++ &qxl->vram_bar); ++ } ++ ++ /* print pci bar details */ ++ dprint(qxl, 1, "ram/%s: %d MB [region 0]\n", ++ qxl->id == 0 ? "pri" : "sec", ++ qxl->vga.vram_size / (1024*1024)); ++ dprint(qxl, 1, "vram/32: %d MB [region 1]\n", ++ qxl->vram32_size / (1024*1024)); ++ dprint(qxl, 1, "vram/64: %d MB %s\n", ++ qxl->vram_size / (1024*1024), ++ qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]"); + + qxl->ssd.qxl.base.sif = &qxl_interface.base; + qxl->ssd.qxl.id = qxl->id; +@@ -1918,7 +1954,7 @@ static VMStateDescription qxl_vmstate = { + static Property qxl_properties[] = { + DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, + 64 * 1024 * 1024), +- DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, ++ DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size, + 64 * 1024 * 1024), + DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, + QXL_DEFAULT_REVISION), +@@ -1926,7 +1962,8 @@ static Property qxl_properties[] = { + DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), + DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), + DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), +- DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram_size_mb, -1), ++ DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, 0), ++ DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, 0), + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/hw/qxl.h b/hw/qxl.h +index 86e415b..11a0db3 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -16,6 +16,10 @@ enum qxl_mode { + QXL_MODE_NATIVE, + }; + ++#ifndef QXL_VRAM64_RANGE_INDEX ++#define QXL_VRAM64_RANGE_INDEX 4 ++#endif ++ + #define QXL_UNDEFINED_IO UINT32_MAX + + #define QXL_NUM_DIRTY_RECTS 64 +@@ -88,6 +92,8 @@ typedef struct PCIQXLDevice { + /* vram pci bar */ + uint32_t vram_size; + MemoryRegion vram_bar; ++ uint32_t vram32_size; ++ MemoryRegion vram32_bar; + + /* io bar */ + MemoryRegion io_bar; +@@ -95,6 +101,7 @@ typedef struct PCIQXLDevice { + /* user-friendly properties (in megabytes) */ + uint32_t ram_size_mb; + uint32_t vram_size_mb; ++ uint32_t vram32_size_mb; + + /* qxl_render_update state */ + int render_update_cookie_num; diff --git a/0131-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch b/0131-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch deleted file mode 100644 index 3f07ca0..0000000 --- a/0131-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch +++ /dev/null @@ -1,44 +0,0 @@ -From cbb6384d32c4926822ba9216992253deef9ef3b5 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 2 Mar 2012 11:02:04 +0100 -Subject: [PATCH 131/140] usb-ehci: Rip the queues when the async or period - schedule is halted - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index b8ba483..11eded7 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -1054,7 +1054,8 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) - - if (!(val & USBCMD_RUNSTOP) && (s->usbcmd & USBCMD_RUNSTOP)) { - qemu_del_timer(s->frame_timer); -- // TODO - should finish out some stuff before setting halt -+ ehci_queues_rip_all(s, 0); -+ ehci_queues_rip_all(s, 1); - ehci_set_usbsts(s, USBSTS_HALT); - } - -@@ -2116,6 +2117,7 @@ static void ehci_advance_async_state(EHCIState *ehci) - - case EST_ACTIVE: - if ( !(ehci->usbcmd & USBCMD_ASE)) { -+ ehci_queues_rip_all(ehci, async); - ehci_clear_usbsts(ehci, USBSTS_ASS); - ehci_set_state(ehci, async, EST_INACTIVE); - break; -@@ -2176,6 +2178,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) - - case EST_ACTIVE: - if ( !(ehci->frindex & 7) && !(ehci->usbcmd & USBCMD_PSE)) { -+ ehci_queues_rip_all(ehci, async); - ehci_clear_usbsts(ehci, USBSTS_PSS); - ehci_set_state(ehci, async, EST_INACTIVE); - break; --- -1.7.9.3 - diff --git a/0132-qxl-set-default-values-of-vram-_size_mb-to-1.patch b/0132-qxl-set-default-values-of-vram-_size_mb-to-1.patch new file mode 100644 index 0000000..4760661 --- /dev/null +++ b/0132-qxl-set-default-values-of-vram-_size_mb-to-1.patch @@ -0,0 +1,32 @@ +From 2d1649d6f8aa97abc0c26172f77d064ea029b9c6 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Thu, 29 Mar 2012 22:24:38 +0200 +Subject: [PATCH] qxl: set default values of vram*_size_mb to -1 + +The addition of those values caused a regression where not specifying +any value for the vram bar size would result in a 4096 _byte_ surface +area. This is ok for the windows driver but causes the X driver to be +unusable. Also, it's a regression. This patch returns the default +behavior of having a 64 megabyte vram BAR. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 18f3759..2135fde 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1962,8 +1962,8 @@ static Property qxl_properties[] = { + DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), + DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), + DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), +- DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, 0), +- DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, 0), ++ DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1), ++ DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1), + DEFINE_PROP_END_OF_LIST(), + }; + diff --git a/0132-usb-ehci-Any-packet-completion-except-for-NAK-should.patch b/0132-usb-ehci-Any-packet-completion-except-for-NAK-should.patch deleted file mode 100644 index 7107ed8..0000000 --- a/0132-usb-ehci-Any-packet-completion-except-for-NAK-should.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 73a9969c47459ee208d6247999823f2a36ee51fe Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 1 Mar 2012 16:34:56 +0100 -Subject: [PATCH 132/140] usb-ehci: Any packet completion except for NAK - should set the interrupt - -As clearly stated in the 2.3.2 of the EHCI spec, any time USBERRINT get -sets then if the td has its IOC bit set USBINT should be set as well. - -This means that for any status except for USB_RET_NAK we should set -USBINT if the IOC bit is set. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index 11eded7..bc5f591 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -1338,7 +1338,7 @@ err: - q->qh.token ^= QTD_TOKEN_DTOGGLE; - q->qh.token &= ~QTD_TOKEN_ACTIVE; - -- if ((q->usb_status >= 0) && (q->qh.token & QTD_TOKEN_IOC)) { -+ if ((q->usb_status != USB_RET_NAK) && (q->qh.token & QTD_TOKEN_IOC)) { - ehci_record_interrupt(q->ehci, USBSTS_INT); - } - } --- -1.7.9.3 - diff --git a/0133-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch b/0133-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch new file mode 100644 index 0000000..eacf4df --- /dev/null +++ b/0133-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch @@ -0,0 +1,26 @@ +From 8545f8bf5f4c4bb373e0805508b7789984672453 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 18 Apr 2012 12:24:28 +0300 +Subject: [PATCH] qxl-render: fix broken vnc+spice since commit f934493 + +Notify any listeners such as vnc that the displaysurface has been +changed, otherwise they will segfault when first accessing the freed old +displaysurface data. + +Signed-off-by: Alon Levy +--- + hw/qxl-render.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index 835dc5e..180b8f9 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -127,6 +127,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + qemu_resize_displaysurface(vga->ds, + qxl->guest_primary.surface.width, + qxl->guest_primary.surface.height); ++ dpy_resize(vga->ds); + } + } + for (i = 0; i < qxl->num_dirty_rects; i++) { diff --git a/0133-usb-ehci-Fix-cerr-tracking.patch b/0133-usb-ehci-Fix-cerr-tracking.patch deleted file mode 100644 index 6ae9d8e..0000000 --- a/0133-usb-ehci-Fix-cerr-tracking.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 6e6bfa88ae3867afd8258b43e3c05cba2585ee37 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 1 Mar 2012 21:43:56 +0100 -Subject: [PATCH 133/140] usb-ehci: Fix cerr tracking - -cerr should only be decremented on errors which cause XactErr to be set, and -when that happens the failing transaction should be retried until cerr reaches -0 and only then should USBSTS_ERRINT be set (and inactive cleared and -USBSTS_INT set if requested). - -Since we don't have any hardware level errors (and in case of redirection -the real hardware has already retried), re-trying makes no sense, so -immediately set cerr to 0 on errors which set XactErr. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 19 ++++++------------- - 1 file changed, 6 insertions(+), 13 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index bc5f591..a3d5c11 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -1269,7 +1269,7 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) - - static void ehci_execute_complete(EHCIQueue *q) - { -- int c_err, reload; -+ int reload; - - assert(q->async != EHCI_ASYNC_INFLIGHT); - q->async = EHCI_ASYNC_NONE; -@@ -1278,15 +1278,10 @@ static void ehci_execute_complete(EHCIQueue *q) - q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status); - - if (q->usb_status < 0) { --err: -- /* TO-DO: put this is in a function that can be invoked below as well */ -- c_err = get_field(q->qh.token, QTD_TOKEN_CERR); -- c_err--; -- set_field(&q->qh.token, c_err, QTD_TOKEN_CERR); -- - switch(q->usb_status) { - case USB_RET_NODEV: - q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); -+ set_field(&q->qh.token, 0, QTD_TOKEN_CERR); - ehci_record_interrupt(q->ehci, USBSTS_ERRINT); - break; - case USB_RET_STALL: -@@ -1314,15 +1309,13 @@ err: - assert(0); - break; - } -+ } else if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) { -+ q->usb_status = USB_RET_BABBLE; -+ q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); -+ ehci_record_interrupt(q->ehci, USBSTS_ERRINT); - } else { -- // DPRINTF("Short packet condition\n"); - // TODO check 4.12 for splits - -- if ((q->usb_status > q->tbytes) && (q->pid == USB_TOKEN_IN)) { -- q->usb_status = USB_RET_BABBLE; -- goto err; -- } -- - if (q->tbytes && q->pid == USB_TOKEN_IN) { - q->tbytes -= q->usb_status; - } else { --- -1.7.9.3 - diff --git a/0134-qxl-don-t-assert-on-guest-create_guest_primary.patch b/0134-qxl-don-t-assert-on-guest-create_guest_primary.patch new file mode 100644 index 0000000..697f396 --- /dev/null +++ b/0134-qxl-don-t-assert-on-guest-create_guest_primary.patch @@ -0,0 +1,33 @@ +From 2b63fc61e815ba6ab09d30381712158599810b28 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 18 Apr 2012 14:00:06 +0300 +Subject: [PATCH] qxl: don't assert on guest create_guest_primary + +initiate the implicit destroy ourselves. + +Signed-off-by: Alon Levy +--- + hw/qxl.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 2135fde..29c8873 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1123,7 +1123,15 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, + QXLDevSurfaceCreate surface; + QXLSurfaceCreate *sc = &qxl->guest_primary.surface; + +- assert(qxl->mode != QXL_MODE_NATIVE); ++ if (qxl->mode == QXL_MODE_NATIVE) { ++ /* ++ * allow a create without a destroy. This could be used ++ * later for an atomic "change primary" but right now just ++ * destroy the primary for the guest. Note that this uses ++ * the ability to have multiple concurrent async commands. ++ */ ++ qxl_destroy_primary(qxl, async); ++ } + qxl_exit_vga_mode(qxl); + + surface.format = le32_to_cpu(sc->format); diff --git a/0134-usb-ehci-Remove-dead-nakcnt-code.patch b/0134-usb-ehci-Remove-dead-nakcnt-code.patch deleted file mode 100644 index 657ab26..0000000 --- a/0134-usb-ehci-Remove-dead-nakcnt-code.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 6177c3610b6416a7200ae6c6985f01fccdbdc7e5 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 1 Mar 2012 23:11:13 +0100 -Subject: [PATCH 134/140] usb-ehci: Remove dead nakcnt code - -This patch removes 2 bits of dead nakcnt code: - -1) usb_ehci_execute calls ehci_qh_do_overlay which does: -nakcnt = reload; -and then has a block of code which is conditional on: -if (reload && !nakcnt) { -which ofcourse is never true now as nakcnt == reload. - -2) ehci_state_fetchqh does: -nakcnt = reload; -but before nakcnt is ever used ehci_state_fetchqh is always followed -by a ehci_qh_do_overlay call which also does: -nakcnt = reload; -So doing this from ehci_state_fetchqh is redundant. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 20 -------------------- - 1 file changed, 20 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index a3d5c11..92cdf2a 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -1643,7 +1643,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) - { - uint32_t entry; - EHCIQueue *q; -- int reload; - - entry = ehci_get_fetch_addr(ehci, async); - q = ehci_find_queue_by_qh(ehci, entry, async); -@@ -1701,11 +1700,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) - } - #endif - -- reload = get_field(q->qh.epchar, QH_EPCHAR_RL); -- if (reload) { -- set_field(&q->qh.altnext_qtd, reload, QH_ALTNEXT_NAKCNT); -- } -- - if (q->qh.token & QTD_TOKEN_HALT) { - ehci_set_state(ehci, async, EST_HORIZONTALQH); - -@@ -1865,25 +1859,11 @@ static void ehci_flush_qh(EHCIQueue *q) - static int ehci_state_execute(EHCIQueue *q, int async) - { - int again = 0; -- int reload, nakcnt; -- int smask; - - if (ehci_qh_do_overlay(q) != 0) { - return -1; - } - -- smask = get_field(q->qh.epcap, QH_EPCAP_SMASK); -- -- if (!smask) { -- reload = get_field(q->qh.epchar, QH_EPCHAR_RL); -- nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT); -- if (reload && !nakcnt) { -- ehci_set_state(q->ehci, async, EST_HORIZONTALQH); -- again = 1; -- goto out; -- } -- } -- - // TODO verify enough time remains in the uframe as in 4.4.1.1 - // TODO write back ptr to async list when done or out of time - // TODO Windows does not seem to ever set the MULT field --- -1.7.9.3 - diff --git a/0135-usb-ehci-Fix-and-simplify-nakcnt-handling.patch b/0135-usb-ehci-Fix-and-simplify-nakcnt-handling.patch deleted file mode 100644 index 351f9e4..0000000 --- a/0135-usb-ehci-Fix-and-simplify-nakcnt-handling.patch +++ /dev/null @@ -1,120 +0,0 @@ -From 2d9b6cb9bd00ede47635dc4db413f647143d5a1d Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 1 Mar 2012 23:55:11 +0100 -Subject: [PATCH 135/140] usb-ehci: Fix and simplify nakcnt handling - -The nakcnt code in ehci_execute_complete() marked transactions as finished -when a packet completed with a result of USB_RET_NAK, but USB_RET_NAK -means that the device cannot receive / send data at that time and that -the transaction should be retried later, which is also what the usb-uhci -and usb-ohci code does. - -Note that there already was some special code in place to handle this -for interrupt endpoints in the form of doing a return from -ehci_execute_complete() when reload == 0, but that for bulk transactions -this was not handled correctly (where as for example the usb-ccid device does -return USB_RET_NAK for bulk packets). - -Besides that the code in ehci_execute_complete() decrement nakcnt by 1 -on a packet result of USB_RET_NAK, but --since the transaction got marked as finished, - nakcnt would never be decremented again --there is no code checking for nakcnt becoming 0 --there is no use in re-trying the transaction within the same usb frame / - usb-ehci frame-timer call, since the status of emulated devices won't change - as long as the usb-ehci frame-timer is running -So we should simply set the nakcnt to 0 when we get a USB_RET_NAK, thus -claiming that we've tried reload times (or as many times as possible if -reload is 0). - -Besides the code in ehci_execute_complete() handling USB_RET_NAK there -was also code handling it in ehci_state_executing(), which calls -ehci_execute_complete(), and then does its own handling on top of the handling -in ehci_execute_complete(), this code would decrement nakcnt *again* (if not -already 0), or restore the reload value (which was never changed) on success. - -Since the double decrement was wrong to begin with, and is no longer needed -now that we set nakcnt directly to 0 on USB_RET_NAK, and the restore of reload -is not needed either, this patch simply removes all nakcnt handling from -ehci_state_executing(). - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 32 ++++---------------------------- - 1 file changed, 4 insertions(+), 28 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index 92cdf2a..aa6fae5 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -1269,8 +1269,6 @@ static void ehci_async_complete_packet(USBPort *port, USBPacket *packet) - - static void ehci_execute_complete(EHCIQueue *q) - { -- int reload; -- - assert(q->async != EHCI_ASYNC_INFLIGHT); - q->async = EHCI_ASYNC_NONE; - -@@ -1289,16 +1287,8 @@ static void ehci_execute_complete(EHCIQueue *q) - ehci_record_interrupt(q->ehci, USBSTS_ERRINT); - break; - case USB_RET_NAK: -- /* 4.10.3 */ -- reload = get_field(q->qh.epchar, QH_EPCHAR_RL); -- if ((q->pid == USB_TOKEN_IN) && reload) { -- int nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT); -- nakcnt--; -- set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT); -- } else if (!reload) { -- return; -- } -- break; -+ set_field(&q->qh.altnext_qtd, 0, QH_ALTNEXT_NAKCNT); -+ return; /* We're not done yet with this transaction */ - case USB_RET_BABBLE: - q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); - ehci_record_interrupt(q->ehci, USBSTS_ERRINT); -@@ -1331,7 +1321,7 @@ static void ehci_execute_complete(EHCIQueue *q) - q->qh.token ^= QTD_TOKEN_DTOGGLE; - q->qh.token &= ~QTD_TOKEN_ACTIVE; - -- if ((q->usb_status != USB_RET_NAK) && (q->qh.token & QTD_TOKEN_IOC)) { -+ if (q->qh.token & QTD_TOKEN_IOC) { - ehci_record_interrupt(q->ehci, USBSTS_INT); - } - } -@@ -1905,7 +1895,6 @@ out: - static int ehci_state_executing(EHCIQueue *q, int async) - { - int again = 0; -- int reload, nakcnt; - - ehci_execute_complete(q); - if (q->usb_status == USB_RET_ASYNC) { -@@ -1925,21 +1914,8 @@ static int ehci_state_executing(EHCIQueue *q, int async) - // counter decrements to 0 - } - -- reload = get_field(q->qh.epchar, QH_EPCHAR_RL); -- if (reload) { -- nakcnt = get_field(q->qh.altnext_qtd, QH_ALTNEXT_NAKCNT); -- if (q->usb_status == USB_RET_NAK) { -- if (nakcnt) { -- nakcnt--; -- } -- } else { -- nakcnt = reload; -- } -- set_field(&q->qh.altnext_qtd, nakcnt, QH_ALTNEXT_NAKCNT); -- } -- - /* 4.10.5 */ -- if ((q->usb_status == USB_RET_NAK) || (q->qh.token & QTD_TOKEN_ACTIVE)) { -+ if (q->usb_status == USB_RET_NAK) { - ehci_set_state(q->ehci, async, EST_HORIZONTALQH); - } else { - ehci_set_state(q->ehci, async, EST_WRITEBACK); --- -1.7.9.3 - diff --git a/0136-usb-ehci-Remove-dead-isoch_pause-code.patch b/0136-usb-ehci-Remove-dead-isoch_pause-code.patch deleted file mode 100644 index 7d47913..0000000 --- a/0136-usb-ehci-Remove-dead-isoch_pause-code.patch +++ /dev/null @@ -1,114 +0,0 @@ -From 0e6cd6e6da3d0648204526e8ebd79047f48d009a Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 2 Mar 2012 00:36:50 +0100 -Subject: [PATCH 136/140] usb-ehci: Remove dead isoch_pause code - -I see no value in keeping this around, so lets delete it. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 60 +++++++++++++++------------------------------------------ - 1 file changed, 15 insertions(+), 45 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index aa6fae5..72c3f2a 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -419,7 +419,6 @@ struct EHCIState { - - USBPacket ipacket; - QEMUSGList isgl; -- int isoch_pause; - - uint64_t last_run_ns; - }; -@@ -886,7 +885,6 @@ static void ehci_reset(void *opaque) - - s->astate = EST_INACTIVE; - s->pstate = EST_INACTIVE; -- s->isoch_pause = -1; - s->attach_poll_counter = 0; - - for(i = 0; i < NB_PORTS; i++) { -@@ -1468,46 +1466,7 @@ static int ehci_process_itd(EHCIState *ehci, - usb_packet_unmap(&ehci->ipacket); - qemu_sglist_destroy(&ehci->isgl); - --#if 0 -- /* In isoch, there is no facility to indicate a NAK so let's -- * instead just complete a zero-byte transaction. Setting -- * DBERR seems too draconian. -- */ -- -- if (ret == USB_RET_NAK) { -- if (ehci->isoch_pause > 0) { -- DPRINTF("ISOCH: received a NAK but paused so returning\n"); -- ehci->isoch_pause--; -- return 0; -- } else if (ehci->isoch_pause == -1) { -- DPRINTF("ISOCH: recv NAK & isoch pause inactive, setting\n"); -- // Pause frindex for up to 50 msec waiting for data from -- // remote -- ehci->isoch_pause = 50; -- return 0; -- } else { -- DPRINTF("ISOCH: isoch pause timeout! return 0\n"); -- ret = 0; -- } -- } else { -- DPRINTF("ISOCH: received ACK, clearing pause\n"); -- ehci->isoch_pause = -1; -- } --#else -- if (ret == USB_RET_NAK) { -- ret = 0; -- } --#endif -- -- if (ret >= 0) { -- if (!dir) { -- /* OUT */ -- set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH); -- } else { -- /* IN */ -- set_field(&itd->transact[i], ret, ITD_XACT_LENGTH); -- } -- } else { -+ if (ret < 0) { - switch (ret) { - default: - fprintf(stderr, "Unexpected iso usb result: %d\n", ret); -@@ -1523,6 +1482,19 @@ static int ehci_process_itd(EHCIState *ehci, - itd->transact[i] |= ITD_XACT_BABBLE; - ehci_record_interrupt(ehci, USBSTS_ERRINT); - break; -+ case USB_RET_NAK: -+ /* no data for us, so do a zero-length transfer */ -+ ret = 0; -+ break; -+ } -+ } -+ if (ret >= 0) { -+ if (!dir) { -+ /* OUT */ -+ set_field(&itd->transact[i], len - ret, ITD_XACT_LENGTH); -+ } else { -+ /* IN */ -+ set_field(&itd->transact[i], ret, ITD_XACT_LENGTH); - } - } - if (itd->transact[i] & ITD_XACT_IOC) { -@@ -2176,9 +2148,7 @@ static void ehci_frame_timer(void *opaque) - - for (i = 0; i < frames; i++) { - if ( !(ehci->usbsts & USBSTS_HALT)) { -- if (ehci->isoch_pause <= 0) { -- ehci->frindex += 8; -- } -+ ehci->frindex += 8; - - if (ehci->frindex > 0x00001fff) { - ehci->frindex = 0; --- -1.7.9.3 - diff --git a/0137-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch b/0137-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch deleted file mode 100644 index 3743d5e..0000000 --- a/0137-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 9726556968aef62213b80bd4e351a4f7f721f941 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 1 Mar 2012 17:22:14 +0100 -Subject: [PATCH 137/140] usb: return BABBLE rather then NAK when we receive - too much data - -Signed-off-by: Hans de Goede ---- - usb-linux.c | 8 +++++++- - usb-redir.c | 4 ++-- - 2 files changed, 9 insertions(+), 3 deletions(-) - -diff --git a/usb-linux.c b/usb-linux.c -index ab4c693..b2d70f9 100644 ---- a/usb-linux.c -+++ b/usb-linux.c -@@ -390,6 +390,10 @@ static void async_complete(void *opaque) - p->result = USB_RET_STALL; - break; - -+ case -EOVERFLOW: -+ p->result = USB_RET_BABBLE; -+ break; -+ - default: - p->result = USB_RET_NAK; - break; -@@ -718,6 +722,8 @@ static int urb_status_to_usb_ret(int status) - switch (status) { - case -EPIPE: - return USB_RET_STALL; -+ case -EOVERFLOW: -+ return USB_RET_BABBLE; - default: - return USB_RET_NAK; - } -@@ -755,7 +761,7 @@ static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p, int in) - } else if (aurb[i].urb.iso_frame_desc[j].actual_length - > p->iov.size) { - printf("husb: received iso data is larger then packet\n"); -- len = USB_RET_NAK; -+ len = USB_RET_BABBLE; - /* All good copy data over */ - } else { - len = aurb[i].urb.iso_frame_desc[j].actual_length; -diff --git a/usb-redir.c b/usb-redir.c -index 629c87d..61860ef 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -457,7 +457,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - ERROR("received iso data is larger then packet ep %02X (%d > %d)\n", - ep, len, (int)p->iov.size); - bufp_free(dev, isop, ep); -- return USB_RET_NAK; -+ return USB_RET_BABBLE; - } - usb_packet_copy(p, isop->data, len); - bufp_free(dev, isop, ep); -@@ -576,7 +576,7 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, - if (len > p->iov.size) { - ERROR("received int data is larger then packet ep %02X\n", ep); - bufp_free(dev, intp, ep); -- return USB_RET_NAK; -+ return USB_RET_BABBLE; - } - usb_packet_copy(p, intp->data, len); - bufp_free(dev, intp, ep); --- -1.7.9.3 - diff --git a/0138-usb-add-USB_RET_IOERROR.patch b/0138-usb-add-USB_RET_IOERROR.patch deleted file mode 100644 index 0ed82a7..0000000 --- a/0138-usb-add-USB_RET_IOERROR.patch +++ /dev/null @@ -1,167 +0,0 @@ -From 2a6bbdddc2aca6af038c42054c3d3a7b09e5ac3a Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 2 Mar 2012 00:26:23 +0100 -Subject: [PATCH 138/140] usb: add USB_RET_IOERROR - -We already have USB_RET_NAK, but that means that a device does not want -to send/receive right now. But with host / network redirection we can -actually have a transaction fail due to some io error, rather then ie -the device just not having any data atm. - -This patch adds a new error code named USB_RET_IOERROR for this, and uses -it were appropriate. - -Notes: --Currently all usb-controllers handle this the same as NODEV, but that - may change in the future, OHCI could indicate a CRC error instead for example. --This patch does not touch hw/usb-musb.c, that is because the code in there - handles STALL and NAK specially and has a if status < 0 generic catch all - for all other errors - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 2 ++ - hw/usb-ohci.c | 2 ++ - hw/usb-uhci.c | 1 + - hw/usb.h | 11 ++++++----- - usb-linux.c | 4 ++-- - usb-redir.c | 9 ++++++--- - 6 files changed, 19 insertions(+), 10 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index 72c3f2a..ba1b9da 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -1275,6 +1275,7 @@ static void ehci_execute_complete(EHCIQueue *q) - - if (q->usb_status < 0) { - switch(q->usb_status) { -+ case USB_RET_IOERROR: - case USB_RET_NODEV: - q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_XACTERR); - set_field(&q->qh.token, 0, QTD_TOKEN_CERR); -@@ -1471,6 +1472,7 @@ static int ehci_process_itd(EHCIState *ehci, - default: - fprintf(stderr, "Unexpected iso usb result: %d\n", ret); - /* Fall through */ -+ case USB_RET_IOERROR: - case USB_RET_NODEV: - /* 3.3.2: XACTERR is only allowed on IN transactions */ - if (dir) { -diff --git a/hw/usb-ohci.c b/hw/usb-ohci.c -index c2981c5..d805497 100644 ---- a/hw/usb-ohci.c -+++ b/hw/usb-ohci.c -@@ -828,6 +828,7 @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed, - OHCI_CC_DATAUNDERRUN); - } else { - switch (ret) { -+ case USB_RET_IOERROR: - case USB_RET_NODEV: - OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC, - OHCI_CC_DEVICENOTRESPONDING); -@@ -1051,6 +1052,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed) - OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DATAUNDERRUN); - } else { - switch (ret) { -+ case USB_RET_IOERROR: - case USB_RET_NODEV: - OHCI_SET_BM(td.flags, TD_CC, OHCI_CC_DEVICENOTRESPONDING); - case USB_RET_NAK: -diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c -index f9e3ea5..a994943 100644 ---- a/hw/usb-uhci.c -+++ b/hw/usb-uhci.c -@@ -751,6 +751,7 @@ out: - break; - return 1; - -+ case USB_RET_IOERROR: - case USB_RET_NODEV: - default: - break; -diff --git a/hw/usb.h b/hw/usb.h -index c6e1870..4010e12 100644 ---- a/hw/usb.h -+++ b/hw/usb.h -@@ -41,11 +41,12 @@ - #define USB_MSG_DETACH 0x101 - #define USB_MSG_RESET 0x102 - --#define USB_RET_NODEV (-1) --#define USB_RET_NAK (-2) --#define USB_RET_STALL (-3) --#define USB_RET_BABBLE (-4) --#define USB_RET_ASYNC (-5) -+#define USB_RET_NODEV (-1) -+#define USB_RET_NAK (-2) -+#define USB_RET_STALL (-3) -+#define USB_RET_BABBLE (-4) -+#define USB_RET_IOERROR (-5) -+#define USB_RET_ASYNC (-6) - - #define USB_SPEED_LOW 0 - #define USB_SPEED_FULL 1 -diff --git a/usb-linux.c b/usb-linux.c -index b2d70f9..9f13d1e 100644 ---- a/usb-linux.c -+++ b/usb-linux.c -@@ -395,7 +395,7 @@ static void async_complete(void *opaque) - break; - - default: -- p->result = USB_RET_NAK; -+ p->result = USB_RET_IOERROR; - break; - } - -@@ -725,7 +725,7 @@ static int urb_status_to_usb_ret(int status) - case -EOVERFLOW: - return USB_RET_BABBLE; - default: -- return USB_RET_NAK; -+ return USB_RET_IOERROR; - } - } - -diff --git a/usb-redir.c b/usb-redir.c -index 61860ef..f64443e 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -441,7 +441,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - /* Check iso_error for stream errors, otherwise its an underrun */ - status = dev->endpoint[EP2I(ep)].iso_error; - dev->endpoint[EP2I(ep)].iso_error = 0; -- return status ? USB_RET_NAK : 0; -+ return status ? USB_RET_IOERROR : 0; - } - DPRINTF2("iso-token-in ep %02X status %d len %d queue-size: %d\n", ep, - isop->status, isop->len, dev->endpoint[EP2I(ep)].bufpq_size); -@@ -449,7 +449,7 @@ static int usbredir_handle_iso_data(USBRedirDevice *dev, USBPacket *p, - status = isop->status; - if (status != usb_redir_success) { - bufp_free(dev, isop, ep); -- return USB_RET_NAK; -+ return USB_RET_IOERROR; - } - - len = isop->len; -@@ -1045,11 +1045,14 @@ static int usbredir_handle_status(USBRedirDevice *dev, - return USB_RET_STALL; - case usb_redir_cancelled: - WARNING("returning cancelled packet to HC?\n"); -+ return USB_RET_NAK; - case usb_redir_inval: -+ WARNING("got invalid param error from usb-host?\n"); -+ return USB_RET_NAK; - case usb_redir_ioerror: - case usb_redir_timeout: - default: -- return USB_RET_NAK; -+ return USB_RET_IOERROR; - } - } - --- -1.7.9.3 - diff --git a/0139-usb-ehci-fix-reset.patch b/0139-usb-ehci-fix-reset.patch deleted file mode 100644 index d9e6ac1..0000000 --- a/0139-usb-ehci-fix-reset.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 21946e621f14553b72cde7fae221ae390a427eac Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 23 Feb 2012 13:24:00 +0000 -Subject: [PATCH 139/140] usb-ehci: fix reset - -Two reset fixes: - * pick up s->usbcmd value after ehci_reset call to make sure it - keeps the reset value and doesn't get rubbish filled in when - val is written back to the mmio register array later on. - * make sure the frame timer is zapped on reset. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb-ehci.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index ba1b9da..ad0f6e1 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -900,6 +900,7 @@ static void ehci_reset(void *opaque) - } - ehci_queues_rip_all(s, 0); - ehci_queues_rip_all(s, 1); -+ qemu_del_timer(s->frame_timer); - } - - static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) -@@ -1059,7 +1060,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) - - if (val & USBCMD_HCRESET) { - ehci_reset(s); -- val &= ~USBCMD_HCRESET; -+ val = s->usbcmd; - } - - /* not supporting dynamic frame list size at the moment */ --- -1.7.9.3 - diff --git a/0140-usb-ehci-sanity-check-iso-xfers.patch b/0140-usb-ehci-sanity-check-iso-xfers.patch deleted file mode 100644 index 1305f51..0000000 --- a/0140-usb-ehci-sanity-check-iso-xfers.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 985b7cfbd45960bb74a13ad8044765a8e35f2251 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Sun, 4 Mar 2012 12:41:11 +0100 -Subject: [PATCH 140/140] usb-ehci: sanity-check iso xfers - -This patch adds a sanity check to itd processing to make sure the -endpoint addressed by the guest is actually an iso endpoint. Also -verify that usb drivers don't return USB_RET_ASYNC which is illegal for -iso xfers. - -Signed-off-by: Gerd Hoffmann -(Cherry picked from: aa0568ff2559d7717f4684af6a83d0bd1a125f56) - -[qemu-kvm-1.0: we don't track ep types on RHEL-6 like we do upstream, so we -cannot check if an itd is pointing to a non iso ep in advance, but we do still -need to make sure that we never handle an iso xfer async. So check if the -device does want to handle it async, and if so cancel the xfer and treat it as -a NAK, like upstream does when the ep type check fails.] - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index ad0f6e1..b5d7037 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -1485,6 +1485,10 @@ static int ehci_process_itd(EHCIState *ehci, - itd->transact[i] |= ITD_XACT_BABBLE; - ehci_record_interrupt(ehci, USBSTS_ERRINT); - break; -+ case USB_RET_ASYNC: -+ /* ISO endpoints are never ASYNC, not an iso endpoint? */ -+ usb_cancel_packet(&ehci->ipacket); -+ /* Treat this as a NAK (fall through) */ - case USB_RET_NAK: - /* no data for us, so do a zero-length transfer */ - ret = 0; --- -1.7.9.3 - diff --git a/0141-usb-ehci-frindex-always-is-a-14-bits-counter.patch b/0141-usb-ehci-frindex-always-is-a-14-bits-counter.patch deleted file mode 100644 index 4481332..0000000 --- a/0141-usb-ehci-frindex-always-is-a-14-bits-counter.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 9d604ddc4770f8f25de148e9b35687817a5d4110 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 28 Mar 2012 20:31:32 +0200 -Subject: [PATCH 141/146] usb-ehci: frindex always is a 14 bits counter - -frindex always is a 14 bits counter, and not a 13 bits one as we were -emulating. There are some subtle hints to this in the spec, first of all -"Table 2-12. FRINDEX - Frame Index Register" says: -"Bit 13:0 Frame Index. The value in this register increments at the end of -each time frame (e.g. micro-frame). Bits [N:3] are used for the Frame List -current index. This means that each location of the frame list is accessed -8 times (frames or micro-frames) before moving to the next index. The -following illustrates values of N based on the value of the Frame List -Size field in the USBCMD register. - -USBCMD[Frame List Size] Number Elements N -00b 1024 12 -01b 512 11 -10b 256 10 -11b Reserved" - -Notice how the text talks about "Bits [N:3]" are used ..., it does -NOT say that when N == 12 (our case) the counter will wrap from 8191 to 0, -or in otherwords that it is a 13 bits counter (bits 0 - 12). - -The other hint is in "Table 2-10. USBSTS USB Status Register Bit Definitions": - -"Bit 3 Frame List Rollover - R/WC. The Host Controller sets this bit to a one -when the Frame List Index (see Section 2.3.4) rolls over from its maximum value -to zero. The exact value at which the rollover occurs depends on the frame -list size. For example, if the frame list size (as programmed in the Frame -List Size field of the USBCMD register) is 1024, the Frame Index Register -rolls over every time FRINDEX[13] toggles. Similarly, if the size is 512, -the Host Controller sets this bit to a one every time FRINDEX[12] toggles." - -Notice how this text talks about setting bit 3 when bit 13 of frindex toggles -(when there are 1024 entries, so our case), so this indicates that frindex -has a bit 13 making it a 14 bit counter. - -Besides these clear hints the real proof is in the pudding. Before this -patch I could not stream data from a USB2 webcam under Windows XP, after -this cam using a USB2 webcam under Windows XP works fine, and no regressions -with other operating systems were seen. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index b5d7037..3934bf0 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -2157,11 +2157,15 @@ static void ehci_frame_timer(void *opaque) - if ( !(ehci->usbsts & USBSTS_HALT)) { - ehci->frindex += 8; - -- if (ehci->frindex > 0x00001fff) { -- ehci->frindex = 0; -+ if (ehci->frindex == 0x00002000) { - ehci_set_interrupt(ehci, USBSTS_FLR); - } - -+ if (ehci->frindex == 0x00004000) { -+ ehci_set_interrupt(ehci, USBSTS_FLR); -+ ehci->frindex = 0; -+ } -+ - ehci->sofv = (ehci->frindex - 1) >> 3; - ehci->sofv &= 0x000003ff; - } --- -1.7.9.3 - diff --git a/0142-usb-ehci-Drop-unused-sofv-value.patch b/0142-usb-ehci-Drop-unused-sofv-value.patch deleted file mode 100644 index d2cf3bf..0000000 --- a/0142-usb-ehci-Drop-unused-sofv-value.patch +++ /dev/null @@ -1,49 +0,0 @@ -From ef3477db39f2eb38610b7e99a4a4f4d8ddb903df Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 29 Mar 2012 16:37:34 +0200 -Subject: [PATCH 142/146] usb-ehci: Drop unused sofv value - -The sofv value only ever gets a value assigned and is never used (read) -anywhere, so we can just drop it. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 8 -------- - 1 file changed, 8 deletions(-) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index 3934bf0..ff69587 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -403,7 +403,6 @@ struct EHCIState { - /* - * Internal states, shadow registers, etc - */ -- uint32_t sofv; - QEMUTimer *frame_timer; - int attach_poll_counter; - int astate; // Current state in asynchronous schedule -@@ -1082,10 +1081,6 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) - val &= USBINTR_MASK; - break; - -- case FRINDEX: -- s->sofv = val >> 3; -- break; -- - case CONFIGFLAG: - val &= 0x1; - if (val) { -@@ -2165,9 +2160,6 @@ static void ehci_frame_timer(void *opaque) - ehci_set_interrupt(ehci, USBSTS_FLR); - ehci->frindex = 0; - } -- -- ehci->sofv = (ehci->frindex - 1) >> 3; -- ehci->sofv &= 0x000003ff; - } - - if (frames - i > ehci->maxframes) { --- -1.7.9.3 - diff --git a/0143-usb-redir-Notify-our-peer-when-we-reject-a-device-du.patch b/0143-usb-redir-Notify-our-peer-when-we-reject-a-device-du.patch deleted file mode 100644 index 1bf631a..0000000 --- a/0143-usb-redir-Notify-our-peer-when-we-reject-a-device-du.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 89c9752afa77c6936ab9839d8fb1ce42147086b2 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 29 Mar 2012 16:41:23 +0200 -Subject: [PATCH 143/146] usb-redir: Notify our peer when we reject a device - due to a speed mismatch - -Also cleanup (reset) our device state when we reject a device due to a -speed mismatch. - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/usb-redir.c b/usb-redir.c -index f64443e..8ee3f07 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -845,7 +845,13 @@ static void usbredir_do_attach(void *opaque) - { - USBRedirDevice *dev = opaque; - -- usb_device_attach(&dev->dev); -+ if (usb_device_attach(&dev->dev) != 0) { -+ usbredir_device_disconnect(dev); -+ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { -+ usbredirparser_send_filter_reject(dev->parser); -+ usbredirparser_do_write(dev->parser); -+ } -+ } - } - - /* --- -1.7.9.3 - diff --git a/0144-usb-redir-An-interface-count-of-0-is-a-valid-value.patch b/0144-usb-redir-An-interface-count-of-0-is-a-valid-value.patch deleted file mode 100644 index f654331..0000000 --- a/0144-usb-redir-An-interface-count-of-0-is-a-valid-value.patch +++ /dev/null @@ -1,47 +0,0 @@ -From c6b10d4d87d8158c1b0bd8648491db8501dff784 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sat, 31 Mar 2012 13:07:24 +0200 -Subject: [PATCH 144/146] usb-redir: An interface count of 0 is a valid value - -An interface-count of 0 happens when a device is in unconfigured state when -it gets redirected. So we should not use 0 to detect not having received -interface info from our peer. - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 5 +++-- - 1 file changed, 3 insertions(+), 2 deletions(-) - -diff --git a/usb-redir.c b/usb-redir.c -index 8ee3f07..3187b68 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -39,6 +39,7 @@ - #include "hw/usb.h" - - #define MAX_ENDPOINTS 32 -+#define NO_INTERFACE_INFO 255 /* Valid interface_count always <= 32 */ - #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) - #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) - -@@ -995,7 +996,7 @@ static void usbredir_handle_destroy(USBDevice *udev) - - static int usbredir_check_filter(USBRedirDevice *dev) - { -- if (dev->interface_info.interface_count == 0) { -+ if (dev->interface_info.interface_count == NO_INTERFACE_INFO) { - ERROR("No interface info for device\n"); - goto error; - } -@@ -1158,7 +1159,7 @@ static void usbredir_device_disconnect(void *priv) - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } -- dev->interface_info.interface_count = 0; -+ dev->interface_info.interface_count = NO_INTERFACE_INFO; - } - - static void usbredir_interface_info(void *priv, --- -1.7.9.3 - diff --git a/0145-usb-redir-Reset-device-address-and-speed-on-disconne.patch b/0145-usb-redir-Reset-device-address-and-speed-on-disconne.patch deleted file mode 100644 index b0c7c81..0000000 --- a/0145-usb-redir-Reset-device-address-and-speed-on-disconne.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 442d81d00308b0145307b175a1910c7443184a3f Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sat, 31 Mar 2012 13:12:09 +0200 -Subject: [PATCH 145/146] usb-redir: Reset device address and speed on - disconnect - -Without this disconnected devices look like the last redirected device -in the monitor in "info usb". - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/usb-redir.c b/usb-redir.c -index 3187b68..1a9d766 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -1160,6 +1160,8 @@ static void usbredir_device_disconnect(void *priv) - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } - dev->interface_info.interface_count = NO_INTERFACE_INFO; -+ dev->dev.addr = 0; -+ dev->dev.speed = 0; - } - - static void usbredir_interface_info(void *priv, --- -1.7.9.3 - diff --git a/0146-usb-redir-Not-finding-an-async-urb-id-is-not-an-erro.patch b/0146-usb-redir-Not-finding-an-async-urb-id-is-not-an-erro.patch deleted file mode 100644 index dcb1a9a..0000000 --- a/0146-usb-redir-Not-finding-an-async-urb-id-is-not-an-erro.patch +++ /dev/null @@ -1,31 +0,0 @@ -From b467871a6a08b8ff12382e33e49f991fe02f3cc7 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Sat, 31 Mar 2012 13:17:13 +0200 -Subject: [PATCH 146/146] usb-redir: Not finding an async urb id is not an - error - -We clear our pending async urb list on device disconnect and we may still -receive "packet complete" packets from our peer after this, which will then -refer to packet ids no longer in our list. - -Signed-off-by: Hans de Goede ---- - usb-redir.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/usb-redir.c b/usb-redir.c -index 1a9d766..a41c231 100644 ---- a/usb-redir.c -+++ b/usb-redir.c -@@ -286,7 +286,7 @@ static AsyncURB *async_find(USBRedirDevice *dev, uint32_t packet_id) - return aurb; - } - } -- ERROR("could not find async urb for packet_id %u\n", packet_id); -+ DPRINTF("could not find async urb for packet_id %u\n", packet_id); - return NULL; - } - --- -1.7.9.3 - diff --git a/0147-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch b/0147-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch deleted file mode 100644 index af7a55c..0000000 --- a/0147-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 4c245e5ecbc7d5c30c8e8bb4bfcd18c79fafddfe Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 3 Apr 2012 14:04:31 +0200 -Subject: [PATCH 147/181] usb-ehci: Ensure frindex writes leave a valid - frindex value - -frindex is a 14 bits counter, so bits 31-14 should always be 0, and -after the commit titled "usb-ehci: frindex always is a 14 bits counter" -we rely on frindex always being a multiple of 8. I've not seen this in -practice, but theoretically a guest can write a value >= 0x4000 or a value -which is not a multiple of 8 value to frindex, this patch ensures that -things will still work when that happens. - -Signed-off-by: Hans de Goede ---- - hw/usb-ehci.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c -index ff69587..16e6053 100644 ---- a/hw/usb-ehci.c -+++ b/hw/usb-ehci.c -@@ -1081,6 +1081,10 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) - val &= USBINTR_MASK; - break; - -+ case FRINDEX: -+ val &= 0x00003ff8; /* frindex is 14bits and always a multiple of 8 */ -+ break; -+ - case CONFIGFLAG: - val &= 0x1; - if (val) { --- -1.7.10 - diff --git a/0201-audio-add-VOICE_VOLUME-ctl.patch b/0201-audio-add-VOICE_VOLUME-ctl.patch new file mode 100644 index 0000000..6f867b9 --- /dev/null +++ b/0201-audio-add-VOICE_VOLUME-ctl.patch @@ -0,0 +1,65 @@ +From 5f04be57d78f368fef2fe3744261061f103c3b6a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:35 +0200 +Subject: [PATCH] audio: add VOICE_VOLUME ctl + +Add a new PCM control operation to update the stream volume on the +audio backend. The argument given is a SWVoiceOut/SWVoiceIn. + +v4: +- verified other backends didn't fail/assert on this new control + they randomly return 0 or -1, but we ignore return value. + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + audio/audio.c | 12 ++++++++++++ + audio/audio_int.h | 1 + + 2 files changed, 13 insertions(+) + +diff --git a/audio/audio.c b/audio/audio.c +index 50d0d71..2ae9b2f 100644 +--- a/audio/audio.c ++++ b/audio/audio.c +@@ -2050,17 +2050,29 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) + void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) + { + if (sw) { ++ HWVoiceOut *hw = sw->hw; ++ + sw->vol.mute = mute; + sw->vol.l = nominal_volume.l * lvol / 255; + sw->vol.r = nominal_volume.r * rvol / 255; ++ ++ if (hw->pcm_ops->ctl_out) { ++ hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw); ++ } + } + } + + void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) + { + if (sw) { ++ HWVoiceIn *hw = sw->hw; ++ + sw->vol.mute = mute; + sw->vol.l = nominal_volume.l * lvol / 255; + sw->vol.r = nominal_volume.r * rvol / 255; ++ ++ if (hw->pcm_ops->ctl_in) { ++ hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw); ++ } + } + } +diff --git a/audio/audio_int.h b/audio/audio_int.h +index 2003f8b..117f95e 100644 +--- a/audio/audio_int.h ++++ b/audio/audio_int.h +@@ -231,6 +231,7 @@ void audio_run (const char *msg); + + #define VOICE_ENABLE 1 + #define VOICE_DISABLE 2 ++#define VOICE_VOLUME 3 + + static inline int audio_ring_dist (int dst, int src, int len) + { diff --git a/0202-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch b/0202-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch new file mode 100644 index 0000000..42f6d8a --- /dev/null +++ b/0202-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch @@ -0,0 +1,96 @@ +From 15d3e952cd3e64e4cc2eee08bdbf29f4f59e1329 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:36 +0200 +Subject: [PATCH] audio: don't apply volume effect if backend has + VOICE_VOLUME_CAP + +If the audio backend is capable of volume control, don't apply +software volume (mixeng_volume ()), but instead, rely on backend +volume control. This will allow guest to have full range volume +control. + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + audio/audio.c | 9 +++++++-- + audio/audio_int.h | 5 +++++ + audio/audio_template.h | 2 ++ + 3 files changed, 14 insertions(+), 2 deletions(-) + +diff --git a/audio/audio.c b/audio/audio.c +index 2ae9b2f..0fe95a7 100644 +--- a/audio/audio.c ++++ b/audio/audio.c +@@ -954,7 +954,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) + total += isamp; + } + +- mixeng_volume (sw->buf, ret, &sw->vol); ++ if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) { ++ mixeng_volume (sw->buf, ret, &sw->vol); ++ } + + sw->clip (buf, sw->buf, ret); + sw->total_hw_samples_acquired += total; +@@ -1038,7 +1040,10 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) + swlim = audio_MIN (swlim, samples); + if (swlim) { + sw->conv (sw->buf, buf, swlim); +- mixeng_volume (sw->buf, swlim, &sw->vol); ++ ++ if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { ++ mixeng_volume (sw->buf, swlim, &sw->vol); ++ } + } + + while (swlim) { +diff --git a/audio/audio_int.h b/audio/audio_int.h +index 117f95e..b9b0676 100644 +--- a/audio/audio_int.h ++++ b/audio/audio_int.h +@@ -82,6 +82,7 @@ typedef struct HWVoiceOut { + int samples; + QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; + QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; ++ int ctl_caps; + struct audio_pcm_ops *pcm_ops; + QLIST_ENTRY (HWVoiceOut) entries; + } HWVoiceOut; +@@ -101,6 +102,7 @@ typedef struct HWVoiceIn { + + int samples; + QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; ++ int ctl_caps; + struct audio_pcm_ops *pcm_ops; + QLIST_ENTRY (HWVoiceIn) entries; + } HWVoiceIn; +@@ -150,6 +152,7 @@ struct audio_driver { + int max_voices_in; + int voice_size_out; + int voice_size_in; ++ int ctl_caps; + }; + + struct audio_pcm_ops { +@@ -233,6 +236,8 @@ void audio_run (const char *msg); + #define VOICE_DISABLE 2 + #define VOICE_VOLUME 3 + ++#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME) ++ + static inline int audio_ring_dist (int dst, int src, int len) + { + return (dst >= src) ? (dst - src) : (len - src + dst); +diff --git a/audio/audio_template.h b/audio/audio_template.h +index e62a713..519432a 100644 +--- a/audio/audio_template.h ++++ b/audio/audio_template.h +@@ -263,6 +263,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) + } + + hw->pcm_ops = drv->pcm_ops; ++ hw->ctl_caps = drv->ctl_caps; ++ + QLIST_INIT (&hw->sw_head); + #ifdef DAC + QLIST_INIT (&hw->cap_head); diff --git a/0203-hw-ac97-remove-USE_MIXER-code.patch b/0203-hw-ac97-remove-USE_MIXER-code.patch new file mode 100644 index 0000000..604e878 --- /dev/null +++ b/0203-hw-ac97-remove-USE_MIXER-code.patch @@ -0,0 +1,167 @@ +From 2464b79664069dff5082e871f2c2cf3b4af19621 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:37 +0200 +Subject: [PATCH] hw/ac97: remove USE_MIXER code + +That code doesn't compile. The interesting bits for volume control are +going to be rewritten in the following patch. + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + hw/ac97.c | 121 -------------------------------------------------------------- + 1 file changed, 121 deletions(-) + +diff --git a/hw/ac97.c b/hw/ac97.c +index 0dbba3b..cd893c3 100644 +--- a/hw/ac97.c ++++ b/hw/ac97.c +@@ -434,99 +434,6 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) + AUD_set_active_in (s->voice_mc, active[MC_INDEX]); + } + +-#ifdef USE_MIXER +-static void set_volume (AC97LinkState *s, int index, +- audmixerctl_t mt, uint32_t val) +-{ +- int mute = (val >> MUTE_SHIFT) & 1; +- uint8_t rvol = VOL_MASK - (val & VOL_MASK); +- uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK); +- rvol = 255 * rvol / VOL_MASK; +- lvol = 255 * lvol / VOL_MASK; +- +-#ifdef SOFT_VOLUME +- if (index == AC97_Master_Volume_Mute) { +- AUD_set_volume_out (s->voice_po, mute, lvol, rvol); +- } +- else { +- AUD_set_volume (mt, &mute, &lvol, &rvol); +- } +-#else +- AUD_set_volume (mt, &mute, &lvol, &rvol); +-#endif +- +- rvol = VOL_MASK - ((VOL_MASK * rvol) / 255); +- lvol = VOL_MASK - ((VOL_MASK * lvol) / 255); +- mixer_store (s, index, val); +-} +- +-static audrecsource_t ac97_to_aud_record_source (uint8_t i) +-{ +- switch (i) { +- case REC_MIC: +- return AUD_REC_MIC; +- +- case REC_CD: +- return AUD_REC_CD; +- +- case REC_VIDEO: +- return AUD_REC_VIDEO; +- +- case REC_AUX: +- return AUD_REC_AUX; +- +- case REC_LINE_IN: +- return AUD_REC_LINE_IN; +- +- case REC_PHONE: +- return AUD_REC_PHONE; +- +- default: +- dolog ("Unknown record source %d, using MIC\n", i); +- return AUD_REC_MIC; +- } +-} +- +-static uint8_t aud_to_ac97_record_source (audrecsource_t rs) +-{ +- switch (rs) { +- case AUD_REC_MIC: +- return REC_MIC; +- +- case AUD_REC_CD: +- return REC_CD; +- +- case AUD_REC_VIDEO: +- return REC_VIDEO; +- +- case AUD_REC_AUX: +- return REC_AUX; +- +- case AUD_REC_LINE_IN: +- return REC_LINE_IN; +- +- case AUD_REC_PHONE: +- return REC_PHONE; +- +- default: +- dolog ("Unknown audio recording source %d using MIC\n", rs); +- return REC_MIC; +- } +-} +- +-static void record_select (AC97LinkState *s, uint32_t val) +-{ +- uint8_t rs = val & REC_MASK; +- uint8_t ls = (val >> 8) & REC_MASK; +- audrecsource_t ars = ac97_to_aud_record_source (rs); +- audrecsource_t als = ac97_to_aud_record_source (ls); +- AUD_set_record_source (&als, &ars); +- rs = aud_to_ac97_record_source (ars); +- ls = aud_to_ac97_record_source (als); +- mixer_store (s, AC97_Record_Select, rs | (ls << 8)); +-} +-#endif +- + static void mixer_reset (AC97LinkState *s) + { + uint8_t active[LAST_INDEX]; +@@ -561,12 +468,6 @@ static void mixer_reset (AC97LinkState *s) + mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); + mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); + +-#ifdef USE_MIXER +- record_select (s, 0); +- set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME , 0x8000); +- set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM , 0x8808); +- set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); +-#endif + reset_voices (s, active); + } + +@@ -625,20 +526,6 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) + val |= mixer_load (s, index) & 0xf; + mixer_store (s, index, val); + break; +-#ifdef USE_MIXER +- case AC97_Master_Volume_Mute: +- set_volume (s, index, AUD_MIXER_VOLUME, val); +- break; +- case AC97_PCM_Out_Volume_Mute: +- set_volume (s, index, AUD_MIXER_PCM, val); +- break; +- case AC97_Line_In_Volume_Mute: +- set_volume (s, index, AUD_MIXER_LINE_IN, val); +- break; +- case AC97_Record_Select: +- record_select (s, val); +- break; +-#endif + case AC97_Vendor_ID1: + case AC97_Vendor_ID2: + dolog ("Attempt to write vendor ID to %#x\n", val); +@@ -1191,14 +1078,6 @@ static int ac97_post_load (void *opaque, int version_id) + uint8_t active[LAST_INDEX]; + AC97LinkState *s = opaque; + +-#ifdef USE_MIXER +- record_select (s, mixer_load (s, AC97_Record_Select)); +-#define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) +- V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); +- V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); +- V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); +-#undef V_ +-#endif + active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); + active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); + active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); diff --git a/0203-pci-fix-corrupted-pci-conf-index-register-by-unaligned-write.patch b/0203-pci-fix-corrupted-pci-conf-index-register-by-unaligned-write.patch deleted file mode 100644 index 609ffe3..0000000 --- a/0203-pci-fix-corrupted-pci-conf-index-register-by-unaligned-write.patch +++ /dev/null @@ -1,33 +0,0 @@ -commit cdde6ffc27517bdf069734fbc5693ce2b14edc75 -Author: Avi Kivity -Date: Wed Jan 4 16:28:42 2012 +0200 - - pci: fix corrupted pci conf index register by unaligned write - - Commit d0ed8076cbdc261 converted the PCI config access to the memory - API, but also inadvertantly changed it to accept unaligned writes, - and corrupt the index register in the process. This causes a regression - booting NetBSD. - - Fix by ignoring unaligned or non-dword writes. - - https://bugs.launchpad.net/qemu/+bug/897771 - - Reported-by: Andreas Gustafsson - Signed-off-by: Avi Kivity - Signed-off-by: Michael S. Tsirkin - -diff --git a/hw/pci_host.c b/hw/pci_host.c -index 44c6c20..8041778 100644 ---- a/hw/pci_host.c -+++ b/hw/pci_host.c -@@ -101,6 +101,9 @@ static void pci_host_config_write(void *opaque, target_phys_addr_t addr, - - PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", - __func__, addr, len, val); -+ if (addr != 0 || len != 4) { -+ return; -+ } - s->config_reg = val; - } - diff --git a/0204-hw-ac97-the-volume-mask-is-not-only-0x1f.patch b/0204-hw-ac97-the-volume-mask-is-not-only-0x1f.patch new file mode 100644 index 0000000..2f57247 --- /dev/null +++ b/0204-hw-ac97-the-volume-mask-is-not-only-0x1f.patch @@ -0,0 +1,25 @@ +From 3f4683eb76bbf666def534029c0646e1ea4a4163 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:38 +0200 +Subject: [PATCH] hw/ac97: the volume mask is not only 0x1f + +It's a case by case (see Table 66. AC ?97 Baseline Audio Register Map) + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + hw/ac97.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/hw/ac97.c b/hw/ac97.c +index cd893c3..aa1babf 100644 +--- a/hw/ac97.c ++++ b/hw/ac97.c +@@ -115,7 +115,6 @@ enum { + #define EACS_VRA 1 + #define EACS_VRM 8 + +-#define VOL_MASK 0x1f + #define MUTE_SHIFT 15 + + #define REC_MASK 7 diff --git a/0205-hw-ac97-add-support-for-volume-control.patch b/0205-hw-ac97-add-support-for-volume-control.patch new file mode 100644 index 0000000..40570fb --- /dev/null +++ b/0205-hw-ac97-add-support-for-volume-control.patch @@ -0,0 +1,131 @@ +From a1635094522e85b18aa23fdfb44357e829b34bd4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:39 +0200 +Subject: [PATCH] hw/ac97: add support for volume control + +Combine output volume with Master and PCM registers values. +Use default values in mixer_reset (). +Set volume on post-load to update backend values. + +v4,v5: +- fix some code style + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + hw/ac97.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 81 insertions(+) + +diff --git a/hw/ac97.c b/hw/ac97.c +index aa1babf..dd4917b 100644 +--- a/hw/ac97.c ++++ b/hw/ac97.c +@@ -433,6 +433,65 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) + AUD_set_active_in (s->voice_mc, active[MC_INDEX]); + } + ++static void get_volume (uint16_t vol, uint16_t mask, int inverse, ++ int *mute, uint8_t *lvol, uint8_t *rvol) ++{ ++ *mute = (vol >> MUTE_SHIFT) & 1; ++ *rvol = (255 * (vol & mask)) / mask; ++ *lvol = (255 * ((vol >> 8) & mask)) / mask; ++ ++ if (inverse) { ++ *rvol = 255 - *rvol; ++ *lvol = 255 - *lvol; ++ } ++} ++ ++static void update_combined_volume_out (AC97LinkState *s) ++{ ++ uint8_t lvol, rvol, plvol, prvol; ++ int mute, pmute; ++ ++ get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, ++ &mute, &lvol, &rvol); ++ /* FIXME: should be 1f according to spec */ ++ get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1, ++ &pmute, &plvol, &prvol); ++ ++ mute = mute | pmute; ++ lvol = (lvol * plvol) / 255; ++ rvol = (rvol * prvol) / 255; ++ ++ AUD_set_volume_out (s->voice_po, mute, lvol, rvol); ++} ++ ++static void update_volume_in (AC97LinkState *s) ++{ ++ uint8_t lvol, rvol; ++ int mute; ++ ++ get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, ++ &mute, &lvol, &rvol); ++ ++ AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); ++} ++ ++static void set_volume (AC97LinkState *s, int index, uint32_t val) ++{ ++ mixer_store (s, index, val); ++ if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) { ++ update_combined_volume_out (s); ++ } else if (index == AC97_Record_Gain_Mute) { ++ update_volume_in (s); ++ } ++} ++ ++static void record_select (AC97LinkState *s, uint32_t val) ++{ ++ uint8_t rs = val & REC_MASK; ++ uint8_t ls = (val >> 8) & REC_MASK; ++ mixer_store (s, AC97_Record_Select, rs | (ls << 8)); ++} ++ + static void mixer_reset (AC97LinkState *s) + { + uint8_t active[LAST_INDEX]; +@@ -467,6 +526,11 @@ static void mixer_reset (AC97LinkState *s) + mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); + mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); + ++ record_select (s, 0); ++ set_volume (s, AC97_Master_Volume_Mute, 0x8000); ++ set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); ++ set_volume (s, AC97_Line_In_Volume_Mute, 0x8808); ++ + reset_voices (s, active); + } + +@@ -525,6 +589,15 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) + val |= mixer_load (s, index) & 0xf; + mixer_store (s, index, val); + break; ++ case AC97_PCM_Out_Volume_Mute: ++ case AC97_Master_Volume_Mute: ++ case AC97_Record_Gain_Mute: ++ case AC97_Line_In_Volume_Mute: ++ set_volume (s, index, val); ++ break; ++ case AC97_Record_Select: ++ record_select (s, val); ++ break; + case AC97_Vendor_ID1: + case AC97_Vendor_ID2: + dolog ("Attempt to write vendor ID to %#x\n", val); +@@ -1077,6 +1150,14 @@ static int ac97_post_load (void *opaque, int version_id) + uint8_t active[LAST_INDEX]; + AC97LinkState *s = opaque; + ++ record_select (s, mixer_load (s, AC97_Record_Select)); ++ set_volume (s, AC97_Master_Volume_Mute, ++ mixer_load (s, AC97_Master_Volume_Mute)); ++ set_volume (s, AC97_PCM_Out_Volume_Mute, ++ mixer_load (s, AC97_PCM_Out_Volume_Mute)); ++ set_volume (s, AC97_Line_In_Volume_Mute, ++ mixer_load (s, AC97_Line_In_Volume_Mute)); ++ + active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); + active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); + active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); diff --git a/0206-audio-spice-add-support-for-volume-control.patch b/0206-audio-spice-add-support-for-volume-control.patch new file mode 100644 index 0000000..ffb3381 --- /dev/null +++ b/0206-audio-spice-add-support-for-volume-control.patch @@ -0,0 +1,81 @@ +From 08e41d00c5896188f059e4030b110d44fae6edcc Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:40 +0200 +Subject: [PATCH] audio/spice: add support for volume control + +Use Spice server volume control API when available. + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + audio/spiceaudio.c | 41 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 41 insertions(+) + +diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c +index f972110..6f15591 100644 +--- a/audio/spiceaudio.c ++++ b/audio/spiceaudio.c +@@ -202,7 +202,26 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) + } + spice_server_playback_stop (&out->sin); + break; ++ case VOICE_VOLUME: ++ { ++#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) ++ SWVoiceOut *sw; ++ va_list ap; ++ uint16_t vol[2]; ++ ++ va_start (ap, cmd); ++ sw = va_arg (ap, SWVoiceOut *); ++ va_end (ap); ++ ++ vol[0] = sw->vol.l / ((1ULL << 16) + 1); ++ vol[1] = sw->vol.r / ((1ULL << 16) + 1); ++ spice_server_playback_set_volume (&out->sin, 2, vol); ++ spice_server_playback_set_mute (&out->sin, sw->vol.mute); ++#endif ++ break; ++ } + } ++ + return 0; + } + +@@ -304,7 +323,26 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) + in->active = 0; + spice_server_record_stop (&in->sin); + break; ++ case VOICE_VOLUME: ++ { ++#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) ++ SWVoiceIn *sw; ++ va_list ap; ++ uint16_t vol[2]; ++ ++ va_start (ap, cmd); ++ sw = va_arg (ap, SWVoiceIn *); ++ va_end (ap); ++ ++ vol[0] = sw->vol.l / ((1ULL << 16) + 1); ++ vol[1] = sw->vol.r / ((1ULL << 16) + 1); ++ spice_server_record_set_volume (&in->sin, 2, vol); ++ spice_server_record_set_mute (&in->sin, sw->vol.mute); ++#endif ++ break; ++ } + } ++ + return 0; + } + +@@ -337,6 +375,9 @@ struct audio_driver spice_audio_driver = { + .max_voices_in = 1, + .voice_size_out = sizeof (SpiceVoiceOut), + .voice_size_in = sizeof (SpiceVoiceIn), ++#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) ++ .ctl_caps = VOICE_VOLUME_CAP ++#endif + }; + + void qemu_spice_audio_init (void) diff --git a/0207-Do-not-use-pa_simple-PulseAudio-API.patch b/0207-Do-not-use-pa_simple-PulseAudio-API.patch new file mode 100644 index 0000000..20d0d93 --- /dev/null +++ b/0207-Do-not-use-pa_simple-PulseAudio-API.patch @@ -0,0 +1,570 @@ +From a667ecabfd0242606e1f5f763116cd8df2ff7fc1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:41 +0200 +Subject: [PATCH] Do not use pa_simple PulseAudio API + +Unfortunately, pa_simple is a limited API which doesn't let us +retrieve the associated pa_stream. It is needed to control the volume +of the stream. + +In v4: +- add missing braces + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + audio/paaudio.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 339 insertions(+), 38 deletions(-) + +diff --git a/audio/paaudio.c b/audio/paaudio.c +index d1f3912..6f50c1c 100644 +--- a/audio/paaudio.c ++++ b/audio/paaudio.c +@@ -2,8 +2,7 @@ + #include "qemu-common.h" + #include "audio.h" + +-#include +-#include ++#include + + #define AUDIO_CAP "pulseaudio" + #include "audio_int.h" +@@ -15,7 +14,7 @@ typedef struct { + int live; + int decr; + int rpos; +- pa_simple *s; ++ pa_stream *stream; + void *pcm_buf; + struct audio_pt pt; + } PAVoiceOut; +@@ -26,17 +25,23 @@ typedef struct { + int dead; + int incr; + int wpos; +- pa_simple *s; ++ pa_stream *stream; + void *pcm_buf; + struct audio_pt pt; ++ const void *read_data; ++ size_t read_index, read_length; + } PAVoiceIn; + +-static struct { ++typedef struct { + int samples; + char *server; + char *sink; + char *source; +-} conf = { ++ pa_threaded_mainloop *mainloop; ++ pa_context *context; ++} paaudio; ++ ++static paaudio glob_paaudio = { + .samples = 4096, + }; + +@@ -51,6 +56,126 @@ static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) + AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err)); + } + ++#define CHECK_SUCCESS_GOTO(c, rerror, expression, label) \ ++ do { \ ++ if (!(expression)) { \ ++ if (rerror) { \ ++ *(rerror) = pa_context_errno ((c)->context); \ ++ } \ ++ goto label; \ ++ } \ ++ } while (0); ++ ++#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ ++ do { \ ++ if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ ++ !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \ ++ if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ ++ ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ ++ if (rerror) { \ ++ *(rerror) = pa_context_errno ((c)->context); \ ++ } \ ++ } else { \ ++ if (rerror) { \ ++ *(rerror) = PA_ERR_BADSTATE; \ ++ } \ ++ } \ ++ goto label; \ ++ } \ ++ } while (0); ++ ++static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror) ++{ ++ paaudio *g = &glob_paaudio; ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); ++ ++ while (length > 0) { ++ size_t l; ++ ++ while (!p->read_data) { ++ int r; ++ ++ r = pa_stream_peek (p->stream, &p->read_data, &p->read_length); ++ CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); ++ ++ if (!p->read_data) { ++ pa_threaded_mainloop_wait (g->mainloop); ++ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); ++ } else { ++ p->read_index = 0; ++ } ++ } ++ ++ l = p->read_length < length ? p->read_length : length; ++ memcpy (data, (const uint8_t *) p->read_data+p->read_index, l); ++ ++ data = (uint8_t *) data + l; ++ length -= l; ++ ++ p->read_index += l; ++ p->read_length -= l; ++ ++ if (!p->read_length) { ++ int r; ++ ++ r = pa_stream_drop (p->stream); ++ p->read_data = NULL; ++ p->read_length = 0; ++ p->read_index = 0; ++ ++ CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); ++ } ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ return 0; ++ ++unlock_and_fail: ++ pa_threaded_mainloop_unlock (g->mainloop); ++ return -1; ++} ++ ++static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror) ++{ ++ paaudio *g = &glob_paaudio; ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); ++ ++ while (length > 0) { ++ size_t l; ++ int r; ++ ++ while (!(l = pa_stream_writable_size (p->stream))) { ++ pa_threaded_mainloop_wait (g->mainloop); ++ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); ++ } ++ ++ CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail); ++ ++ if (l > length) { ++ l = length; ++ } ++ ++ r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE); ++ CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail); ++ ++ data = (const uint8_t *) data + l; ++ length -= l; ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ return 0; ++ ++unlock_and_fail: ++ pa_threaded_mainloop_unlock (g->mainloop); ++ return -1; ++} ++ + static void *qpa_thread_out (void *arg) + { + PAVoiceOut *pa = arg; +@@ -77,7 +202,7 @@ static void *qpa_thread_out (void *arg) + } + } + +- decr = to_mix = audio_MIN (pa->live, conf.samples >> 2); ++ decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2); + rpos = pa->rpos; + + if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { +@@ -91,8 +216,8 @@ static void *qpa_thread_out (void *arg) + + hw->clip (pa->pcm_buf, src, chunk); + +- if (pa_simple_write (pa->s, pa->pcm_buf, +- chunk << hw->info.shift, &error) < 0) { ++ if (qpa_simple_write (pa, pa->pcm_buf, ++ chunk << hw->info.shift, &error) < 0) { + qpa_logerr (error, "pa_simple_write failed\n"); + return NULL; + } +@@ -169,7 +294,7 @@ static void *qpa_thread_in (void *arg) + } + } + +- incr = to_grab = audio_MIN (pa->dead, conf.samples >> 2); ++ incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2); + wpos = pa->wpos; + + if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { +@@ -181,8 +306,8 @@ static void *qpa_thread_in (void *arg) + int chunk = audio_MIN (to_grab, hw->samples - wpos); + void *buf = advance (pa->pcm_buf, wpos); + +- if (pa_simple_read (pa->s, buf, +- chunk << hw->info.shift, &error) < 0) { ++ if (qpa_simple_read (pa, buf, ++ chunk << hw->info.shift, &error) < 0) { + qpa_logerr (error, "pa_simple_read failed\n"); + return NULL; + } +@@ -283,6 +408,109 @@ static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness) + } + } + ++static void context_state_cb (pa_context *c, void *userdata) ++{ ++ paaudio *g = &glob_paaudio; ++ ++ switch (pa_context_get_state(c)) { ++ case PA_CONTEXT_READY: ++ case PA_CONTEXT_TERMINATED: ++ case PA_CONTEXT_FAILED: ++ pa_threaded_mainloop_signal (g->mainloop, 0); ++ break; ++ ++ case PA_CONTEXT_UNCONNECTED: ++ case PA_CONTEXT_CONNECTING: ++ case PA_CONTEXT_AUTHORIZING: ++ case PA_CONTEXT_SETTING_NAME: ++ break; ++ } ++} ++ ++static void stream_state_cb (pa_stream *s, void * userdata) ++{ ++ paaudio *g = &glob_paaudio; ++ ++ switch (pa_stream_get_state (s)) { ++ ++ case PA_STREAM_READY: ++ case PA_STREAM_FAILED: ++ case PA_STREAM_TERMINATED: ++ pa_threaded_mainloop_signal (g->mainloop, 0); ++ break; ++ ++ case PA_STREAM_UNCONNECTED: ++ case PA_STREAM_CREATING: ++ break; ++ } ++} ++ ++static void stream_request_cb (pa_stream *s, size_t length, void *userdata) ++{ ++ paaudio *g = &glob_paaudio; ++ ++ pa_threaded_mainloop_signal (g->mainloop, 0); ++} ++ ++static pa_stream *qpa_simple_new ( ++ const char *server, ++ const char *name, ++ pa_stream_direction_t dir, ++ const char *dev, ++ const char *stream_name, ++ const pa_sample_spec *ss, ++ const pa_channel_map *map, ++ const pa_buffer_attr *attr, ++ int *rerror) ++{ ++ paaudio *g = &glob_paaudio; ++ int r; ++ pa_stream *stream; ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ stream = pa_stream_new (g->context, name, ss, map); ++ if (!stream) { ++ goto fail; ++ } ++ ++ pa_stream_set_state_callback (stream, stream_state_cb, g); ++ pa_stream_set_read_callback (stream, stream_request_cb, g); ++ pa_stream_set_write_callback (stream, stream_request_cb, g); ++ ++ if (dir == PA_STREAM_PLAYBACK) { ++ r = pa_stream_connect_playback (stream, dev, attr, ++ PA_STREAM_INTERPOLATE_TIMING ++ |PA_STREAM_ADJUST_LATENCY ++ |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); ++ } else { ++ r = pa_stream_connect_record (stream, dev, attr, ++ PA_STREAM_INTERPOLATE_TIMING ++ |PA_STREAM_ADJUST_LATENCY ++ |PA_STREAM_AUTO_TIMING_UPDATE); ++ } ++ ++ if (r < 0) { ++ goto fail; ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ ++ return stream; ++ ++fail: ++ pa_threaded_mainloop_unlock (g->mainloop); ++ ++ if (stream) { ++ pa_stream_unref (stream); ++ } ++ ++ qpa_logerr (pa_context_errno (g->context), ++ "stream_new() failed\n"); ++ ++ return NULL; ++} ++ + static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as) + { + int error; +@@ -306,24 +534,24 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as) + + obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); + +- pa->s = pa_simple_new ( +- conf.server, ++ pa->stream = qpa_simple_new ( ++ glob_paaudio.server, + "qemu", + PA_STREAM_PLAYBACK, +- conf.sink, ++ glob_paaudio.sink, + "pcm.playback", + &ss, + NULL, /* channel map */ + &ba, /* buffering attributes */ + &error + ); +- if (!pa->s) { ++ if (!pa->stream) { + qpa_logerr (error, "pa_simple_new for playback failed\n"); + goto fail1; + } + + audio_pcm_init_info (&hw->info, &obt_as); +- hw->samples = conf.samples; ++ hw->samples = glob_paaudio.samples; + pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + pa->rpos = hw->rpos; + if (!pa->pcm_buf) { +@@ -342,8 +570,10 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as) + g_free (pa->pcm_buf); + pa->pcm_buf = NULL; + fail2: +- pa_simple_free (pa->s); +- pa->s = NULL; ++ if (pa->stream) { ++ pa_stream_unref (pa->stream); ++ pa->stream = NULL; ++ } + fail1: + return -1; + } +@@ -361,24 +591,24 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as) + + obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); + +- pa->s = pa_simple_new ( +- conf.server, ++ pa->stream = qpa_simple_new ( ++ glob_paaudio.server, + "qemu", + PA_STREAM_RECORD, +- conf.source, ++ glob_paaudio.source, + "pcm.capture", + &ss, + NULL, /* channel map */ + NULL, /* buffering attributes */ + &error + ); +- if (!pa->s) { ++ if (!pa->stream) { + qpa_logerr (error, "pa_simple_new for capture failed\n"); + goto fail1; + } + + audio_pcm_init_info (&hw->info, &obt_as); +- hw->samples = conf.samples; ++ hw->samples = glob_paaudio.samples; + pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); + pa->wpos = hw->wpos; + if (!pa->pcm_buf) { +@@ -397,8 +627,10 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as) + g_free (pa->pcm_buf); + pa->pcm_buf = NULL; + fail2: +- pa_simple_free (pa->s); +- pa->s = NULL; ++ if (pa->stream) { ++ pa_stream_unref (pa->stream); ++ pa->stream = NULL; ++ } + fail1: + return -1; + } +@@ -413,9 +645,9 @@ static void qpa_fini_out (HWVoiceOut *hw) + audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); + audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); + +- if (pa->s) { +- pa_simple_free (pa->s); +- pa->s = NULL; ++ if (pa->stream) { ++ pa_stream_unref (pa->stream); ++ pa->stream = NULL; + } + + audio_pt_fini (&pa->pt, AUDIO_FUNC); +@@ -433,9 +665,9 @@ static void qpa_fini_in (HWVoiceIn *hw) + audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); + audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); + +- if (pa->s) { +- pa_simple_free (pa->s); +- pa->s = NULL; ++ if (pa->stream) { ++ pa_stream_unref (pa->stream); ++ pa->stream = NULL; + } + + audio_pt_fini (&pa->pt, AUDIO_FUNC); +@@ -460,37 +692,106 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) + /* common */ + static void *qpa_audio_init (void) + { +- return &conf; ++ paaudio *g = &glob_paaudio; ++ ++ g->mainloop = pa_threaded_mainloop_new (); ++ if (!g->mainloop) { ++ goto fail; ++ } ++ ++ g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), glob_paaudio.server); ++ if (!g->context) { ++ goto fail; ++ } ++ ++ pa_context_set_state_callback (g->context, context_state_cb, g); ++ ++ if (pa_context_connect (g->context, glob_paaudio.server, 0, NULL) < 0) { ++ qpa_logerr (pa_context_errno (g->context), ++ "pa_context_connect() failed\n"); ++ goto fail; ++ } ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ if (pa_threaded_mainloop_start (g->mainloop) < 0) { ++ goto unlock_and_fail; ++ } ++ ++ for (;;) { ++ pa_context_state_t state; ++ ++ state = pa_context_get_state (g->context); ++ ++ if (state == PA_CONTEXT_READY) { ++ break; ++ } ++ ++ if (!PA_CONTEXT_IS_GOOD (state)) { ++ qpa_logerr (pa_context_errno (g->context), ++ "Wrong context state\n"); ++ goto unlock_and_fail; ++ } ++ ++ /* Wait until the context is ready */ ++ pa_threaded_mainloop_wait (g->mainloop); ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ ++ return &glob_paaudio; ++ ++unlock_and_fail: ++ pa_threaded_mainloop_unlock (g->mainloop); ++fail: ++ AUD_log (AUDIO_CAP, "Failed to initialize PA context"); ++ return NULL; + } + + static void qpa_audio_fini (void *opaque) + { +- (void) opaque; ++ paaudio *g = opaque; ++ ++ if (g->mainloop) { ++ pa_threaded_mainloop_stop (g->mainloop); ++ } ++ ++ if (g->context) { ++ pa_context_disconnect (g->context); ++ pa_context_unref (g->context); ++ g->context = NULL; ++ } ++ ++ if (g->mainloop) { ++ pa_threaded_mainloop_free (g->mainloop); ++ } ++ ++ g->mainloop = NULL; + } + + struct audio_option qpa_options[] = { + { + .name = "SAMPLES", + .tag = AUD_OPT_INT, +- .valp = &conf.samples, ++ .valp = &glob_paaudio.samples, + .descr = "buffer size in samples" + }, + { + .name = "SERVER", + .tag = AUD_OPT_STR, +- .valp = &conf.server, ++ .valp = &glob_paaudio.server, + .descr = "server address" + }, + { + .name = "SINK", + .tag = AUD_OPT_STR, +- .valp = &conf.sink, ++ .valp = &glob_paaudio.sink, + .descr = "sink device name" + }, + { + .name = "SOURCE", + .tag = AUD_OPT_STR, +- .valp = &conf.source, ++ .valp = &glob_paaudio.source, + .descr = "source device name" + }, + { /* End of list */ } diff --git a/0208-configure-pa_simple-is-not-needed-anymore.patch b/0208-configure-pa_simple-is-not-needed-anymore.patch new file mode 100644 index 0000000..7b5b5f9 --- /dev/null +++ b/0208-configure-pa_simple-is-not-needed-anymore.patch @@ -0,0 +1,28 @@ +From c0c2606fbf87ee34cca9545017471b185e7e4b46 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:42 +0200 +Subject: [PATCH] configure: pa_simple is not needed anymore + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + configure | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/configure b/configure +index 9bdeea7..33bdf10 100755 +--- a/configure ++++ b/configure +@@ -1791,9 +1791,9 @@ for drv in $audio_drv_list; do + ;; + + pa) +- audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \ +- "pa_simple *s = 0; pa_simple_free(s); return 0;" +- libs_softmmu="-lpulse -lpulse-simple $libs_softmmu" ++ audio_drv_probe $drv pulse/mainloop.h "-lpulse" \ ++ "pa_mainloop *m = 0; pa_mainloop_free (m); return 0;" ++ libs_softmmu="-lpulse $libs_softmmu" + audio_pt_int="yes" + ;; + diff --git a/0209-Allow-controlling-volume-with-PulseAudio-backend.patch b/0209-Allow-controlling-volume-with-PulseAudio-backend.patch new file mode 100644 index 0000000..3166981 --- /dev/null +++ b/0209-Allow-controlling-volume-with-PulseAudio-backend.patch @@ -0,0 +1,131 @@ +From 4667260627791ff2282c7ca53cffd296f0472bf0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Tue, 17 Apr 2012 14:32:43 +0200 +Subject: [PATCH] Allow controlling volume with PulseAudio backend + +Signed-off-by: Marc-Andr? Lureau +Signed-off-by: malc +--- + audio/paaudio.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 94 insertions(+), 5 deletions(-) + +diff --git a/audio/paaudio.c b/audio/paaudio.c +index 6f50c1c..e6708d0 100644 +--- a/audio/paaudio.c ++++ b/audio/paaudio.c +@@ -677,15 +677,103 @@ static void qpa_fini_in (HWVoiceIn *hw) + + static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) + { +- (void) hw; +- (void) cmd; ++ PAVoiceOut *pa = (PAVoiceOut *) hw; ++ pa_operation *op; ++ pa_cvolume v; ++ paaudio *g = &glob_paaudio; ++ ++ pa_cvolume_init (&v); ++ ++ switch (cmd) { ++ case VOICE_VOLUME: ++ { ++ SWVoiceOut *sw; ++ va_list ap; ++ ++ va_start (ap, cmd); ++ sw = va_arg (ap, SWVoiceOut *); ++ va_end (ap); ++ ++ v.channels = 2; ++ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; ++ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ op = pa_context_set_sink_input_volume (g->context, ++ pa_stream_get_index (pa->stream), ++ &v, NULL, NULL); ++ if (!op) ++ qpa_logerr (pa_context_errno (g->context), ++ "set_sink_input_volume() failed\n"); ++ else ++ pa_operation_unref (op); ++ ++ op = pa_context_set_sink_input_mute (g->context, ++ pa_stream_get_index (pa->stream), ++ sw->vol.mute, NULL, NULL); ++ if (!op) { ++ qpa_logerr (pa_context_errno (g->context), ++ "set_sink_input_mute() failed\n"); ++ } else { ++ pa_operation_unref (op); ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ } ++ } + return 0; + } + + static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) + { +- (void) hw; +- (void) cmd; ++ PAVoiceIn *pa = (PAVoiceIn *) hw; ++ pa_operation *op; ++ pa_cvolume v; ++ paaudio *g = &glob_paaudio; ++ ++ pa_cvolume_init (&v); ++ ++ switch (cmd) { ++ case VOICE_VOLUME: ++ { ++ SWVoiceIn *sw; ++ va_list ap; ++ ++ va_start (ap, cmd); ++ sw = va_arg (ap, SWVoiceIn *); ++ va_end (ap); ++ ++ v.channels = 2; ++ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; ++ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; ++ ++ pa_threaded_mainloop_lock (g->mainloop); ++ ++ /* FIXME: use the upcoming "set_source_output_{volume,mute}" */ ++ op = pa_context_set_source_volume_by_index (g->context, ++ pa_stream_get_device_index (pa->stream), ++ &v, NULL, NULL); ++ if (!op) { ++ qpa_logerr (pa_context_errno (g->context), ++ "set_source_volume() failed\n"); ++ } else { ++ pa_operation_unref(op); ++ } ++ ++ op = pa_context_set_source_mute_by_index (g->context, ++ pa_stream_get_index (pa->stream), ++ sw->vol.mute, NULL, NULL); ++ if (!op) { ++ qpa_logerr (pa_context_errno (g->context), ++ "set_source_mute() failed\n"); ++ } else { ++ pa_operation_unref (op); ++ } ++ ++ pa_threaded_mainloop_unlock (g->mainloop); ++ } ++ } + return 0; + } + +@@ -822,5 +910,6 @@ struct audio_driver pa_audio_driver = { + .max_voices_out = INT_MAX, + .max_voices_in = INT_MAX, + .voice_size_out = sizeof (PAVoiceOut), +- .voice_size_in = sizeof (PAVoiceIn) ++ .voice_size_in = sizeof (PAVoiceIn), ++ .ctl_caps = VOICE_VOLUME_CAP + }; diff --git a/0301-enable-architectural-PMU-cpuid-leaf-for-kvm.patch b/0301-enable-architectural-PMU-cpuid-leaf-for-kvm.patch new file mode 100644 index 0000000..5e8a826 --- /dev/null +++ b/0301-enable-architectural-PMU-cpuid-leaf-for-kvm.patch @@ -0,0 +1,40 @@ +From e8b330acc45acd7e5a1d23a0a07a3caa73205be5 Mon Sep 17 00:00:00 2001 +From: Gleb Natapov +Date: Thu, 15 Dec 2011 12:44:05 +0200 +Subject: [PATCH] enable architectural PMU cpuid leaf for kvm + +Signed-off-by: Gleb Natapov +Signed-off-by: Marcelo Tosatti +(cherry picked from commit a0fa82085e175bf8ce6d69a3f83695f81af2a649) +--- + target-i386/cpuid.c | 17 +++++++++++++---- + 1 file changed, 13 insertions(+), 4 deletions(-) + +diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c +index 0b3af90..91a104b 100644 +--- a/target-i386/cpuid.c ++++ b/target-i386/cpuid.c +@@ -1180,10 +1180,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, + break; + case 0xA: + /* Architectural Performance Monitoring Leaf */ +- *eax = 0; +- *ebx = 0; +- *ecx = 0; +- *edx = 0; ++ if (kvm_enabled()) { ++ KVMState *s = env->kvm_state; ++ ++ *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX); ++ *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX); ++ *ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX); ++ *edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX); ++ } else { ++ *eax = 0; ++ *ebx = 0; ++ *ecx = 0; ++ *edx = 0; ++ } + break; + case 0xD: + /* Processor Extended State */ diff --git a/0302-virtio-scsi-backport.patch b/0302-virtio-scsi-backport.patch new file mode 100644 index 0000000..44077ef --- /dev/null +++ b/0302-virtio-scsi-backport.patch @@ -0,0 +1,1708 @@ +From 656eb6b31a82b5fbca7257adc58bc1842de588aa Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Wed, 6 Feb 2013 16:41:30 -0500 +Subject: [PATCH] virtio scsi backport + +--- + Makefile.target | 1 + + default-configs/pci.mak | 1 + + default-configs/s390x-softmmu.mak | 1 + + dma-helpers.c | 36 +++ + dma.h | 20 +- + hw/esp.c | 3 +- + hw/ide/ahci.c | 82 +---- + hw/lsi53c895a.c | 2 +- + hw/pci.h | 1 + + hw/s390-virtio-bus.c | 24 ++ + hw/s390-virtio-bus.h | 2 + + hw/scsi-bus.c | 143 ++++++++- + hw/scsi-disk.c | 126 ++++++-- + hw/scsi-generic.c | 25 ++ + hw/scsi.h | 22 +- + hw/spapr_vscsi.c | 2 +- + hw/usb-msd.c | 2 +- + hw/virtio-pci.c | 42 +++ + hw/virtio-pci.h | 2 + + hw/virtio-scsi.c | 607 ++++++++++++++++++++++++++++++++++++++ + hw/virtio-scsi.h | 36 +++ + hw/virtio.h | 3 + + 22 files changed, 1077 insertions(+), 106 deletions(-) + create mode 100644 hw/virtio-scsi.c + create mode 100644 hw/virtio-scsi.h + +diff --git a/Makefile.target b/Makefile.target +index 29eaa68..64c1b49 100644 +--- a/Makefile.target ++++ b/Makefile.target +@@ -205,6 +205,7 @@ obj-y = arch_init.o cpus.o monitor.o machine.o gdbstub.o balloon.o ioport.o + obj-$(CONFIG_NO_PCI) += pci-stub.o + obj-$(CONFIG_PCI) += pci.o + obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o ++obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi.o + obj-y += vhost_net.o + obj-$(CONFIG_VHOST_NET) += vhost.o + obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o +diff --git a/default-configs/pci.mak b/default-configs/pci.mak +index 22bd350..9c8edd4 100644 +--- a/default-configs/pci.mak ++++ b/default-configs/pci.mak +@@ -1,5 +1,6 @@ + CONFIG_PCI=y + CONFIG_VIRTIO_PCI=y ++CONFIG_VIRTIO_SCSI=y + CONFIG_VIRTIO=y + CONFIG_USB_UHCI=y + CONFIG_USB_OHCI=y +diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak +index 3005729..e588803 100644 +--- a/default-configs/s390x-softmmu.mak ++++ b/default-configs/s390x-softmmu.mak +@@ -1 +1,2 @@ + CONFIG_VIRTIO=y ++CONFIG_VIRTIO_SCSI=y +diff --git a/dma-helpers.c b/dma-helpers.c +index bdcd38c..fc35f23 100644 +--- a/dma-helpers.c ++++ b/dma-helpers.c +@@ -196,3 +196,39 @@ BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs, + { + return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, true); + } ++ ++ ++static uint64_t dma_buf_rw(uint8_t *ptr, int32_t len, QEMUSGList *sg, bool to_dev) ++{ ++ uint64_t resid; ++ int sg_cur_index; ++ ++ resid = sg->size; ++ sg_cur_index = 0; ++ len = MIN(len, resid); ++ while (len > 0) { ++ ScatterGatherEntry entry = sg->sg[sg_cur_index++]; ++ cpu_physical_memory_rw(entry.base, ptr, MIN(len, entry.len), !to_dev); ++ ptr += entry.len; ++ len -= entry.len; ++ resid -= entry.len; ++ } ++ ++ return resid; ++} ++ ++uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg) ++{ ++ return dma_buf_rw(ptr, len, sg, 0); ++} ++ ++uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg) ++{ ++ return dma_buf_rw(ptr, len, sg, 1); ++} ++ ++void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, ++ QEMUSGList *sg, enum BlockAcctType type) ++{ ++ bdrv_acct_start(bs, cookie, sg->size, type); ++} +diff --git a/dma.h b/dma.h +index a13209d..20e86d2 100644 +--- a/dma.h ++++ b/dma.h +@@ -17,6 +17,13 @@ + + typedef struct ScatterGatherEntry ScatterGatherEntry; + ++struct QEMUSGList { ++ ScatterGatherEntry *sg; ++ int nsg; ++ int nalloc; ++ size_t size; ++}; ++ + #if defined(TARGET_PHYS_ADDR_BITS) + typedef target_phys_addr_t dma_addr_t; + +@@ -32,13 +39,6 @@ struct ScatterGatherEntry { + dma_addr_t len; + }; + +-struct QEMUSGList { +- ScatterGatherEntry *sg; +- int nsg; +- int nalloc; +- dma_addr_t size; +-}; +- + void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint); + void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len); + void qemu_sglist_destroy(QEMUSGList *qsg); +@@ -58,4 +58,10 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDriverState *bs, + BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs, + QEMUSGList *sg, uint64_t sector, + BlockDriverCompletionFunc *cb, void *opaque); ++uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg); ++uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg); ++ ++void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, ++ QEMUSGList *sg, enum BlockAcctType type); ++ + #endif +diff --git a/hw/esp.c b/hw/esp.c +index b698a43..8516db5 100644 +--- a/hw/esp.c ++++ b/hw/esp.c +@@ -389,7 +389,8 @@ static void esp_do_dma(ESPState *s) + esp_dma_done(s); + } + +-static void esp_command_complete(SCSIRequest *req, uint32_t status) ++static void esp_command_complete(SCSIRequest *req, uint32_t status, ++ int32_t resid) + { + ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); + +diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c +index 0af201d..c6aa058 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -425,55 +425,6 @@ static void ahci_reg_init(AHCIState *s) + } + } + +-static uint32_t read_from_sglist(uint8_t *buffer, uint32_t len, +- QEMUSGList *sglist) +-{ +- uint32_t i = 0; +- uint32_t total = 0, once; +- ScatterGatherEntry *cur_prd; +- uint32_t sgcount; +- +- cur_prd = sglist->sg; +- sgcount = sglist->nsg; +- for (i = 0; len && sgcount; i++) { +- once = MIN(cur_prd->len, len); +- cpu_physical_memory_read(cur_prd->base, buffer, once); +- cur_prd++; +- sgcount--; +- len -= once; +- buffer += once; +- total += once; +- } +- +- return total; +-} +- +-static uint32_t write_to_sglist(uint8_t *buffer, uint32_t len, +- QEMUSGList *sglist) +-{ +- uint32_t i = 0; +- uint32_t total = 0, once; +- ScatterGatherEntry *cur_prd; +- uint32_t sgcount; +- +- DPRINTF(-1, "total: 0x%x bytes\n", len); +- +- cur_prd = sglist->sg; +- sgcount = sglist->nsg; +- for (i = 0; len && sgcount; i++) { +- once = MIN(cur_prd->len, len); +- DPRINTF(-1, "write 0x%x bytes to 0x%lx\n", once, (long)cur_prd->base); +- cpu_physical_memory_write(cur_prd->base, buffer, once); +- cur_prd++; +- sgcount--; +- len -= once; +- buffer += once; +- total += once; +- } +- +- return total; +-} +- + static void check_cmd(AHCIState *s, int port) + { + AHCIPortRegs *pr = &s->dev[port].port_regs; +@@ -794,9 +745,8 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, + DPRINTF(port, "tag %d aio read %"PRId64"\n", + ncq_tfs->tag, ncq_tfs->lba); + +- bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct, +- (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE, +- BDRV_ACCT_READ); ++ dma_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct, ++ &ncq_tfs->sglist, BDRV_ACCT_READ); + ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs, + &ncq_tfs->sglist, ncq_tfs->lba, + ncq_cb, ncq_tfs); +@@ -808,9 +758,8 @@ static void process_ncq_command(AHCIState *s, int port, uint8_t *cmd_fis, + DPRINTF(port, "tag %d aio write %"PRId64"\n", + ncq_tfs->tag, ncq_tfs->lba); + +- bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct, +- (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE, +- BDRV_ACCT_WRITE); ++ dma_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct, ++ &ncq_tfs->sglist, BDRV_ACCT_WRITE); + ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs, + &ncq_tfs->sglist, ncq_tfs->lba, + ncq_cb, ncq_tfs); +@@ -1015,12 +964,12 @@ static int ahci_start_transfer(IDEDMA *dma) + is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata", + has_sglist ? "" : "o"); + +- if (is_write && has_sglist && (s->data_ptr < s->data_end)) { +- read_from_sglist(s->data_ptr, size, &s->sg); +- } +- +- if (!is_write && has_sglist && (s->data_ptr < s->data_end)) { +- write_to_sglist(s->data_ptr, size, &s->sg); ++ if (has_sglist && size) { ++ if (is_write) { ++ dma_buf_write(s->data_ptr, size, &s->sg); ++ } else { ++ dma_buf_read(s->data_ptr, size, &s->sg); ++ } + } + + /* update number of transferred bytes */ +@@ -1059,14 +1008,9 @@ static int ahci_dma_prepare_buf(IDEDMA *dma, int is_write) + { + AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); + IDEState *s = &ad->port.ifs[0]; +- int i; + + ahci_populate_sglist(ad, &s->sg); +- +- s->io_buffer_size = 0; +- for (i = 0; i < s->sg.nsg; i++) { +- s->io_buffer_size += s->sg.sg[i].len; +- } ++ s->io_buffer_size = s->sg.size; + + DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size); + return s->io_buffer_size != 0; +@@ -1084,9 +1028,9 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write) + } + + if (is_write) { +- write_to_sglist(p, l, &s->sg); ++ dma_buf_read(p, l, &s->sg); + } else { +- read_from_sglist(p, l, &s->sg); ++ dma_buf_write(p, l, &s->sg); + } + + /* update number of transferred bytes */ +diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c +index fcc27d7..c53760b 100644 +--- a/hw/lsi53c895a.c ++++ b/hw/lsi53c895a.c +@@ -699,7 +699,7 @@ static int lsi_queue_req(LSIState *s, SCSIRequest *req, uint32_t len) + } + + /* Callback to indicate that the SCSI layer has completed a command. */ +-static void lsi_command_complete(SCSIRequest *req, uint32_t status) ++static void lsi_command_complete(SCSIRequest *req, uint32_t status, int32_t resid) + { + LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); + int out; +diff --git a/hw/pci.h b/hw/pci.h +index 4220151..187bb5c 100644 +--- a/hw/pci.h ++++ b/hw/pci.h +@@ -76,6 +76,7 @@ + #define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 + #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 + #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 ++#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 + + #define FMT_PCIBUS PRIx64 + +diff --git a/hw/s390-virtio-bus.c b/hw/s390-virtio-bus.c +index c4b9a99..2da52c2 100644 +--- a/hw/s390-virtio-bus.c ++++ b/hw/s390-virtio-bus.c +@@ -158,6 +158,18 @@ static int s390_virtio_serial_init(VirtIOS390Device *dev) + return r; + } + ++static int s390_virtio_scsi_init(VirtIOS390Device *dev) ++{ ++ VirtIODevice *vdev; ++ ++ vdev = virtio_scsi_init((DeviceState *)dev, &dev->scsi); ++ if (!vdev) { ++ return -1; ++ } ++ ++ return s390_virtio_device_init(dev, vdev); ++} ++ + static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq) + { + ram_addr_t token_off; +@@ -370,6 +382,17 @@ static VirtIOS390DeviceInfo s390_virtio_serial = { + }, + }; + ++static VirtIOS390DeviceInfo s390_virtio_scsi = { ++ .init = s390_virtio_scsi_init, ++ .qdev.name = "virtio-scsi-s390", ++ .qdev.alias = "virtio-scsi", ++ .qdev.size = sizeof(VirtIOS390Device), ++ .qdev.props = (Property[]) { ++ DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOS390Device, host_features, scsi), ++ DEFINE_PROP_END_OF_LIST(), ++ }, ++}; ++ + static int s390_virtio_busdev_init(DeviceState *dev, DeviceInfo *info) + { + VirtIOS390DeviceInfo *_info = (VirtIOS390DeviceInfo *)info; +@@ -392,6 +415,7 @@ static void s390_virtio_register(void) + s390_virtio_bus_register_withprop(&s390_virtio_serial); + s390_virtio_bus_register_withprop(&s390_virtio_blk); + s390_virtio_bus_register_withprop(&s390_virtio_net); ++ s390_virtio_bus_register_withprop(&s390_virtio_scsi); + } + device_init(s390_virtio_register); + +diff --git a/hw/s390-virtio-bus.h b/hw/s390-virtio-bus.h +index f1bece7..a840936 100644 +--- a/hw/s390-virtio-bus.h ++++ b/hw/s390-virtio-bus.h +@@ -19,6 +19,7 @@ + + #include "virtio-net.h" + #include "virtio-serial.h" ++#include "virtio-scsi.h" + + #define VIRTIO_DEV_OFFS_TYPE 0 /* 8 bits */ + #define VIRTIO_DEV_OFFS_NUM_VQ 1 /* 8 bits */ +@@ -47,6 +48,7 @@ typedef struct VirtIOS390Device { + uint32_t host_features; + virtio_serial_conf serial; + virtio_net_conf net; ++ VirtIOSCSIConf scsi; + } VirtIOS390Device; + + typedef struct VirtIOS390Bus { +diff --git a/hw/scsi-bus.c b/hw/scsi-bus.c +index 64e709e..a1bfbbe 100644 +--- a/hw/scsi-bus.c ++++ b/hw/scsi-bus.c +@@ -5,6 +5,7 @@ + #include "qdev.h" + #include "blockdev.h" + #include "trace.h" ++#include "dma.h" + + static char *scsibus_get_fw_dev_path(DeviceState *dev); + static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf); +@@ -50,6 +51,7 @@ static void scsi_dma_restart_bh(void *opaque) + scsi_req_continue(req); + break; + case SCSI_XFER_NONE: ++ assert(!req->sg); + scsi_req_dequeue(req); + scsi_req_enqueue(req); + break; +@@ -512,6 +514,8 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun, + } + + req->cmd = cmd; ++ req->resid = req->cmd.xfer; ++ + switch (buf[0]) { + case INQUIRY: + trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]); +@@ -624,15 +628,25 @@ void scsi_req_build_sense(SCSIRequest *req, SCSISense sense) + req->sense_len = 18; + } + +-int32_t scsi_req_enqueue(SCSIRequest *req) ++static void scsi_req_enqueue_internal(SCSIRequest *req) + { +- int32_t rc; +- + assert(!req->enqueued); + scsi_req_ref(req); ++ if (req->bus->info->get_sg_list) { ++ req->sg = req->bus->info->get_sg_list(req); ++ } else { ++ req->sg = NULL; ++ } + req->enqueued = true; + QTAILQ_INSERT_TAIL(&req->dev->requests, req, next); ++} ++ ++int32_t scsi_req_enqueue(SCSIRequest *req) ++{ ++ int32_t rc; + ++ assert (!req->retry); ++ scsi_req_enqueue_internal(req); + scsi_req_ref(req); + rc = req->ops->send_command(req, req->cmd.buf); + scsi_req_unref(req); +@@ -1254,12 +1268,32 @@ void scsi_req_continue(SCSIRequest *req) + Once it completes, calling scsi_req_continue will restart I/O. */ + void scsi_req_data(SCSIRequest *req, int len) + { ++ uint8_t *buf; + if (req->io_canceled) { + trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len); +- } else { +- trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); ++ return; ++ } ++ trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); ++ assert(req->cmd.mode != SCSI_XFER_NONE); ++ if (!req->sg) { ++ req->resid -= len; + req->bus->info->transfer_data(req, len); ++ return; + } ++ ++ /* If the device calls scsi_req_data and the HBA specified a ++ * scatter/gather list, the transfer has to happen in a single ++ * step. */ ++ assert(!req->dma_started); ++ req->dma_started = true; ++ ++ buf = scsi_req_get_buf(req); ++ if (req->cmd.mode == SCSI_XFER_FROM_DEV) { ++ req->resid = dma_buf_read(buf, len, req->sg); ++ } else { ++ req->resid = dma_buf_write(buf, len, req->sg); ++ } ++ scsi_req_continue(req); + } + + void scsi_req_print(SCSIRequest *req) +@@ -1318,7 +1352,7 @@ void scsi_req_complete(SCSIRequest *req, int status) + + scsi_req_ref(req); + scsi_req_dequeue(req); +- req->bus->info->complete(req, req->status); ++ req->bus->info->complete(req, req->status, req->resid); + scsi_req_unref(req); + } + +@@ -1393,3 +1427,100 @@ SCSIDevice *scsi_device_find(SCSIBus *bus, int channel, int id, int lun) + } + return target_dev; + } ++ ++ ++/* SCSI request list. For simplicity, pv points to the whole device */ ++ ++static void put_scsi_requests(QEMUFile *f, void *pv, size_t size) ++{ ++ SCSIDevice *s = pv; ++ SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus); ++ SCSIRequest *req; ++ ++ QTAILQ_FOREACH(req, &s->requests, next) { ++ assert(!req->io_canceled); ++ assert(req->status == -1); ++ assert(req->retry); ++ assert(req->enqueued); ++ ++ qemu_put_sbyte(f, 1); ++ qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf)); ++ qemu_put_be32s(f, &req->tag); ++ qemu_put_be32s(f, &req->lun); ++ if (bus->info->save_request) { ++ bus->info->save_request(f, req); ++ } ++ if (req->ops->save_request) { ++ req->ops->save_request(f, req); ++ } ++ } ++ qemu_put_sbyte(f, 0); ++} ++ ++static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) ++{ ++ SCSIDevice *s = pv; ++ SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus); ++ ++ while (qemu_get_sbyte(f)) { ++ uint8_t buf[SCSI_CMD_BUF_SIZE]; ++ uint32_t tag; ++ uint32_t lun; ++ SCSIRequest *req; ++ ++ qemu_get_buffer(f, buf, sizeof(buf)); ++ qemu_get_be32s(f, &tag); ++ qemu_get_be32s(f, &lun); ++ req = scsi_req_new(s, tag, lun, buf, NULL); ++ if (bus->info->load_request) { ++ req->hba_private = bus->info->load_request(f, req); ++ } ++ if (req->ops->load_request) { ++ req->ops->load_request(f, req); ++ } ++ ++ /* Just restart it later. */ ++ req->retry = true; ++ scsi_req_enqueue_internal(req); ++ ++ /* At this point, the request will be kept alive by the reference ++ * added by scsi_req_enqueue_internal, so we can release our reference. ++ * The HBA of course will add its own reference in the load_request ++ * callback if it needs to hold on the SCSIRequest. ++ */ ++ scsi_req_unref(req); ++ } ++ ++ return 0; ++} ++ ++const VMStateInfo vmstate_info_scsi_requests = { ++ .name = "scsi-requests", ++ .get = get_scsi_requests, ++ .put = put_scsi_requests, ++}; ++ ++const VMStateDescription vmstate_scsi_device = { ++ .name = "SCSIDevice", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .minimum_version_id_old = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT8(unit_attention.key, SCSIDevice), ++ VMSTATE_UINT8(unit_attention.asc, SCSIDevice), ++ VMSTATE_UINT8(unit_attention.ascq, SCSIDevice), ++ VMSTATE_BOOL(sense_is_ua, SCSIDevice), ++ VMSTATE_UINT8_ARRAY(sense, SCSIDevice, SCSI_SENSE_BUF_SIZE), ++ VMSTATE_UINT32(sense_len, SCSIDevice), ++ { ++ .name = "requests", ++ .version_id = 0, ++ .field_exists = NULL, ++ .size = 0, /* ouch */ ++ .info = &vmstate_info_scsi_requests, ++ .flags = VMS_SINGLE, ++ .offset = 0, ++ }, ++ VMSTATE_END_OF_LIST() ++ } ++}; +diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c +index 673948c..c3474f2 100644 +--- a/hw/scsi-disk.c ++++ b/hw/scsi-disk.c +@@ -38,6 +38,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , ## __VA_ARGS__); } while (0) + #include "sysemu.h" + #include "blockdev.h" + #include "block_int.h" ++#include "dma.h" + + #ifdef __linux + #include +@@ -110,12 +111,12 @@ static void scsi_cancel_io(SCSIRequest *req) + r->req.aiocb = NULL; + } + +-static uint32_t scsi_init_iovec(SCSIDiskReq *r) ++static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size) + { + SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); + + if (!r->iov.iov_base) { +- r->buflen = SCSI_DMA_BUF_SIZE; ++ r->buflen = size; + r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen); + } + r->iov.iov_len = MIN(r->sector_count * 512, r->buflen); +@@ -123,6 +124,56 @@ static uint32_t scsi_init_iovec(SCSIDiskReq *r) + return r->qiov.size / 512; + } + ++static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req) ++{ ++ SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); ++ ++ qemu_put_be64s(f, &r->sector); ++ qemu_put_be32s(f, &r->sector_count); ++ qemu_put_be32s(f, &r->buflen); ++ if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { ++ qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); ++ } ++} ++ ++static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) ++{ ++ SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); ++ ++ qemu_get_be64s(f, &r->sector); ++ qemu_get_be32s(f, &r->sector_count); ++ qemu_get_be32s(f, &r->buflen); ++ if (r->buflen) { ++ scsi_init_iovec(r, r->buflen); ++ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { ++ qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len); ++ } ++ } ++ ++ qemu_iovec_init_external(&r->qiov, &r->iov, 1); ++} ++ ++static void scsi_dma_complete(void * opaque, int ret) ++{ ++ SCSIDiskReq *r = (SCSIDiskReq *)opaque; ++ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); ++ ++ bdrv_acct_done(s->qdev.conf.bs, &r->acct); ++ ++ if (ret) { ++ if (scsi_handle_rw_error(r, -ret)) { ++ goto done; ++ } ++ } ++ ++ r->sector += r->sector_count; ++ r->sector_count = 0; ++ scsi_req_complete(&r->req, GOOD); ++ ++done: ++ scsi_req_unref(&r->req); ++} ++ + static void scsi_read_complete(void * opaque, int ret) + { + SCSIDiskReq *r = (SCSIDiskReq *)opaque; +@@ -213,10 +264,17 @@ static void scsi_read_data(SCSIRequest *req) + return; + } + +- n = scsi_init_iovec(r); +- bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ); +- r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n, +- scsi_read_complete, r); ++ if (r->req.sg) { ++ dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ); ++ r->req.resid -= r->req.sg->size; ++ r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector, ++ scsi_dma_complete, r); ++ } else { ++ n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); ++ bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ); ++ r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n, ++ scsi_read_complete, r); ++ } + if (r->req.aiocb == NULL) { + scsi_read_complete(r, -EIO); + } +@@ -290,7 +348,7 @@ static void scsi_write_complete(void * opaque, int ret) + if (r->sector_count == 0) { + scsi_req_complete(&r->req, GOOD); + } else { +- scsi_init_iovec(r); ++ scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); + DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size); + scsi_req_data(&r->req, r->qiov.size); + } +@@ -318,21 +376,29 @@ static void scsi_write_data(SCSIRequest *req) + return; + } + +- n = r->qiov.size / 512; +- if (n) { +- if (s->tray_open) { +- scsi_write_complete(r, -ENOMEDIUM); +- return; +- } ++ if (!r->req.sg && !r->qiov.size) { ++ /* Called for the first time. Ask the driver to send us more data. */ ++ scsi_write_complete(r, 0); ++ return; ++ } ++ if (s->tray_open) { ++ scsi_write_complete(r, -ENOMEDIUM); ++ return; ++ } ++ ++ if (r->req.sg) { ++ dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_WRITE); ++ r->req.resid -= r->req.sg->size; ++ r->req.aiocb = dma_bdrv_write(s->qdev.conf.bs, r->req.sg, r->sector, ++ scsi_dma_complete, r); ++ } else { ++ n = r->qiov.size / 512; + bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE); + r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n, + scsi_write_complete, r); +- if (r->req.aiocb == NULL) { +- scsi_write_complete(r, -ENOMEM); +- } +- } else { +- /* Called for the first time. Ask the driver to send us more data. */ +- scsi_write_complete(r, 0); ++ } ++ if (r->req.aiocb == NULL) { ++ scsi_write_complete(r, -ENOMEM); + } + } + +@@ -1601,6 +1667,8 @@ static const SCSIReqOps scsi_disk_reqops = { + .write_data = scsi_write_data, + .cancel_io = scsi_cancel_io, + .get_buf = scsi_get_buf, ++ .load_request = scsi_disk_load_request, ++ .save_request = scsi_disk_save_request, + }; + + static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, +@@ -1729,6 +1797,22 @@ static SCSIRequest *scsi_block_new_request(SCSIDevice *d, uint32_t tag, + DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ + DEFINE_PROP_STRING("serial", SCSIDiskState, serial) + ++static const VMStateDescription vmstate_scsi_disk_state = { ++ .name = "scsi-disk", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .minimum_version_id_old = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_SCSI_DEVICE(qdev, SCSIDiskState), ++ VMSTATE_BOOL(media_changed, SCSIDiskState), ++ VMSTATE_BOOL(media_event, SCSIDiskState), ++ VMSTATE_BOOL(eject_request, SCSIDiskState), ++ VMSTATE_BOOL(tray_open, SCSIDiskState), ++ VMSTATE_BOOL(tray_locked, SCSIDiskState), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + static SCSIDeviceInfo scsi_disk_info[] = { + { + .qdev.name = "scsi-hd", +@@ -1736,6 +1820,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { + .qdev.desc = "virtual SCSI disk", + .qdev.size = sizeof(SCSIDiskState), + .qdev.reset = scsi_disk_reset, ++ .qdev.vmsd = &vmstate_scsi_disk_state, + .init = scsi_hd_initfn, + .destroy = scsi_destroy, + .alloc_req = scsi_new_request, +@@ -1751,6 +1836,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { + .qdev.desc = "virtual SCSI CD-ROM", + .qdev.size = sizeof(SCSIDiskState), + .qdev.reset = scsi_disk_reset, ++ .qdev.vmsd = &vmstate_scsi_disk_state, + .init = scsi_cd_initfn, + .destroy = scsi_destroy, + .alloc_req = scsi_new_request, +@@ -1766,6 +1852,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { + .qdev.desc = "SCSI block device passthrough", + .qdev.size = sizeof(SCSIDiskState), + .qdev.reset = scsi_disk_reset, ++ .qdev.vmsd = &vmstate_scsi_disk_state, + .init = scsi_block_initfn, + .destroy = scsi_destroy, + .alloc_req = scsi_block_new_request, +@@ -1780,6 +1867,7 @@ static SCSIDeviceInfo scsi_disk_info[] = { + .qdev.desc = "virtual SCSI disk or CD-ROM (legacy)", + .qdev.size = sizeof(SCSIDiskState), + .qdev.reset = scsi_disk_reset, ++ .qdev.vmsd = &vmstate_scsi_disk_state, + .init = scsi_disk_initfn, + .destroy = scsi_destroy, + .alloc_req = scsi_new_request, +diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c +index e62044f..378359c 100644 +--- a/hw/scsi-generic.c ++++ b/hw/scsi-generic.c +@@ -59,6 +59,28 @@ typedef struct SCSIGenericReq { + sg_io_hdr_t io_header; + } SCSIGenericReq; + ++static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req) ++{ ++ SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); ++ ++ qemu_put_sbe32s(f, &r->buflen); ++ if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { ++ assert(!r->req.sg); ++ qemu_put_buffer(f, r->buf, r->req.cmd.xfer); ++ } ++} ++ ++static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req) ++{ ++ SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); ++ ++ qemu_get_sbe32s(f, &r->buflen); ++ if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { ++ assert(!r->req.sg); ++ qemu_get_buffer(f, r->buf, r->req.cmd.xfer); ++ } ++} ++ + static void scsi_free_request(SCSIRequest *req) + { + SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); +@@ -450,6 +472,8 @@ const SCSIReqOps scsi_generic_req_ops = { + .write_data = scsi_write_data, + .cancel_io = scsi_cancel_io, + .get_buf = scsi_get_buf, ++ .load_request = scsi_generic_load_request, ++ .save_request = scsi_generic_save_request, + }; + + static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, +@@ -467,6 +491,7 @@ static SCSIDeviceInfo scsi_generic_info = { + .qdev.desc = "pass through generic scsi device (/dev/sg*)", + .qdev.size = sizeof(SCSIDevice), + .qdev.reset = scsi_generic_reset, ++ .qdev.vmsd = &vmstate_scsi_device, + .init = scsi_generic_initfn, + .destroy = scsi_destroy, + .alloc_req = scsi_new_request, +diff --git a/hw/scsi.h b/hw/scsi.h +index ab6e952..f933937 100644 +--- a/hw/scsi.h ++++ b/hw/scsi.h +@@ -47,8 +47,11 @@ struct SCSIRequest { + uint32_t tag; + uint32_t lun; + uint32_t status; ++ size_t resid; + SCSICommand cmd; + BlockDriverAIOCB *aiocb; ++ QEMUSGList *sg; ++ bool dma_started; + uint8_t sense[SCSI_SENSE_BUF_SIZE]; + uint32_t sense_len; + bool enqueued; +@@ -78,6 +81,16 @@ struct SCSIDevice + uint64_t max_lba; + }; + ++extern const VMStateDescription vmstate_scsi_device; ++ ++#define VMSTATE_SCSI_DEVICE(_field, _state) { \ ++ .name = (stringify(_field)), \ ++ .size = sizeof(SCSIDevice), \ ++ .vmsd = &vmstate_scsi_device, \ ++ .flags = VMS_STRUCT, \ ++ .offset = vmstate_offset_value(_state, _field, SCSIDevice), \ ++} ++ + /* cdrom.c */ + int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); + int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); +@@ -91,6 +104,9 @@ struct SCSIReqOps { + void (*write_data)(SCSIRequest *req); + void (*cancel_io)(SCSIRequest *req); + uint8_t *(*get_buf)(SCSIRequest *req); ++ ++ void (*save_request)(QEMUFile *f, SCSIRequest *req); ++ void (*load_request)(QEMUFile *f, SCSIRequest *req); + }; + + typedef int (*scsi_qdev_initfn)(SCSIDevice *dev); +@@ -107,8 +123,12 @@ struct SCSIBusInfo { + int tcq; + int max_channel, max_target, max_lun; + void (*transfer_data)(SCSIRequest *req, uint32_t arg); +- void (*complete)(SCSIRequest *req, uint32_t arg); ++ void (*complete)(SCSIRequest *req, uint32_t arg, int32_t len); + void (*cancel)(SCSIRequest *req); ++ QEMUSGList *(*get_sg_list)(SCSIRequest *req); ++ ++ void (*save_request)(QEMUFile *f, SCSIRequest *req); ++ void *(*load_request)(QEMUFile *f, SCSIRequest *req); + }; + + struct SCSIBus { +diff --git a/hw/spapr_vscsi.c b/hw/spapr_vscsi.c +index 00e2d2d..c28bba9 100644 +--- a/hw/spapr_vscsi.c ++++ b/hw/spapr_vscsi.c +@@ -494,7 +494,7 @@ static void vscsi_transfer_data(SCSIRequest *sreq, uint32_t len) + } + + /* Callback to indicate that the SCSI layer has completed a transfer. */ +-static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status) ++static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, int32_t resid) + { + VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); + vscsi_req *req = sreq->hba_private; +diff --git a/hw/usb-msd.c b/hw/usb-msd.c +index 3147131..4b572a0 100644 +--- a/hw/usb-msd.c ++++ b/hw/usb-msd.c +@@ -223,7 +223,7 @@ static void usb_msd_transfer_data(SCSIRequest *req, uint32_t len) + } + } + +-static void usb_msd_command_complete(SCSIRequest *req, uint32_t status) ++static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, int32_t resid) + { + MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); + USBPacket *p = s->packet; +diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c +index 6fbab07..7f7b598 100644 +--- a/hw/virtio-pci.c ++++ b/hw/virtio-pci.c +@@ -19,6 +19,7 @@ + #include "virtio-blk.h" + #include "virtio-net.h" + #include "virtio-serial.h" ++#include "virtio-scsi.h" + #include "pci.h" + #include "qemu-error.h" + #include "msix.h" +@@ -855,6 +856,32 @@ static int virtio_balloon_exit_pci(PCIDevice *pci_dev) + return virtio_exit_pci(pci_dev); + } + ++static int virtio_scsi_init_pci(PCIDevice *pci_dev) ++{ ++ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); ++ VirtIODevice *vdev; ++ ++ vdev = virtio_scsi_init(&pci_dev->qdev, &proxy->scsi); ++ if (!vdev) { ++ return -EINVAL; ++ } ++ ++ vdev->nvectors = proxy->nvectors; ++ virtio_init_pci(proxy, vdev); ++ ++ /* make the actual value visible */ ++ proxy->nvectors = vdev->nvectors; ++ return 0; ++} ++ ++static int virtio_scsi_exit_pci(PCIDevice *pci_dev) ++{ ++ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); ++ ++ virtio_scsi_exit(proxy->vdev); ++ return virtio_exit_pci(pci_dev); ++} ++ + static PCIDeviceInfo virtio_info[] = { + { + .qdev.name = "virtio-blk-pci", +@@ -940,6 +967,21 @@ static PCIDeviceInfo virtio_info[] = { + }, + .qdev.reset = virtio_pci_reset, + },{ ++ .qdev.name = "virtio-scsi-pci", ++ .qdev.alias = "virtio-scsi", ++ .qdev.size = sizeof(VirtIOPCIProxy), ++ .init = virtio_scsi_init_pci, ++ .exit = virtio_scsi_exit_pci, ++ .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, ++ .device_id = PCI_DEVICE_ID_VIRTIO_SCSI, ++ .class_id = PCI_CLASS_STORAGE_SCSI, ++ .revision = 0x00, ++ .qdev.props = (Property[]) { ++ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), ++ DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOPCIProxy, host_features, scsi), ++ DEFINE_PROP_END_OF_LIST(), ++ }, ++ }, { + /* end of list */ + } + }; +diff --git a/hw/virtio-pci.h b/hw/virtio-pci.h +index 344c22b..e560428 100644 +--- a/hw/virtio-pci.h ++++ b/hw/virtio-pci.h +@@ -17,6 +17,7 @@ + + #include "virtio-net.h" + #include "virtio-serial.h" ++#include "virtio-scsi.h" + + /* Performance improves when virtqueue kick processing is decoupled from the + * vcpu thread using ioeventfd for some devices. */ +@@ -40,6 +41,7 @@ typedef struct { + #endif + virtio_serial_conf serial; + virtio_net_conf net; ++ VirtIOSCSIConf scsi; + bool ioeventfd_disabled; + bool ioeventfd_started; + } VirtIOPCIProxy; +diff --git a/hw/virtio-scsi.c b/hw/virtio-scsi.c +new file mode 100644 +index 0000000..f5cecfc +--- /dev/null ++++ b/hw/virtio-scsi.c +@@ -0,0 +1,607 @@ ++/* ++ * Virtio SCSI HBA ++ * ++ * Copyright IBM, Corp. 2010 ++ * Copyright Red Hat, Inc. 2011 ++ * ++ * Authors: ++ * Stefan Hajnoczi ++ * Paolo Bonzini ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2 or later. ++ * See the COPYING file in the top-level directory. ++ * ++ */ ++ ++#include "virtio-scsi.h" ++#include ++#include ++ ++#define VIRTIO_SCSI_VQ_SIZE 128 ++#define VIRTIO_SCSI_CDB_SIZE 32 ++#define VIRTIO_SCSI_SENSE_SIZE 96 ++#define VIRTIO_SCSI_MAX_CHANNEL 0 ++#define VIRTIO_SCSI_MAX_TARGET 255 ++#define VIRTIO_SCSI_MAX_LUN 16383 ++ ++/* Response codes */ ++#define VIRTIO_SCSI_S_OK 0 ++#define VIRTIO_SCSI_S_OVERRUN 1 ++#define VIRTIO_SCSI_S_ABORTED 2 ++#define VIRTIO_SCSI_S_BAD_TARGET 3 ++#define VIRTIO_SCSI_S_RESET 4 ++#define VIRTIO_SCSI_S_BUSY 5 ++#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6 ++#define VIRTIO_SCSI_S_TARGET_FAILURE 7 ++#define VIRTIO_SCSI_S_NEXUS_FAILURE 8 ++#define VIRTIO_SCSI_S_FAILURE 9 ++#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10 ++#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11 ++#define VIRTIO_SCSI_S_INCORRECT_LUN 12 ++ ++/* Controlq type codes. */ ++#define VIRTIO_SCSI_T_TMF 0 ++#define VIRTIO_SCSI_T_AN_QUERY 1 ++#define VIRTIO_SCSI_T_AN_SUBSCRIBE 2 ++ ++/* Valid TMF subtypes. */ ++#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0 ++#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1 ++#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2 ++#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3 ++#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4 ++#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5 ++#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6 ++#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7 ++ ++/* Events. */ ++#define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000 ++#define VIRTIO_SCSI_T_NO_EVENT 0 ++#define VIRTIO_SCSI_T_TRANSPORT_RESET 1 ++#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2 ++ ++/* SCSI command request, followed by data-out */ ++typedef struct { ++ uint8_t lun[8]; /* Logical Unit Number */ ++ uint64_t tag; /* Command identifier */ ++ uint8_t task_attr; /* Task attribute */ ++ uint8_t prio; ++ uint8_t crn; ++ uint8_t cdb[]; ++} QEMU_PACKED VirtIOSCSICmdReq; ++ ++/* Response, followed by sense data and data-in */ ++typedef struct { ++ uint32_t sense_len; /* Sense data length */ ++ uint32_t resid; /* Residual bytes in data buffer */ ++ uint16_t status_qualifier; /* Status qualifier */ ++ uint8_t status; /* Command completion status */ ++ uint8_t response; /* Response values */ ++ uint8_t sense[]; ++} QEMU_PACKED VirtIOSCSICmdResp; ++ ++/* Task Management Request */ ++typedef struct { ++ uint32_t type; ++ uint32_t subtype; ++ uint8_t lun[8]; ++ uint64_t tag; ++} QEMU_PACKED VirtIOSCSICtrlTMFReq; ++ ++typedef struct { ++ uint8_t response; ++} QEMU_PACKED VirtIOSCSICtrlTMFResp; ++ ++/* Asynchronous notification query/subscription */ ++typedef struct { ++ uint32_t type; ++ uint8_t lun[8]; ++ uint32_t event_requested; ++} QEMU_PACKED VirtIOSCSICtrlANReq; ++ ++typedef struct { ++ uint32_t event_actual; ++ uint8_t response; ++} QEMU_PACKED VirtIOSCSICtrlANResp; ++ ++typedef struct { ++ uint32_t event; ++ uint8_t lun[8]; ++ uint32_t reason; ++} QEMU_PACKED VirtIOSCSIEvent; ++ ++typedef struct { ++ uint32_t num_queues; ++ uint32_t seg_max; ++ uint32_t max_sectors; ++ uint32_t cmd_per_lun; ++ uint32_t event_info_size; ++ uint32_t sense_size; ++ uint32_t cdb_size; ++ uint16_t max_channel; ++ uint16_t max_target; ++ uint32_t max_lun; ++} QEMU_PACKED VirtIOSCSIConfig; ++ ++typedef struct { ++ VirtIODevice vdev; ++ DeviceState *qdev; ++ VirtIOSCSIConf *conf; ++ ++ SCSIBus bus; ++ VirtQueue *ctrl_vq; ++ VirtQueue *event_vq; ++ VirtQueue *cmd_vq; ++ uint32_t sense_size; ++ uint32_t cdb_size; ++ bool resetting; ++} VirtIOSCSI; ++ ++typedef struct VirtIOSCSIReq { ++ VirtIOSCSI *dev; ++ VirtQueue *vq; ++ VirtQueueElement elem; ++ QEMUSGList qsgl; ++ SCSIRequest *sreq; ++ union { ++ char *buf; ++ VirtIOSCSICmdReq *cmd; ++ VirtIOSCSICtrlTMFReq *tmf; ++ VirtIOSCSICtrlANReq *an; ++ } req; ++ union { ++ char *buf; ++ VirtIOSCSICmdResp *cmd; ++ VirtIOSCSICtrlTMFResp *tmf; ++ VirtIOSCSICtrlANResp *an; ++ VirtIOSCSIEvent *event; ++ } resp; ++} VirtIOSCSIReq; ++ ++static inline int virtio_scsi_get_lun(uint8_t *lun) ++{ ++ return ((lun[2] << 8) | lun[3]) & 0x3FFF; ++} ++ ++static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun) ++{ ++ if (lun[0] != 1) { ++ return NULL; ++ } ++ if (lun[2] != 0 && !(lun[2] >= 0x40 && lun[2] < 0x80)) { ++ return NULL; ++ } ++ return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun)); ++} ++ ++static void virtio_scsi_complete_req(VirtIOSCSIReq *req) ++{ ++ VirtIOSCSI *s = req->dev; ++ VirtQueue *vq = req->vq; ++ virtqueue_push(vq, &req->elem, req->qsgl.size + req->elem.in_sg[0].iov_len); ++ qemu_sglist_destroy(&req->qsgl); ++ if (req->sreq) { ++ req->sreq->hba_private = NULL; ++ scsi_req_unref(req->sreq); ++ } ++ g_free(req); ++ virtio_notify(&s->vdev, vq); ++} ++ ++static void virtio_scsi_bad_req(void) ++{ ++ error_report("wrong size for virtio-scsi headers"); ++ exit(1); ++} ++ ++static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg, ++ target_phys_addr_t *addr, int num) ++{ ++ memset(qsgl, 0, sizeof(*qsgl)); ++ while (num--) { ++ qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len); ++ } ++} ++ ++static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq, ++ VirtIOSCSIReq *req) ++{ ++ assert(req->elem.out_num && req->elem.in_num); ++ req->vq = vq; ++ req->dev = s; ++ req->sreq = NULL; ++ req->req.buf = req->elem.out_sg[0].iov_base; ++ req->resp.buf = req->elem.in_sg[0].iov_base; ++ ++ if (req->elem.out_num > 1) { ++ qemu_sgl_init_external(&req->qsgl, &req->elem.out_sg[1], ++ &req->elem.out_addr[1], ++ req->elem.out_num - 1); ++ } else { ++ qemu_sgl_init_external(&req->qsgl, &req->elem.in_sg[1], ++ &req->elem.in_addr[1], ++ req->elem.in_num - 1); ++ } ++} ++ ++static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq) ++{ ++ VirtIOSCSIReq *req; ++ req = g_malloc(sizeof(*req)); ++ if (!virtqueue_pop(vq, &req->elem)) { ++ g_free(req); ++ return NULL; ++ } ++ ++ virtio_scsi_parse_req(s, vq, req); ++ return req; ++} ++ ++static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq) ++{ ++ VirtIOSCSIReq *req = sreq->hba_private; ++ ++ qemu_put_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem)); ++} ++ ++static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) ++{ ++ SCSIBus *bus = sreq->bus; ++ VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); ++ VirtIOSCSIReq *req; ++ ++ req = g_malloc(sizeof(*req)); ++ qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem)); ++ virtio_scsi_parse_req(s, s->cmd_vq, req); ++ ++ scsi_req_ref(sreq); ++ req->sreq = sreq; ++ if (req->sreq->cmd.mode != SCSI_XFER_NONE) { ++ int req_mode = ++ (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV); ++ ++ assert (req->sreq->cmd.mode == req_mode); ++ } ++ return req; ++} ++ ++static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) ++{ ++ SCSIDevice *d = virtio_scsi_device_find(s, req->req.cmd->lun); ++ SCSIRequest *r, *next; ++ DeviceState *qdev; ++ int target; ++ ++ switch (req->req.tmf->subtype) { ++ case VIRTIO_SCSI_T_TMF_ABORT_TASK: ++ case VIRTIO_SCSI_T_TMF_QUERY_TASK: ++ d = virtio_scsi_device_find(s, req->req.cmd->lun); ++ if (!d) { ++ goto fail; ++ } ++ if (d->lun != virtio_scsi_get_lun(req->req.cmd->lun)) { ++ req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN; ++ break; ++ } ++ QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { ++ if (r->tag == req->req.cmd->tag) { ++ break; ++ } ++ } ++ if (r && r->hba_private) { ++ if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_ABORT_TASK) { ++ scsi_req_cancel(r); ++ } ++ req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; ++ } else { ++ req->resp.tmf->response = VIRTIO_SCSI_S_OK; ++ } ++ break; ++ ++ case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET: ++ d = virtio_scsi_device_find(s, req->req.cmd->lun); ++ if (!d) { ++ goto fail; ++ } ++ if (d->lun == virtio_scsi_get_lun(req->req.cmd->lun)) { ++ s->resetting++; ++ qdev_reset_all(&d->qdev); ++ s->resetting--; ++ } ++ break; ++ ++ case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET: ++ case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET: ++ case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET: ++ d = virtio_scsi_device_find(s, req->req.cmd->lun); ++ if (!d) { ++ goto fail; ++ } ++ if (d->lun != virtio_scsi_get_lun(req->req.cmd->lun)) { ++ req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN; ++ break; ++ } ++ req->resp.tmf->response = VIRTIO_SCSI_S_OK; ++ QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { ++ if (r->hba_private) { ++ if (req->req.tmf->subtype != VIRTIO_SCSI_T_TMF_QUERY_TASK) { ++ scsi_req_cancel(r); ++ } ++ req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; ++ } ++ } ++ break; ++ ++ case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: ++ target = req->req.cmd->lun[1]; ++ s->resetting++; ++ QTAILQ_FOREACH(qdev, &s->bus.qbus.children, sibling) { ++ d = DO_UPCAST(SCSIDevice, qdev, qdev); ++ if (d->channel == 0 && d->id == target) { ++ qdev_reset_all(&d->qdev); ++ } ++ } ++ s->resetting--; ++ break; ++ ++ case VIRTIO_SCSI_T_TMF_CLEAR_ACA: ++ default: ++ req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_REJECTED; ++ break; ++ } ++ ++ return; ++ ++fail: ++ req->resp.tmf->response = VIRTIO_SCSI_S_BAD_TARGET; ++} ++ ++static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) ++{ ++ VirtIOSCSI *s = (VirtIOSCSI *)vdev; ++ VirtIOSCSIReq *req; ++ ++ while ((req = virtio_scsi_pop_req(s, vq))) { ++ int out_size, in_size; ++ if (req->elem.out_num < 1 || req->elem.in_num < 1) { ++ virtio_scsi_bad_req(); ++ continue; ++ } ++ ++ out_size = req->elem.out_sg[0].iov_len; ++ in_size = req->elem.in_sg[0].iov_len; ++ if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) { ++ if (out_size < sizeof(VirtIOSCSICtrlTMFReq) || ++ in_size < sizeof(VirtIOSCSICtrlTMFResp)) { ++ virtio_scsi_bad_req(); ++ } ++ virtio_scsi_do_tmf(s, req); ++ ++ } else if (req->req.tmf->type == VIRTIO_SCSI_T_AN_QUERY || ++ req->req.tmf->type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { ++ if (out_size < sizeof(VirtIOSCSICtrlANReq) || ++ in_size < sizeof(VirtIOSCSICtrlANResp)) { ++ virtio_scsi_bad_req(); ++ } ++ req->resp.an->event_actual = 0; ++ req->resp.an->response = VIRTIO_SCSI_S_OK; ++ } ++ virtio_scsi_complete_req(req); ++ } ++} ++ ++static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, ++ int32_t resid) ++{ ++ VirtIOSCSIReq *req = r->hba_private; ++ ++ req->resp.cmd->response = VIRTIO_SCSI_S_OK; ++ req->resp.cmd->status = status; ++ if (req->resp.cmd->status == GOOD) { ++ req->resp.cmd->resid = resid; ++ } else { ++ req->resp.cmd->resid = 0; ++ scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE); ++ } ++ virtio_scsi_complete_req(req); ++} ++ ++static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r) ++{ ++ VirtIOSCSIReq *req = r->hba_private; ++ ++ return &req->qsgl; ++} ++ ++static void virtio_scsi_request_cancelled(SCSIRequest *r) ++{ ++ VirtIOSCSIReq *req = r->hba_private; ++ ++ if (!req) { ++ return; ++ } ++ if (req->dev->resetting) { ++ req->resp.cmd->response = VIRTIO_SCSI_S_RESET; ++ } else { ++ req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED; ++ } ++ virtio_scsi_complete_req(req); ++} ++ ++static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) ++{ ++ req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE; ++ virtio_scsi_complete_req(req); ++} ++ ++static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) ++{ ++ VirtIOSCSI *s = (VirtIOSCSI *)vdev; ++ VirtIOSCSIReq *req; ++ int n; ++ ++ while ((req = virtio_scsi_pop_req(s, vq))) { ++ SCSIDevice *d; ++ int out_size, in_size; ++ if (req->elem.out_num < 1 || req->elem.in_num < 1) { ++ virtio_scsi_bad_req(); ++ } ++ ++ out_size = req->elem.out_sg[0].iov_len; ++ in_size = req->elem.in_sg[0].iov_len; ++ if (out_size < sizeof(VirtIOSCSICmdReq) + s->cdb_size || ++ in_size < sizeof(VirtIOSCSICmdResp) + s->sense_size) { ++ virtio_scsi_bad_req(); ++ } ++ ++ if (req->elem.out_num > 1 && req->elem.in_num > 1) { ++ virtio_scsi_fail_cmd_req(req); ++ continue; ++ } ++ ++ d = virtio_scsi_device_find(s, req->req.cmd->lun); ++ if (!d) { ++ req->resp.cmd->response = VIRTIO_SCSI_S_BAD_TARGET; ++ virtio_scsi_complete_req(req); ++ continue; ++ } ++ req->sreq = scsi_req_new(d, req->req.cmd->tag, ++ virtio_scsi_get_lun(req->req.cmd->lun), ++ req->req.cmd->cdb, req); ++ ++ if (req->sreq->cmd.mode != SCSI_XFER_NONE) { ++ int req_mode = ++ (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV); ++ ++ if (req->sreq->cmd.mode != req_mode || ++ req->sreq->cmd.xfer > req->qsgl.size) { ++ req->resp.cmd->response = VIRTIO_SCSI_S_OVERRUN; ++ virtio_scsi_complete_req(req); ++ continue; ++ } ++ } ++ ++ n = scsi_req_enqueue(req->sreq); ++ if (n) { ++ scsi_req_continue(req->sreq); ++ } ++ } ++} ++ ++static void virtio_scsi_get_config(VirtIODevice *vdev, ++ uint8_t *config) ++{ ++ VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; ++ VirtIOSCSI *s = (VirtIOSCSI *)vdev; ++ ++ stl_raw(&scsiconf->num_queues, s->conf->num_queues); ++ stl_raw(&scsiconf->seg_max, 128 - 2); ++ stl_raw(&scsiconf->max_sectors, s->conf->max_sectors); ++ stl_raw(&scsiconf->cmd_per_lun, s->conf->cmd_per_lun); ++ stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent)); ++ stl_raw(&scsiconf->sense_size, s->sense_size); ++ stl_raw(&scsiconf->cdb_size, s->cdb_size); ++ stl_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL); ++ stl_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET); ++ stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN); ++} ++ ++static void virtio_scsi_set_config(VirtIODevice *vdev, ++ const uint8_t *config) ++{ ++ VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; ++ VirtIOSCSI *s = (VirtIOSCSI *)vdev; ++ ++ if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 || ++ (uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) { ++ error_report("bad data written to virtio-scsi configuration space"); ++ exit(1); ++ } ++ ++ s->sense_size = ldl_raw(&scsiconf->sense_size); ++ s->cdb_size = ldl_raw(&scsiconf->cdb_size); ++} ++ ++static uint32_t virtio_scsi_get_features(VirtIODevice *vdev, ++ uint32_t requested_features) ++{ ++ return requested_features; ++} ++ ++static void virtio_scsi_reset(VirtIODevice *vdev) ++{ ++ VirtIOSCSI *s = (VirtIOSCSI *)vdev; ++ ++ s->sense_size = VIRTIO_SCSI_SENSE_SIZE; ++ s->cdb_size = VIRTIO_SCSI_CDB_SIZE; ++} ++ ++/* The device does not have anything to save beyond the virtio data. ++ * Request data is saved with callbacks from SCSI devices. ++ */ ++static void virtio_scsi_save(QEMUFile *f, void *opaque) ++{ ++ VirtIOSCSI *s = opaque; ++ virtio_save(&s->vdev, f); ++} ++ ++static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) ++{ ++ VirtIOSCSI *s = opaque; ++ virtio_load(&s->vdev, f); ++ return 0; ++} ++ ++static struct SCSIBusInfo virtio_scsi_scsi_info = { ++ .tcq = true, ++ .max_channel = VIRTIO_SCSI_MAX_CHANNEL, ++ .max_target = VIRTIO_SCSI_MAX_TARGET, ++ .max_lun = VIRTIO_SCSI_MAX_LUN, ++ ++ .complete = virtio_scsi_command_complete, ++ .cancel = virtio_scsi_request_cancelled, ++ .get_sg_list = virtio_scsi_get_sg_list, ++ .save_request = virtio_scsi_save_request, ++ .load_request = virtio_scsi_load_request, ++}; ++ ++VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf) ++{ ++ VirtIOSCSI *s; ++ static int virtio_scsi_id; ++ ++ s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI, ++ sizeof(VirtIOSCSIConfig), ++ sizeof(VirtIOSCSI)); ++ ++ s->qdev = dev; ++ s->conf = proxyconf; ++ ++ /* TODO set up vdev function pointers */ ++ s->vdev.get_config = virtio_scsi_get_config; ++ s->vdev.set_config = virtio_scsi_set_config; ++ s->vdev.get_features = virtio_scsi_get_features; ++ s->vdev.reset = virtio_scsi_reset; ++ ++ s->ctrl_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE, ++ virtio_scsi_handle_ctrl); ++ s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE, ++ NULL); ++ s->cmd_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE, ++ virtio_scsi_handle_cmd); ++ ++ scsi_bus_new(&s->bus, dev, &virtio_scsi_scsi_info); ++ if (!dev->hotplugged) { ++ scsi_bus_legacy_handle_cmdline(&s->bus); ++ } ++ ++ register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1, ++ virtio_scsi_save, virtio_scsi_load, s); ++ ++ return &s->vdev; ++} ++ ++void virtio_scsi_exit(VirtIODevice *vdev) ++{ ++ virtio_cleanup(vdev); ++} +diff --git a/hw/virtio-scsi.h b/hw/virtio-scsi.h +new file mode 100644 +index 0000000..4bc889d +--- /dev/null ++++ b/hw/virtio-scsi.h +@@ -0,0 +1,36 @@ ++/* ++ * Virtio SCSI HBA ++ * ++ * Copyright IBM, Corp. 2010 ++ * ++ * Authors: ++ * Stefan Hajnoczi ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2. See ++ * the COPYING file in the top-level directory. ++ * ++ */ ++ ++#ifndef _QEMU_VIRTIO_SCSI_H ++#define _QEMU_VIRTIO_SCSI_H ++ ++#include "virtio.h" ++#include "net.h" ++#include "pci.h" ++ ++/* The ID for virtio_scsi */ ++#define VIRTIO_ID_SCSI 8 ++ ++struct VirtIOSCSIConf { ++ uint32_t num_queues; ++ uint32_t max_sectors; ++ uint32_t cmd_per_lun; ++}; ++ ++#define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _features_field, _conf_field) \ ++ DEFINE_VIRTIO_COMMON_FEATURES(_state, _features_field), \ ++ DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \ ++ DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF), \ ++ DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128) ++ ++#endif /* _QEMU_VIRTIO_SCSI_H */ +diff --git a/hw/virtio.h b/hw/virtio.h +index 25f5564..400c092 100644 +--- a/hw/virtio.h ++++ b/hw/virtio.h +@@ -199,6 +199,8 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, + typedef struct virtio_serial_conf virtio_serial_conf; + VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial); + VirtIODevice *virtio_balloon_init(DeviceState *dev); ++typedef struct VirtIOSCSIConf VirtIOSCSIConf; ++VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf); + #ifdef CONFIG_LINUX + VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf); + #endif +@@ -208,6 +210,7 @@ void virtio_net_exit(VirtIODevice *vdev); + void virtio_blk_exit(VirtIODevice *vdev); + void virtio_serial_exit(VirtIODevice *vdev); + void virtio_balloon_exit(VirtIODevice *vdev); ++void virtio_scsi_exit(VirtIODevice *vdev); + + #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \ + DEFINE_PROP_BIT("indirect_desc", _state, _field, \ diff --git a/0303-hw-9pfs-Remove-O_NOATIME-flag-from-9pfs-open-calls-i.patch b/0303-hw-9pfs-Remove-O_NOATIME-flag-from-9pfs-open-calls-i.patch new file mode 100644 index 0000000..c493147 --- /dev/null +++ b/0303-hw-9pfs-Remove-O_NOATIME-flag-from-9pfs-open-calls-i.patch @@ -0,0 +1,44 @@ +From 9dfc18664eff3d85be4a7bcb7c503adc41099565 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Mon, 16 Jan 2012 18:11:40 +0000 +Subject: [PATCH] hw/9pfs: Remove O_NOATIME flag from 9pfs open() calls in + readonly mode + +When 2c74c2cb4bedddbfa67628fbd5f9273b4e0e9903 added support for +the 'readonly' flag against 9p filesystems, it also made QEMU +add the O_NOATIME flag as a side-effect. + +The O_NOATIME flag, however, may only be set by the file owner, +or a user with CAP_FOWNER capability. QEMU cannot assume that +this is the case for filesytems exported to QEMU. + +eg, run QEMU as non-root, and attempt to pass the host OS +filesystem through to the guest OS with readonly enable. +The result is that the guest OS cannot open any files at +all. + +If O_NOATIME is really required, it should be optionally +enabled via a separate QEMU command line flag. + + * hw/9pfs/virtio-9p.c: Remove O_NOATIME + +Acked-by: M. Mohan Kumar +Signed-off-by: Daniel P. Berrange +Signed-off-by: Aneesh Kumar K.V +(cherry picked from commit eed968607d656a218712df47a5e0432c21fd6994) +--- + hw/9pfs/virtio-9p.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c +index b3fc3d0..2503e49 100644 +--- a/hw/9pfs/virtio-9p.c ++++ b/hw/9pfs/virtio-9p.c +@@ -1560,7 +1560,6 @@ static void v9fs_open(void *opaque) + err = -EROFS; + goto out; + } +- flags |= O_NOATIME; + } + err = v9fs_co_open(pdu, fidp, flags); + if (err < 0) { diff --git a/0304-pci-fix-corrupted-pci-conf-index-register-by-unalign.patch b/0304-pci-fix-corrupted-pci-conf-index-register-by-unalign.patch new file mode 100644 index 0000000..b7c9171 --- /dev/null +++ b/0304-pci-fix-corrupted-pci-conf-index-register-by-unalign.patch @@ -0,0 +1,36 @@ +From 61c38140c3453b854502ed2eac2c7d844b844ad0 Mon Sep 17 00:00:00 2001 +From: Avi Kivity +Date: Wed, 4 Jan 2012 16:28:42 +0200 +Subject: [PATCH] pci: fix corrupted pci conf index register by unaligned write + +Commit d0ed8076cbdc261 converted the PCI config access to the memory +API, but also inadvertantly changed it to accept unaligned writes, +and corrupt the index register in the process. This causes a regression +booting NetBSD. + +Fix by ignoring unaligned or non-dword writes. + +https://bugs.launchpad.net/qemu/+bug/897771 + +Reported-by: Andreas Gustafsson +Signed-off-by: Avi Kivity +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit cdde6ffc27517bdf069734fbc5693ce2b14edc75) +--- + hw/pci_host.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/pci_host.c b/hw/pci_host.c +index 44c6c20..8041778 100644 +--- a/hw/pci_host.c ++++ b/hw/pci_host.c +@@ -101,6 +101,9 @@ static void pci_host_config_write(void *opaque, target_phys_addr_t addr, + + PCI_DPRINTF("%s addr " TARGET_FMT_plx " len %d val %"PRIx64"\n", + __func__, addr, len, val); ++ if (addr != 0 || len != 4) { ++ return; ++ } + s->config_reg = val; + } + diff --git a/0305-virtio-console-Fix-failure-on-unconnected-pty.patch b/0305-virtio-console-Fix-failure-on-unconnected-pty.patch new file mode 100644 index 0000000..57fd997 --- /dev/null +++ b/0305-virtio-console-Fix-failure-on-unconnected-pty.patch @@ -0,0 +1,50 @@ +From 7f090a666a5d0408b98dc4b339c00222cf66163b Mon Sep 17 00:00:00 2001 +From: Christian Borntraeger +Date: Thu, 29 Dec 2011 13:47:43 +0100 +Subject: [PATCH] virtio-console: Fix failure on unconnected pty + +when I tried qemu with -virtio-console pty the guest hangs and attaching +on /dev/pts/ does not return anything if the attachment is too late. + +This results in pty_chr_write() returning 0, which causes the port to +get throttled. This results in the guest getting frozen as the +guest->host virtio_console writes don't return until the host releases +the vq element back to the guest. + +For the virtio-serial use case we don't want to lose data but for the +console case we better drop data instead of "killing" the guest +console. If we get chardev->frontend notification and a better behaving +virtio-console we can revert this fix. + +Signed-off-by: Christian Borntraeger +Signed-off-by: Amit Shah +(cherry picked from commit ed8e5a85a1741147ce06932b478a509ce3407061) +--- + hw/virtio-serial-bus.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c +index e5f343f..b126a83 100644 +--- a/hw/virtio-serial-bus.c ++++ b/hw/virtio-serial-bus.c +@@ -163,7 +163,19 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, + abort(); + } + if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) { +- virtio_serial_throttle_port(port, true); ++ /* ++ * this is a temporary check until chardevs can signal to ++ * frontends that they are writable again. This prevents ++ * the console from going into throttled mode (forever) ++ * if virtio-console is connected to a pty without a ++ * listener. Otherwise the guest spins forever. ++ * We can revert this if ++ * 1: chardevs can notify frondends ++ * 2: the guest driver does not spin in these cases ++ */ ++ if (!info->is_console) { ++ virtio_serial_throttle_port(port, true); ++ } + port->iov_idx = i; + if (ret > 0) { + port->iov_offset += ret; diff --git a/0306-audio-Unbreak-capturing-in-mixemu-case.patch b/0306-audio-Unbreak-capturing-in-mixemu-case.patch new file mode 100644 index 0000000..66bc0a6 --- /dev/null +++ b/0306-audio-Unbreak-capturing-in-mixemu-case.patch @@ -0,0 +1,23 @@ +From 5b2531d6e6cbedfd1f2987680bded39ddcd4954c Mon Sep 17 00:00:00 2001 +From: malc +Date: Mon, 16 Jul 2012 18:08:36 +0400 +Subject: [PATCH] audio: Unbreak capturing in mixemu case + +Signed-off-by: malc +(cherry picked from commit 83617103984eb4d81cf46c94435f3da2c6f33b55) +--- + audio/audio.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/audio/audio.c b/audio/audio.c +index 0fe95a7..5779f9a 100644 +--- a/audio/audio.c ++++ b/audio/audio.c +@@ -815,6 +815,7 @@ static int audio_attach_capture (HWVoiceOut *hw) + sw->active = hw->enabled; + sw->conv = noop_conv; + sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq; ++ sw->vol = nominal_volume; + sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq); + if (!sw->rate) { + dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw)); diff --git a/0307-block-prevent-snapshot-mode-TMPDIR-symlink-attack.patch b/0307-block-prevent-snapshot-mode-TMPDIR-symlink-attack.patch new file mode 100644 index 0000000..a328e8a --- /dev/null +++ b/0307-block-prevent-snapshot-mode-TMPDIR-symlink-attack.patch @@ -0,0 +1,131 @@ +From 2d96e0d8673003d961c1c7b01c26a2fe60ca5bdd Mon Sep 17 00:00:00 2001 +From: Jim Meyering +Date: Mon, 28 May 2012 09:27:54 +0200 +Subject: [PATCH] block: prevent snapshot mode $TMPDIR symlink attack + +In snapshot mode, bdrv_open creates an empty temporary file without +checking for mkstemp or close failure, and ignoring the possibility +of a buffer overrun given a surprisingly long $TMPDIR. +Change the get_tmp_filename function to return int (not void), +so that it can inform its two callers of those failures. +Also avoid the risk of buffer overrun and do not ignore mkstemp +or close failure. +Update both callers (in block.c and vvfat.c) to propagate +temp-file-creation failure to their callers. + +get_tmp_filename creates and closes an empty file, while its +callers later open that presumed-existing file with O_CREAT. +The problem was that a malicious user could provoke mkstemp failure +and race to create a symlink with the selected temporary file name, +thus causing the qemu process (usually root owned) to open through +the symlink, overwriting an attacker-chosen file. + +This addresses CVE-2012-2652. +http://bugzilla.redhat.com/CVE-2012-2652 + +Signed-off-by: Jim Meyering +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Kevin Wolf +(cherry picked from commit c2d76497b6eafcaedc806e07804e7bed55a98a0b) +--- + block.c | 37 ++++++++++++++++++++++++------------- + block/vvfat.c | 7 ++++++- + block_int.h | 2 +- + 3 files changed, 31 insertions(+), 15 deletions(-) + +diff --git a/block.c b/block.c +index d015887..b752e84 100644 +--- a/block.c ++++ b/block.c +@@ -272,28 +272,36 @@ int bdrv_create_file(const char* filename, QEMUOptionParameter *options) + return bdrv_create(drv, filename, options); + } + +-#ifdef _WIN32 +-void get_tmp_filename(char *filename, int size) ++/* ++ * Create a uniquely-named empty temporary file. ++ * Return 0 upon success, otherwise a negative errno value. ++ */ ++int get_tmp_filename(char *filename, int size) + { ++#ifdef _WIN32 + char temp_dir[MAX_PATH]; +- +- GetTempPath(MAX_PATH, temp_dir); +- GetTempFileName(temp_dir, "qem", 0, filename); +-} ++ /* GetTempFileName requires that its output buffer (4th param) ++ have length MAX_PATH or greater. */ ++ assert(size >= MAX_PATH); ++ return (GetTempPath(MAX_PATH, temp_dir) ++ && GetTempFileName(temp_dir, "qem", 0, filename) ++ ? 0 : -GetLastError()); + #else +-void get_tmp_filename(char *filename, int size) +-{ + int fd; + const char *tmpdir; +- /* XXX: race condition possible */ + tmpdir = getenv("TMPDIR"); + if (!tmpdir) + tmpdir = "/tmp"; +- snprintf(filename, size, "%s/vl.XXXXXX", tmpdir); ++ if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) { ++ return -EOVERFLOW; ++ } + fd = mkstemp(filename); +- close(fd); +-} ++ if (fd < 0 || close(fd)) { ++ return -errno; ++ } ++ return 0; + #endif ++} + + /* + * Detect host devices. By convention, /dev/cdrom[N] is always +@@ -601,7 +609,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, + + bdrv_delete(bs1); + +- get_tmp_filename(tmp_filename, sizeof(tmp_filename)); ++ ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename)); ++ if (ret < 0) { ++ return ret; ++ } + + /* Real path is meaningless for protocols */ + if (is_protocol) +diff --git a/block/vvfat.c b/block/vvfat.c +index a310ce8..19e3aca 100644 +--- a/block/vvfat.c ++++ b/block/vvfat.c +@@ -2799,7 +2799,12 @@ static int enable_write_target(BDRVVVFATState *s) + array_init(&(s->commits), sizeof(commit_t)); + + s->qcow_filename = g_malloc(1024); +- get_tmp_filename(s->qcow_filename, 1024); ++ ret = get_tmp_filename(s->qcow_filename, 1024); ++ if (ret < 0) { ++ g_free(s->qcow_filename); ++ s->qcow_filename = NULL; ++ return ret; ++ } + + bdrv_qcow = bdrv_find_format("qcow"); + options = parse_option_parameters("", bdrv_qcow->create_options, NULL); +diff --git a/block_int.h b/block_int.h +index 77c0187..415a84a 100644 +--- a/block_int.h ++++ b/block_int.h +@@ -238,7 +238,7 @@ struct BlockDriverAIOCB { + BlockDriverAIOCB *next; + }; + +-void get_tmp_filename(char *filename, int size); ++int get_tmp_filename(char *filename, int size); + + void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque); diff --git a/0308-Fix-systemtap-keyword-collisions.patch b/0308-Fix-systemtap-keyword-collisions.patch new file mode 100644 index 0000000..140f3b0 --- /dev/null +++ b/0308-Fix-systemtap-keyword-collisions.patch @@ -0,0 +1,30 @@ +From 7d065557153bd8fdcb6c97aed8554bb1f2c39496 Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Wed, 6 Feb 2013 16:48:17 -0500 +Subject: [PATCH] Fix systemtap keyword collisions + +This is all upstream, this is just a manual backport +--- + scripts/tracetool | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/scripts/tracetool b/scripts/tracetool +index 4c9951d..3b4e39b 100755 +--- a/scripts/tracetool ++++ b/scripts/tracetool +@@ -500,6 +500,15 @@ EOF + if [ "$arg" = "limit" ]; then + arg="_limit" + fi ++ if [ "$arg" = "in" ]; then ++ arg="_in" ++ fi ++ if [ "$arg" = "next" ]; then ++ arg="_next" ++ fi ++ if [ "$arg" = "self" ]; then ++ arg="_self" ++ fi + cat < +Date: Sat, 18 Feb 2012 16:05:44 -0800 +Subject: [PATCH] qemu-1.0.1/VERSION + +Hello, + +The VERSION file in stable release qemu-1.0.1 has what I believe might be a typo: "1.0,1" rather than "1.0.1". This is causing a parsing issue for windres.exe in Win32 which chokes on: + #define CONFIG_FILEVERSION 1,0,1,0,1,0 + #define CONFIG_PRODUCTVERSION 1,0,1,0,1,0 + +when it should be seeing this: + #define CONFIG_FILEVERSION 1,0,1,0 + #define CONFIG_PRODUCTVERSION 1,0,1,0 + +Patch: + +Signed-off-by: Justin M. Forbes +Signed-off-by: Cole Robinson +--- + VERSION | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/VERSION b/VERSION +index b70c292..7dea76e 100644 +--- a/VERSION ++++ b/VERSION +@@ -1 +1 @@ +-1.0,1 ++1.0.1 diff --git a/0310-console-bounds-check-whenever-changing-the-cursor-du.patch b/0310-console-bounds-check-whenever-changing-the-cursor-du.patch new file mode 100644 index 0000000..aa6bf87 --- /dev/null +++ b/0310-console-bounds-check-whenever-changing-the-cursor-du.patch @@ -0,0 +1,123 @@ +From 7d3636fdbf59f1e7c2a50d73cc55475a0af00d0a Mon Sep 17 00:00:00 2001 +From: Ian Campbell +Date: Tue, 4 Sep 2012 10:26:09 -0500 +Subject: [PATCH] console: bounds check whenever changing the cursor due to an + escape code + +This is XSA-17 / CVE-2012-3515 + +Signed-off-by: Ian Campbell +Signed-off-by: Anthony Liguori +(cherry picked from commit 3eea5498ca501922520b3447ba94815bfc109743) +Signed-off-by: Cole Robinson +--- + console.c | 57 ++++++++++++++++++++++++++++----------------------------- + 1 file changed, 28 insertions(+), 29 deletions(-) + +diff --git a/console.c b/console.c +index ed6a653..bfad360 100644 +--- a/console.c ++++ b/console.c +@@ -841,6 +841,26 @@ static void console_clear_xy(TextConsole *s, int x, int y) + update_xy(s, x, y); + } + ++/* set cursor, checking bounds */ ++static void set_cursor(TextConsole *s, int x, int y) ++{ ++ if (x < 0) { ++ x = 0; ++ } ++ if (y < 0) { ++ y = 0; ++ } ++ if (y >= s->height) { ++ y = s->height - 1; ++ } ++ if (x >= s->width) { ++ x = s->width - 1; ++ } ++ ++ s->x = x; ++ s->y = y; ++} ++ + static void console_putchar(TextConsole *s, int ch) + { + TextCell *c; +@@ -912,7 +932,8 @@ static void console_putchar(TextConsole *s, int ch) + s->esc_params[s->nb_esc_params] * 10 + ch - '0'; + } + } else { +- s->nb_esc_params++; ++ if (s->nb_esc_params < MAX_ESC_PARAMS) ++ s->nb_esc_params++; + if (ch == ';') + break; + #ifdef DEBUG_CONSOLE +@@ -926,59 +947,37 @@ static void console_putchar(TextConsole *s, int ch) + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } +- s->y -= s->esc_params[0]; +- if (s->y < 0) { +- s->y = 0; +- } ++ set_cursor(s, s->x, s->y - s->esc_params[0]); + break; + case 'B': + /* move cursor down */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } +- s->y += s->esc_params[0]; +- if (s->y >= s->height) { +- s->y = s->height - 1; +- } ++ set_cursor(s, s->x, s->y + s->esc_params[0]); + break; + case 'C': + /* move cursor right */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } +- s->x += s->esc_params[0]; +- if (s->x >= s->width) { +- s->x = s->width - 1; +- } ++ set_cursor(s, s->x + s->esc_params[0], s->y); + break; + case 'D': + /* move cursor left */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } +- s->x -= s->esc_params[0]; +- if (s->x < 0) { +- s->x = 0; +- } ++ set_cursor(s, s->x - s->esc_params[0], s->y); + break; + case 'G': + /* move cursor to column */ +- s->x = s->esc_params[0] - 1; +- if (s->x < 0) { +- s->x = 0; +- } ++ set_cursor(s, s->esc_params[0] - 1, s->y); + break; + case 'f': + case 'H': + /* move cursor to row, column */ +- s->x = s->esc_params[1] - 1; +- if (s->x < 0) { +- s->x = 0; +- } +- s->y = s->esc_params[0] - 1; +- if (s->y < 0) { +- s->y = 0; +- } ++ set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1); + break; + case 'J': + switch (s->esc_params[0]) { diff --git a/0311-slirp-Fix-requeuing-of-batchq-packets-in-if_start.patch b/0311-slirp-Fix-requeuing-of-batchq-packets-in-if_start.patch new file mode 100644 index 0000000..88a3432 --- /dev/null +++ b/0311-slirp-Fix-requeuing-of-batchq-packets-in-if_start.patch @@ -0,0 +1,89 @@ +From 67e7070899cdef35a94714569cd48b7ea0b5e572 Mon Sep 17 00:00:00 2001 +From: Jan Kiszka +Date: Fri, 17 Feb 2012 16:26:38 +0100 +Subject: [PATCH] slirp: Fix requeuing of batchq packets in if_start + +In case we requeued a packet that was the head of a longer session +queue, we failed to restore this ordering. Also, we did not properly +deal with changes to Slirp::next_m. + +Instead of a cumbersome roll back, this fix simply avoids any changes +until we know if the packet was actually sent. Both fixes crashes due +to inconsistent queues and simplifies the logic. + +Thanks to Zhi Yong Wu who found the reason for these crashes. + +CC: Zhi Yong Wu +CC: Fabien Chouteau +Signed-off-by: Jan Kiszka +(cherry picked from commit b248ede2ef2792d364bd305e5e92e24921c924a8) +Signed-off-by: Cole Robinson +--- + slirp/if.c | 35 +++++++++++++++++++---------------- + 1 file changed, 19 insertions(+), 16 deletions(-) + +diff --git a/slirp/if.c b/slirp/if.c +index 2852396..75a3c26 100644 +--- a/slirp/if.c ++++ b/slirp/if.c +@@ -156,6 +156,7 @@ if_start(Slirp *slirp) + { + uint64_t now = qemu_get_clock_ns(rt_clock); + int requeued = 0; ++ bool from_batchq = false; + struct mbuf *ifm, *ifqt; + + DEBUG_CALL("if_start"); +@@ -181,13 +182,26 @@ if_start(Slirp *slirp) + else + ifm = slirp->if_batchq.ifq_next; + +- /* Set which packet to send on next iteration */ +- slirp->next_m = ifm->ifq_next; ++ from_batchq = true; + } ++ ++ slirp->if_queued--; ++ ++ /* Try to send packet unless it already expired */ ++ if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) { ++ /* Packet is delayed due to pending ARP resolution */ ++ requeued++; ++ goto out; ++ } ++ ++ if (from_batchq) { ++ /* Set which packet to send on next iteration */ ++ slirp->next_m = ifm->ifq_next; ++ } ++ + /* Remove it from the queue */ + ifqt = ifm->ifq_prev; + remque(ifm); +- slirp->if_queued--; + + /* If there are more packets for this session, re-queue them */ + if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) { +@@ -202,20 +216,9 @@ if_start(Slirp *slirp) + ifm->ifq_so->so_nqueued = 0; + } + +- if (ifm->expiration_date < now) { +- /* Expired */ +- m_free(ifm); +- } else { +- /* Encapsulate the packet for sending */ +- if (if_encap(slirp, ifm)) { +- m_free(ifm); +- } else { +- /* re-queue */ +- insque(ifm, ifqt); +- requeued++; +- } +- } ++ m_free(ifm); + ++ out: + if (slirp->if_queued) + goto again; + diff --git a/0312-e1000-Discard-packets-that-are-too-long-if-SBP-and-L.patch b/0312-e1000-Discard-packets-that-are-too-long-if-SBP-and-L.patch new file mode 100644 index 0000000..fc99fe0 --- /dev/null +++ b/0312-e1000-Discard-packets-that-are-too-long-if-SBP-and-L.patch @@ -0,0 +1,46 @@ +From d1fdcb2607d138f7207eda62a07a04e13c96be83 Mon Sep 17 00:00:00 2001 +From: Michael Contreras +Date: Sun, 2 Dec 2012 20:11:22 -0800 +Subject: [PATCH] e1000: Discard packets that are too long if !SBP and !LPE + +The e1000_receive function for the e1000 needs to discard packets longer than +1522 bytes if the SBP and LPE flags are disabled. The linux driver assumes +this behavior and allocates memory based on this assumption. + +Signed-off-by: Michael Contreras +Signed-off-by: Anthony Liguori +(cherry picked from commit b0d9ffcd0251161c7c92f94804dcf599dfa3edeb) + +Signed-off-by: Michael Roth +--- + hw/e1000.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/hw/e1000.c b/hw/e1000.c +index e164d79..37d207e 100644 +--- a/hw/e1000.c ++++ b/hw/e1000.c +@@ -59,6 +59,9 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); + #define PNPMMIO_SIZE 0x20000 + #define MIN_BUF_SIZE 60 /* Min. octets in an ethernet frame sans FCS */ + ++/* this is the size past which hardware will drop packets when setting LPE=0 */ ++#define MAXIMUM_ETHERNET_VLAN_SIZE 1522 ++ + /* + * HW models: + * E1000_DEV_ID_82540EM works with Windows and Linux +@@ -693,6 +696,13 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) + size = sizeof(min_buf); + } + ++ /* Discard oversized packets if !LPE and !SBP. */ ++ if (size > MAXIMUM_ETHERNET_VLAN_SIZE ++ && !(s->mac_reg[RCTL] & E1000_RCTL_LPE) ++ && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) { ++ return size; ++ } ++ + if (!receive_filter(s, buf, size)) + return size; + diff --git a/0313-e1000-Discard-oversized-packets-based-on-SBP-LPE.patch b/0313-e1000-Discard-oversized-packets-based-on-SBP-LPE.patch new file mode 100644 index 0000000..0474c84 --- /dev/null +++ b/0313-e1000-Discard-oversized-packets-based-on-SBP-LPE.patch @@ -0,0 +1,38 @@ +From e603b5632a4c4eb95bc7dd9c70f1fe7822a87da9 Mon Sep 17 00:00:00 2001 +From: Michael Contreras +Date: Wed, 5 Dec 2012 13:31:30 -0500 +Subject: [PATCH] e1000: Discard oversized packets based on SBP|LPE + +Discard packets longer than 16384 when !SBP to match the hardware behavior. + +Signed-off-by: Michael Contreras +Signed-off-by: Stefan Hajnoczi +--- + hw/e1000.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/hw/e1000.c b/hw/e1000.c +index 37d207e..a5e67a8 100644 +--- a/hw/e1000.c ++++ b/hw/e1000.c +@@ -61,6 +61,8 @@ static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL); + + /* this is the size past which hardware will drop packets when setting LPE=0 */ + #define MAXIMUM_ETHERNET_VLAN_SIZE 1522 ++/* this is the size past which hardware will drop packets when setting LPE=1 */ ++#define MAXIMUM_ETHERNET_LPE_SIZE 16384 + + /* + * HW models: +@@ -697,8 +699,9 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size) + } + + /* Discard oversized packets if !LPE and !SBP. */ +- if (size > MAXIMUM_ETHERNET_VLAN_SIZE +- && !(s->mac_reg[RCTL] & E1000_RCTL_LPE) ++ if ((size > MAXIMUM_ETHERNET_LPE_SIZE || ++ (size > MAXIMUM_ETHERNET_VLAN_SIZE ++ && !(s->mac_reg[RCTL] & E1000_RCTL_LPE))) + && !(s->mac_reg[RCTL] & E1000_RCTL_SBP)) { + return size; + } diff --git a/0314-vmware_vga-fix-out-of-bounds-and-invalid-rects-updat.patch b/0314-vmware_vga-fix-out-of-bounds-and-invalid-rects-updat.patch new file mode 100644 index 0000000..7356685 --- /dev/null +++ b/0314-vmware_vga-fix-out-of-bounds-and-invalid-rects-updat.patch @@ -0,0 +1,109 @@ +From 0aceb6a68b81defbf34872e69284c7179249f561 Mon Sep 17 00:00:00 2001 +From: Michael Tokarev +Date: Fri, 25 Jan 2013 21:23:24 +0400 +Subject: [PATCH] vmware_vga: fix out of bounds and invalid rects updating + +This is a follow up for several attempts to fix this issue. + +Previous incarnations: + +1. http://thread.gmane.org/gmane.linux.ubuntu.bugs.general/3156089 +https://bugs.launchpad.net/bugs/918791 +"qemu-kvm dies when using vmvga driver and unity in the guest" bug. +Fix by Serge Hallyn: + https://launchpadlibrarian.net/94916786/qemu-vmware.debdiff +This fix is incomplete, since it does not check width and height +for being negative. Serge weren't sure if that's the right place +to fix it, maybe the fix should be up the stack somewhere. + +2. http://thread.gmane.org/gmane.comp.emulators.qemu/166064 +by Marek Vasut: "vmware_vga: Redraw only visible area" + +This one adds the (incomplete) check to vmsvga_update_rect_delayed(), +the routine just queues the rect updating but does no interesting +stuff. It is also incomplete in the same way as patch by Serge, +but also does not touch width&height at all after adjusting x&y, +which is wrong. + +As far as I can see, when processing guest requests, the device +places them into a queue (vmsvga_update_rect_delayed()) and +processes this queue in different place/time, namely, in +vmsvga_update_rect(). Sometimes, vmsvga_update_rect() is +called directly, without placing the request to the gueue. +This is the place this patch changes, which is the last +(deepest) in the stack. I'm not sure if this is the right +place still, since it is possible we have some queue optimization +(or may have in the future) which will be upset by negative/wrong +values here, so maybe we should check for validity of input +right when receiving request from the guest (and maybe even +use unsigned types there). But I don't know the protocol +and implementation enough to have a definitive answer. + +But since vmsvga_update_rect() has other sanity checks already, +I'm adding the missing ones there as well. + +Cc'ing BALATON Zoltan and Andrzej Zaborowski who shows in `git blame' +output and may know something in this area. + +If this patch is accepted, it should be applied to all active +stable branches (at least since 1.1, maybe even before), with +minor context change (ds_get_*(s->vga.ds) => s->*). I'm not +Cc'ing -stable yet, will do it explicitly once the patch is +accepted. + +BTW, these checks use fprintf(stderr) -- it should be converted +to something more appropriate, since stderr will most likely +disappear somewhere. + +Cc: Marek Vasut +CC: Serge Hallyn +Cc: BALATON Zoltan +Cc: Andrzej Zaborowski +Signed-off-by: Michael Tokarev +Reviewed-by: Marek Vasut +Signed-off-by: Serge Hallyn +Signed-off-by: Blue Swirl +(cherry picked from commit 8cb6bfb54e91b1a31a6ae704def595c2099efde1) + +Conflicts: + hw/vmware_vga.c +--- + hw/vmware_vga.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c +index af70bde..8b053a8 100644 +--- a/hw/vmware_vga.c ++++ b/hw/vmware_vga.c +@@ -298,6 +298,15 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, + uint8_t *src; + uint8_t *dst; + ++ if (x < 0) { ++ fprintf(stderr, "%s: update x was < 0 (%d)\n", __func__, x); ++ w += x; ++ x = 0; ++ } ++ if (w < 0) { ++ fprintf(stderr, "%s: update w was < 0 (%d)\n", __func__, w); ++ w = 0; ++ } + if (x + w > s->width) { + fprintf(stderr, "%s: update width too large x: %d, w: %d\n", + __FUNCTION__, x, w); +@@ -305,6 +314,15 @@ static inline void vmsvga_update_rect(struct vmsvga_state_s *s, + w = s->width - x; + } + ++ if (y < 0) { ++ fprintf(stderr, "%s: update y was < 0 (%d)\n", __func__, y); ++ h += y; ++ y = 0; ++ } ++ if (h < 0) { ++ fprintf(stderr, "%s: update h was < 0 (%d)\n", __func__, h); ++ h = 0; ++ } + if (y + h > s->height) { + fprintf(stderr, "%s: update height too large y: %d, h: %d\n", + __FUNCTION__, y, h); diff --git a/0315-vhost-Fix-size-of-dirty-log-sync-on-resize.patch b/0315-vhost-Fix-size-of-dirty-log-sync-on-resize.patch new file mode 100644 index 0000000..45aeb09 --- /dev/null +++ b/0315-vhost-Fix-size-of-dirty-log-sync-on-resize.patch @@ -0,0 +1,60 @@ +From 7bf47a086242370adfabd65e38d28d7b3e36933d Mon Sep 17 00:00:00 2001 +From: Alex Williamson +Date: Fri, 13 Aug 2010 09:54:52 -0400 +Subject: [PATCH] vhost: Fix size of dirty log sync on resize + +When the vhost log is resized, we want to sync up to +the size of the old log. With that end address in place, +ignore regions that start after then end rather than +hitting assert. + +This also addresses the following crash report: +When migrating a vm using vhost-net we hit the following assertion: + +qemu-kvm: /usr/src/packages/BUILD/qemu-kvm-0.15.1/hw/vhost.c:30: +vhost_dev_sync_region: Assertion `start / (0x1000 * (8 * +sizeof(vhost_log_chunk_t))) < dev->log_size' failed. + +The cases which the end < start check is intended to catch, such as +for vga video memory, will also likely trigger the assertion. +Reorder the code to handle this correctly. + +Reported-by: Josh Durgin +Signed-off-by: Bruce Rogers +Signed-off-by: Alex Williamson +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit e314672a8a95f5dc98534f0682fce50fb83dbc5c) + +Conflicts: + hw/vhost.c +--- + hw/vhost.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/vhost.c b/hw/vhost.c +index 0870cb7..06daa7e 100644 +--- a/hw/vhost.c ++++ b/hw/vhost.c +@@ -26,11 +26,11 @@ static void vhost_dev_sync_region(struct vhost_dev *dev, + vhost_log_chunk_t *to = dev->log + end / VHOST_LOG_CHUNK + 1; + uint64_t addr = (start / VHOST_LOG_CHUNK) * VHOST_LOG_CHUNK; + +- assert(end / VHOST_LOG_CHUNK < dev->log_size); +- assert(start / VHOST_LOG_CHUNK < dev->log_size); + if (end < start) { + return; + } ++ assert(end / VHOST_LOG_CHUNK < dev->log_size); ++ + for (;from < to; ++from) { + vhost_log_chunk_t log; + int bit; +@@ -260,7 +260,7 @@ static inline void vhost_dev_log_resize(struct vhost_dev* dev, uint64_t size) + r = ioctl(dev->control, VHOST_SET_LOG_BASE, &log_base); + assert(r >= 0); + vhost_client_sync_dirty_bitmap(&dev->client, 0, +- (target_phys_addr_t)~0x0ull); ++ dev->log_size * VHOST_LOG_CHUNK - 1); + if (dev->log) { + g_free(dev->log); + } diff --git a/0401-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch b/0401-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch deleted file mode 100644 index df4ed85..0000000 --- a/0401-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 8858b6d0dac346d9f841cfa84f57cb03bffdf050 Mon Sep 17 00:00:00 2001 -From: Markus Armbruster -Date: Fri, 4 Nov 2011 10:34:24 +0100 -Subject: [PATCH 401/434] qxl: Slot sanity check in qxl_phys2virt() is off by - one, fix - -Spotted by Coverity. - -Signed-off-by: Markus Armbruster -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 41500e9..e0f9d4a 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1020,7 +1020,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) - case MEMSLOT_GROUP_HOST: - return (void*)offset; - case MEMSLOT_GROUP_GUEST: -- PANIC_ON(slot > NUM_MEMSLOTS); -+ PANIC_ON(slot >= NUM_MEMSLOTS); - PANIC_ON(!qxl->guest_slots[slot].active); - PANIC_ON(offset < qxl->guest_slots[slot].delta); - offset -= qxl->guest_slots[slot].delta; --- -1.7.10 - diff --git a/0402-input-send-kbd-mouse-events-only-to-running-guests.patch b/0402-input-send-kbd-mouse-events-only-to-running-guests.patch deleted file mode 100644 index ba35d9b..0000000 --- a/0402-input-send-kbd-mouse-events-only-to-running-guests.patch +++ /dev/null @@ -1,45 +0,0 @@ -From f87b93c3944652f90e2c0010da6ee8c182382369 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 15 Feb 2012 09:15:37 +0100 -Subject: [PATCH 402/434] input: send kbd+mouse events only to running guests. - -Trying to interact with a stopped guest will queue up the events, -then send them all at once when the guest continues running, with -a high chance to have them cause unwanted actions. - -Avoid that by only injecting the input events only when the guest -is in running state. - -Signed-off-by: Gerd Hoffmann -Signed-off-by: Anthony Liguori ---- - input.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/input.c b/input.c -index 9ade63f..b48408d 100644 ---- a/input.c -+++ b/input.c -@@ -130,6 +130,9 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry) - - void kbd_put_keycode(int keycode) - { -+ if (!runstate_is_running()) { -+ return; -+ } - if (qemu_put_kbd_event) { - qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode); - } -@@ -151,6 +154,9 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) - void *mouse_event_opaque; - int width, height; - -+ if (!runstate_is_running()) { -+ return; -+ } - if (QTAILQ_EMPTY(&mouse_handlers)) { - return; - } --- -1.7.10 - diff --git a/0403-qxl-fix-warnings-on-32bit.patch b/0403-qxl-fix-warnings-on-32bit.patch deleted file mode 100644 index c358780..0000000 --- a/0403-qxl-fix-warnings-on-32bit.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 3b36dd31d54b24e02493fdd86269ba5286086c98 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 8 Feb 2012 15:58:35 +0100 -Subject: [PATCH 403/434] qxl: fix warnings on 32bit - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 7 ++++--- - 1 file changed, 4 insertions(+), 3 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index e0f9d4a..4fd5e4e 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -628,7 +628,7 @@ static void interface_release_resource(QXLInstance *sin, - - if (ext.group_id == MEMSLOT_GROUP_HOST) { - /* host group -> vga mode update request */ -- qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id); -+ qemu_spice_destroy_update(&qxl->ssd, (void *)(intptr_t)ext.info->id); - return; - } - -@@ -751,7 +751,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) - qxl->current_async = QXL_UNDEFINED_IO; - qemu_mutex_unlock(&qxl->async_lock); - -- dprint(qxl, 2, "async_complete: %d (%ld) done\n", current_async, cookie); -+ dprint(qxl, 2, "async_complete: %d (%" PRId64 ") done\n", -+ current_async, cookie); - switch (current_async) { - case QXL_IO_CREATE_PRIMARY_ASYNC: - qxl_create_guest_primary_complete(qxl); -@@ -1018,7 +1019,7 @@ void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) - - switch (group_id) { - case MEMSLOT_GROUP_HOST: -- return (void*)offset; -+ return (void *)(intptr_t)offset; - case MEMSLOT_GROUP_GUEST: - PANIC_ON(slot >= NUM_MEMSLOTS); - PANIC_ON(!qxl->guest_slots[slot].active); --- -1.7.10 - diff --git a/0404-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch b/0404-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch deleted file mode 100644 index 24722a4..0000000 --- a/0404-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 29fdb0f3a401e5590e465a0cc37d82383f3d5f07 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 15 Feb 2012 14:04:44 +0100 -Subject: [PATCH 404/434] qxl: don't render stuff when the vm is stopped. - -This patch fixes the local qxl renderer to not kick spice-server -in case the vm is stopped. First it is largely pointless because -we ask spice-server to process all not-yet processed commands when -the vm is stopped, so there isn't much do do anyway. Second we -avoid triggering an assert in spice-server. - -The patch makes sure we still honor redraw requests, even if we don't -ask spice-server for updates. This is needed to handle displaysurface -changes with a stopped vm correctly. - -With this patch applied it is possible to take screen shots (via -screendump monitor command) from a qxl gpu even in case the guest -is stopped. - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl-render.c | 12 +++++------- - 1 file changed, 5 insertions(+), 7 deletions(-) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index 2c51ba9..a7891b2 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -121,19 +121,17 @@ void qxl_render_update(PCIQXLDevice *qxl) - dpy_resize(vga->ds); - } - -- if (!qxl->guest_primary.commands) { -- return; -- } -- qxl->guest_primary.commands = 0; -- - update.left = 0; - update.right = qxl->guest_primary.surface.width; - update.top = 0; - update.bottom = qxl->guest_primary.surface.height; - - memset(dirty, 0, sizeof(dirty)); -- qxl_spice_update_area(qxl, 0, &update, -- dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); -+ if (runstate_is_running() && qxl->guest_primary.commands) { -+ qxl->guest_primary.commands = 0; -+ qxl_spice_update_area(qxl, 0, &update, -+ dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); -+ } - if (redraw) { - memset(dirty, 0, sizeof(dirty)); - dirty[0] = update; --- -1.7.10 - diff --git a/0405-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch b/0405-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch deleted file mode 100644 index 8c642a0..0000000 --- a/0405-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 0386bf2be16745ce87f35ce65153ef4e11f93b22 Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -Date: Wed, 15 Feb 2012 11:22:15 +0200 -Subject: [PATCH 405/434] qxl: set only off-screen surfaces dirty instead of - the whole vram - -We used to assure the guest surfaces were saved before migration by -setting the whole vram dirty. This patch sets dirty only the areas -that are actually used in the vram. - -Signed-off-by: Yonit Halperin -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 53 ++++++++++++++++++++++++++++++++++++++++++++--------- - 1 file changed, 44 insertions(+), 9 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 4fd5e4e..3d9b1b3 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1010,7 +1010,7 @@ static void qxl_reset_surfaces(PCIQXLDevice *d) - qxl_spice_destroy_surfaces(d, QXL_SYNC); - } - --/* called from spice server thread context only */ -+/* can be also called from spice server thread context */ - void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) - { - uint64_t phys = le64_to_cpu(pqxl); -@@ -1469,6 +1469,46 @@ static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) - } - } - -+static void qxl_dirty_surfaces(PCIQXLDevice *qxl) -+{ -+ intptr_t vram_start; -+ int i; -+ -+ if (qxl->mode != QXL_MODE_NATIVE) { -+ return; -+ } -+ -+ /* dirty the primary surface */ -+ qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, -+ qxl->shadow_rom.surface0_area_size); -+ -+ vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); -+ -+ /* dirty the off-screen surfaces */ -+ for (i = 0; i < NUM_SURFACES; i++) { -+ QXLSurfaceCmd *cmd; -+ intptr_t surface_offset; -+ int surface_size; -+ -+ if (qxl->guest_surfaces.cmds[i] == 0) { -+ continue; -+ } -+ -+ cmd = qxl_phys2virt(qxl, qxl->guest_surfaces.cmds[i], -+ MEMSLOT_GROUP_GUEST); -+ assert(cmd->type == QXL_SURFACE_CMD_CREATE); -+ surface_offset = (intptr_t)qxl_phys2virt(qxl, -+ cmd->u.surface_create.data, -+ MEMSLOT_GROUP_GUEST); -+ surface_offset -= vram_start; -+ surface_size = cmd->u.surface_create.height * -+ abs(cmd->u.surface_create.stride); -+ dprint(qxl, 3, "%s: dirty surface %d, offset %d, size %d\n", __func__, -+ i, (int)surface_offset, surface_size); -+ qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size); -+ } -+} -+ - static void qxl_vm_change_state_handler(void *opaque, int running, - RunState state) - { -@@ -1482,14 +1522,9 @@ static void qxl_vm_change_state_handler(void *opaque, int running, - * called - */ - qxl_update_irq(qxl); -- } else if (qxl->mode == QXL_MODE_NATIVE) { -- /* dirty all vram (which holds surfaces) and devram (primary surface) -- * to make sure they are saved */ -- /* FIXME #1: should go out during "live" stage */ -- /* FIXME #2: we only need to save the areas which are actually used */ -- qxl_set_dirty(&qxl->vram_bar, 0, qxl->vram_size); -- qxl_set_dirty(&qxl->vga.vram, qxl->shadow_rom.draw_area_offset, -- qxl->shadow_rom.surface0_area_size); -+ } else { -+ /* make sure surfaces are saved before migration */ -+ qxl_dirty_surfaces(qxl); - } - } - --- -1.7.10 - diff --git a/0406-qxl-make-sure-primary-surface-is-saved-on-migration-.patch b/0406-qxl-make-sure-primary-surface-is-saved-on-migration-.patch deleted file mode 100644 index b07d4b6..0000000 --- a/0406-qxl-make-sure-primary-surface-is-saved-on-migration-.patch +++ /dev/null @@ -1,30 +0,0 @@ -From ba922e5e6a5687f13def623e36bfb834ece2defc Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -Date: Wed, 15 Feb 2012 11:22:16 +0200 -Subject: [PATCH 406/434] qxl: make sure primary surface is saved on migration - also in compat mode - -RHBZ #790083 - -Signed-off-by: Yonit Halperin -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 3d9b1b3..b910337 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1474,7 +1474,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) - intptr_t vram_start; - int i; - -- if (qxl->mode != QXL_MODE_NATIVE) { -+ if (qxl->mode != QXL_MODE_NATIVE && qxl->mode != QXL_MODE_COMPAT) { - return; - } - --- -1.7.10 - diff --git a/0407-Add-SPICE-support-to-add_client-monitor-command.patch b/0407-Add-SPICE-support-to-add_client-monitor-command.patch deleted file mode 100644 index 1ba56e5..0000000 --- a/0407-Add-SPICE-support-to-add_client-monitor-command.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 9ada192cfea65a92a765c6a2f6b56a08f1b865df Mon Sep 17 00:00:00 2001 -From: "Daniel P. Berrange" -Date: Mon, 13 Feb 2012 13:43:08 +0000 -Subject: [PATCH 407/434] Add SPICE support to add_client monitor command - -With the acceptance of some new APIs to libspice-server.so it -is possible to add support for SPICE to the 'add_client' -monitor command, bringing parity with VNC. Since SPICE can -use TLS or plain connections, the command also gains a new -'tls' parameter to specify whether TLS should be attempted -on the injected client sockets. - -This new feature is only enabled if building against a -libspice-server >= 0.10.1 - -* qmp-commands.hx: Add 'tls' parameter & missing doc for - 'skipauth' parameter -* monitor.c: Wire up SPICE for 'add_client' command -* ui/qemu-spice.h, ui/spice-core.c: Add qemu_spice_display_add_client - API to wire up from monitor - -[1] http://cgit.freedesktop.org/spice/spice/commit/server/spice.h?id=d55b68b6b44f2499278fa860fb47ff22f5011faa - http://cgit.freedesktop.org/spice/spice/commit/server/spice.h?id=bd07dde530d9504e1cfe7ed5837fc00c26f36716 - -Changes in v3: - - Added 'optional' flag to new parameters documented - - Added no-op impl of qemu_spice_display_add_client when - SPICE is disabled during build - -Signed-off-by: Daniel P. Berrange -Signed-off-by: Gerd Hoffmann ---- - monitor.c | 9 +++++++-- - qmp-commands.hx | 6 ++++-- - ui/qemu-spice.h | 7 +++++++ - ui/spice-core.c | 13 +++++++++++++ - 4 files changed, 31 insertions(+), 4 deletions(-) - -diff --git a/monitor.c b/monitor.c -index a82fda3..3c23aa4 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -998,13 +998,18 @@ static int add_graphics_client(Monitor *mon, const QDict *qdict, QObject **ret_d - CharDriverState *s; - - if (strcmp(protocol, "spice") == 0) { -+ int fd = monitor_get_fd(mon, fdname); -+ int skipauth = qdict_get_try_bool(qdict, "skipauth", 0); -+ int tls = qdict_get_try_bool(qdict, "tls", 0); - if (!using_spice) { - /* correct one? spice isn't a device ,,, */ - qerror_report(QERR_DEVICE_NOT_ACTIVE, "spice"); - return -1; - } -- qerror_report(QERR_ADD_CLIENT_FAILED); -- return -1; -+ if (qemu_spice_display_add_client(fd, skipauth, tls) < 0) { -+ close(fd); -+ } -+ return 0; - #ifdef CONFIG_VNC - } else if (strcmp(protocol, "vnc") == 0) { - int fd = monitor_get_fd(mon, fdname); -diff --git a/qmp-commands.hx b/qmp-commands.hx -index 97975a5..122b10d 100644 ---- a/qmp-commands.hx -+++ b/qmp-commands.hx -@@ -909,8 +909,8 @@ EQMP - - { - .name = "add_client", -- .args_type = "protocol:s,fdname:s,skipauth:b?", -- .params = "protocol fdname skipauth", -+ .args_type = "protocol:s,fdname:s,skipauth:b?,tls:b?", -+ .params = "protocol fdname skipauth tls", - .help = "add a graphics client", - .user_print = monitor_user_noop, - .mhandler.cmd_new = add_graphics_client, -@@ -926,6 +926,8 @@ Arguments: - - - "protocol": protocol name (json-string) - - "fdname": file descriptor name (json-string) -+- "skipauth": whether to skip authentication (json-bool, optional) -+- "tls": whether to perform TLS (json-bool, optional) - - Example: - -diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h -index c35b29c..680206a 100644 ---- a/ui/qemu-spice.h -+++ b/ui/qemu-spice.h -@@ -33,6 +33,7 @@ void qemu_spice_init(void); - void qemu_spice_input_init(void); - void qemu_spice_audio_init(void); - void qemu_spice_display_init(DisplayState *ds); -+int qemu_spice_display_add_client(int csock, int skipauth, int tls); - int qemu_spice_add_interface(SpiceBaseInstance *sin); - int qemu_spice_set_passwd(const char *passwd, - bool fail_if_connected, bool disconnect_if_connected); -@@ -68,6 +69,12 @@ static inline int qemu_spice_migrate_info(const char *h, int p, int t, - return -1; - } - -+static inline int qemu_spice_display_add_client(int csock, int skipauth, -+ int tls) -+{ -+ return -1; -+} -+ - #endif /* CONFIG_SPICE */ - - #endif /* QEMU_SPICE_H */ -diff --git a/ui/spice-core.c b/ui/spice-core.c -index 5639c6f..d98863e 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -747,6 +747,19 @@ int qemu_spice_set_pw_expire(time_t expires) - return qemu_spice_set_ticket(false, false); - } - -+int qemu_spice_display_add_client(int csock, int skipauth, int tls) -+{ -+#if SPICE_SERVER_VERSION >= 0x000a01 -+ if (tls) { -+ return spice_server_add_ssl_client(spice_server, csock, skipauth); -+ } else { -+ return spice_server_add_client(spice_server, csock, skipauth); -+ } -+#else -+ return -1; -+#endif -+} -+ - static void spice_register_config(void) - { - qemu_add_opts(&qemu_spice_opts); --- -1.7.10 - diff --git a/0408-spice-support-ipv6-channel-address-in-monitor-events.patch b/0408-spice-support-ipv6-channel-address-in-monitor-events.patch deleted file mode 100644 index 4709e09..0000000 --- a/0408-spice-support-ipv6-channel-address-in-monitor-events.patch +++ /dev/null @@ -1,83 +0,0 @@ -From 6594551ebe427cae4298b038be02ddc9c335219f Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -Date: Wed, 8 Feb 2012 15:40:15 +0200 -Subject: [PATCH 408/434] spice: support ipv6 channel address in monitor - events and in spice info - -RHBZ #788444 - -CC: Gerd Hoffmann - -Signed-off-by: Yonit Halperin -Signed-off-by: Gerd Hoffmann ---- - ui/spice-core.c | 37 ++++++++++++++++++++++++++++++++----- - 1 file changed, 32 insertions(+), 5 deletions(-) - -diff --git a/ui/spice-core.c b/ui/spice-core.c -index d98863e..27216e9 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -220,10 +220,23 @@ static void channel_event(int event, SpiceChannelEventInfo *info) - } - - client = qdict_new(); -- add_addr_info(client, &info->paddr, info->plen); -- - server = qdict_new(); -- add_addr_info(server, &info->laddr, info->llen); -+ -+#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT -+ if (info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { -+ add_addr_info(client, (struct sockaddr *)&info->paddr_ext, -+ info->plen_ext); -+ add_addr_info(server, (struct sockaddr *)&info->laddr_ext, -+ info->llen_ext); -+ } else { -+ fprintf(stderr, "spice: %s, extended address is expected\n", -+ __func__); -+#endif -+ add_addr_info(client, &info->paddr, info->plen); -+ add_addr_info(server, &info->laddr, info->llen); -+#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT -+ } -+#endif - - if (event == SPICE_CHANNEL_EVENT_INITIALIZED) { - qdict_put(server, "auth", qstring_from_str(auth)); -@@ -376,16 +389,30 @@ static SpiceChannelList *qmp_query_spice_channels(void) - QTAILQ_FOREACH(item, &channel_list, link) { - SpiceChannelList *chan; - char host[NI_MAXHOST], port[NI_MAXSERV]; -+ struct sockaddr *paddr; -+ socklen_t plen; - - chan = g_malloc0(sizeof(*chan)); - chan->value = g_malloc0(sizeof(*chan->value)); - -- getnameinfo(&item->info->paddr, item->info->plen, -+#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT -+ if (item->info->flags & SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT) { -+ paddr = (struct sockaddr *)&item->info->paddr_ext; -+ plen = item->info->plen_ext; -+ } else { -+#endif -+ paddr = &item->info->paddr; -+ plen = item->info->plen; -+#ifdef SPICE_CHANNEL_EVENT_FLAG_ADDR_EXT -+ } -+#endif -+ -+ getnameinfo(paddr, plen, - host, sizeof(host), port, sizeof(port), - NI_NUMERICHOST | NI_NUMERICSERV); - chan->value->host = g_strdup(host); - chan->value->port = g_strdup(port); -- chan->value->family = g_strdup(inet_strfamily(item->info->paddr.sa_family)); -+ chan->value->family = g_strdup(inet_strfamily(paddr->sa_family)); - - chan->value->connection_id = item->info->connection_id; - chan->value->channel_type = item->info->type; --- -1.7.10 - diff --git a/0409-qxl-drop-vram-bar-minimum-size.patch b/0409-qxl-drop-vram-bar-minimum-size.patch deleted file mode 100644 index f7a740d..0000000 --- a/0409-qxl-drop-vram-bar-minimum-size.patch +++ /dev/null @@ -1,30 +0,0 @@ -From f7656005900f3c07450303afa66151b6a1bb9599 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 17 Feb 2012 14:40:01 +0100 -Subject: [PATCH 409/434] qxl: drop vram bar minimum size - -There is no reason to require a minimum size of 16 MB for the vram. -Lower the limit to 4096 (one page). Make it disapper completely would -break guests. ---- - hw/qxl.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index b910337..d71c94d 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1595,8 +1595,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) - init_qxl_rom(qxl); - init_qxl_ram(qxl); - -- if (qxl->vram_size < 16 * 1024 * 1024) { -- qxl->vram_size = 16 * 1024 * 1024; -+ if (qxl->vram_size < 4096) { -+ qxl->vram_size = 4096; - } - if (qxl->revision == 1) { - qxl->vram_size = 4096; --- -1.7.10 - diff --git a/0410-qxl-move-ram-size-init-to-new-function.patch b/0410-qxl-move-ram-size-init-to-new-function.patch deleted file mode 100644 index 97b12cf..0000000 --- a/0410-qxl-move-ram-size-init-to-new-function.patch +++ /dev/null @@ -1,97 +0,0 @@ -From 619c68418809149d56025e5b4e7a9828eef90ea8 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 17 Feb 2012 15:02:40 +0100 -Subject: [PATCH 410/434] qxl: move ram size init to new function - -Factor memory bar sizing bits out to a separate function. - -Signed-off-by: Gerd Hoffmann - -Conflicts: - - hw/qxl.c ---- - hw/qxl.c | 41 ++++++++++++++++++++++------------------- - 1 file changed, 22 insertions(+), 19 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index d71c94d..df8efbc 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1557,6 +1557,25 @@ static DisplayChangeListener display_listener = { - .dpy_refresh = display_refresh, - }; - -+static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) -+{ -+ /* vga ram (bar 0) */ -+ if (qxl->vga.vram_size < ram_min_mb * 1024 * 1024) { -+ qxl->vga.vram_size = ram_min_mb * 1024 * 1024; -+ } -+ -+ /* vram (surfaces, bar 1) */ -+ if (qxl->vram_size < 4096) { -+ qxl->vram_size = 4096; -+ } -+ if (qxl->revision == 1) { -+ qxl->vram_size = 4096; -+ } -+ -+ qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1); -+ qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); -+} -+ - static int qxl_init_common(PCIQXLDevice *qxl) - { - uint8_t* config = qxl->pci.config; -@@ -1595,13 +1614,6 @@ static int qxl_init_common(PCIQXLDevice *qxl) - init_qxl_rom(qxl); - init_qxl_ram(qxl); - -- if (qxl->vram_size < 4096) { -- qxl->vram_size = 4096; -- } -- if (qxl->revision == 1) { -- qxl->vram_size = 4096; -- } -- qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); - memory_region_init_ram(&qxl->vram_bar, &qxl->pci.qdev, "qxl.vram", - qxl->vram_size); - -@@ -1644,15 +1656,11 @@ static int qxl_init_primary(PCIDevice *dev) - { - PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); - VGACommonState *vga = &qxl->vga; -- ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); - PortioList *qxl_vga_port_list = g_new(PortioList, 1); - - qxl->id = 0; -- -- if (ram_size < 32 * 1024 * 1024) { -- ram_size = 32 * 1024 * 1024; -- } -- vga_common_init(vga, ram_size); -+ qxl_init_ramsize(qxl, 32); -+ vga_common_init(vga, qxl->vga.vram_size); - vga_init(vga, pci_address_space(dev), pci_address_space_io(dev), false); - portio_list_init(qxl_vga_port_list, qxl_vga_portio_list, vga, "vga"); - portio_list_add(qxl_vga_port_list, pci_address_space_io(dev), 0x3b0); -@@ -1671,14 +1679,9 @@ static int qxl_init_secondary(PCIDevice *dev) - { - static int device_id = 1; - PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); -- ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); - - qxl->id = device_id++; -- -- if (ram_size < 16 * 1024 * 1024) { -- ram_size = 16 * 1024 * 1024; -- } -- qxl->vga.vram_size = ram_size; -+ qxl_init_ramsize(qxl, 16); - memory_region_init_ram(&qxl->vga.vram, &qxl->pci.qdev, "qxl.vgavram", - qxl->vga.vram_size); - qxl->vga.vram_ptr = memory_region_get_ram_ptr(&qxl->vga.vram); --- -1.7.10 - diff --git a/0411-qxl-add-user-friendly-bar-size-properties.patch b/0411-qxl-add-user-friendly-bar-size-properties.patch deleted file mode 100644 index 30fae99..0000000 --- a/0411-qxl-add-user-friendly-bar-size-properties.patch +++ /dev/null @@ -1,63 +0,0 @@ -From eff66c7db18e9a3ef0b6ce5deb9a49b61090d809 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 17 Feb 2012 15:03:24 +0100 -Subject: [PATCH 411/434] qxl: add user-friendly bar size properties - -Add two properties to specify bar sizes in megabytes instead of bytes, -which is alot more user-friendly. - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 8 ++++++++ - hw/qxl.h | 4 ++++ - 2 files changed, 12 insertions(+) - -diff --git a/hw/qxl.c b/hw/qxl.c -index df8efbc..c8839c3 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1560,11 +1560,17 @@ static DisplayChangeListener display_listener = { - static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) - { - /* vga ram (bar 0) */ -+ if (qxl->ram_size_mb != -1) { -+ qxl->vga.vram_size = qxl->ram_size_mb * 1024 * 1024; -+ } - if (qxl->vga.vram_size < ram_min_mb * 1024 * 1024) { - qxl->vga.vram_size = ram_min_mb * 1024 * 1024; - } - - /* vram (surfaces, bar 1) */ -+ if (qxl->vram_size_mb != -1) { -+ qxl->vram_size = qxl->vram_size_mb * 1024 * 1024; -+ } - if (qxl->vram_size < 4096) { - qxl->vram_size = 4096; - } -@@ -1863,6 +1869,8 @@ static Property qxl_properties[] = { - DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), - DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), - DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), -+ DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), -+ DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram_size_mb, -1), - DEFINE_PROP_END_OF_LIST(), - }; - -diff --git a/hw/qxl.h b/hw/qxl.h -index 766aa6d..d062991 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -89,6 +89,10 @@ typedef struct PCIQXLDevice { - - /* io bar */ - MemoryRegion io_bar; -+ -+ /* user-friendly properties (in megabytes) */ -+ uint32_t ram_size_mb; -+ uint32_t vram_size_mb; - } PCIQXLDevice; - - #define PANIC_ON(x) if ((x)) { \ --- -1.7.10 - diff --git a/0412-qxl-fix-spice-sdl-no-cursor-regression.patch b/0412-qxl-fix-spice-sdl-no-cursor-regression.patch deleted file mode 100644 index 6c4a6d7..0000000 --- a/0412-qxl-fix-spice-sdl-no-cursor-regression.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 1cae61c4d4fe994e5158d63d5f4fe9b52a7b8211 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Fri, 24 Feb 2012 23:19:25 +0200 -Subject: [PATCH 412/434] qxl: fix spice+sdl no cursor regression -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -regression introduced by 075360945860ad9bdd491921954b383bf762b0e5, - -v2: lock around qemu_spice_cursor_refresh_unlocked - -Reported-by: Fabiano Fidêncio -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 4 ++++ - ui/spice-display.c | 23 ++++++++++++++--------- - ui/spice-display.h | 1 + - 3 files changed, 19 insertions(+), 9 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index c8839c3..17f2576 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1548,6 +1548,10 @@ static void display_refresh(struct DisplayState *ds) - { - if (qxl0->mode == QXL_MODE_VGA) { - qemu_spice_display_refresh(&qxl0->ssd); -+ } else { -+ qemu_mutex_lock(&qxl0->ssd.lock); -+ qemu_spice_cursor_refresh_unlocked(&qxl0->ssd); -+ qemu_mutex_unlock(&qxl0->ssd.lock); - } - } - -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 6c302a3..c6e61d8 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -317,16 +317,8 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) - ssd->notify++; - } - --void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) -+void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd) - { -- dprint(3, "%s:\n", __FUNCTION__); -- vga_hw_update(); -- -- qemu_mutex_lock(&ssd->lock); -- if (ssd->update == NULL) { -- ssd->update = qemu_spice_create_update(ssd); -- ssd->notify++; -- } - if (ssd->cursor) { - ssd->ds->cursor_define(ssd->cursor); - cursor_put(ssd->cursor); -@@ -337,6 +329,19 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) - ssd->mouse_x = -1; - ssd->mouse_y = -1; - } -+} -+ -+void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) -+{ -+ dprint(3, "%s:\n", __func__); -+ vga_hw_update(); -+ -+ qemu_mutex_lock(&ssd->lock); -+ if (ssd->update == NULL) { -+ ssd->update = qemu_spice_create_update(ssd); -+ ssd->notify++; -+ } -+ qemu_spice_cursor_refresh_unlocked(ssd); - qemu_mutex_unlock(&ssd->lock); - - if (ssd->notify) { -diff --git a/ui/spice-display.h b/ui/spice-display.h -index 5e52df9..a23bfc8 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -97,6 +97,7 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, - int x, int y, int w, int h); - void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); - void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); -+void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd); - - void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, - qxl_async_io async); --- -1.7.10 - diff --git a/0413-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch b/0413-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch deleted file mode 100644 index 8eddcc9..0000000 --- a/0413-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 4888e60d646b0f8cdfe4180bacc90857d3d2a5dd Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Fri, 24 Feb 2012 23:19:26 +0200 -Subject: [PATCH 413/434] sdl: remove NULL check, g_malloc0 can't fail - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - ui/sdl.c | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/ui/sdl.c b/ui/sdl.c -index 8cafc44..6844c83 100644 ---- a/ui/sdl.c -+++ b/ui/sdl.c -@@ -167,10 +167,6 @@ static PixelFormat sdl_to_qemu_pixelformat(SDL_PixelFormat *sdl_pf) - static DisplaySurface* sdl_create_displaysurface(int width, int height) - { - DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface)); -- if (surface == NULL) { -- fprintf(stderr, "sdl_create_displaysurface: malloc failed\n"); -- exit(1); -- } - - surface->width = width; - surface->height = height; --- -1.7.10 - diff --git a/0414-qxl-drop-qxl_spice_update_area_async-definition.patch b/0414-qxl-drop-qxl_spice_update_area_async-definition.patch deleted file mode 100644 index 0edba27..0000000 --- a/0414-qxl-drop-qxl_spice_update_area_async-definition.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 813c46edf4f3f69347353749755e040bc5fbd597 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Fri, 24 Feb 2012 23:19:27 +0200 -Subject: [PATCH 414/434] qxl: drop qxl_spice_update_area_async definition - -It was never used. Introduced in -5ff4e36c804157bd84af43c139f8cd3a59722db9 -qxl: async io support using new spice api - -But not used even then. - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.h | 6 ------ - 1 file changed, 6 deletions(-) - -diff --git a/hw/qxl.h b/hw/qxl.h -index d062991..a615eca 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -138,9 +138,3 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); - void qxl_render_resize(PCIQXLDevice *qxl); - void qxl_render_update(PCIQXLDevice *qxl); - void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); --#if SPICE_INTERFACE_QXL_MINOR >= 1 --void qxl_spice_update_area_async(PCIQXLDevice *qxl, uint32_t surface_id, -- struct QXLRect *area, -- uint32_t clear_dirty_region, -- int is_vga); --#endif --- -1.7.10 - diff --git a/0415-qxl-require-spice-0.8.2.patch b/0415-qxl-require-spice-0.8.2.patch deleted file mode 100644 index e00a42e..0000000 --- a/0415-qxl-require-spice-0.8.2.patch +++ /dev/null @@ -1,358 +0,0 @@ -From e07eeb01819b40b839cc12b2eb658f48f13a5ff0 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Fri, 24 Feb 2012 23:19:28 +0200 -Subject: [PATCH 415/434] qxl: require spice >= 0.8.2 - -drop all ifdefs on SPICE_INTERFACE_QXL_MINOR >= 1 as a result, -any check for SPICE_SERVER_VERSION that is now always satisfied, -and SPICE_INTERFACE_CORE_MINOR >= 3 tests, because -0.8.2 has SPICE_INTERFACE_QXL_MINOR == 1 and -SPICE_INTERFACE_CORE_MINOR == 3. - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - configure | 2 +- - hw/qxl.c | 40 ---------------------------------------- - hw/qxl.h | 4 ---- - ui/spice-core.c | 17 ----------------- - ui/spice-display.c | 12 ------------ - 5 files changed, 1 insertion(+), 74 deletions(-) - -diff --git a/configure b/configure -index a4848a4..b03172c 100755 ---- a/configure -+++ b/configure -@@ -2501,7 +2501,7 @@ int main(void) { spice_server_new(); return 0; } - EOF - spice_cflags=$($pkg_config --cflags spice-protocol spice-server 2>/dev/null) - spice_libs=$($pkg_config --libs spice-protocol spice-server 2>/dev/null) -- if $pkg_config --atleast-version=0.6.0 spice-server >/dev/null 2>&1 && \ -+ if $pkg_config --atleast-version=0.8.2 spice-server >/dev/null 2>&1 && \ - compile_prog "$spice_cflags" "$spice_libs" ; then - spice="yes" - libs_softmmu="$libs_softmmu $spice_libs" -diff --git a/hw/qxl.c b/hw/qxl.c -index 17f2576..0be9859 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -125,9 +125,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl); - - void qxl_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) - { --#if SPICE_INTERFACE_QXL_MINOR >= 1 - qxl_send_events(qxl, QXL_INTERRUPT_ERROR); --#endif - if (qxl->guestdebug) { - va_list ap; - va_start(ap, msg); -@@ -149,12 +147,8 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, - dirty_rects, num_dirty_rects, clear_dirty_region); - } else { --#if SPICE_INTERFACE_QXL_MINOR >= 1 - spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, - clear_dirty_region, 0); --#else -- abort(); --#endif - } - } - -@@ -171,24 +165,18 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, - qxl_async_io async) - { - if (async) { --#if SPICE_INTERFACE_QXL_MINOR < 1 -- abort(); --#else - spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, - (uint64_t)id); --#endif - } else { - qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); - qxl_spice_destroy_surface_wait_complete(qxl, id); - } - } - --#if SPICE_INTERFACE_QXL_MINOR >= 1 - static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) - { - spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0); - } --#endif - - void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, - uint32_t count) -@@ -217,11 +205,7 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) - static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) - { - if (async) { --#if SPICE_INTERFACE_QXL_MINOR < 1 -- abort(); --#else - spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0); --#endif - } else { - qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); - qxl_spice_destroy_surfaces_complete(qxl); -@@ -493,7 +477,6 @@ static const char *io_port_to_string(uint32_t io_port) - [QXL_IO_DESTROY_PRIMARY] = "QXL_IO_DESTROY_PRIMARY", - [QXL_IO_DESTROY_SURFACE_WAIT] = "QXL_IO_DESTROY_SURFACE_WAIT", - [QXL_IO_DESTROY_ALL_SURFACES] = "QXL_IO_DESTROY_ALL_SURFACES", --#if SPICE_INTERFACE_QXL_MINOR >= 1 - [QXL_IO_UPDATE_AREA_ASYNC] = "QXL_IO_UPDATE_AREA_ASYNC", - [QXL_IO_MEMSLOT_ADD_ASYNC] = "QXL_IO_MEMSLOT_ADD_ASYNC", - [QXL_IO_CREATE_PRIMARY_ASYNC] = "QXL_IO_CREATE_PRIMARY_ASYNC", -@@ -503,7 +486,6 @@ static const char *io_port_to_string(uint32_t io_port) - = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC", - [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC", - [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE", --#endif - }; - return io_port_to_string[io_port]; - } -@@ -738,8 +720,6 @@ static int interface_flush_resources(QXLInstance *sin) - - static void qxl_create_guest_primary_complete(PCIQXLDevice *d); - --#if SPICE_INTERFACE_QXL_MINOR >= 1 -- - /* called from spice server thread context only */ - static void interface_async_complete(QXLInstance *sin, uint64_t cookie) - { -@@ -767,8 +747,6 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) - qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); - } - --#endif -- - static const QXLInterface qxl_interface = { - .base.type = SPICE_INTERFACE_QXL, - .base.description = "qxl gpu", -@@ -788,9 +766,7 @@ static const QXLInterface qxl_interface = { - .req_cursor_notification = interface_req_cursor_notification, - .notify_update = interface_notify_update, - .flush_resources = interface_flush_resources, --#if SPICE_INTERFACE_QXL_MINOR >= 1 - .async_complete = interface_async_complete, --#endif - }; - - static void qxl_enter_vga_mode(PCIQXLDevice *d) -@@ -1140,9 +1116,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, - PCIQXLDevice *d = opaque; - uint32_t io_port = addr; - qxl_async_io async = QXL_SYNC; --#if SPICE_INTERFACE_QXL_MINOR >= 1 - uint32_t orig_io_port = io_port; --#endif - - switch (io_port) { - case QXL_IO_RESET: -@@ -1152,10 +1126,8 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, - case QXL_IO_CREATE_PRIMARY: - case QXL_IO_UPDATE_IRQ: - case QXL_IO_LOG: --#if SPICE_INTERFACE_QXL_MINOR >= 1 - case QXL_IO_MEMSLOT_ADD_ASYNC: - case QXL_IO_CREATE_PRIMARY_ASYNC: --#endif - break; - default: - if (d->mode != QXL_MODE_VGA) { -@@ -1163,17 +1135,14 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, - } - dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", - __func__, io_port, io_port_to_string(io_port)); --#if SPICE_INTERFACE_QXL_MINOR >= 1 - /* be nice to buggy guest drivers */ - if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && - io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) { - qxl_send_events(d, QXL_INTERRUPT_IO_CMD); - } --#endif - return; - } - --#if SPICE_INTERFACE_QXL_MINOR >= 1 - /* we change the io_port to avoid ifdeffery in the main switch */ - orig_io_port = io_port; - switch (io_port) { -@@ -1212,7 +1181,6 @@ async_common: - default: - break; - } --#endif - - switch (io_port) { - case QXL_IO_UPDATE_AREA: -@@ -1304,7 +1272,6 @@ async_common: - } - qxl_spice_destroy_surface_wait(d, val, async); - break; --#if SPICE_INTERFACE_QXL_MINOR >= 1 - case QXL_IO_FLUSH_RELEASE: { - QXLReleaseRing *ring = &d->ram->release_ring; - if (ring->prod - ring->cons + 1 == ring->num_items) { -@@ -1325,7 +1292,6 @@ async_common: - d->num_free_res); - qxl_spice_flush_surfaces_async(d); - break; --#endif - case QXL_IO_DESTROY_ALL_SURFACES: - d->mode = QXL_MODE_UNDEFINED; - qxl_spice_destroy_surfaces(d, async); -@@ -1336,16 +1302,12 @@ async_common: - } - return; - cancel_async: --#if SPICE_INTERFACE_QXL_MINOR >= 1 - if (async) { - qxl_send_events(d, QXL_INTERRUPT_IO_CMD); - qemu_mutex_lock(&d->async_lock); - d->current_async = QXL_UNDEFINED_IO; - qemu_mutex_unlock(&d->async_lock); - } --#else -- return; --#endif - } - - static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, -@@ -1607,9 +1569,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) - case 2: /* spice 0.6 -- qxl-2 */ - pci_device_rev = QXL_REVISION_STABLE_V06; - break; --#if SPICE_INTERFACE_QXL_MINOR >= 1 - case 3: /* qxl-3 */ --#endif - default: - pci_device_rev = QXL_DEFAULT_REVISION; - break; -diff --git a/hw/qxl.h b/hw/qxl.h -index a615eca..9288e46 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -108,11 +108,7 @@ typedef struct PCIQXLDevice { - } \ - } while (0) - --#if SPICE_INTERFACE_QXL_MINOR >= 1 - #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10 --#else --#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V06 --#endif - - /* qxl.c */ - void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); -diff --git a/ui/spice-core.c b/ui/spice-core.c -index 27216e9..2c815f1 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -139,8 +139,6 @@ static void watch_remove(SpiceWatch *watch) - g_free(watch); - } - --#if SPICE_INTERFACE_CORE_MINOR >= 3 -- - typedef struct ChannelList ChannelList; - struct ChannelList { - SpiceChannelEventInfo *info; -@@ -257,15 +255,6 @@ static void channel_event(int event, SpiceChannelEventInfo *info) - } - } - --#else /* SPICE_INTERFACE_CORE_MINOR >= 3 */ -- --static QList *channel_list_get(void) --{ -- return NULL; --} -- --#endif /* SPICE_INTERFACE_CORE_MINOR >= 3 */ -- - static SpiceCoreInterface core_interface = { - .base.type = SPICE_INTERFACE_CORE, - .base.description = "qemu core services", -@@ -281,9 +270,7 @@ static SpiceCoreInterface core_interface = { - .watch_update_mask = watch_update_mask, - .watch_remove = watch_remove, - --#if SPICE_INTERFACE_CORE_MINOR >= 3 - .channel_event = channel_event, --#endif - }; - - #ifdef SPICE_INTERFACE_MIGRATION -@@ -490,7 +477,6 @@ static void migration_state_notifier(Notifier *notifier, void *data) - spice_server_migrate_start(spice_server); - #endif - } else if (migration_has_finished(s)) { --#if SPICE_SERVER_VERSION >= 0x000701 /* 0.7.1 */ - #ifndef SPICE_INTERFACE_MIGRATION - spice_server_migrate_switch(spice_server); - #else -@@ -498,7 +484,6 @@ static void migration_state_notifier(Notifier *notifier, void *data) - } else if (migration_has_failed(s)) { - spice_server_migrate_end(spice_server, false); - #endif --#endif - } - } - -@@ -659,11 +644,9 @@ void qemu_spice_init(void) - spice_server_set_noauth(spice_server); - } - --#if SPICE_SERVER_VERSION >= 0x000801 - if (qemu_opt_get_bool(opts, "disable-copy-paste", 0)) { - spice_server_set_agent_copypaste(spice_server, false); - } --#endif - - compression = SPICE_IMAGE_COMPRESS_AUTO_GLZ; - str = qemu_opt_get(opts, "image-compression"); -diff --git a/ui/spice-display.c b/ui/spice-display.c -index c6e61d8..ad76bae 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -64,11 +64,7 @@ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, - qxl_async_io async) - { - if (async != QXL_SYNC) { --#if SPICE_INTERFACE_QXL_MINOR >= 1 - spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0); --#else -- abort(); --#endif - } else { - ssd->worker->add_memslot(ssd->worker, memslot); - } -@@ -84,11 +80,7 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, - qxl_async_io async) - { - if (async != QXL_SYNC) { --#if SPICE_INTERFACE_QXL_MINOR >= 1 - spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0); --#else -- abort(); --#endif - } else { - ssd->worker->create_primary_surface(ssd->worker, id, surface); - } -@@ -99,11 +91,7 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, - uint32_t id, qxl_async_io async) - { - if (async != QXL_SYNC) { --#if SPICE_INTERFACE_QXL_MINOR >= 1 - spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0); --#else -- abort(); --#endif - } else { - ssd->worker->destroy_primary_surface(ssd->worker, id); - } --- -1.7.10 - diff --git a/0416-qxl-remove-flipped.patch b/0416-qxl-remove-flipped.patch deleted file mode 100644 index 3820b9b..0000000 --- a/0416-qxl-remove-flipped.patch +++ /dev/null @@ -1,145 +0,0 @@ -From f9344933bcc1425cf1e8142dc2f8321522dc00af Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Fri, 24 Feb 2012 23:19:29 +0200 -Subject: [PATCH 416/434] qxl: remove flipped - -Tested on linux and windows guests. For negative stride, qxl_flip copies -directly to vga->ds->surface->data, for positive it's reallocated to -share qxl->guest_primary.data - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl-render.c | 66 +++++++++++++++++++++++++------------------------------ - hw/qxl.h | 2 +- - 2 files changed, 31 insertions(+), 37 deletions(-) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index a7891b2..5811d74 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -23,10 +23,21 @@ - - static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) - { -- uint8_t *src = qxl->guest_primary.data; -- uint8_t *dst = qxl->guest_primary.flipped; -+ uint8_t *src; -+ uint8_t *dst = qxl->vga.ds->surface->data; - int len, i; - -+ if (qxl->guest_primary.qxl_stride > 0) { -+ return; -+ } -+ if (!qxl->guest_primary.data) { -+ dprint(qxl, 1, "%s: initializing guest_primary.data\n", __func__); -+ qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); -+ } -+ dprint(qxl, 1, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, -+ qxl->guest_primary.qxl_stride, -+ rect->left, rect->right, rect->top, rect->bottom); -+ src = qxl->guest_primary.data; - src += (qxl->guest_primary.surface.height - rect->top - 1) * - qxl->guest_primary.abs_stride; - dst += rect->top * qxl->guest_primary.abs_stride; -@@ -75,52 +86,38 @@ void qxl_render_update(PCIQXLDevice *qxl) - { - VGACommonState *vga = &qxl->vga; - QXLRect dirty[32], update; -- void *ptr; - int i, redraw = 0; -- -- if (!is_buffer_shared(vga->ds->surface)) { -- dprint(qxl, 1, "%s: restoring shared displaysurface\n", __func__); -- qxl->guest_primary.resized++; -- qxl->guest_primary.commands++; -- redraw = 1; -- } -+ DisplaySurface *surface = vga->ds->surface; - - if (qxl->guest_primary.resized) { - qxl->guest_primary.resized = 0; - -- if (qxl->guest_primary.flipped) { -- g_free(qxl->guest_primary.flipped); -- qxl->guest_primary.flipped = NULL; -- } -- qemu_free_displaysurface(vga->ds); -- - qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); -- if (qxl->guest_primary.qxl_stride < 0) { -- /* spice surface is upside down -> need extra buffer to flip */ -- qxl->guest_primary.flipped = -- g_malloc(qxl->guest_primary.surface.width * -- qxl->guest_primary.abs_stride); -- ptr = qxl->guest_primary.flipped; -- } else { -- ptr = qxl->guest_primary.data; -- } -- dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n", -+ dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d\n", - __FUNCTION__, - qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height, - qxl->guest_primary.qxl_stride, - qxl->guest_primary.bytes_pp, -- qxl->guest_primary.bits_pp, -- qxl->guest_primary.flipped ? "yes" : "no"); -- vga->ds->surface = -+ qxl->guest_primary.bits_pp); -+ } -+ if (surface->width != qxl->guest_primary.surface.width || -+ surface->height != qxl->guest_primary.surface.height) { -+ dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", -+ __func__); -+ if (qxl->guest_primary.qxl_stride > 0) { -+ qemu_free_displaysurface(vga->ds); - qemu_create_displaysurface_from(qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height, - qxl->guest_primary.bits_pp, - qxl->guest_primary.abs_stride, -- ptr); -- dpy_resize(vga->ds); -+ qxl->guest_primary.data); -+ } else { -+ qemu_resize_displaysurface(vga->ds, -+ qxl->guest_primary.surface.width, -+ qxl->guest_primary.surface.height); -+ } - } -- - update.left = 0; - update.right = qxl->guest_primary.surface.width; - update.top = 0; -@@ -136,14 +133,11 @@ void qxl_render_update(PCIQXLDevice *qxl) - memset(dirty, 0, sizeof(dirty)); - dirty[0] = update; - } -- - for (i = 0; i < ARRAY_SIZE(dirty); i++) { - if (qemu_spice_rect_is_empty(dirty+i)) { - break; - } -- if (qxl->guest_primary.flipped) { -- qxl_flip(qxl, dirty+i); -- } -+ qxl_flip(qxl, dirty+i); - dpy_update(vga->ds, - dirty[i].left, dirty[i].top, - dirty[i].right - dirty[i].left, -diff --git a/hw/qxl.h b/hw/qxl.h -index 9288e46..53a3ace 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -52,7 +52,7 @@ typedef struct PCIQXLDevice { - uint32_t abs_stride; - uint32_t bits_pp; - uint32_t bytes_pp; -- uint8_t *data, *flipped; -+ uint8_t *data; - } guest_primary; - - struct surfaces { --- -1.7.10 - diff --git a/0417-qxl-introduce-QXLCookie.patch b/0417-qxl-introduce-QXLCookie.patch deleted file mode 100644 index 1eeff47..0000000 --- a/0417-qxl-introduce-QXLCookie.patch +++ /dev/null @@ -1,264 +0,0 @@ -From bbe362cd6a386d98a94ac791f1263671bd79b754 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Fri, 24 Feb 2012 23:19:30 +0200 -Subject: [PATCH 417/434] qxl: introduce QXLCookie - -Will be used in the next patch. - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl-render.c | 2 +- - hw/qxl.c | 61 ++++++++++++++++++++++++++++++++++++++++------------ - hw/qxl.h | 2 +- - ui/spice-display.c | 22 ++++++++++++++++--- - ui/spice-display.h | 14 ++++++++++++ - 5 files changed, 82 insertions(+), 19 deletions(-) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index 5811d74..4c22166 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -127,7 +127,7 @@ void qxl_render_update(PCIQXLDevice *qxl) - if (runstate_is_running() && qxl->guest_primary.commands) { - qxl->guest_primary.commands = 0; - qxl_spice_update_area(qxl, 0, &update, -- dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC); -+ dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL); - } - if (redraw) { - memset(dirty, 0, sizeof(dirty)); -diff --git a/hw/qxl.c b/hw/qxl.c -index 0be9859..e6e65d9 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -141,14 +141,15 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - struct QXLRect *area, struct QXLRect *dirty_rects, - uint32_t num_dirty_rects, - uint32_t clear_dirty_region, -- qxl_async_io async) -+ qxl_async_io async, struct QXLCookie *cookie) - { - if (async == QXL_SYNC) { - qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, - dirty_rects, num_dirty_rects, clear_dirty_region); - } else { -+ assert(cookie != NULL); - spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, -- clear_dirty_region, 0); -+ clear_dirty_region, (uint64_t)cookie); - } - } - -@@ -164,9 +165,13 @@ static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl, - static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, - qxl_async_io async) - { -+ QXLCookie *cookie; -+ - if (async) { -- spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, -- (uint64_t)id); -+ cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_DESTROY_SURFACE_ASYNC); -+ cookie->u.surface_id = id; -+ spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uint64_t)cookie); - } else { - qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); - qxl_spice_destroy_surface_wait_complete(qxl, id); -@@ -175,7 +180,9 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, - - static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) - { -- spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0); -+ spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, -+ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_FLUSH_SURFACES_ASYNC)); - } - - void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, -@@ -205,7 +212,9 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) - static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) - { - if (async) { -- spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, 0); -+ spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, -+ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_DESTROY_ALL_SURFACES_ASYNC)); - } else { - qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); - qxl_spice_destroy_surfaces_complete(qxl); -@@ -721,9 +730,8 @@ static int interface_flush_resources(QXLInstance *sin) - static void qxl_create_guest_primary_complete(PCIQXLDevice *d); - - /* called from spice server thread context only */ --static void interface_async_complete(QXLInstance *sin, uint64_t cookie) -+static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) - { -- PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - uint32_t current_async; - - qemu_mutex_lock(&qxl->async_lock); -@@ -731,8 +739,16 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) - qxl->current_async = QXL_UNDEFINED_IO; - qemu_mutex_unlock(&qxl->async_lock); - -- dprint(qxl, 2, "async_complete: %d (%" PRId64 ") done\n", -- current_async, cookie); -+ dprint(qxl, 2, "async_complete: %d (%p) done\n", current_async, cookie); -+ if (!cookie) { -+ fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__); -+ return; -+ } -+ if (cookie && current_async != cookie->io) { -+ fprintf(stderr, -+ "qxl: %s: error: current_async = %d != %ld = cookie->io\n", -+ __func__, current_async, cookie->io); -+ } - switch (current_async) { - case QXL_IO_CREATE_PRIMARY_ASYNC: - qxl_create_guest_primary_complete(qxl); -@@ -741,12 +757,29 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie) - qxl_spice_destroy_surfaces_complete(qxl); - break; - case QXL_IO_DESTROY_SURFACE_ASYNC: -- qxl_spice_destroy_surface_wait_complete(qxl, (uint32_t)cookie); -+ qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id); - break; - } - qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); - } - -+/* called from spice server thread context only */ -+static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ QXLCookie *cookie = (QXLCookie *)cookie_token; -+ -+ switch (cookie->type) { -+ case QXL_COOKIE_TYPE_IO: -+ interface_async_complete_io(qxl, cookie); -+ break; -+ default: -+ fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", -+ __func__, cookie->type); -+ } -+ g_free(cookie); -+} -+ - static const QXLInterface qxl_interface = { - .base.type = SPICE_INTERFACE_QXL, - .base.description = "qxl gpu", -@@ -1057,9 +1090,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) - if (d->mode == QXL_MODE_UNDEFINED) { - return 0; - } -- - dprint(d, 1, "%s\n", __FUNCTION__); -- - d->mode = QXL_MODE_UNDEFINED; - qemu_spice_destroy_primary_surface(&d->ssd, 0, async); - qxl_spice_reset_cursor(d); -@@ -1187,7 +1218,9 @@ async_common: - { - QXLRect update = d->ram->update_area; - qxl_spice_update_area(d, d->ram->update_surface, -- &update, NULL, 0, 0, async); -+ &update, NULL, 0, 0, async, -+ qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_UPDATE_AREA_ASYNC)); - break; - } - case QXL_IO_NOTIFY_CMD: -diff --git a/hw/qxl.h b/hw/qxl.h -index 53a3ace..1443925 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -118,7 +118,7 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - struct QXLRect *area, struct QXLRect *dirty_rects, - uint32_t num_dirty_rects, - uint32_t clear_dirty_region, -- qxl_async_io async); -+ qxl_async_io async, QXLCookie *cookie); - void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, - uint32_t count); - void qxl_spice_oom(PCIQXLDevice *qxl); -diff --git a/ui/spice-display.c b/ui/spice-display.c -index ad76bae..ab266ae 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -60,11 +60,23 @@ void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) - dest->right = MAX(dest->right, r->right); - } - -+QXLCookie *qxl_cookie_new(int type, uint64_t io) -+{ -+ QXLCookie *cookie; -+ -+ cookie = g_malloc0(sizeof(*cookie)); -+ cookie->type = type; -+ cookie->io = io; -+ return cookie; -+} -+ - void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, - qxl_async_io async) - { - if (async != QXL_SYNC) { -- spice_qxl_add_memslot_async(&ssd->qxl, memslot, 0); -+ spice_qxl_add_memslot_async(&ssd->qxl, memslot, -+ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_MEMSLOT_ADD_ASYNC)); - } else { - ssd->worker->add_memslot(ssd->worker, memslot); - } -@@ -80,7 +92,9 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, - qxl_async_io async) - { - if (async != QXL_SYNC) { -- spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, 0); -+ spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, -+ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_CREATE_PRIMARY_ASYNC)); - } else { - ssd->worker->create_primary_surface(ssd->worker, id, surface); - } -@@ -91,7 +105,9 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, - uint32_t id, qxl_async_io async) - { - if (async != QXL_SYNC) { -- spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, 0); -+ spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, -+ (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_DESTROY_PRIMARY_ASYNC)); - } else { - ssd->worker->destroy_primary_surface(ssd->worker, id); - } -diff --git a/ui/spice-display.h b/ui/spice-display.h -index a23bfc8..8a010cb 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -48,6 +48,20 @@ typedef enum qxl_async_io { - QXL_ASYNC, - } qxl_async_io; - -+enum { -+ QXL_COOKIE_TYPE_IO, -+}; -+ -+typedef struct QXLCookie { -+ int type; -+ uint64_t io; -+ union { -+ uint32_t surface_id; -+ } u; -+} QXLCookie; -+ -+QXLCookie *qxl_cookie_new(int type, uint64_t io); -+ - typedef struct SimpleSpiceDisplay SimpleSpiceDisplay; - typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; - --- -1.7.10 - diff --git a/0418-qxl-make-qxl_render_update-async.patch b/0418-qxl-make-qxl_render_update-async.patch deleted file mode 100644 index c569d73..0000000 --- a/0418-qxl-make-qxl_render_update-async.patch +++ /dev/null @@ -1,360 +0,0 @@ -From c26805e29312fee136008a57c70a2f5f140ba706 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Fri, 24 Feb 2012 23:19:31 +0200 -Subject: [PATCH 418/434] qxl: make qxl_render_update async - -RHBZ# 747011 - -Removes the last user of QXL_SYNC when using update drivers that use the -_ASYNC io ports. - -The last user is qxl_render_update, it is called both by qxl_hw_update -which is the vga_hw_update_ptr passed to graphic_console_init, and by -qxl_hw_screen_dump. - -At the same time the QXLRect area being passed to the red_worker thread -is passed as a copy, as part of the QXLCookie. - -The implementation uses interface_update_area_complete with a bh to make -sure dpy_update and qxl_flip are called from the io thread, otherwise -the vga->ds->surface.data can change under our feet. - -With this patch sdl+spice works fine. But spice by itself doesn't -produce the expected screendumps unless repeated a few times, due to -ppm_save being called before update_area (rendering done in spice server -thread) having a chance to complete. Fixed by next patch, but see commit -message for problem introduced by it. - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl-render.c | 96 +++++++++++++++++++++++++++++++++++++--------------- - hw/qxl.c | 69 ++++++++++++++++++++++++++++++++++--- - hw/qxl.h | 10 ++++++ - ui/spice-display.h | 6 ++++ - 4 files changed, 150 insertions(+), 31 deletions(-) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index 4c22166..4857838 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -82,17 +82,25 @@ void qxl_render_resize(PCIQXLDevice *qxl) - } - } - --void qxl_render_update(PCIQXLDevice *qxl) -+static void qxl_set_rect_to_surface(PCIQXLDevice *qxl, QXLRect *area) -+{ -+ area->left = 0; -+ area->right = qxl->guest_primary.surface.width; -+ area->top = 0; -+ area->bottom = qxl->guest_primary.surface.height; -+} -+ -+static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) - { - VGACommonState *vga = &qxl->vga; -- QXLRect dirty[32], update; -- int i, redraw = 0; -+ int i; - DisplaySurface *surface = vga->ds->surface; - - if (qxl->guest_primary.resized) { - qxl->guest_primary.resized = 0; -- - qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); -+ qxl_set_rect_to_surface(qxl, &qxl->dirty[0]); -+ qxl->num_dirty_rects = 1; - dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d\n", - __FUNCTION__, - qxl->guest_primary.surface.width, -@@ -103,9 +111,9 @@ void qxl_render_update(PCIQXLDevice *qxl) - } - if (surface->width != qxl->guest_primary.surface.width || - surface->height != qxl->guest_primary.surface.height) { -- dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", -- __func__); - if (qxl->guest_primary.qxl_stride > 0) { -+ dprint(qxl, 1, "%s: using guest_primary for displaysurface\n", -+ __func__); - qemu_free_displaysurface(vga->ds); - qemu_create_displaysurface_from(qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height, -@@ -113,36 +121,70 @@ void qxl_render_update(PCIQXLDevice *qxl) - qxl->guest_primary.abs_stride, - qxl->guest_primary.data); - } else { -+ dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", -+ __func__); - qemu_resize_displaysurface(vga->ds, - qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height); - } - } -- update.left = 0; -- update.right = qxl->guest_primary.surface.width; -- update.top = 0; -- update.bottom = qxl->guest_primary.surface.height; -- -- memset(dirty, 0, sizeof(dirty)); -- if (runstate_is_running() && qxl->guest_primary.commands) { -- qxl->guest_primary.commands = 0; -- qxl_spice_update_area(qxl, 0, &update, -- dirty, ARRAY_SIZE(dirty), 1, QXL_SYNC, NULL); -- } -- if (redraw) { -- memset(dirty, 0, sizeof(dirty)); -- dirty[0] = update; -- } -- for (i = 0; i < ARRAY_SIZE(dirty); i++) { -- if (qemu_spice_rect_is_empty(dirty+i)) { -+ for (i = 0; i < qxl->num_dirty_rects; i++) { -+ if (qemu_spice_rect_is_empty(qxl->dirty+i)) { - break; - } -- qxl_flip(qxl, dirty+i); -+ qxl_flip(qxl, qxl->dirty+i); - dpy_update(vga->ds, -- dirty[i].left, dirty[i].top, -- dirty[i].right - dirty[i].left, -- dirty[i].bottom - dirty[i].top); -+ qxl->dirty[i].left, qxl->dirty[i].top, -+ qxl->dirty[i].right - qxl->dirty[i].left, -+ qxl->dirty[i].bottom - qxl->dirty[i].top); -+ } -+ qxl->num_dirty_rects = 0; -+} -+ -+/* -+ * use ssd.lock to protect render_update_cookie_num. -+ * qxl_render_update is called by io thread or vcpu thread, and the completion -+ * callbacks are called by spice_server thread, defering to bh called from the -+ * io thread. -+ */ -+void qxl_render_update(PCIQXLDevice *qxl) -+{ -+ QXLCookie *cookie; -+ -+ qemu_mutex_lock(&qxl->ssd.lock); -+ -+ if (!runstate_is_running() || !qxl->guest_primary.commands) { -+ qxl_render_update_area_unlocked(qxl); -+ qemu_mutex_unlock(&qxl->ssd.lock); -+ return; - } -+ -+ qxl->guest_primary.commands = 0; -+ qxl->render_update_cookie_num++; -+ qemu_mutex_unlock(&qxl->ssd.lock); -+ cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, -+ 0); -+ qxl_set_rect_to_surface(qxl, &cookie->u.render.area); -+ qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL, -+ 0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie); -+} -+ -+void qxl_render_update_area_bh(void *opaque) -+{ -+ PCIQXLDevice *qxl = opaque; -+ -+ qemu_mutex_lock(&qxl->ssd.lock); -+ qxl_render_update_area_unlocked(qxl); -+ qemu_mutex_unlock(&qxl->ssd.lock); -+} -+ -+void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie) -+{ -+ qemu_mutex_lock(&qxl->ssd.lock); -+ qemu_bh_schedule(qxl->update_area_bh); -+ qxl->render_update_cookie_num--; -+ qemu_mutex_unlock(&qxl->ssd.lock); -+ g_free(cookie); - } - - static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor) -diff --git a/hw/qxl.c b/hw/qxl.c -index e6e65d9..73be115 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -750,6 +750,11 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) - __func__, current_async, cookie->io); - } - switch (current_async) { -+ case QXL_IO_MEMSLOT_ADD_ASYNC: -+ case QXL_IO_DESTROY_PRIMARY_ASYNC: -+ case QXL_IO_UPDATE_AREA_ASYNC: -+ case QXL_IO_FLUSH_SURFACES_ASYNC: -+ break; - case QXL_IO_CREATE_PRIMARY_ASYNC: - qxl_create_guest_primary_complete(qxl); - break; -@@ -759,11 +764,54 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) - case QXL_IO_DESTROY_SURFACE_ASYNC: - qxl_spice_destroy_surface_wait_complete(qxl, cookie->u.surface_id); - break; -+ default: -+ fprintf(stderr, "qxl: %s: unexpected current_async %d\n", __func__, -+ current_async); - } - qxl_send_events(qxl, QXL_INTERRUPT_IO_CMD); - } - - /* called from spice server thread context only */ -+static void interface_update_area_complete(QXLInstance *sin, -+ uint32_t surface_id, -+ QXLRect *dirty, uint32_t num_updated_rects) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ int i; -+ int qxl_i; -+ -+ qemu_mutex_lock(&qxl->ssd.lock); -+ if (surface_id != 0 || !qxl->render_update_cookie_num) { -+ qemu_mutex_unlock(&qxl->ssd.lock); -+ return; -+ } -+ if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) { -+ /* -+ * overflow - treat this as a full update. Not expected to be common. -+ */ -+ dprint(qxl, 1, "%s: overflow of dirty rects\n", __func__); -+ qxl->guest_primary.resized = 1; -+ } -+ if (qxl->guest_primary.resized) { -+ /* -+ * Don't bother copying or scheduling the bh since we will flip -+ * the whole area anyway on completion of the update_area async call -+ */ -+ qemu_mutex_unlock(&qxl->ssd.lock); -+ return; -+ } -+ qxl_i = qxl->num_dirty_rects; -+ for (i = 0; i < num_updated_rects; i++) { -+ qxl->dirty[qxl_i++] = dirty[i]; -+ } -+ qxl->num_dirty_rects += num_updated_rects; -+ dprint(qxl, 1, "%s: scheduling update_area_bh, #dirty %d\n", -+ __func__, qxl->num_dirty_rects); -+ qemu_bh_schedule(qxl->update_area_bh); -+ qemu_mutex_unlock(&qxl->ssd.lock); -+} -+ -+/* called from spice server thread context only */ - static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) - { - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -@@ -772,12 +820,16 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) - switch (cookie->type) { - case QXL_COOKIE_TYPE_IO: - interface_async_complete_io(qxl, cookie); -+ g_free(cookie); -+ break; -+ case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA: -+ qxl_render_update_area_done(qxl, cookie); - break; - default: - fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", - __func__, cookie->type); -+ g_free(cookie); - } -- g_free(cookie); - } - - static const QXLInterface qxl_interface = { -@@ -800,6 +852,7 @@ static const QXLInterface qxl_interface = { - .notify_update = interface_notify_update, - .flush_resources = interface_flush_resources, - .async_complete = interface_async_complete, -+ .update_area_complete = interface_update_area_complete, - }; - - static void qxl_enter_vga_mode(PCIQXLDevice *d) -@@ -1216,11 +1269,17 @@ async_common: - switch (io_port) { - case QXL_IO_UPDATE_AREA: - { -+ QXLCookie *cookie = NULL; - QXLRect update = d->ram->update_area; -+ -+ if (async == QXL_ASYNC) { -+ cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_UPDATE_AREA_ASYNC); -+ cookie->u.area = update; -+ } - qxl_spice_update_area(d, d->ram->update_surface, -- &update, NULL, 0, 0, async, -- qxl_cookie_new(QXL_COOKIE_TYPE_IO, -- QXL_IO_UPDATE_AREA_ASYNC)); -+ cookie ? &cookie->u.area : &update, -+ NULL, 0, 0, async, cookie); - break; - } - case QXL_IO_NOTIFY_CMD: -@@ -1652,6 +1711,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) - init_pipe_signaling(qxl); - qxl_reset_state(qxl); - -+ qxl->update_area_bh = qemu_bh_new(qxl_render_update_area_bh, qxl); -+ - return 0; - } - -diff --git a/hw/qxl.h b/hw/qxl.h -index 1443925..86e415b 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -18,6 +18,8 @@ enum qxl_mode { - - #define QXL_UNDEFINED_IO UINT32_MAX - -+#define QXL_NUM_DIRTY_RECTS 64 -+ - typedef struct PCIQXLDevice { - PCIDevice pci; - SimpleSpiceDisplay ssd; -@@ -93,6 +95,12 @@ typedef struct PCIQXLDevice { - /* user-friendly properties (in megabytes) */ - uint32_t ram_size_mb; - uint32_t vram_size_mb; -+ -+ /* qxl_render_update state */ -+ int render_update_cookie_num; -+ int num_dirty_rects; -+ QXLRect dirty[QXL_NUM_DIRTY_RECTS]; -+ QEMUBH *update_area_bh; - } PCIQXLDevice; - - #define PANIC_ON(x) if ((x)) { \ -@@ -134,3 +142,5 @@ void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); - void qxl_render_resize(PCIQXLDevice *qxl); - void qxl_render_update(PCIQXLDevice *qxl); - void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); -+void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie); -+void qxl_render_update_area_bh(void *opaque); -diff --git a/ui/spice-display.h b/ui/spice-display.h -index 8a010cb..12e50b6 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -50,6 +50,7 @@ typedef enum qxl_async_io { - - enum { - QXL_COOKIE_TYPE_IO, -+ QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, - }; - - typedef struct QXLCookie { -@@ -57,6 +58,11 @@ typedef struct QXLCookie { - uint64_t io; - union { - uint32_t surface_id; -+ QXLRect area; -+ struct { -+ QXLRect area; -+ int redraw; -+ } render; - } u; - } QXLCookie; - --- -1.7.10 - diff --git a/0419-spice-use-error_report-to-report-errors.patch b/0419-spice-use-error_report-to-report-errors.patch deleted file mode 100644 index ac7464a..0000000 --- a/0419-spice-use-error_report-to-report-errors.patch +++ /dev/null @@ -1,102 +0,0 @@ -From 2b973a5ea22635211cbde2e559cc6e6355ca8205 Mon Sep 17 00:00:00 2001 -From: Christophe Fergeau -Date: Fri, 24 Feb 2012 18:13:12 +0100 -Subject: [PATCH 419/434] spice: use error_report to report errors - -Error message reporting during spice startup wasn't consistent, it was done -with fprintf(stderr, "") but sometimes the message didn't have a trailing -\n. Using error_report make the intent of the message clearer and deal -with the final \n for us. - -Signed-off-by: Gerd Hoffmann ---- - ui/spice-core.c | 22 +++++++++++----------- - 1 file changed, 11 insertions(+), 11 deletions(-) - -diff --git a/ui/spice-core.c b/ui/spice-core.c -index 2c815f1..8503f03 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -227,8 +227,8 @@ static void channel_event(int event, SpiceChannelEventInfo *info) - add_addr_info(server, (struct sockaddr *)&info->laddr_ext, - info->llen_ext); - } else { -- fprintf(stderr, "spice: %s, extended address is expected\n", -- __func__); -+ error_report("spice: %s, extended address is expected", -+ __func__); - #endif - add_addr_info(client, &info->paddr, info->plen); - add_addr_info(server, &info->laddr, info->llen); -@@ -333,7 +333,7 @@ static int parse_name(const char *string, const char *optname, - if (value != -1) { - return value; - } -- fprintf(stderr, "spice: invalid %s: %s\n", optname, string); -+ error_report("spice: invalid %s: %s", optname, string); - exit(1); - } - -@@ -525,7 +525,7 @@ static int add_channel(const char *name, const char *value, void *opaque) - rc = spice_server_set_channel_security(spice_server, value, security); - } - if (rc != 0) { -- fprintf(stderr, "spice: failed to set channel security for %s\n", value); -+ error_report("spice: failed to set channel security for %s", value); - exit(1); - } - return 0; -@@ -553,15 +553,15 @@ void qemu_spice_init(void) - port = qemu_opt_get_number(opts, "port", 0); - tls_port = qemu_opt_get_number(opts, "tls-port", 0); - if (!port && !tls_port) { -- fprintf(stderr, "neither port nor tls-port specified for spice."); -+ error_report("neither port nor tls-port specified for spice"); - exit(1); - } - if (port < 0 || port > 65535) { -- fprintf(stderr, "spice port is out of range"); -+ error_report("spice port is out of range"); - exit(1); - } - if (tls_port < 0 || tls_port > 65535) { -- fprintf(stderr, "spice tls-port is out of range"); -+ error_report("spice tls-port is out of range"); - exit(1); - } - password = qemu_opt_get(opts, "password"); -@@ -631,11 +631,11 @@ void qemu_spice_init(void) - #if SPICE_SERVER_VERSION >= 0x000900 /* 0.9.0 */ - if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 || - spice_server_set_sasl(spice_server, 1) == -1) { -- fprintf(stderr, "spice: failed to enable sasl\n"); -+ error_report("spice: failed to enable sasl"); - exit(1); - } - #else -- fprintf(stderr, "spice: sasl is not available (spice >= 0.9 required)\n"); -+ error_report("spice: sasl is not available (spice >= 0.9 required)"); - exit(1); - #endif - } -@@ -683,7 +683,7 @@ void qemu_spice_init(void) - qemu_opt_foreach(opts, add_channel, NULL, 0); - - if (0 != spice_server_init(spice_server, &core_interface)) { -- fprintf(stderr, "failed to initialize spice server"); -+ error_report("failed to initialize spice server"); - exit(1); - }; - using_spice = 1; -@@ -708,7 +708,7 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin) - { - if (!spice_server) { - if (QTAILQ_FIRST(&qemu_spice_opts.head) != NULL) { -- fprintf(stderr, "Oops: spice configured but not active\n"); -+ error_report("Oops: spice configured but not active"); - exit(1); - } - /* --- -1.7.10 - diff --git a/0420-Error-out-when-tls-channel-option-is-used-without-TL.patch b/0420-Error-out-when-tls-channel-option-is-used-without-TL.patch deleted file mode 100644 index 3c73fc3..0000000 --- a/0420-Error-out-when-tls-channel-option-is-used-without-TL.patch +++ /dev/null @@ -1,44 +0,0 @@ -From d01f59d652b8ac906ecd129afa338f56b2aaef90 Mon Sep 17 00:00:00 2001 -From: Christophe Fergeau -Date: Fri, 24 Feb 2012 18:28:32 +0100 -Subject: [PATCH 420/434] Error out when tls-channel option is used without - TLS - -It's currently possible to setup spice channels using TLS when -no TLS port has been specified (ie TLS is disabled). This cannot -work, so better to error out in such a situation. - -Signed-off-by: Gerd Hoffmann ---- - ui/spice-core.c | 8 +++++++- - 1 file changed, 7 insertions(+), 1 deletion(-) - -diff --git a/ui/spice-core.c b/ui/spice-core.c -index 8503f03..98356b0 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -511,6 +511,12 @@ static int add_channel(const char *name, const char *value, void *opaque) - int rc; - - if (strcmp(name, "tls-channel") == 0) { -+ int *tls_port = opaque; -+ if (!*tls_port) { -+ error_report("spice: tried to setup tls-channel" -+ " without specifying a TLS port"); -+ exit(1); -+ } - security = SPICE_CHANNEL_SECURITY_SSL; - } - if (strcmp(name, "plaintext-channel") == 0) { -@@ -680,7 +686,7 @@ void qemu_spice_init(void) - spice_server_set_playback_compression - (spice_server, qemu_opt_get_bool(opts, "playback-compression", 1)); - -- qemu_opt_foreach(opts, add_channel, NULL, 0); -+ qemu_opt_foreach(opts, add_channel, &tls_port, 0); - - if (0 != spice_server_init(spice_server, &core_interface)) { - error_report("failed to initialize spice server"); --- -1.7.10 - diff --git a/0421-qxl-properly-handle-upright-and-non-shared-surfaces.patch b/0421-qxl-properly-handle-upright-and-non-shared-surfaces.patch deleted file mode 100644 index d5b0eb1..0000000 --- a/0421-qxl-properly-handle-upright-and-non-shared-surfaces.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 7027fa0d3be22f48a51420a45aff13bec54fef1e Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Mon, 27 Feb 2012 11:05:09 +0100 -Subject: [PATCH 421/434] qxl: properly handle upright and non-shared surfaces - -Although qxl creates a shared displaysurface when the qxl surface is -upright and doesn't need to be flipped there is no guarantee that the -surface doesn't become unshared for some reason. Rename qxl_flip to -qxl_blit and fix it to handle both flip and non-flip cases. - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl-render.c | 20 +++++++++++++------- - 1 file changed, 13 insertions(+), 7 deletions(-) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index 4857838..2e10e93 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -21,25 +21,31 @@ - - #include "qxl.h" - --static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) -+static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) - { - uint8_t *src; - uint8_t *dst = qxl->vga.ds->surface->data; - int len, i; - -- if (qxl->guest_primary.qxl_stride > 0) { -+ if (is_buffer_shared(qxl->vga.ds->surface)) { - return; - } - if (!qxl->guest_primary.data) { - dprint(qxl, 1, "%s: initializing guest_primary.data\n", __func__); - qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); - } -- dprint(qxl, 1, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, -+ dprint(qxl, 2, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, - qxl->guest_primary.qxl_stride, - rect->left, rect->right, rect->top, rect->bottom); - src = qxl->guest_primary.data; -- src += (qxl->guest_primary.surface.height - rect->top - 1) * -- qxl->guest_primary.abs_stride; -+ if (qxl->guest_primary.qxl_stride < 0) { -+ /* qxl surface is upside down, walk src scanlines -+ * in reverse order to flip it */ -+ src += (qxl->guest_primary.surface.height - rect->top - 1) * -+ qxl->guest_primary.abs_stride; -+ } else { -+ src += rect->top * qxl->guest_primary.abs_stride; -+ } - dst += rect->top * qxl->guest_primary.abs_stride; - src += rect->left * qxl->guest_primary.bytes_pp; - dst += rect->left * qxl->guest_primary.bytes_pp; -@@ -48,7 +54,7 @@ static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) - for (i = rect->top; i < rect->bottom; i++) { - memcpy(dst, src, len); - dst += qxl->guest_primary.abs_stride; -- src -= qxl->guest_primary.abs_stride; -+ src += qxl->guest_primary.qxl_stride; - } - } - -@@ -132,7 +138,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) - if (qemu_spice_rect_is_empty(qxl->dirty+i)) { - break; - } -- qxl_flip(qxl, qxl->dirty+i); -+ qxl_blit(qxl, qxl->dirty+i); - dpy_update(vga->ds, - qxl->dirty[i].left, qxl->dirty[i].top, - qxl->dirty[i].right - qxl->dirty[i].left, --- -1.7.10 - diff --git a/0422-spice-set-spice-uuid-and-name.patch b/0422-spice-set-spice-uuid-and-name.patch deleted file mode 100644 index bba1015..0000000 --- a/0422-spice-set-spice-uuid-and-name.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 544cfc4a2c730aca346df7215a0dd83280f864d5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Mon, 5 Mar 2012 18:22:26 +0100 -Subject: [PATCH 422/434] spice: set spice uuid and name - -This allows a Spice client to identify a VM - -Signed-off-by: Gerd Hoffmann ---- - ui/spice-core.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/ui/spice-core.c b/ui/spice-core.c -index 98356b0..4ad0a67 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -19,6 +19,7 @@ - #include - - #include -+#include "sysemu.h" - - #include "qemu-common.h" - #include "qemu-spice.h" -@@ -688,6 +689,11 @@ void qemu_spice_init(void) - - qemu_opt_foreach(opts, add_channel, &tls_port, 0); - -+#if SPICE_SERVER_VERSION >= 0x000a02 /* 0.10.2 */ -+ spice_server_set_name(spice_server, qemu_name); -+ spice_server_set_uuid(spice_server, qemu_uuid); -+#endif -+ - if (0 != spice_server_init(spice_server, &core_interface)) { - error_report("failed to initialize spice server"); - exit(1); --- -1.7.10 - diff --git a/0423-monitor-fix-client_migrate_info-error-handling.patch b/0423-monitor-fix-client_migrate_info-error-handling.patch deleted file mode 100644 index b691cf5..0000000 --- a/0423-monitor-fix-client_migrate_info-error-handling.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 63f3e6ee49e0a88bbd7915d81962c9046205c411 Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -Date: Sun, 18 Mar 2012 09:42:39 +0200 -Subject: [PATCH 423/434] monitor: fix client_migrate_info error handling - -Report QERR_MISSING_PARAMETER when port is missing. Otherwise -QERR_UNDEFINED_ERROR will occur. - -rhbz #795652 - -Signed-off-by: Yonit Halperin -Signed-off-by: Gerd Hoffmann ---- - monitor.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/monitor.c b/monitor.c -index 3c23aa4..76739d7 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -1046,6 +1046,11 @@ static int client_migrate_info(Monitor *mon, const QDict *qdict, - return -1; - } - -+ if (port == -1 && tls_port == -1) { -+ qerror_report(QERR_MISSING_PARAMETER, "port/tls-port"); -+ return -1; -+ } -+ - ret = qemu_spice_migrate_info(hostname, port, tls_port, subject, - cb, opaque); - if (ret != 0) { --- -1.7.10 - diff --git a/0424-qxl-init_pipe_signaling-exit-on-failure.patch b/0424-qxl-init_pipe_signaling-exit-on-failure.patch deleted file mode 100644 index 3de1920..0000000 --- a/0424-qxl-init_pipe_signaling-exit-on-failure.patch +++ /dev/null @@ -1,49 +0,0 @@ -From d3e6c37f68e7e4573a47b0540f626a2add0d05e4 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Sun, 18 Mar 2012 13:46:13 +0100 -Subject: [PATCH 424/434] qxl: init_pipe_signaling: exit on failure - -If pipe creation fails, exit, don't log and continue. Fix indentation at -the same time. - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 21 +++++++++++---------- - 1 file changed, 11 insertions(+), 10 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 73be115..9ad5807 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1453,16 +1453,17 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) - - static void init_pipe_signaling(PCIQXLDevice *d) - { -- if (pipe(d->pipe) < 0) { -- dprint(d, 1, "%s: pipe creation failed\n", __FUNCTION__); -- return; -- } -- fcntl(d->pipe[0], F_SETFL, O_NONBLOCK); -- fcntl(d->pipe[1], F_SETFL, O_NONBLOCK); -- fcntl(d->pipe[0], F_SETOWN, getpid()); -- -- qemu_thread_get_self(&d->main); -- qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d); -+ if (pipe(d->pipe) < 0) { -+ fprintf(stderr, "%s:%s: qxl pipe creation failed\n", -+ __FILE__, __func__); -+ exit(1); -+ } -+ fcntl(d->pipe[0], F_SETFL, O_NONBLOCK); -+ fcntl(d->pipe[1], F_SETFL, O_NONBLOCK); -+ fcntl(d->pipe[0], F_SETOWN, getpid()); -+ -+ qemu_thread_get_self(&d->main); -+ qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d); - } - - /* graphics console */ --- -1.7.10 - diff --git a/0425-qxl-switch-qxl.c-to-trace-events.patch b/0425-qxl-switch-qxl.c-to-trace-events.patch deleted file mode 100644 index e60bd4c..0000000 --- a/0425-qxl-switch-qxl.c-to-trace-events.patch +++ /dev/null @@ -1,753 +0,0 @@ -From 29304ce6b6863b544f1ad8535a927dfc8864354c Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Sun, 18 Mar 2012 13:46:14 +0100 -Subject: [PATCH 425/434] qxl: switch qxl.c to trace-events - -dprint is still used for qxl_init_common one time prints. - -also switched parts of spice-display.c over, mainly all the callbacks to -spice server. - -All qxl device trace events start with the qxl device id. - -Signed-off-by: Alon Levy -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Gerd Hoffmann - -Conflicts: - - trace-events ---- - hw/qxl.c | 141 +++++++++++++++++++++++++--------------------------- - trace-events | 59 ++++++++++++++++++++++ - ui/spice-display.c | 14 +++++- - 3 files changed, 140 insertions(+), 74 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 9ad5807..813873a 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -23,6 +23,7 @@ - #include "qemu-queue.h" - #include "monitor.h" - #include "sysemu.h" -+#include "trace.h" - - #include "qxl.h" - -@@ -143,6 +144,10 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - uint32_t clear_dirty_region, - qxl_async_io async, struct QXLCookie *cookie) - { -+ trace_qxl_spice_update_area(qxl->id, surface_id, area->left, area->right, -+ area->top, area->bottom); -+ trace_qxl_spice_update_area_rest(qxl->id, num_dirty_rects, -+ clear_dirty_region); - if (async == QXL_SYNC) { - qxl->ssd.worker->update_area(qxl->ssd.worker, surface_id, area, - dirty_rects, num_dirty_rects, clear_dirty_region); -@@ -156,6 +161,7 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - static void qxl_spice_destroy_surface_wait_complete(PCIQXLDevice *qxl, - uint32_t id) - { -+ trace_qxl_spice_destroy_surface_wait_complete(qxl->id, id); - qemu_mutex_lock(&qxl->track_lock); - qxl->guest_surfaces.cmds[id] = 0; - qxl->guest_surfaces.count--; -@@ -167,6 +173,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, - { - QXLCookie *cookie; - -+ trace_qxl_spice_destroy_surface_wait(qxl->id, id, async); - if (async) { - cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, - QXL_IO_DESTROY_SURFACE_ASYNC); -@@ -174,12 +181,13 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, - spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uint64_t)cookie); - } else { - qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); -- qxl_spice_destroy_surface_wait_complete(qxl, id); - } - } - - static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) - { -+ trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count, -+ qxl->num_free_res); - spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, - (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, - QXL_IO_FLUSH_SURFACES_ASYNC)); -@@ -188,21 +196,25 @@ static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) - void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, - uint32_t count) - { -+ trace_qxl_spice_loadvm_commands(qxl->id, ext, count); - qxl->ssd.worker->loadvm_commands(qxl->ssd.worker, ext, count); - } - - void qxl_spice_oom(PCIQXLDevice *qxl) - { -+ trace_qxl_spice_oom(qxl->id); - qxl->ssd.worker->oom(qxl->ssd.worker); - } - - void qxl_spice_reset_memslots(PCIQXLDevice *qxl) - { -+ trace_qxl_spice_reset_memslots(qxl->id); - qxl->ssd.worker->reset_memslots(qxl->ssd.worker); - } - - static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) - { -+ trace_qxl_spice_destroy_surfaces_complete(qxl->id); - qemu_mutex_lock(&qxl->track_lock); - memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); - qxl->guest_surfaces.count = 0; -@@ -211,6 +223,7 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) - - static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) - { -+ trace_qxl_spice_destroy_surfaces(qxl->id, async); - if (async) { - spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, - (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -@@ -223,11 +236,13 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) - - void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) - { -+ trace_qxl_spice_reset_image_cache(qxl->id); - qxl->ssd.worker->reset_image_cache(qxl->ssd.worker); - } - - void qxl_spice_reset_cursor(PCIQXLDevice *qxl) - { -+ trace_qxl_spice_reset_cursor(qxl->id); - qxl->ssd.worker->reset_cursor(qxl->ssd.worker); - qemu_mutex_lock(&qxl->track_lock); - qxl->guest_cursor = 0; -@@ -412,7 +427,7 @@ static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) - { - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - -- dprint(qxl, 1, "%s:\n", __FUNCTION__); -+ trace_qxl_interface_attach_worker(qxl->id); - qxl->ssd.worker = qxl_worker; - } - -@@ -420,7 +435,7 @@ static void interface_set_compression_level(QXLInstance *sin, int level) - { - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - -- dprint(qxl, 1, "%s: %d\n", __FUNCTION__, level); -+ trace_qxl_interface_set_compression_level(qxl->id, level); - qxl->shadow_rom.compression_level = cpu_to_le32(level); - qxl->rom->compression_level = cpu_to_le32(level); - qxl_rom_set_dirty(qxl); -@@ -430,6 +445,7 @@ static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) - { - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - -+ trace_qxl_interface_set_mm_time(qxl->id, mm_time); - qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time); - qxl->rom->mm_clock = cpu_to_le32(mm_time); - qxl_rom_set_dirty(qxl); -@@ -439,7 +455,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) - { - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - -- dprint(qxl, 1, "%s:\n", __FUNCTION__); -+ trace_qxl_interface_get_init_info(qxl->id); - info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; - info->memslot_id_bits = MEMSLOT_SLOT_BITS; - info->num_memslots = NUM_MEMSLOTS; -@@ -508,9 +524,10 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) - QXLCommand *cmd; - int notify, ret; - -+ trace_qxl_ring_command_check(qxl->id, qxl_mode_to_string(qxl->mode)); -+ - switch (qxl->mode) { - case QXL_MODE_VGA: -- dprint(qxl, 2, "%s: vga\n", __FUNCTION__); - ret = false; - qemu_mutex_lock(&qxl->ssd.lock); - if (qxl->ssd.update != NULL) { -@@ -521,19 +538,18 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) - } - qemu_mutex_unlock(&qxl->ssd.lock); - if (ret) { -- dprint(qxl, 2, "%s %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); -+ trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); - qxl_log_command(qxl, "vga", ext); - } - return ret; - case QXL_MODE_COMPAT: - case QXL_MODE_NATIVE: - case QXL_MODE_UNDEFINED: -- dprint(qxl, 4, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); - ring = &qxl->ram->cmd_ring; - if (SPICE_RING_IS_EMPTY(ring)) { - return false; - } -- dprint(qxl, 2, "%s: %s\n", __FUNCTION__, qxl_mode_to_string(qxl->mode)); -+ trace_qxl_ring_command_get(qxl->id, qxl_mode_to_string(qxl->mode)); - SPICE_RING_CONS_ITEM(ring, cmd); - ext->cmd = *cmd; - ext->group_id = MEMSLOT_GROUP_GUEST; -@@ -558,6 +574,7 @@ static int interface_req_cmd_notification(QXLInstance *sin) - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - int wait = 1; - -+ trace_qxl_ring_command_req_notification(qxl->id); - switch (qxl->mode) { - case QXL_MODE_COMPAT: - case QXL_MODE_NATIVE: -@@ -595,10 +612,11 @@ static inline void qxl_push_free_res(PCIQXLDevice *d, int flush) - } - - SPICE_RING_PUSH(ring, notify); -- dprint(d, 2, "free: push %d items, notify %s, ring %d/%d [%d,%d]\n", -- d->num_free_res, notify ? "yes" : "no", -- ring->prod - ring->cons, ring->num_items, -- ring->prod, ring->cons); -+ trace_qxl_ring_res_push(d->id, qxl_mode_to_string(d->mode), -+ d->guest_surfaces.count, d->num_free_res, -+ d->last_release, notify ? "yes" : "no"); -+ trace_qxl_ring_res_push_rest(d->id, ring->prod - ring->cons, -+ ring->num_items, ring->prod, ring->cons); - if (notify) { - qxl_send_events(d, QXL_INTERRUPT_DISPLAY); - } -@@ -645,7 +663,7 @@ static void interface_release_resource(QXLInstance *sin, - } - qxl->last_release = ext.info; - qxl->num_free_res++; -- dprint(qxl, 3, "%4d\r", qxl->num_free_res); -+ trace_qxl_ring_res_put(qxl->id, qxl->num_free_res); - qxl_push_free_res(qxl, 0); - } - -@@ -657,6 +675,8 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * - QXLCommand *cmd; - int notify; - -+ trace_qxl_ring_cursor_check(qxl->id, qxl_mode_to_string(qxl->mode)); -+ - switch (qxl->mode) { - case QXL_MODE_COMPAT: - case QXL_MODE_NATIVE: -@@ -680,6 +700,7 @@ static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt * - if (qxl->id == 0) { - qxl_render_cursor(qxl, ext); - } -+ trace_qxl_ring_cursor_get(qxl->id, qxl_mode_to_string(qxl->mode)); - return true; - default: - return false; -@@ -692,6 +713,7 @@ static int interface_req_cursor_notification(QXLInstance *sin) - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - int wait = 1; - -+ trace_qxl_ring_cursor_req_notification(qxl->id); - switch (qxl->mode) { - case QXL_MODE_COMPAT: - case QXL_MODE_NATIVE: -@@ -719,7 +741,6 @@ static int interface_flush_resources(QXLInstance *sin) - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - int ret; - -- dprint(qxl, 1, "free: guest flush (have %d)\n", qxl->num_free_res); - ret = qxl->num_free_res; - if (ret) { - qxl_push_free_res(qxl, 1); -@@ -739,7 +760,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) - qxl->current_async = QXL_UNDEFINED_IO; - qemu_mutex_unlock(&qxl->async_lock); - -- dprint(qxl, 2, "async_complete: %d (%p) done\n", current_async, cookie); -+ trace_qxl_interface_async_complete_io(qxl->id, current_async, cookie); - if (!cookie) { - fprintf(stderr, "qxl: %s: error, cookie is NULL\n", __func__); - return; -@@ -785,11 +806,15 @@ static void interface_update_area_complete(QXLInstance *sin, - qemu_mutex_unlock(&qxl->ssd.lock); - return; - } -+ trace_qxl_interface_update_area_complete(qxl->id, surface_id, dirty->left, -+ dirty->right, dirty->top, dirty->bottom); -+ trace_qxl_interface_update_area_complete_rest(qxl->id, num_updated_rects); - if (qxl->num_dirty_rects + num_updated_rects > QXL_NUM_DIRTY_RECTS) { - /* - * overflow - treat this as a full update. Not expected to be common. - */ -- dprint(qxl, 1, "%s: overflow of dirty rects\n", __func__); -+ trace_qxl_interface_update_area_complete_overflow(qxl->id, -+ QXL_NUM_DIRTY_RECTS); - qxl->guest_primary.resized = 1; - } - if (qxl->guest_primary.resized) { -@@ -805,8 +830,8 @@ static void interface_update_area_complete(QXLInstance *sin, - qxl->dirty[qxl_i++] = dirty[i]; - } - qxl->num_dirty_rects += num_updated_rects; -- dprint(qxl, 1, "%s: scheduling update_area_bh, #dirty %d\n", -- __func__, qxl->num_dirty_rects); -+ trace_qxl_interface_update_area_complete_schedule_bh(qxl->id, -+ qxl->num_dirty_rects); - qemu_bh_schedule(qxl->update_area_bh); - qemu_mutex_unlock(&qxl->ssd.lock); - } -@@ -860,7 +885,7 @@ static void qxl_enter_vga_mode(PCIQXLDevice *d) - if (d->mode == QXL_MODE_VGA) { - return; - } -- dprint(d, 1, "%s\n", __FUNCTION__); -+ trace_qxl_enter_vga_mode(d->id); - qemu_spice_create_host_primary(&d->ssd); - d->mode = QXL_MODE_VGA; - memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); -@@ -871,7 +896,7 @@ static void qxl_exit_vga_mode(PCIQXLDevice *d) - if (d->mode != QXL_MODE_VGA) { - return; - } -- dprint(d, 1, "%s\n", __FUNCTION__); -+ trace_qxl_exit_vga_mode(d->id); - qxl_destroy_primary(d, QXL_SYNC); - } - -@@ -908,7 +933,7 @@ static void qxl_reset_state(PCIQXLDevice *d) - - static void qxl_soft_reset(PCIQXLDevice *d) - { -- dprint(d, 1, "%s:\n", __FUNCTION__); -+ trace_qxl_soft_reset(d->id); - qxl_check_state(d); - - if (d->id == 0) { -@@ -920,8 +945,7 @@ static void qxl_soft_reset(PCIQXLDevice *d) - - static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) - { -- dprint(d, 1, "%s: start%s\n", __FUNCTION__, -- loadvm ? " (loadvm)" : ""); -+ trace_qxl_hard_reset(d->id, loadvm); - - qxl_spice_reset_cursor(d); - qxl_spice_reset_image_cache(d); -@@ -936,13 +960,12 @@ static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) - } - qemu_spice_create_host_memslot(&d->ssd); - qxl_soft_reset(d); -- -- dprint(d, 1, "%s: done\n", __FUNCTION__); - } - - static void qxl_reset_handler(DeviceState *dev) - { - PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev); -+ - qxl_hard_reset(d, 0); - } - -@@ -951,8 +974,8 @@ static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) - VGACommonState *vga = opaque; - PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga); - -+ trace_qxl_io_write_vga(qxl->id, qxl_mode_to_string(qxl->mode), addr, val); - if (qxl->mode != QXL_MODE_VGA) { -- dprint(qxl, 1, "%s\n", __FUNCTION__); - qxl_destroy_primary(qxl, QXL_SYNC); - qxl_soft_reset(qxl); - } -@@ -992,9 +1015,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, - guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start); - guest_end = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end); - -- dprint(d, 1, "%s: slot %d: guest phys 0x%" PRIx64 " - 0x%" PRIx64 "\n", -- __FUNCTION__, slot_id, -- guest_start, guest_end); -+ trace_qxl_memslot_add_guest(d->id, slot_id, guest_start, guest_end); - - PANIC_ON(slot_id >= NUM_MEMSLOTS); - PANIC_ON(guest_start > guest_end); -@@ -1040,10 +1061,6 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, - memslot.generation = d->rom->slot_generation = 0; - qxl_rom_set_dirty(d); - -- dprint(d, 1, "%s: slot %d: host virt 0x%lx - 0x%lx\n", -- __FUNCTION__, memslot.slot_id, -- memslot.virt_start, memslot.virt_end); -- - qemu_spice_add_memslot(&d->ssd, &memslot, async); - d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; - d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; -@@ -1053,21 +1070,19 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, - - static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) - { -- dprint(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id); - qemu_spice_del_memslot(&d->ssd, MEMSLOT_GROUP_HOST, slot_id); - d->guest_slots[slot_id].active = 0; - } - - static void qxl_reset_memslots(PCIQXLDevice *d) - { -- dprint(d, 1, "%s:\n", __FUNCTION__); - qxl_spice_reset_memslots(d); - memset(&d->guest_slots, 0, sizeof(d->guest_slots)); - } - - static void qxl_reset_surfaces(PCIQXLDevice *d) - { -- dprint(d, 1, "%s:\n", __FUNCTION__); -+ trace_qxl_reset_surfaces(d->id); - d->mode = QXL_MODE_UNDEFINED; - qxl_spice_destroy_surfaces(d, QXL_SYNC); - } -@@ -1109,9 +1124,6 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, - assert(qxl->mode != QXL_MODE_NATIVE); - qxl_exit_vga_mode(qxl); - -- dprint(qxl, 1, "%s: %dx%d\n", __FUNCTION__, -- le32_to_cpu(sc->width), le32_to_cpu(sc->height)); -- - surface.format = le32_to_cpu(sc->format); - surface.height = le32_to_cpu(sc->height); - surface.mem = le64_to_cpu(sc->mem); -@@ -1120,6 +1132,10 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, - surface.width = le32_to_cpu(sc->width); - surface.type = le32_to_cpu(sc->type); - surface.flags = le32_to_cpu(sc->flags); -+ trace_qxl_create_guest_primary(qxl->id, sc->width, sc->height, sc->mem, -+ sc->format, sc->position); -+ trace_qxl_create_guest_primary_rest(qxl->id, sc->stride, sc->type, -+ sc->flags); - - surface.mouse_mode = true; - surface.group_id = MEMSLOT_GROUP_GUEST; -@@ -1143,7 +1159,7 @@ static int qxl_destroy_primary(PCIQXLDevice *d, qxl_async_io async) - if (d->mode == QXL_MODE_UNDEFINED) { - return 0; - } -- dprint(d, 1, "%s\n", __FUNCTION__); -+ trace_qxl_destroy_primary(d->id); - d->mode = QXL_MODE_UNDEFINED; - qemu_spice_destroy_primary_surface(&d->ssd, 0, async); - qxl_spice_reset_cursor(d); -@@ -1170,8 +1186,8 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) - .mem = devmem + d->shadow_rom.draw_area_offset, - }; - -- dprint(d, 1, "%s: mode %d [ %d x %d @ %d bpp devmem 0x%" PRIx64 " ]\n", -- __func__, modenr, mode->x_res, mode->y_res, mode->bits, devmem); -+ trace_qxl_set_mode(d->id, modenr, mode->x_res, mode->y_res, mode->bits, -+ devmem); - if (!loadvm) { - qxl_hard_reset(d, 0); - } -@@ -1217,8 +1233,8 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, - if (d->mode != QXL_MODE_VGA) { - break; - } -- dprint(d, 1, "%s: unexpected port 0x%x (%s) in vga mode\n", -- __func__, io_port, io_port_to_string(io_port)); -+ trace_qxl_io_unexpected_vga_mode(d->id, -+ io_port, io_port_to_string(io_port)); - /* be nice to buggy guest drivers */ - if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && - io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) { -@@ -1260,11 +1276,12 @@ async_common: - } - d->current_async = orig_io_port; - qemu_mutex_unlock(&d->async_lock); -- dprint(d, 2, "start async %d (%"PRId64")\n", io_port, val); - break; - default: - break; - } -+ trace_qxl_io_write(d->id, qxl_mode_to_string(d->mode), addr, val, size, -+ async); - - switch (io_port) { - case QXL_IO_UPDATE_AREA: -@@ -1300,7 +1317,6 @@ async_common: - d->oom_running = 0; - break; - case QXL_IO_SET_MODE: -- dprint(d, 1, "QXL_SET_MODE %d\n", (int)val); - qxl_set_mode(d, val, 0); - break; - case QXL_IO_LOG: -@@ -1310,7 +1326,6 @@ async_common: - } - break; - case QXL_IO_RESET: -- dprint(d, 1, "QXL_IO_RESET\n"); - qxl_hard_reset(d, 0); - break; - case QXL_IO_MEMSLOT_ADD: -@@ -1338,7 +1353,6 @@ async_common: - async); - goto cancel_async; - } -- dprint(d, 1, "QXL_IO_CREATE_PRIMARY async=%d\n", async); - d->guest_primary.surface = d->ram->create_surface; - qxl_create_guest_primary(d, 0, async); - break; -@@ -1348,11 +1362,9 @@ async_common: - async); - goto cancel_async; - } -- dprint(d, 1, "QXL_IO_DESTROY_PRIMARY (async=%d) (%s)\n", async, -- qxl_mode_to_string(d->mode)); - if (!qxl_destroy_primary(d, async)) { -- dprint(d, 1, "QXL_IO_DESTROY_PRIMARY_ASYNC in %s, ignored\n", -- qxl_mode_to_string(d->mode)); -+ trace_qxl_io_destroy_primary_ignored(d->id, -+ qxl_mode_to_string(d->mode)); - goto cancel_async; - } - break; -@@ -1372,16 +1384,9 @@ async_common: - ring->prod, ring->cons); - } - qxl_push_free_res(d, 1 /* flush */); -- dprint(d, 1, "QXL_IO_FLUSH_RELEASE exit (%s, s#=%d, res#=%d,%p)\n", -- qxl_mode_to_string(d->mode), d->guest_surfaces.count, -- d->num_free_res, d->last_release); - break; - } - case QXL_IO_FLUSH_SURFACES_ASYNC: -- dprint(d, 1, "QXL_IO_FLUSH_SURFACES_ASYNC" -- " (%"PRId64") (%s, s#=%d, res#=%d)\n", -- val, qxl_mode_to_string(d->mode), d->guest_surfaces.count, -- d->num_free_res); - qxl_spice_flush_surfaces_async(d); - break; - case QXL_IO_DESTROY_ALL_SURFACES: -@@ -1407,7 +1412,7 @@ static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, - { - PCIQXLDevice *d = opaque; - -- dprint(d, 1, "%s: unexpected\n", __FUNCTION__); -+ trace_qxl_io_read_unexpected(d->id); - return 0xff; - } - -@@ -1558,8 +1563,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) - surface_offset -= vram_start; - surface_size = cmd->u.surface_create.height * - abs(cmd->u.surface_create.stride); -- dprint(qxl, 3, "%s: dirty surface %d, offset %d, size %d\n", __func__, -- i, (int)surface_offset, surface_size); -+ trace_qxl_surfaces_dirty(qxl->id, i, (int)surface_offset, surface_size); - qxl_set_dirty(&qxl->vram_bar, surface_offset, surface_size); - } - } -@@ -1759,7 +1763,7 @@ static void qxl_pre_save(void *opaque) - PCIQXLDevice* d = opaque; - uint8_t *ram_start = d->vga.vram_ptr; - -- dprint(d, 1, "%s:\n", __FUNCTION__); -+ trace_qxl_pre_save(d->id); - if (d->last_release == NULL) { - d->last_release_offset = 0; - } else { -@@ -1772,10 +1776,9 @@ static int qxl_pre_load(void *opaque) - { - PCIQXLDevice* d = opaque; - -- dprint(d, 1, "%s: start\n", __FUNCTION__); -+ trace_qxl_pre_load(d->id); - qxl_hard_reset(d, 1); - qxl_exit_vga_mode(d); -- dprint(d, 1, "%s: done\n", __FUNCTION__); - return 0; - } - -@@ -1787,7 +1790,6 @@ static void qxl_create_memslots(PCIQXLDevice *d) - if (!d->guest_slots[i].active) { - continue; - } -- dprint(d, 1, "%s: restoring guest slot %d\n", __func__, i); - qxl_add_memslot(d, i, 0, QXL_SYNC); - } - } -@@ -1799,8 +1801,6 @@ static int qxl_post_load(void *opaque, int version) - QXLCommandExt *cmds; - int in, out, newmode; - -- dprint(d, 1, "%s: start\n", __FUNCTION__); -- - assert(d->last_release_offset < d->vga.vram_size); - if (d->last_release_offset == 0) { - d->last_release = NULL; -@@ -1810,8 +1810,7 @@ static int qxl_post_load(void *opaque, int version) - - d->modes = (QXLModes*)((uint8_t*)d->rom + d->rom->modes_offset); - -- dprint(d, 1, "%s: restore mode (%s)\n", __FUNCTION__, -- qxl_mode_to_string(d->mode)); -+ trace_qxl_post_load(d->id, qxl_mode_to_string(d->mode)); - newmode = d->mode; - d->mode = QXL_MODE_UNDEFINED; - -@@ -1853,8 +1852,6 @@ static int qxl_post_load(void *opaque, int version) - qxl_set_mode(d, d->shadow_rom.mode, 1); - break; - } -- dprint(d, 1, "%s: done\n", __FUNCTION__); -- - return 0; - } - -diff --git a/trace-events b/trace-events -index 962caca..0bc290f 100644 ---- a/trace-events -+++ b/trace-events -@@ -631,3 +631,62 @@ win_helper_no_switch_pstate(uint32_t new_pstate_regs) "change_pstate: regs new=% - win_helper_wrpil(uint32_t psrpil, uint32_t new_pil) "old=%x new=%x" - win_helper_done(uint32_t tl) "tl=%d" - win_helper_retry(uint32_t tl) "tl=%d" -+ -+# hw/qxl.c -+disable qxl_interface_set_mm_time(int qid, uint32_t mm_time) "%d %d" -+disable qxl_io_write_vga(int qid, const char *mode, uint32_t addr, uint32_t val) "%d %s addr=%u val=%u" -+qxl_create_guest_primary(int qid, uint32_t width, uint32_t height, uint64_t mem, uint32_t format, uint32_t position) "%d %dx%d mem=%lx %d,%d" -+qxl_create_guest_primary_rest(int qid, int32_t stride, uint32_t type, uint32_t flags) "%d %d,%d,%d" -+qxl_destroy_primary(int qid) "%d" -+qxl_enter_vga_mode(int qid) "%d" -+qxl_exit_vga_mode(int qid) "%d" -+qxl_hard_reset(int qid, int64_t loadvm) "%d loadvm=%"PRId64"" -+qxl_interface_async_complete_io(int qid, uint32_t current_async, void *cookie) "%d current=%d cookie=%p" -+qxl_interface_attach_worker(int qid) "%d" -+qxl_interface_get_init_info(int qid) "%d" -+qxl_interface_set_compression_level(int qid, int64_t level) "%d %"PRId64 -+qxl_interface_update_area_complete(int qid, uint32_t surface_id, uint32_t dirty_left, uint32_t dirty_right, uint32_t dirty_top, uint32_t dirty_bottom) "%d surface=%d [%d,%d,%d,%d]" -+qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d #=%d" -+qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" -+qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" -+qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" -+qxl_io_read_unexpected(int qid) "%d" -+qxl_io_unexpected_vga_mode(int qid, uint32_t io_port, const char *desc) "%d 0x%x (%s)" -+qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" -+qxl_memslot_add_guest(int qid, uint32_t slot_id, uint64_t guest_start, uint64_t guest_end) "%d %u: guest phys 0x%"PRIx64 " - 0x%" PRIx64 -+qxl_post_load(int qid, const char *mode) "%d %s" -+qxl_pre_load(int qid) "%d" -+qxl_pre_save(int qid) "%d" -+qxl_reset_surfaces(int qid) "%d" -+qxl_ring_command_check(int qid, const char *mode) "%d %s" -+qxl_ring_command_get(int qid, const char *mode) "%d %s" -+qxl_ring_command_req_notification(int qid) "%d" -+qxl_ring_cursor_check(int qid, const char *mode) "%d %s" -+qxl_ring_cursor_get(int qid, const char *mode) "%d %s" -+qxl_ring_cursor_req_notification(int qid) "%d" -+qxl_ring_res_push(int qid, const char *mode, uint32_t surface_count, uint32_t free_res, void *last_release, const char *notify) "%d %s s#=%d res#=%d last=%p notify=%s" -+qxl_ring_res_push_rest(int qid, uint32_t ring_has, uint32_t ring_size, uint32_t prod, uint32_t cons) "%d ring %d/%d [%d,%d]" -+qxl_ring_res_put(int qid, uint32_t free_res) "%d #res=%d" -+qxl_set_mode(int qid, int modenr, uint32_t x_res, uint32_t y_res, uint32_t bits, uint64_t devmem) "%d mode=%d [ x=%d y=%d @ bpp=%d devmem=0x%" PRIx64 " ]" -+qxl_soft_reset(int qid) "%d" -+qemu_spice_add_memslot(int qid, uint32_t slot_id, unsigned long virt_start, unsigned long virt_end, int async) "%d %u: host virt 0x%lx - 0x%lx async=%d" -+qemu_spice_del_memslot(int qid, uint32_t gid, uint32_t slot_id) "%d gid=%u sid=%u" -+qemu_spice_create_primary_surface(int qid, uint32_t sid, void *surface, int async) "%d sid=%u surface=%p async=%d" -+qemu_spice_destroy_primary_surface(int qid, uint32_t sid, int async) "%d sid=%u async=%d" -+qemu_spice_wakeup(uint32_t qid) "%d" -+qemu_spice_start(uint32_t qid) "%d" -+qemu_spice_stop(uint32_t qid) "%d" -+qemu_spice_create_update(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "lr %d -> %d, tb -> %d -> %d" -+qxl_spice_destroy_surfaces_complete(int qid) "%d" -+qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d" -+qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d" -+qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d" -+qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d" -+qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d" -+qxl_spice_oom(int qid) "%d" -+qxl_spice_reset_cursor(int qid) "%d" -+qxl_spice_reset_image_cache(int qid) "%d" -+qxl_spice_reset_memslots(int qid) "%d" -+qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" -+qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" -+qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" -diff --git a/ui/spice-display.c b/ui/spice-display.c -index ab266ae..28d6d4a 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -22,6 +22,7 @@ - #include "monitor.h" - #include "console.h" - #include "sysemu.h" -+#include "trace.h" - - #include "spice-display.h" - -@@ -73,6 +74,10 @@ QXLCookie *qxl_cookie_new(int type, uint64_t io) - void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, - qxl_async_io async) - { -+ trace_qemu_spice_add_memslot(ssd->qxl.id, memslot->slot_id, -+ memslot->virt_start, memslot->virt_end, -+ async); -+ - if (async != QXL_SYNC) { - spice_qxl_add_memslot_async(&ssd->qxl, memslot, - (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -@@ -84,6 +89,7 @@ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, - - void qemu_spice_del_memslot(SimpleSpiceDisplay *ssd, uint32_t gid, uint32_t sid) - { -+ trace_qemu_spice_del_memslot(ssd->qxl.id, gid, sid); - ssd->worker->del_memslot(ssd->worker, gid, sid); - } - -@@ -91,6 +97,7 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, - QXLDevSurfaceCreate *surface, - qxl_async_io async) - { -+ trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async); - if (async != QXL_SYNC) { - spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, - (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -@@ -100,10 +107,10 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, - } - } - -- - void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, - uint32_t id, qxl_async_io async) - { -+ trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async); - if (async != QXL_SYNC) { - spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, - (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -@@ -115,16 +122,19 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, - - void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) - { -+ trace_qemu_spice_wakeup(ssd->qxl.id); - ssd->worker->wakeup(ssd->worker); - } - - void qemu_spice_start(SimpleSpiceDisplay *ssd) - { -+ trace_qemu_spice_start(ssd->qxl.id); - ssd->worker->start(ssd->worker); - } - - void qemu_spice_stop(SimpleSpiceDisplay *ssd) - { -+ trace_qemu_spice_stop(ssd->qxl.id); - ssd->worker->stop(ssd->worker); - } - -@@ -142,7 +152,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) - return NULL; - }; - -- dprint(2, "%s: lr %d -> %d, tb -> %d -> %d\n", __FUNCTION__, -+ trace_qemu_spice_create_update( - ssd->dirty.left, ssd->dirty.right, - ssd->dirty.top, ssd->dirty.bottom); - --- -1.7.10 - diff --git a/0426-qxl-qxl_render.c-add-trace-events.patch b/0426-qxl-qxl_render.c-add-trace-events.patch deleted file mode 100644 index 90c4069..0000000 --- a/0426-qxl-qxl_render.c-add-trace-events.patch +++ /dev/null @@ -1,95 +0,0 @@ -From 6b3e0d7afd011b8d40207fe45f6518937df1d99e Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Sun, 18 Mar 2012 13:46:15 +0100 -Subject: [PATCH 426/434] qxl/qxl_render.c: add trace events - -Signed-off-by: Alon Levy -Reviewed-by: Stefan Hajnoczi -Signed-off-by: Gerd Hoffmann - -Cherry-pick: Added missing include "trace.h" ---- - hw/qxl-render.c | 14 +++++--------- - trace-events | 7 +++++++ - 2 files changed, 12 insertions(+), 9 deletions(-) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index 2e10e93..835dc5e 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -20,6 +20,7 @@ - */ - - #include "qxl.h" -+#include "trace.h" - - static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) - { -@@ -31,11 +32,10 @@ static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect) - return; - } - if (!qxl->guest_primary.data) { -- dprint(qxl, 1, "%s: initializing guest_primary.data\n", __func__); -+ trace_qxl_render_blit_guest_primary_initialized(); - qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); - } -- dprint(qxl, 2, "%s: stride %d, [%d, %d, %d, %d]\n", __func__, -- qxl->guest_primary.qxl_stride, -+ trace_qxl_render_blit(qxl->guest_primary.qxl_stride, - rect->left, rect->right, rect->top, rect->bottom); - src = qxl->guest_primary.data; - if (qxl->guest_primary.qxl_stride < 0) { -@@ -107,8 +107,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) - qxl->guest_primary.data = memory_region_get_ram_ptr(&qxl->vga.vram); - qxl_set_rect_to_surface(qxl, &qxl->dirty[0]); - qxl->num_dirty_rects = 1; -- dprint(qxl, 1, "%s: %dx%d, stride %d, bpp %d, depth %d\n", -- __FUNCTION__, -+ trace_qxl_render_guest_primary_resized( - qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height, - qxl->guest_primary.qxl_stride, -@@ -118,8 +117,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) - if (surface->width != qxl->guest_primary.surface.width || - surface->height != qxl->guest_primary.surface.height) { - if (qxl->guest_primary.qxl_stride > 0) { -- dprint(qxl, 1, "%s: using guest_primary for displaysurface\n", -- __func__); - qemu_free_displaysurface(vga->ds); - qemu_create_displaysurface_from(qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height, -@@ -127,8 +124,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) - qxl->guest_primary.abs_stride, - qxl->guest_primary.data); - } else { -- dprint(qxl, 1, "%s: resizing displaysurface to guest_primary\n", -- __func__); - qemu_resize_displaysurface(vga->ds, - qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height); -@@ -187,6 +182,7 @@ void qxl_render_update_area_bh(void *opaque) - void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie) - { - qemu_mutex_lock(&qxl->ssd.lock); -+ trace_qxl_render_update_area_done(cookie); - qemu_bh_schedule(qxl->update_area_bh); - qxl->render_update_cookie_num--; - qemu_mutex_unlock(&qxl->ssd.lock); -diff --git a/trace-events b/trace-events -index 0bc290f..6050d92 100644 ---- a/trace-events -+++ b/trace-events -@@ -690,3 +690,10 @@ qxl_spice_reset_memslots(int qid) "%d" - qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" - qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" - qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" -+qxl_vga_ioport_while_not_in_vga_mode(int qid) "%d (int qid, reset to VGA mode because of VGA io)" -+ -+# hw/qxl-render.c -+qxl_render_blit_guest_primary_initialized(void) "" -+qxl_render_blit(int32_t stride, int32_t left, int32_t right, int32_t top, int32_t bottom) "stride=%d [%d, %d, %d, %d]" -+qxl_render_guest_primary_resized(int32_t width, int32_t height, int32_t stride, int32_t bytes_pp, int32_t bits_pp) "%dx%d, stride %d, bpp %d, depth %d" -+qxl_render_update_area_done(void *cookie) "%p" --- -1.7.10 - diff --git a/0427-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch b/0427-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch deleted file mode 100644 index b723016..0000000 --- a/0427-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 1ca7f74b31de28e9170e404ce2b932e311e4d2d0 Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Fri, 16 Mar 2012 13:50:04 +0000 -Subject: [PATCH 427/434] hw/qxl.c: Fix compilation failures on 32 bit hosts - -Fix compilation failures on 32 bit hosts (cast from pointer to -integer of different size; %ld expects 'long int' not uint64_t). - -Reported-by: Steve Langasek -Signed-off-by: Peter Maydell -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 16 ++++++++-------- - 1 file changed, 8 insertions(+), 8 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 813873a..bcdf274 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -154,7 +154,7 @@ void qxl_spice_update_area(PCIQXLDevice *qxl, uint32_t surface_id, - } else { - assert(cookie != NULL); - spice_qxl_update_area_async(&qxl->ssd.qxl, surface_id, area, -- clear_dirty_region, (uint64_t)cookie); -+ clear_dirty_region, (uintptr_t)cookie); - } - } - -@@ -178,7 +178,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, - cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, - QXL_IO_DESTROY_SURFACE_ASYNC); - cookie->u.surface_id = id; -- spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uint64_t)cookie); -+ spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie); - } else { - qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); - } -@@ -189,8 +189,8 @@ static void qxl_spice_flush_surfaces_async(PCIQXLDevice *qxl) - trace_qxl_spice_flush_surfaces_async(qxl->id, qxl->guest_surfaces.count, - qxl->num_free_res); - spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, -- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -- QXL_IO_FLUSH_SURFACES_ASYNC)); -+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_FLUSH_SURFACES_ASYNC)); - } - - void qxl_spice_loadvm_commands(PCIQXLDevice *qxl, struct QXLCommandExt *ext, -@@ -226,8 +226,8 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) - trace_qxl_spice_destroy_surfaces(qxl->id, async); - if (async) { - spice_qxl_destroy_surfaces_async(&qxl->ssd.qxl, -- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -- QXL_IO_DESTROY_ALL_SURFACES_ASYNC)); -+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_DESTROY_ALL_SURFACES_ASYNC)); - } else { - qxl->ssd.worker->destroy_surfaces(qxl->ssd.worker); - qxl_spice_destroy_surfaces_complete(qxl); -@@ -767,7 +767,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) - } - if (cookie && current_async != cookie->io) { - fprintf(stderr, -- "qxl: %s: error: current_async = %d != %ld = cookie->io\n", -+ "qxl: %s: error: current_async = %d != %" PRId64 " = cookie->io\n", - __func__, current_async, cookie->io); - } - switch (current_async) { -@@ -840,7 +840,7 @@ static void interface_update_area_complete(QXLInstance *sin, - static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) - { - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -- QXLCookie *cookie = (QXLCookie *)cookie_token; -+ QXLCookie *cookie = (QXLCookie *)(uintptr_t)cookie_token; - - switch (cookie->type) { - case QXL_COOKIE_TYPE_IO: --- -1.7.10 - diff --git a/0428-spice-fix-broken-initialization.patch b/0428-spice-fix-broken-initialization.patch deleted file mode 100644 index 6559660..0000000 --- a/0428-spice-fix-broken-initialization.patch +++ /dev/null @@ -1,67 +0,0 @@ -From 9f7bc0be9a5c353d076bb42b3bfdf77d8709063f Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 14 Mar 2012 20:33:37 +0200 -Subject: [PATCH 428/434] spice: fix broken initialization - -Commit 1b71f7c14fab6f00c2680d4489fbee7baf796e4f moved MODULE_INIT_QOM to -way before MODULE_INIT_MACHINE, thereby breaking assumptions made in -spice-core.c which registered both a type initializer and a machine -intializer. - -This fix removes the type registration, and replaces it with calling -qemu_spice_init in vl.c after command line parsing (second pass) is -done, and after timers are armed, required by spice server. - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann - -Conflicts: - - ui/spice-core.c ---- - ui/spice-core.c | 8 +------- - vl.c | 5 +++++ - 2 files changed, 6 insertions(+), 7 deletions(-) - -diff --git a/ui/spice-core.c b/ui/spice-core.c -index 4ad0a67..a468524 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -554,7 +554,7 @@ void qemu_spice_init(void) - - qemu_thread_get_self(&me); - -- if (!opts) { -+ if (!opts) { - return; - } - port = qemu_opt_get_number(opts, "port", 0); -@@ -787,9 +787,3 @@ static void spice_register_config(void) - qemu_add_opts(&qemu_spice_opts); - } - machine_init(spice_register_config); -- --static void spice_initialize(void) --{ -- qemu_spice_init(); --} --device_init(spice_initialize); -diff --git a/vl.c b/vl.c -index fdefa86..d33eb03 100644 ---- a/vl.c -+++ b/vl.c -@@ -3271,6 +3271,11 @@ int main(int argc, char **argv, char **envp) - exit(1); - } - -+#ifdef CONFIG_SPICE -+ /* spice needs the timers to be initialized by this point */ -+ qemu_spice_init(); -+#endif -+ - if (icount_option && (kvm_enabled() || xen_enabled())) { - fprintf(stderr, "-icount is not allowed with kvm or xen\n"); - exit(1); --- -1.7.10 - diff --git a/0429-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch b/0429-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch deleted file mode 100644 index 27fb514..0000000 --- a/0429-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 2b4d2ccd83280b22d2fea0801e11af5a944a135d Mon Sep 17 00:00:00 2001 -From: Peter Maydell -Date: Wed, 7 Mar 2012 13:36:48 +0000 -Subject: [PATCH 429/434] ui/spice-display.c: Fix compilation warnings on 32 - bit hosts - -Fix compilation failures ("cast from pointer to integer of -different size [-Werror=pointer-to-int-cast]") by using -uintptr_t instead. - -Signed-off-by: Peter Maydell -Signed-off-by: Gerd Hoffmann ---- - ui/spice-display.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 28d6d4a..6d7563f 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -80,8 +80,8 @@ void qemu_spice_add_memslot(SimpleSpiceDisplay *ssd, QXLDevMemSlot *memslot, - - if (async != QXL_SYNC) { - spice_qxl_add_memslot_async(&ssd->qxl, memslot, -- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -- QXL_IO_MEMSLOT_ADD_ASYNC)); -+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_MEMSLOT_ADD_ASYNC)); - } else { - ssd->worker->add_memslot(ssd->worker, memslot); - } -@@ -100,8 +100,8 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, - trace_qemu_spice_create_primary_surface(ssd->qxl.id, id, surface, async); - if (async != QXL_SYNC) { - spice_qxl_create_primary_surface_async(&ssd->qxl, id, surface, -- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -- QXL_IO_CREATE_PRIMARY_ASYNC)); -+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_CREATE_PRIMARY_ASYNC)); - } else { - ssd->worker->create_primary_surface(ssd->worker, id, surface); - } -@@ -113,8 +113,8 @@ void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, - trace_qemu_spice_destroy_primary_surface(ssd->qxl.id, id, async); - if (async != QXL_SYNC) { - spice_qxl_destroy_primary_surface_async(&ssd->qxl, id, -- (uint64_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -- QXL_IO_DESTROY_PRIMARY_ASYNC)); -+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_DESTROY_PRIMARY_ASYNC)); - } else { - ssd->worker->destroy_primary_surface(ssd->worker, id); - } --- -1.7.10 - diff --git a/0430-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch b/0430-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch deleted file mode 100644 index bdfc59e..0000000 --- a/0430-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch +++ /dev/null @@ -1,78 +0,0 @@ -From 626eb7b96445815945600895a411ee14c10b9056 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 21 Mar 2012 18:17:18 +0200 -Subject: [PATCH 430/434] ui/spice-display: use uintptr_t when casting qxl - physical addresses - -The current intptr_t casts are a problem when the address's highest -bit is 1, and it is cast to a intptr_t and then to uint64_t, such -as at: - surface.mem = (intptr_t)ssd->buf; - -This causes the sign bit to be extended which causes a wrong address to -be passed on to spice, which then complains when it gets the wrong -slot_id number, since the slot_id is taken from the higher bits. - -The assertion happens early - during the first primary surface creation. - -This fixes running "-vga qxl -spice" with 32 bit compiled -qemu-system-i386. - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - ui/spice-display.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 6d7563f..cb8a7ad 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -168,7 +168,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) - drawable->bbox = ssd->dirty; - drawable->clip.type = SPICE_CLIP_TYPE_NONE; - drawable->effect = QXL_EFFECT_OPAQUE; -- drawable->release_info.id = (intptr_t)update; -+ drawable->release_info.id = (uintptr_t)update; - drawable->type = QXL_DRAW_COPY; - drawable->surfaces_dest[0] = -1; - drawable->surfaces_dest[1] = -1; -@@ -179,7 +179,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) - + time_space.tv_nsec / 1000 / 1000; - - drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; -- drawable->u.copy.src_bitmap = (intptr_t)image; -+ drawable->u.copy.src_bitmap = (uintptr_t)image; - drawable->u.copy.src_area.right = bw; - drawable->u.copy.src_area.bottom = bh; - -@@ -189,7 +189,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) - image->bitmap.stride = bw * 4; - image->descriptor.width = image->bitmap.x = bw; - image->descriptor.height = image->bitmap.y = bh; -- image->bitmap.data = (intptr_t)(update->bitmap); -+ image->bitmap.data = (uintptr_t)(update->bitmap); - image->bitmap.palette = 0; - image->bitmap.format = SPICE_BITMAP_FMT_32BIT; - -@@ -210,7 +210,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) - } - - cmd->type = QXL_CMD_DRAW; -- cmd->data = (intptr_t)drawable; -+ cmd->data = (uintptr_t)drawable; - - memset(&ssd->dirty, 0, sizeof(ssd->dirty)); - return update; -@@ -254,7 +254,7 @@ void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) - surface.mouse_mode = true; - surface.flags = 0; - surface.type = 0; -- surface.mem = (intptr_t)ssd->buf; -+ surface.mem = (uintptr_t)ssd->buf; - surface.group_id = MEMSLOT_GROUP_HOST; - - qemu_spice_create_primary_surface(ssd, 0, &surface, QXL_SYNC); --- -1.7.10 - diff --git a/0431-qxl-add-optinal-64bit-vram-bar.patch b/0431-qxl-add-optinal-64bit-vram-bar.patch deleted file mode 100644 index f686f01..0000000 --- a/0431-qxl-add-optinal-64bit-vram-bar.patch +++ /dev/null @@ -1,185 +0,0 @@ -From f1e729a041efbd2d562e8202407e927745210bbd Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 14 Oct 2011 18:05:48 +0200 -Subject: [PATCH 431/434] qxl: add optinal 64bit vram bar - -This patch adds an 64bit pci bar for vram. It is turned off by default. -It can be enabled by setting the size of the 64bit bar to be larger than -the 32bit bar. Both 32bit and 64bit bar refer to the same memory. Only -the first part of the memory is available via 32bit bar. - -The intention is to allow large vram sizes for 64bit guests, by allowing -the vram bar being mapped above 4G, so we don't have to squeeze it into -the pci I/O window below 4G. - -With vram_size_mb=16 and vram64_size_mb=256 it looks like this: - -00:02.0 VGA compatible controller: Red Hat, Inc. Device 0100 (rev 02) (prog-if 00 [VGA controller]) - Subsystem: Red Hat, Inc Device 1100 - Physical Slot: 2 - Flags: fast devsel, IRQ 10 - Memory at f8000000 (32-bit, non-prefetchable) [size=64M] - Memory at fc000000 (32-bit, non-prefetchable) [size=16M] - Memory at fd020000 (32-bit, non-prefetchable) [size=8K] - I/O ports at c5a0 [size=32] - Memory at ffe0000000 (64-bit, prefetchable) [size=256M] - Expansion ROM at fd000000 [disabled] [size=64K] - -[ mapping above 4G needs patched seabios: - http://www.kraxel.org/cgit/seabios/commit/?h=pci64 ] - -Conflicts: - - hw/qxl.c ---- - hw/qxl.c | 51 ++++++++++++++++++++++++++++++++++++++++++++------- - hw/qxl.h | 7 +++++++ - 2 files changed, 51 insertions(+), 7 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index bcdf274..18f3759 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1002,6 +1002,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, - static const int regions[] = { - QXL_RAM_RANGE_INDEX, - QXL_VRAM_RANGE_INDEX, -+ QXL_VRAM64_RANGE_INDEX, - }; - uint64_t guest_start; - uint64_t guest_end; -@@ -1046,6 +1047,7 @@ static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta, - virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vga.vram); - break; - case QXL_VRAM_RANGE_INDEX: -+ case 4 /* vram 64bit */: - virt_start = (intptr_t)memory_region_get_ram_ptr(&d->vram_bar); - break; - default: -@@ -1630,18 +1632,28 @@ static void qxl_init_ramsize(PCIQXLDevice *qxl, uint32_t ram_min_mb) - qxl->vga.vram_size = ram_min_mb * 1024 * 1024; - } - -- /* vram (surfaces, bar 1) */ -+ /* vram32 (surfaces, 32bit, bar 1) */ -+ if (qxl->vram32_size_mb != -1) { -+ qxl->vram32_size = qxl->vram32_size_mb * 1024 * 1024; -+ } -+ if (qxl->vram32_size < 4096) { -+ qxl->vram32_size = 4096; -+ } -+ -+ /* vram (surfaces, 64bit, bar 4+5) */ - if (qxl->vram_size_mb != -1) { - qxl->vram_size = qxl->vram_size_mb * 1024 * 1024; - } -- if (qxl->vram_size < 4096) { -- qxl->vram_size = 4096; -+ if (qxl->vram_size < qxl->vram32_size) { -+ qxl->vram_size = qxl->vram32_size; - } -+ - if (qxl->revision == 1) { -+ qxl->vram32_size = 4096; - qxl->vram_size = 4096; - } -- - qxl->vga.vram_size = msb_mask(qxl->vga.vram_size * 2 - 1); -+ qxl->vram32_size = msb_mask(qxl->vram32_size * 2 - 1); - qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); - } - -@@ -1683,6 +1695,8 @@ static int qxl_init_common(PCIQXLDevice *qxl) - - memory_region_init_ram(&qxl->vram_bar, &qxl->pci.qdev, "qxl.vram", - qxl->vram_size); -+ memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar, -+ 0, qxl->vram32_size); - - io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); - if (qxl->revision == 1) { -@@ -1706,7 +1720,29 @@ static int qxl_init_common(PCIQXLDevice *qxl) - PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vga.vram); - - pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, -- PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram_bar); -+ PCI_BASE_ADDRESS_SPACE_MEMORY, &qxl->vram32_bar); -+ -+ if (qxl->vram32_size < qxl->vram_size) { -+ /* -+ * Make the 64bit vram bar show up only in case it is -+ * configured to be larger than the 32bit vram bar. -+ */ -+ pci_register_bar(&qxl->pci, QXL_VRAM64_RANGE_INDEX, -+ PCI_BASE_ADDRESS_SPACE_MEMORY | -+ PCI_BASE_ADDRESS_MEM_TYPE_64 | -+ PCI_BASE_ADDRESS_MEM_PREFETCH, -+ &qxl->vram_bar); -+ } -+ -+ /* print pci bar details */ -+ dprint(qxl, 1, "ram/%s: %d MB [region 0]\n", -+ qxl->id == 0 ? "pri" : "sec", -+ qxl->vga.vram_size / (1024*1024)); -+ dprint(qxl, 1, "vram/32: %d MB [region 1]\n", -+ qxl->vram32_size / (1024*1024)); -+ dprint(qxl, 1, "vram/64: %d MB %s\n", -+ qxl->vram_size / (1024*1024), -+ qxl->vram32_size < qxl->vram_size ? "[region 4]" : "[unmapped]"); - - qxl->ssd.qxl.base.sif = &qxl_interface.base; - qxl->ssd.qxl.id = qxl->id; -@@ -1918,7 +1954,7 @@ static VMStateDescription qxl_vmstate = { - static Property qxl_properties[] = { - DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, - 64 * 1024 * 1024), -- DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, -+ DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram32_size, - 64 * 1024 * 1024), - DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, - QXL_DEFAULT_REVISION), -@@ -1926,7 +1962,8 @@ static Property qxl_properties[] = { - DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), - DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), - DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), -- DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram_size_mb, -1), -+ DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, 0), -+ DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, 0), - DEFINE_PROP_END_OF_LIST(), - }; - -diff --git a/hw/qxl.h b/hw/qxl.h -index 86e415b..11a0db3 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -16,6 +16,10 @@ enum qxl_mode { - QXL_MODE_NATIVE, - }; - -+#ifndef QXL_VRAM64_RANGE_INDEX -+#define QXL_VRAM64_RANGE_INDEX 4 -+#endif -+ - #define QXL_UNDEFINED_IO UINT32_MAX - - #define QXL_NUM_DIRTY_RECTS 64 -@@ -88,6 +92,8 @@ typedef struct PCIQXLDevice { - /* vram pci bar */ - uint32_t vram_size; - MemoryRegion vram_bar; -+ uint32_t vram32_size; -+ MemoryRegion vram32_bar; - - /* io bar */ - MemoryRegion io_bar; -@@ -95,6 +101,7 @@ typedef struct PCIQXLDevice { - /* user-friendly properties (in megabytes) */ - uint32_t ram_size_mb; - uint32_t vram_size_mb; -+ uint32_t vram32_size_mb; - - /* qxl_render_update state */ - int render_update_cookie_num; --- -1.7.10 - diff --git a/0432-qxl-set-default-values-of-vram-_size_mb-to-1.patch b/0432-qxl-set-default-values-of-vram-_size_mb-to-1.patch deleted file mode 100644 index 3972342..0000000 --- a/0432-qxl-set-default-values-of-vram-_size_mb-to-1.patch +++ /dev/null @@ -1,35 +0,0 @@ -From c18b8163ec4ebec3a7f99865038fa1ad36b2add2 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Thu, 29 Mar 2012 22:24:38 +0200 -Subject: [PATCH 432/434] qxl: set default values of vram*_size_mb to -1 - -The addition of those values caused a regression where not specifying -any value for the vram bar size would result in a 4096 _byte_ surface -area. This is ok for the windows driver but causes the X driver to be -unusable. Also, it's a regression. This patch returns the default -behavior of having a 64 megabyte vram BAR. - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 18f3759..2135fde 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1962,8 +1962,8 @@ static Property qxl_properties[] = { - DEFINE_PROP_UINT32("guestdebug", PCIQXLDevice, guestdebug, 0), - DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), - DEFINE_PROP_UINT32("ram_size_mb", PCIQXLDevice, ram_size_mb, -1), -- DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, 0), -- DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, 0), -+ DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1), -+ DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1), - DEFINE_PROP_END_OF_LIST(), - }; - --- -1.7.10 - diff --git a/0433-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch b/0433-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch deleted file mode 100644 index 16e821e..0000000 --- a/0433-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 68fc3d666b28d14c5023c1f2115cd3a51389f838 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 18 Apr 2012 12:24:28 +0300 -Subject: [PATCH 433/434] qxl-render: fix broken vnc+spice since commit - f934493 - -Notify any listeners such as vnc that the displaysurface has been -changed, otherwise they will segfault when first accessing the freed old -displaysurface data. - -Signed-off-by: Alon Levy ---- - hw/qxl-render.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index 835dc5e..180b8f9 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -127,6 +127,7 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) - qemu_resize_displaysurface(vga->ds, - qxl->guest_primary.surface.width, - qxl->guest_primary.surface.height); -+ dpy_resize(vga->ds); - } - } - for (i = 0; i < qxl->num_dirty_rects; i++) { --- -1.7.10 - diff --git a/0434-qxl-don-t-assert-on-guest-create_guest_primary.patch b/0434-qxl-don-t-assert-on-guest-create_guest_primary.patch deleted file mode 100644 index f98970f..0000000 --- a/0434-qxl-don-t-assert-on-guest-create_guest_primary.patch +++ /dev/null @@ -1,36 +0,0 @@ -From f9f547a6646d72204d88a79960191a0285774c23 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 18 Apr 2012 14:00:06 +0300 -Subject: [PATCH 434/434] qxl: don't assert on guest create_guest_primary - -initiate the implicit destroy ourselves. - -Signed-off-by: Alon Levy ---- - hw/qxl.c | 10 +++++++++- - 1 file changed, 9 insertions(+), 1 deletion(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 2135fde..29c8873 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1123,7 +1123,15 @@ static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm, - QXLDevSurfaceCreate surface; - QXLSurfaceCreate *sc = &qxl->guest_primary.surface; - -- assert(qxl->mode != QXL_MODE_NATIVE); -+ if (qxl->mode == QXL_MODE_NATIVE) { -+ /* -+ * allow a create without a destroy. This could be used -+ * later for an atomic "change primary" but right now just -+ * destroy the primary for the guest. Note that this uses -+ * the ability to have multiple concurrent async commands. -+ */ -+ qxl_destroy_primary(qxl, async); -+ } - qxl_exit_vga_mode(qxl); - - surface.format = le32_to_cpu(sc->format); --- -1.7.10 - diff --git a/0501-audio-add-VOICE_VOLUME-ctl.patch b/0501-audio-add-VOICE_VOLUME-ctl.patch deleted file mode 100644 index b981b77..0000000 --- a/0501-audio-add-VOICE_VOLUME-ctl.patch +++ /dev/null @@ -1,68 +0,0 @@ -From be81272bafb948278e5e5739ef975cd7bbf0ee0c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 17 Apr 2012 14:32:35 +0200 -Subject: [PATCH 501/509] audio: add VOICE_VOLUME ctl - -Add a new PCM control operation to update the stream volume on the -audio backend. The argument given is a SWVoiceOut/SWVoiceIn. - -v4: -- verified other backends didn't fail/assert on this new control - they randomly return 0 or -1, but we ignore return value. - -Signed-off-by: Marc-Andr? Lureau -Signed-off-by: malc ---- - audio/audio.c | 12 ++++++++++++ - audio/audio_int.h | 1 + - 2 files changed, 13 insertions(+) - -diff --git a/audio/audio.c b/audio/audio.c -index 50d0d71..2ae9b2f 100644 ---- a/audio/audio.c -+++ b/audio/audio.c -@@ -2050,17 +2050,29 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) - void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) - { - if (sw) { -+ HWVoiceOut *hw = sw->hw; -+ - sw->vol.mute = mute; - sw->vol.l = nominal_volume.l * lvol / 255; - sw->vol.r = nominal_volume.r * rvol / 255; -+ -+ if (hw->pcm_ops->ctl_out) { -+ hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw); -+ } - } - } - - void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) - { - if (sw) { -+ HWVoiceIn *hw = sw->hw; -+ - sw->vol.mute = mute; - sw->vol.l = nominal_volume.l * lvol / 255; - sw->vol.r = nominal_volume.r * rvol / 255; -+ -+ if (hw->pcm_ops->ctl_in) { -+ hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw); -+ } - } - } -diff --git a/audio/audio_int.h b/audio/audio_int.h -index 2003f8b..117f95e 100644 ---- a/audio/audio_int.h -+++ b/audio/audio_int.h -@@ -231,6 +231,7 @@ void audio_run (const char *msg); - - #define VOICE_ENABLE 1 - #define VOICE_DISABLE 2 -+#define VOICE_VOLUME 3 - - static inline int audio_ring_dist (int dst, int src, int len) - { --- -1.7.10 - diff --git a/0502-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch b/0502-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch deleted file mode 100644 index 656989d..0000000 --- a/0502-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch +++ /dev/null @@ -1,99 +0,0 @@ -From eaa3b2d4cc2ac17b2aaf0d6387d3991b9d08c56e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 17 Apr 2012 14:32:36 +0200 -Subject: [PATCH 502/509] audio: don't apply volume effect if backend has - VOICE_VOLUME_CAP - -If the audio backend is capable of volume control, don't apply -software volume (mixeng_volume ()), but instead, rely on backend -volume control. This will allow guest to have full range volume -control. - -Signed-off-by: Marc-Andr? Lureau -Signed-off-by: malc ---- - audio/audio.c | 9 +++++++-- - audio/audio_int.h | 5 +++++ - audio/audio_template.h | 2 ++ - 3 files changed, 14 insertions(+), 2 deletions(-) - -diff --git a/audio/audio.c b/audio/audio.c -index 2ae9b2f..0fe95a7 100644 ---- a/audio/audio.c -+++ b/audio/audio.c -@@ -954,7 +954,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) - total += isamp; - } - -- mixeng_volume (sw->buf, ret, &sw->vol); -+ if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) { -+ mixeng_volume (sw->buf, ret, &sw->vol); -+ } - - sw->clip (buf, sw->buf, ret); - sw->total_hw_samples_acquired += total; -@@ -1038,7 +1040,10 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) - swlim = audio_MIN (swlim, samples); - if (swlim) { - sw->conv (sw->buf, buf, swlim); -- mixeng_volume (sw->buf, swlim, &sw->vol); -+ -+ if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { -+ mixeng_volume (sw->buf, swlim, &sw->vol); -+ } - } - - while (swlim) { -diff --git a/audio/audio_int.h b/audio/audio_int.h -index 117f95e..b9b0676 100644 ---- a/audio/audio_int.h -+++ b/audio/audio_int.h -@@ -82,6 +82,7 @@ typedef struct HWVoiceOut { - int samples; - QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; - QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; -+ int ctl_caps; - struct audio_pcm_ops *pcm_ops; - QLIST_ENTRY (HWVoiceOut) entries; - } HWVoiceOut; -@@ -101,6 +102,7 @@ typedef struct HWVoiceIn { - - int samples; - QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; -+ int ctl_caps; - struct audio_pcm_ops *pcm_ops; - QLIST_ENTRY (HWVoiceIn) entries; - } HWVoiceIn; -@@ -150,6 +152,7 @@ struct audio_driver { - int max_voices_in; - int voice_size_out; - int voice_size_in; -+ int ctl_caps; - }; - - struct audio_pcm_ops { -@@ -233,6 +236,8 @@ void audio_run (const char *msg); - #define VOICE_DISABLE 2 - #define VOICE_VOLUME 3 - -+#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME) -+ - static inline int audio_ring_dist (int dst, int src, int len) - { - return (dst >= src) ? (dst - src) : (len - src + dst); -diff --git a/audio/audio_template.h b/audio/audio_template.h -index e62a713..519432a 100644 ---- a/audio/audio_template.h -+++ b/audio/audio_template.h -@@ -263,6 +263,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) - } - - hw->pcm_ops = drv->pcm_ops; -+ hw->ctl_caps = drv->ctl_caps; -+ - QLIST_INIT (&hw->sw_head); - #ifdef DAC - QLIST_INIT (&hw->cap_head); --- -1.7.10 - diff --git a/0503-hw-ac97-remove-USE_MIXER-code.patch b/0503-hw-ac97-remove-USE_MIXER-code.patch deleted file mode 100644 index 763773a..0000000 --- a/0503-hw-ac97-remove-USE_MIXER-code.patch +++ /dev/null @@ -1,170 +0,0 @@ -From e27e5ceeee3d8cb55ba0749446b49ccc6ec5b96d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 17 Apr 2012 14:32:37 +0200 -Subject: [PATCH 503/509] hw/ac97: remove USE_MIXER code - -That code doesn't compile. The interesting bits for volume control are -going to be rewritten in the following patch. - -Signed-off-by: Marc-Andr? Lureau -Signed-off-by: malc ---- - hw/ac97.c | 121 ------------------------------------------------------------- - 1 file changed, 121 deletions(-) - -diff --git a/hw/ac97.c b/hw/ac97.c -index 0dbba3b..cd893c3 100644 ---- a/hw/ac97.c -+++ b/hw/ac97.c -@@ -434,99 +434,6 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) - AUD_set_active_in (s->voice_mc, active[MC_INDEX]); - } - --#ifdef USE_MIXER --static void set_volume (AC97LinkState *s, int index, -- audmixerctl_t mt, uint32_t val) --{ -- int mute = (val >> MUTE_SHIFT) & 1; -- uint8_t rvol = VOL_MASK - (val & VOL_MASK); -- uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK); -- rvol = 255 * rvol / VOL_MASK; -- lvol = 255 * lvol / VOL_MASK; -- --#ifdef SOFT_VOLUME -- if (index == AC97_Master_Volume_Mute) { -- AUD_set_volume_out (s->voice_po, mute, lvol, rvol); -- } -- else { -- AUD_set_volume (mt, &mute, &lvol, &rvol); -- } --#else -- AUD_set_volume (mt, &mute, &lvol, &rvol); --#endif -- -- rvol = VOL_MASK - ((VOL_MASK * rvol) / 255); -- lvol = VOL_MASK - ((VOL_MASK * lvol) / 255); -- mixer_store (s, index, val); --} -- --static audrecsource_t ac97_to_aud_record_source (uint8_t i) --{ -- switch (i) { -- case REC_MIC: -- return AUD_REC_MIC; -- -- case REC_CD: -- return AUD_REC_CD; -- -- case REC_VIDEO: -- return AUD_REC_VIDEO; -- -- case REC_AUX: -- return AUD_REC_AUX; -- -- case REC_LINE_IN: -- return AUD_REC_LINE_IN; -- -- case REC_PHONE: -- return AUD_REC_PHONE; -- -- default: -- dolog ("Unknown record source %d, using MIC\n", i); -- return AUD_REC_MIC; -- } --} -- --static uint8_t aud_to_ac97_record_source (audrecsource_t rs) --{ -- switch (rs) { -- case AUD_REC_MIC: -- return REC_MIC; -- -- case AUD_REC_CD: -- return REC_CD; -- -- case AUD_REC_VIDEO: -- return REC_VIDEO; -- -- case AUD_REC_AUX: -- return REC_AUX; -- -- case AUD_REC_LINE_IN: -- return REC_LINE_IN; -- -- case AUD_REC_PHONE: -- return REC_PHONE; -- -- default: -- dolog ("Unknown audio recording source %d using MIC\n", rs); -- return REC_MIC; -- } --} -- --static void record_select (AC97LinkState *s, uint32_t val) --{ -- uint8_t rs = val & REC_MASK; -- uint8_t ls = (val >> 8) & REC_MASK; -- audrecsource_t ars = ac97_to_aud_record_source (rs); -- audrecsource_t als = ac97_to_aud_record_source (ls); -- AUD_set_record_source (&als, &ars); -- rs = aud_to_ac97_record_source (ars); -- ls = aud_to_ac97_record_source (als); -- mixer_store (s, AC97_Record_Select, rs | (ls << 8)); --} --#endif -- - static void mixer_reset (AC97LinkState *s) - { - uint8_t active[LAST_INDEX]; -@@ -561,12 +468,6 @@ static void mixer_reset (AC97LinkState *s) - mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); - mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); - --#ifdef USE_MIXER -- record_select (s, 0); -- set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME , 0x8000); -- set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM , 0x8808); -- set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); --#endif - reset_voices (s, active); - } - -@@ -625,20 +526,6 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) - val |= mixer_load (s, index) & 0xf; - mixer_store (s, index, val); - break; --#ifdef USE_MIXER -- case AC97_Master_Volume_Mute: -- set_volume (s, index, AUD_MIXER_VOLUME, val); -- break; -- case AC97_PCM_Out_Volume_Mute: -- set_volume (s, index, AUD_MIXER_PCM, val); -- break; -- case AC97_Line_In_Volume_Mute: -- set_volume (s, index, AUD_MIXER_LINE_IN, val); -- break; -- case AC97_Record_Select: -- record_select (s, val); -- break; --#endif - case AC97_Vendor_ID1: - case AC97_Vendor_ID2: - dolog ("Attempt to write vendor ID to %#x\n", val); -@@ -1191,14 +1078,6 @@ static int ac97_post_load (void *opaque, int version_id) - uint8_t active[LAST_INDEX]; - AC97LinkState *s = opaque; - --#ifdef USE_MIXER -- record_select (s, mixer_load (s, AC97_Record_Select)); --#define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) -- V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); -- V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); -- V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); --#undef V_ --#endif - active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); - active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); - active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); --- -1.7.10 - diff --git a/0504-hw-ac97-the-volume-mask-is-not-only-0x1f.patch b/0504-hw-ac97-the-volume-mask-is-not-only-0x1f.patch deleted file mode 100644 index 015f995..0000000 --- a/0504-hw-ac97-the-volume-mask-is-not-only-0x1f.patch +++ /dev/null @@ -1,28 +0,0 @@ -From c0bcb346459445db2895fb56c78ab71e592c0c90 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 17 Apr 2012 14:32:38 +0200 -Subject: [PATCH 504/509] hw/ac97: the volume mask is not only 0x1f - -It's a case by case (see Table 66. AC ?97 Baseline Audio Register Map) - -Signed-off-by: Marc-Andr? Lureau -Signed-off-by: malc ---- - hw/ac97.c | 1 - - 1 file changed, 1 deletion(-) - -diff --git a/hw/ac97.c b/hw/ac97.c -index cd893c3..aa1babf 100644 ---- a/hw/ac97.c -+++ b/hw/ac97.c -@@ -115,7 +115,6 @@ enum { - #define EACS_VRA 1 - #define EACS_VRM 8 - --#define VOL_MASK 0x1f - #define MUTE_SHIFT 15 - - #define REC_MASK 7 --- -1.7.10 - diff --git a/0505-hw-ac97-add-support-for-volume-control.patch b/0505-hw-ac97-add-support-for-volume-control.patch deleted file mode 100644 index 551ae8e..0000000 --- a/0505-hw-ac97-add-support-for-volume-control.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 41d13bd2047a3a3ae8f451ff4aaf0585231ba1c6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 17 Apr 2012 14:32:39 +0200 -Subject: [PATCH 505/509] hw/ac97: add support for volume control - -Combine output volume with Master and PCM registers values. -Use default values in mixer_reset (). -Set volume on post-load to update backend values. - -v4,v5: -- fix some code style - -Signed-off-by: Marc-Andr? Lureau -Signed-off-by: malc ---- - hw/ac97.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 81 insertions(+) - -diff --git a/hw/ac97.c b/hw/ac97.c -index aa1babf..dd4917b 100644 ---- a/hw/ac97.c -+++ b/hw/ac97.c -@@ -433,6 +433,65 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) - AUD_set_active_in (s->voice_mc, active[MC_INDEX]); - } - -+static void get_volume (uint16_t vol, uint16_t mask, int inverse, -+ int *mute, uint8_t *lvol, uint8_t *rvol) -+{ -+ *mute = (vol >> MUTE_SHIFT) & 1; -+ *rvol = (255 * (vol & mask)) / mask; -+ *lvol = (255 * ((vol >> 8) & mask)) / mask; -+ -+ if (inverse) { -+ *rvol = 255 - *rvol; -+ *lvol = 255 - *lvol; -+ } -+} -+ -+static void update_combined_volume_out (AC97LinkState *s) -+{ -+ uint8_t lvol, rvol, plvol, prvol; -+ int mute, pmute; -+ -+ get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, -+ &mute, &lvol, &rvol); -+ /* FIXME: should be 1f according to spec */ -+ get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1, -+ &pmute, &plvol, &prvol); -+ -+ mute = mute | pmute; -+ lvol = (lvol * plvol) / 255; -+ rvol = (rvol * prvol) / 255; -+ -+ AUD_set_volume_out (s->voice_po, mute, lvol, rvol); -+} -+ -+static void update_volume_in (AC97LinkState *s) -+{ -+ uint8_t lvol, rvol; -+ int mute; -+ -+ get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, -+ &mute, &lvol, &rvol); -+ -+ AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); -+} -+ -+static void set_volume (AC97LinkState *s, int index, uint32_t val) -+{ -+ mixer_store (s, index, val); -+ if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) { -+ update_combined_volume_out (s); -+ } else if (index == AC97_Record_Gain_Mute) { -+ update_volume_in (s); -+ } -+} -+ -+static void record_select (AC97LinkState *s, uint32_t val) -+{ -+ uint8_t rs = val & REC_MASK; -+ uint8_t ls = (val >> 8) & REC_MASK; -+ mixer_store (s, AC97_Record_Select, rs | (ls << 8)); -+} -+ - static void mixer_reset (AC97LinkState *s) - { - uint8_t active[LAST_INDEX]; -@@ -467,6 +526,11 @@ static void mixer_reset (AC97LinkState *s) - mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); - mixer_store (s, AC97_MIC_ADC_Rate , 0xbb80); - -+ record_select (s, 0); -+ set_volume (s, AC97_Master_Volume_Mute, 0x8000); -+ set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); -+ set_volume (s, AC97_Line_In_Volume_Mute, 0x8808); -+ - reset_voices (s, active); - } - -@@ -525,6 +589,15 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) - val |= mixer_load (s, index) & 0xf; - mixer_store (s, index, val); - break; -+ case AC97_PCM_Out_Volume_Mute: -+ case AC97_Master_Volume_Mute: -+ case AC97_Record_Gain_Mute: -+ case AC97_Line_In_Volume_Mute: -+ set_volume (s, index, val); -+ break; -+ case AC97_Record_Select: -+ record_select (s, val); -+ break; - case AC97_Vendor_ID1: - case AC97_Vendor_ID2: - dolog ("Attempt to write vendor ID to %#x\n", val); -@@ -1077,6 +1150,14 @@ static int ac97_post_load (void *opaque, int version_id) - uint8_t active[LAST_INDEX]; - AC97LinkState *s = opaque; - -+ record_select (s, mixer_load (s, AC97_Record_Select)); -+ set_volume (s, AC97_Master_Volume_Mute, -+ mixer_load (s, AC97_Master_Volume_Mute)); -+ set_volume (s, AC97_PCM_Out_Volume_Mute, -+ mixer_load (s, AC97_PCM_Out_Volume_Mute)); -+ set_volume (s, AC97_Line_In_Volume_Mute, -+ mixer_load (s, AC97_Line_In_Volume_Mute)); -+ - active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); - active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); - active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); --- -1.7.10 - diff --git a/0506-audio-spice-add-support-for-volume-control.patch b/0506-audio-spice-add-support-for-volume-control.patch deleted file mode 100644 index e713e87..0000000 --- a/0506-audio-spice-add-support-for-volume-control.patch +++ /dev/null @@ -1,84 +0,0 @@ -From a9f796f670f3c34c3b5874026b61bbe4d782be2e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 17 Apr 2012 14:32:40 +0200 -Subject: [PATCH 506/509] audio/spice: add support for volume control - -Use Spice server volume control API when available. - -Signed-off-by: Marc-Andr? Lureau -Signed-off-by: malc ---- - audio/spiceaudio.c | 41 +++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 41 insertions(+) - -diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c -index f972110..6f15591 100644 ---- a/audio/spiceaudio.c -+++ b/audio/spiceaudio.c -@@ -202,7 +202,26 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) - } - spice_server_playback_stop (&out->sin); - break; -+ case VOICE_VOLUME: -+ { -+#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) -+ SWVoiceOut *sw; -+ va_list ap; -+ uint16_t vol[2]; -+ -+ va_start (ap, cmd); -+ sw = va_arg (ap, SWVoiceOut *); -+ va_end (ap); -+ -+ vol[0] = sw->vol.l / ((1ULL << 16) + 1); -+ vol[1] = sw->vol.r / ((1ULL << 16) + 1); -+ spice_server_playback_set_volume (&out->sin, 2, vol); -+ spice_server_playback_set_mute (&out->sin, sw->vol.mute); -+#endif -+ break; -+ } - } -+ - return 0; - } - -@@ -304,7 +323,26 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) - in->active = 0; - spice_server_record_stop (&in->sin); - break; -+ case VOICE_VOLUME: -+ { -+#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) -+ SWVoiceIn *sw; -+ va_list ap; -+ uint16_t vol[2]; -+ -+ va_start (ap, cmd); -+ sw = va_arg (ap, SWVoiceIn *); -+ va_end (ap); -+ -+ vol[0] = sw->vol.l / ((1ULL << 16) + 1); -+ vol[1] = sw->vol.r / ((1ULL << 16) + 1); -+ spice_server_record_set_volume (&in->sin, 2, vol); -+ spice_server_record_set_mute (&in->sin, sw->vol.mute); -+#endif -+ break; -+ } - } -+ - return 0; - } - -@@ -337,6 +375,9 @@ struct audio_driver spice_audio_driver = { - .max_voices_in = 1, - .voice_size_out = sizeof (SpiceVoiceOut), - .voice_size_in = sizeof (SpiceVoiceIn), -+#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) -+ .ctl_caps = VOICE_VOLUME_CAP -+#endif - }; - - void qemu_spice_audio_init (void) --- -1.7.10 - diff --git a/0507-Do-not-use-pa_simple-PulseAudio-API.patch b/0507-Do-not-use-pa_simple-PulseAudio-API.patch deleted file mode 100644 index 28f7df7..0000000 --- a/0507-Do-not-use-pa_simple-PulseAudio-API.patch +++ /dev/null @@ -1,573 +0,0 @@ -From 5c8ce128ec78d17a8a0f49115dc07726a3d3f0c1 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 17 Apr 2012 14:32:41 +0200 -Subject: [PATCH 507/509] Do not use pa_simple PulseAudio API - -Unfortunately, pa_simple is a limited API which doesn't let us -retrieve the associated pa_stream. It is needed to control the volume -of the stream. - -In v4: -- add missing braces - -Signed-off-by: Marc-Andr? Lureau -Signed-off-by: malc ---- - audio/paaudio.c | 377 +++++++++++++++++++++++++++++++++++++++++++++++++------ - 1 file changed, 339 insertions(+), 38 deletions(-) - -diff --git a/audio/paaudio.c b/audio/paaudio.c -index d1f3912..6f50c1c 100644 ---- a/audio/paaudio.c -+++ b/audio/paaudio.c -@@ -2,8 +2,7 @@ - #include "qemu-common.h" - #include "audio.h" - --#include --#include -+#include - - #define AUDIO_CAP "pulseaudio" - #include "audio_int.h" -@@ -15,7 +14,7 @@ typedef struct { - int live; - int decr; - int rpos; -- pa_simple *s; -+ pa_stream *stream; - void *pcm_buf; - struct audio_pt pt; - } PAVoiceOut; -@@ -26,17 +25,23 @@ typedef struct { - int dead; - int incr; - int wpos; -- pa_simple *s; -+ pa_stream *stream; - void *pcm_buf; - struct audio_pt pt; -+ const void *read_data; -+ size_t read_index, read_length; - } PAVoiceIn; - --static struct { -+typedef struct { - int samples; - char *server; - char *sink; - char *source; --} conf = { -+ pa_threaded_mainloop *mainloop; -+ pa_context *context; -+} paaudio; -+ -+static paaudio glob_paaudio = { - .samples = 4096, - }; - -@@ -51,6 +56,126 @@ static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) - AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err)); - } - -+#define CHECK_SUCCESS_GOTO(c, rerror, expression, label) \ -+ do { \ -+ if (!(expression)) { \ -+ if (rerror) { \ -+ *(rerror) = pa_context_errno ((c)->context); \ -+ } \ -+ goto label; \ -+ } \ -+ } while (0); -+ -+#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ -+ do { \ -+ if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ -+ !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \ -+ if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ -+ ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ -+ if (rerror) { \ -+ *(rerror) = pa_context_errno ((c)->context); \ -+ } \ -+ } else { \ -+ if (rerror) { \ -+ *(rerror) = PA_ERR_BADSTATE; \ -+ } \ -+ } \ -+ goto label; \ -+ } \ -+ } while (0); -+ -+static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror) -+{ -+ paaudio *g = &glob_paaudio; -+ -+ pa_threaded_mainloop_lock (g->mainloop); -+ -+ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); -+ -+ while (length > 0) { -+ size_t l; -+ -+ while (!p->read_data) { -+ int r; -+ -+ r = pa_stream_peek (p->stream, &p->read_data, &p->read_length); -+ CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); -+ -+ if (!p->read_data) { -+ pa_threaded_mainloop_wait (g->mainloop); -+ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); -+ } else { -+ p->read_index = 0; -+ } -+ } -+ -+ l = p->read_length < length ? p->read_length : length; -+ memcpy (data, (const uint8_t *) p->read_data+p->read_index, l); -+ -+ data = (uint8_t *) data + l; -+ length -= l; -+ -+ p->read_index += l; -+ p->read_length -= l; -+ -+ if (!p->read_length) { -+ int r; -+ -+ r = pa_stream_drop (p->stream); -+ p->read_data = NULL; -+ p->read_length = 0; -+ p->read_index = 0; -+ -+ CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); -+ } -+ } -+ -+ pa_threaded_mainloop_unlock (g->mainloop); -+ return 0; -+ -+unlock_and_fail: -+ pa_threaded_mainloop_unlock (g->mainloop); -+ return -1; -+} -+ -+static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror) -+{ -+ paaudio *g = &glob_paaudio; -+ -+ pa_threaded_mainloop_lock (g->mainloop); -+ -+ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); -+ -+ while (length > 0) { -+ size_t l; -+ int r; -+ -+ while (!(l = pa_stream_writable_size (p->stream))) { -+ pa_threaded_mainloop_wait (g->mainloop); -+ CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); -+ } -+ -+ CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail); -+ -+ if (l > length) { -+ l = length; -+ } -+ -+ r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE); -+ CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail); -+ -+ data = (const uint8_t *) data + l; -+ length -= l; -+ } -+ -+ pa_threaded_mainloop_unlock (g->mainloop); -+ return 0; -+ -+unlock_and_fail: -+ pa_threaded_mainloop_unlock (g->mainloop); -+ return -1; -+} -+ - static void *qpa_thread_out (void *arg) - { - PAVoiceOut *pa = arg; -@@ -77,7 +202,7 @@ static void *qpa_thread_out (void *arg) - } - } - -- decr = to_mix = audio_MIN (pa->live, conf.samples >> 2); -+ decr = to_mix = audio_MIN (pa->live, glob_paaudio.samples >> 2); - rpos = pa->rpos; - - if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { -@@ -91,8 +216,8 @@ static void *qpa_thread_out (void *arg) - - hw->clip (pa->pcm_buf, src, chunk); - -- if (pa_simple_write (pa->s, pa->pcm_buf, -- chunk << hw->info.shift, &error) < 0) { -+ if (qpa_simple_write (pa, pa->pcm_buf, -+ chunk << hw->info.shift, &error) < 0) { - qpa_logerr (error, "pa_simple_write failed\n"); - return NULL; - } -@@ -169,7 +294,7 @@ static void *qpa_thread_in (void *arg) - } - } - -- incr = to_grab = audio_MIN (pa->dead, conf.samples >> 2); -+ incr = to_grab = audio_MIN (pa->dead, glob_paaudio.samples >> 2); - wpos = pa->wpos; - - if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { -@@ -181,8 +306,8 @@ static void *qpa_thread_in (void *arg) - int chunk = audio_MIN (to_grab, hw->samples - wpos); - void *buf = advance (pa->pcm_buf, wpos); - -- if (pa_simple_read (pa->s, buf, -- chunk << hw->info.shift, &error) < 0) { -+ if (qpa_simple_read (pa, buf, -+ chunk << hw->info.shift, &error) < 0) { - qpa_logerr (error, "pa_simple_read failed\n"); - return NULL; - } -@@ -283,6 +408,109 @@ static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness) - } - } - -+static void context_state_cb (pa_context *c, void *userdata) -+{ -+ paaudio *g = &glob_paaudio; -+ -+ switch (pa_context_get_state(c)) { -+ case PA_CONTEXT_READY: -+ case PA_CONTEXT_TERMINATED: -+ case PA_CONTEXT_FAILED: -+ pa_threaded_mainloop_signal (g->mainloop, 0); -+ break; -+ -+ case PA_CONTEXT_UNCONNECTED: -+ case PA_CONTEXT_CONNECTING: -+ case PA_CONTEXT_AUTHORIZING: -+ case PA_CONTEXT_SETTING_NAME: -+ break; -+ } -+} -+ -+static void stream_state_cb (pa_stream *s, void * userdata) -+{ -+ paaudio *g = &glob_paaudio; -+ -+ switch (pa_stream_get_state (s)) { -+ -+ case PA_STREAM_READY: -+ case PA_STREAM_FAILED: -+ case PA_STREAM_TERMINATED: -+ pa_threaded_mainloop_signal (g->mainloop, 0); -+ break; -+ -+ case PA_STREAM_UNCONNECTED: -+ case PA_STREAM_CREATING: -+ break; -+ } -+} -+ -+static void stream_request_cb (pa_stream *s, size_t length, void *userdata) -+{ -+ paaudio *g = &glob_paaudio; -+ -+ pa_threaded_mainloop_signal (g->mainloop, 0); -+} -+ -+static pa_stream *qpa_simple_new ( -+ const char *server, -+ const char *name, -+ pa_stream_direction_t dir, -+ const char *dev, -+ const char *stream_name, -+ const pa_sample_spec *ss, -+ const pa_channel_map *map, -+ const pa_buffer_attr *attr, -+ int *rerror) -+{ -+ paaudio *g = &glob_paaudio; -+ int r; -+ pa_stream *stream; -+ -+ pa_threaded_mainloop_lock (g->mainloop); -+ -+ stream = pa_stream_new (g->context, name, ss, map); -+ if (!stream) { -+ goto fail; -+ } -+ -+ pa_stream_set_state_callback (stream, stream_state_cb, g); -+ pa_stream_set_read_callback (stream, stream_request_cb, g); -+ pa_stream_set_write_callback (stream, stream_request_cb, g); -+ -+ if (dir == PA_STREAM_PLAYBACK) { -+ r = pa_stream_connect_playback (stream, dev, attr, -+ PA_STREAM_INTERPOLATE_TIMING -+ |PA_STREAM_ADJUST_LATENCY -+ |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); -+ } else { -+ r = pa_stream_connect_record (stream, dev, attr, -+ PA_STREAM_INTERPOLATE_TIMING -+ |PA_STREAM_ADJUST_LATENCY -+ |PA_STREAM_AUTO_TIMING_UPDATE); -+ } -+ -+ if (r < 0) { -+ goto fail; -+ } -+ -+ pa_threaded_mainloop_unlock (g->mainloop); -+ -+ return stream; -+ -+fail: -+ pa_threaded_mainloop_unlock (g->mainloop); -+ -+ if (stream) { -+ pa_stream_unref (stream); -+ } -+ -+ qpa_logerr (pa_context_errno (g->context), -+ "stream_new() failed\n"); -+ -+ return NULL; -+} -+ - static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as) - { - int error; -@@ -306,24 +534,24 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as) - - obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); - -- pa->s = pa_simple_new ( -- conf.server, -+ pa->stream = qpa_simple_new ( -+ glob_paaudio.server, - "qemu", - PA_STREAM_PLAYBACK, -- conf.sink, -+ glob_paaudio.sink, - "pcm.playback", - &ss, - NULL, /* channel map */ - &ba, /* buffering attributes */ - &error - ); -- if (!pa->s) { -+ if (!pa->stream) { - qpa_logerr (error, "pa_simple_new for playback failed\n"); - goto fail1; - } - - audio_pcm_init_info (&hw->info, &obt_as); -- hw->samples = conf.samples; -+ hw->samples = glob_paaudio.samples; - pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - pa->rpos = hw->rpos; - if (!pa->pcm_buf) { -@@ -342,8 +570,10 @@ static int qpa_init_out (HWVoiceOut *hw, struct audsettings *as) - g_free (pa->pcm_buf); - pa->pcm_buf = NULL; - fail2: -- pa_simple_free (pa->s); -- pa->s = NULL; -+ if (pa->stream) { -+ pa_stream_unref (pa->stream); -+ pa->stream = NULL; -+ } - fail1: - return -1; - } -@@ -361,24 +591,24 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as) - - obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); - -- pa->s = pa_simple_new ( -- conf.server, -+ pa->stream = qpa_simple_new ( -+ glob_paaudio.server, - "qemu", - PA_STREAM_RECORD, -- conf.source, -+ glob_paaudio.source, - "pcm.capture", - &ss, - NULL, /* channel map */ - NULL, /* buffering attributes */ - &error - ); -- if (!pa->s) { -+ if (!pa->stream) { - qpa_logerr (error, "pa_simple_new for capture failed\n"); - goto fail1; - } - - audio_pcm_init_info (&hw->info, &obt_as); -- hw->samples = conf.samples; -+ hw->samples = glob_paaudio.samples; - pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - pa->wpos = hw->wpos; - if (!pa->pcm_buf) { -@@ -397,8 +627,10 @@ static int qpa_init_in (HWVoiceIn *hw, struct audsettings *as) - g_free (pa->pcm_buf); - pa->pcm_buf = NULL; - fail2: -- pa_simple_free (pa->s); -- pa->s = NULL; -+ if (pa->stream) { -+ pa_stream_unref (pa->stream); -+ pa->stream = NULL; -+ } - fail1: - return -1; - } -@@ -413,9 +645,9 @@ static void qpa_fini_out (HWVoiceOut *hw) - audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); - audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); - -- if (pa->s) { -- pa_simple_free (pa->s); -- pa->s = NULL; -+ if (pa->stream) { -+ pa_stream_unref (pa->stream); -+ pa->stream = NULL; - } - - audio_pt_fini (&pa->pt, AUDIO_FUNC); -@@ -433,9 +665,9 @@ static void qpa_fini_in (HWVoiceIn *hw) - audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); - audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); - -- if (pa->s) { -- pa_simple_free (pa->s); -- pa->s = NULL; -+ if (pa->stream) { -+ pa_stream_unref (pa->stream); -+ pa->stream = NULL; - } - - audio_pt_fini (&pa->pt, AUDIO_FUNC); -@@ -460,37 +692,106 @@ static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) - /* common */ - static void *qpa_audio_init (void) - { -- return &conf; -+ paaudio *g = &glob_paaudio; -+ -+ g->mainloop = pa_threaded_mainloop_new (); -+ if (!g->mainloop) { -+ goto fail; -+ } -+ -+ g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), glob_paaudio.server); -+ if (!g->context) { -+ goto fail; -+ } -+ -+ pa_context_set_state_callback (g->context, context_state_cb, g); -+ -+ if (pa_context_connect (g->context, glob_paaudio.server, 0, NULL) < 0) { -+ qpa_logerr (pa_context_errno (g->context), -+ "pa_context_connect() failed\n"); -+ goto fail; -+ } -+ -+ pa_threaded_mainloop_lock (g->mainloop); -+ -+ if (pa_threaded_mainloop_start (g->mainloop) < 0) { -+ goto unlock_and_fail; -+ } -+ -+ for (;;) { -+ pa_context_state_t state; -+ -+ state = pa_context_get_state (g->context); -+ -+ if (state == PA_CONTEXT_READY) { -+ break; -+ } -+ -+ if (!PA_CONTEXT_IS_GOOD (state)) { -+ qpa_logerr (pa_context_errno (g->context), -+ "Wrong context state\n"); -+ goto unlock_and_fail; -+ } -+ -+ /* Wait until the context is ready */ -+ pa_threaded_mainloop_wait (g->mainloop); -+ } -+ -+ pa_threaded_mainloop_unlock (g->mainloop); -+ -+ return &glob_paaudio; -+ -+unlock_and_fail: -+ pa_threaded_mainloop_unlock (g->mainloop); -+fail: -+ AUD_log (AUDIO_CAP, "Failed to initialize PA context"); -+ return NULL; - } - - static void qpa_audio_fini (void *opaque) - { -- (void) opaque; -+ paaudio *g = opaque; -+ -+ if (g->mainloop) { -+ pa_threaded_mainloop_stop (g->mainloop); -+ } -+ -+ if (g->context) { -+ pa_context_disconnect (g->context); -+ pa_context_unref (g->context); -+ g->context = NULL; -+ } -+ -+ if (g->mainloop) { -+ pa_threaded_mainloop_free (g->mainloop); -+ } -+ -+ g->mainloop = NULL; - } - - struct audio_option qpa_options[] = { - { - .name = "SAMPLES", - .tag = AUD_OPT_INT, -- .valp = &conf.samples, -+ .valp = &glob_paaudio.samples, - .descr = "buffer size in samples" - }, - { - .name = "SERVER", - .tag = AUD_OPT_STR, -- .valp = &conf.server, -+ .valp = &glob_paaudio.server, - .descr = "server address" - }, - { - .name = "SINK", - .tag = AUD_OPT_STR, -- .valp = &conf.sink, -+ .valp = &glob_paaudio.sink, - .descr = "sink device name" - }, - { - .name = "SOURCE", - .tag = AUD_OPT_STR, -- .valp = &conf.source, -+ .valp = &glob_paaudio.source, - .descr = "source device name" - }, - { /* End of list */ } --- -1.7.10 - diff --git a/0508-configure-pa_simple-is-not-needed-anymore.patch b/0508-configure-pa_simple-is-not-needed-anymore.patch deleted file mode 100644 index 14e8766..0000000 --- a/0508-configure-pa_simple-is-not-needed-anymore.patch +++ /dev/null @@ -1,31 +0,0 @@ -From 1b4ee5ccd426102b9ea415a8ce563bf96d7aa1f4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 17 Apr 2012 14:32:42 +0200 -Subject: [PATCH 508/509] configure: pa_simple is not needed anymore - -Signed-off-by: Marc-Andr? Lureau -Signed-off-by: malc ---- - configure | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/configure b/configure -index b03172c..4559836 100755 ---- a/configure -+++ b/configure -@@ -1791,9 +1791,9 @@ for drv in $audio_drv_list; do - ;; - - pa) -- audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \ -- "pa_simple *s = 0; pa_simple_free(s); return 0;" -- libs_softmmu="-lpulse -lpulse-simple $libs_softmmu" -+ audio_drv_probe $drv pulse/mainloop.h "-lpulse" \ -+ "pa_mainloop *m = 0; pa_mainloop_free (m); return 0;" -+ libs_softmmu="-lpulse $libs_softmmu" - audio_pt_int="yes" - ;; - --- -1.7.10 - diff --git a/0509-Allow-controlling-volume-with-PulseAudio-backend.patch b/0509-Allow-controlling-volume-with-PulseAudio-backend.patch deleted file mode 100644 index acc8ded..0000000 --- a/0509-Allow-controlling-volume-with-PulseAudio-backend.patch +++ /dev/null @@ -1,134 +0,0 @@ -From 4b09edbfdaad4536617bbb53ccadfe531156ed56 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= -Date: Tue, 17 Apr 2012 14:32:43 +0200 -Subject: [PATCH 509/509] Allow controlling volume with PulseAudio backend - -Signed-off-by: Marc-Andr? Lureau -Signed-off-by: malc ---- - audio/paaudio.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 94 insertions(+), 5 deletions(-) - -diff --git a/audio/paaudio.c b/audio/paaudio.c -index 6f50c1c..e6708d0 100644 ---- a/audio/paaudio.c -+++ b/audio/paaudio.c -@@ -677,15 +677,103 @@ static void qpa_fini_in (HWVoiceIn *hw) - - static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) - { -- (void) hw; -- (void) cmd; -+ PAVoiceOut *pa = (PAVoiceOut *) hw; -+ pa_operation *op; -+ pa_cvolume v; -+ paaudio *g = &glob_paaudio; -+ -+ pa_cvolume_init (&v); -+ -+ switch (cmd) { -+ case VOICE_VOLUME: -+ { -+ SWVoiceOut *sw; -+ va_list ap; -+ -+ va_start (ap, cmd); -+ sw = va_arg (ap, SWVoiceOut *); -+ va_end (ap); -+ -+ v.channels = 2; -+ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; -+ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; -+ -+ pa_threaded_mainloop_lock (g->mainloop); -+ -+ op = pa_context_set_sink_input_volume (g->context, -+ pa_stream_get_index (pa->stream), -+ &v, NULL, NULL); -+ if (!op) -+ qpa_logerr (pa_context_errno (g->context), -+ "set_sink_input_volume() failed\n"); -+ else -+ pa_operation_unref (op); -+ -+ op = pa_context_set_sink_input_mute (g->context, -+ pa_stream_get_index (pa->stream), -+ sw->vol.mute, NULL, NULL); -+ if (!op) { -+ qpa_logerr (pa_context_errno (g->context), -+ "set_sink_input_mute() failed\n"); -+ } else { -+ pa_operation_unref (op); -+ } -+ -+ pa_threaded_mainloop_unlock (g->mainloop); -+ } -+ } - return 0; - } - - static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) - { -- (void) hw; -- (void) cmd; -+ PAVoiceIn *pa = (PAVoiceIn *) hw; -+ pa_operation *op; -+ pa_cvolume v; -+ paaudio *g = &glob_paaudio; -+ -+ pa_cvolume_init (&v); -+ -+ switch (cmd) { -+ case VOICE_VOLUME: -+ { -+ SWVoiceIn *sw; -+ va_list ap; -+ -+ va_start (ap, cmd); -+ sw = va_arg (ap, SWVoiceIn *); -+ va_end (ap); -+ -+ v.channels = 2; -+ v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; -+ v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; -+ -+ pa_threaded_mainloop_lock (g->mainloop); -+ -+ /* FIXME: use the upcoming "set_source_output_{volume,mute}" */ -+ op = pa_context_set_source_volume_by_index (g->context, -+ pa_stream_get_device_index (pa->stream), -+ &v, NULL, NULL); -+ if (!op) { -+ qpa_logerr (pa_context_errno (g->context), -+ "set_source_volume() failed\n"); -+ } else { -+ pa_operation_unref(op); -+ } -+ -+ op = pa_context_set_source_mute_by_index (g->context, -+ pa_stream_get_index (pa->stream), -+ sw->vol.mute, NULL, NULL); -+ if (!op) { -+ qpa_logerr (pa_context_errno (g->context), -+ "set_source_mute() failed\n"); -+ } else { -+ pa_operation_unref (op); -+ } -+ -+ pa_threaded_mainloop_unlock (g->mainloop); -+ } -+ } - return 0; - } - -@@ -822,5 +910,6 @@ struct audio_driver pa_audio_driver = { - .max_voices_out = INT_MAX, - .max_voices_in = INT_MAX, - .voice_size_out = sizeof (PAVoiceOut), -- .voice_size_in = sizeof (PAVoiceIn) -+ .voice_size_in = sizeof (PAVoiceIn), -+ .ctl_caps = VOICE_VOLUME_CAP - }; --- -1.7.10 - diff --git a/enable_architectural_PMU_cpuid_leaf.patch b/enable_architectural_PMU_cpuid_leaf.patch deleted file mode 100644 index f0a7415..0000000 --- a/enable_architectural_PMU_cpuid_leaf.patch +++ /dev/null @@ -1,37 +0,0 @@ -commit a0fa82085e175bf8ce6d69a3f83695f81af2a649 -Author: Gleb Natapov -Date: Thu Dec 15 12:44:05 2011 +0200 - - enable architectural PMU cpuid leaf for kvm - - Signed-off-by: Gleb Natapov - Signed-off-by: Marcelo Tosatti - -diff --git a/target-i386/cpuid.c b/target-i386/cpuid.c -index 0b3af90..91a104b 100644 ---- a/target-i386/cpuid.c -+++ b/target-i386/cpuid.c -@@ -1180,10 +1180,19 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count, - break; - case 0xA: - /* Architectural Performance Monitoring Leaf */ -- *eax = 0; -- *ebx = 0; -- *ecx = 0; -- *edx = 0; -+ if (kvm_enabled()) { -+ KVMState *s = env->kvm_state; -+ -+ *eax = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EAX); -+ *ebx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EBX); -+ *ecx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_ECX); -+ *edx = kvm_arch_get_supported_cpuid(s, 0xA, count, R_EDX); -+ } else { -+ *eax = 0; -+ *ebx = 0; -+ *ecx = 0; -+ *edx = 0; -+ } - break; - case 0xD: - /* Processor Extended State */ diff --git a/qemu-fix-systemtap.patch b/qemu-fix-systemtap.patch deleted file mode 100644 index 3191eec..0000000 --- a/qemu-fix-systemtap.patch +++ /dev/null @@ -1,19 +0,0 @@ -diff -rup qemu-kvm-1.0.1/scripts/tracetool z/scripts/tracetool ---- qemu-kvm-1.0.1/scripts/tracetool 2012-04-16 22:15:17.000000000 -0400 -+++ z/scripts/tracetool 2012-07-29 21:10:51.326868987 -0400 -@@ -500,6 +500,15 @@ EOF - if [ "$arg" = "limit" ]; then - arg="_limit" - fi -+ if [ "$arg" = "in" ]; then -+ arg="_in" -+ fi -+ if [ "$arg" = "next" ]; then -+ arg="_next" -+ fi -+ if [ "$arg" = "self" ]; then -+ arg="_self" -+ fi - cat < -Date: Mon Jul 16 18:08:36 2012 +0400 - - audio: Unbreak capturing in mixemu case - - Signed-off-by: malc - -diff --git a/audio/audio.c b/audio/audio.c -index 583ee51..1c77389 100644 ---- a/audio/audio.c -+++ b/audio/audio.c -@@ -818,6 +818,7 @@ static int audio_attach_capture (HWVoiceOut *hw) - sw->active = hw->enabled; - sw->conv = noop_conv; - sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq; -+ sw->vol = nominal_volume; - sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq); - if (!sw->rate) { - dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw)); diff --git a/qemu-snapshot-symlink-attack.patch b/qemu-snapshot-symlink-attack.patch deleted file mode 100644 index 198c010..0000000 --- a/qemu-snapshot-symlink-attack.patch +++ /dev/null @@ -1,93 +0,0 @@ -diff -rup qemu-kvm-1.0.1/block/vvfat.c foo/block/vvfat.c ---- qemu-kvm-1.0.1/block/vvfat.c 2012-04-16 22:15:17.000000000 -0400 -+++ foo/block/vvfat.c 2012-07-29 20:00:15.515321504 -0400 -@@ -2799,7 +2799,12 @@ static int enable_write_target(BDRVVVFAT - array_init(&(s->commits), sizeof(commit_t)); - - s->qcow_filename = g_malloc(1024); -- get_tmp_filename(s->qcow_filename, 1024); -+ ret = get_tmp_filename(s->qcow_filename, 1024); -+ if (ret < 0) { -+ g_free(s->qcow_filename); -+ s->qcow_filename = NULL; -+ return ret; -+ } - - bdrv_qcow = bdrv_find_format("qcow"); - options = parse_option_parameters("", bdrv_qcow->create_options, NULL); -diff -rup qemu-kvm-1.0.1/block.c foo/block.c ---- qemu-kvm-1.0.1/block.c 2012-04-16 22:15:17.000000000 -0400 -+++ foo/block.c 2012-07-29 20:00:15.513321760 -0400 -@@ -272,28 +272,36 @@ int bdrv_create_file(const char* filenam - return bdrv_create(drv, filename, options); - } - --#ifdef _WIN32 --void get_tmp_filename(char *filename, int size) -+/* -+ * Create a uniquely-named empty temporary file. -+ * Return 0 upon success, otherwise a negative errno value. -+ */ -+int get_tmp_filename(char *filename, int size) - { -+#ifdef _WIN32 - char temp_dir[MAX_PATH]; -- -- GetTempPath(MAX_PATH, temp_dir); -- GetTempFileName(temp_dir, "qem", 0, filename); --} -+ /* GetTempFileName requires that its output buffer (4th param) -+ have length MAX_PATH or greater. */ -+ assert(size >= MAX_PATH); -+ return (GetTempPath(MAX_PATH, temp_dir) -+ && GetTempFileName(temp_dir, "qem", 0, filename) -+ ? 0 : -GetLastError()); - #else --void get_tmp_filename(char *filename, int size) --{ - int fd; - const char *tmpdir; -- /* XXX: race condition possible */ - tmpdir = getenv("TMPDIR"); - if (!tmpdir) - tmpdir = "/tmp"; -- snprintf(filename, size, "%s/vl.XXXXXX", tmpdir); -+ if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) { -+ return -EOVERFLOW; -+ } - fd = mkstemp(filename); -- close(fd); --} -+ if (fd < 0 || close(fd)) { -+ return -errno; -+ } -+ return 0; - #endif -+} - - /* - * Detect host devices. By convention, /dev/cdrom[N] is always -@@ -601,7 +609,10 @@ int bdrv_open(BlockDriverState *bs, cons - - bdrv_delete(bs1); - -- get_tmp_filename(tmp_filename, sizeof(tmp_filename)); -+ ret = get_tmp_filename(tmp_filename, sizeof(tmp_filename)); -+ if (ret < 0) { -+ return ret; -+ } - - /* Real path is meaningless for protocols */ - if (is_protocol) -diff -rup qemu-kvm-1.0.1/block_int.h foo/block_int.h ---- qemu-kvm-1.0.1/block_int.h 2012-04-16 22:15:17.000000000 -0400 -+++ foo/block_int.h 2012-07-29 20:00:15.515321504 -0400 -@@ -238,7 +238,7 @@ struct BlockDriverAIOCB { - BlockDriverAIOCB *next; - }; - --void get_tmp_filename(char *filename, int size); -+int get_tmp_filename(char *filename, int size); - - void *qemu_aio_get(AIOPool *pool, BlockDriverState *bs, - BlockDriverCompletionFunc *cb, void *opaque); diff --git a/qemu-virtio-9p-noatime.patch b/qemu-virtio-9p-noatime.patch deleted file mode 100644 index e363509..0000000 --- a/qemu-virtio-9p-noatime.patch +++ /dev/null @@ -1,40 +0,0 @@ -commit eed968607d656a218712df47a5e0432c21fd6994 -Author: Daniel P. Berrange -Date: Mon Jan 16 18:11:40 2012 +0000 - - hw/9pfs: Remove O_NOATIME flag from 9pfs open() calls in readonly mode - - When 2c74c2cb4bedddbfa67628fbd5f9273b4e0e9903 added support for - the 'readonly' flag against 9p filesystems, it also made QEMU - add the O_NOATIME flag as a side-effect. - - The O_NOATIME flag, however, may only be set by the file owner, - or a user with CAP_FOWNER capability. QEMU cannot assume that - this is the case for filesytems exported to QEMU. - - eg, run QEMU as non-root, and attempt to pass the host OS - filesystem through to the guest OS with readonly enable. - The result is that the guest OS cannot open any files at - all. - - If O_NOATIME is really required, it should be optionally - enabled via a separate QEMU command line flag. - - * hw/9pfs/virtio-9p.c: Remove O_NOATIME - - Acked-by: M. Mohan Kumar - Signed-off-by: Daniel P. Berrange - Signed-off-by: Aneesh Kumar K.V - -diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c -index dfe2025..a72ffc3 100644 ---- a/hw/9pfs/virtio-9p.c -+++ b/hw/9pfs/virtio-9p.c -@@ -1391,7 +1391,6 @@ static void v9fs_open(void *opaque) - err = -EROFS; - goto out; - } -- flags |= O_NOATIME; - } - err = v9fs_co_open(pdu, fidp, flags); - if (err < 0) { diff --git a/qemu-virtio-console-unconnected-pty.patch b/qemu-virtio-console-unconnected-pty.patch deleted file mode 100644 index 7b95b82..0000000 --- a/qemu-virtio-console-unconnected-pty.patch +++ /dev/null @@ -1,47 +0,0 @@ -commit ed8e5a85a1741147ce06932b478a509ce3407061 -Author: Christian Borntraeger -Date: Thu Dec 29 13:47:43 2011 +0100 - - virtio-console: Fix failure on unconnected pty - - when I tried qemu with -virtio-console pty the guest hangs and attaching - on /dev/pts/ does not return anything if the attachment is too late. - - This results in pty_chr_write() returning 0, which causes the port to - get throttled. This results in the guest getting frozen as the - guest->host virtio_console writes don't return until the host releases - the vq element back to the guest. - - For the virtio-serial use case we don't want to lose data but for the - console case we better drop data instead of "killing" the guest - console. If we get chardev->frontend notification and a better behaving - virtio-console we can revert this fix. - - Signed-off-by: Christian Borntraeger - Signed-off-by: Amit Shah - -diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c -index fe0233f..3a9004a 100644 ---- a/hw/virtio-serial-bus.c -+++ b/hw/virtio-serial-bus.c -@@ -163,7 +163,19 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, - abort(); - } - if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) { -- virtio_serial_throttle_port(port, true); -+ /* -+ * this is a temporary check until chardevs can signal to -+ * frontends that they are writable again. This prevents -+ * the console from going into throttled mode (forever) -+ * if virtio-console is connected to a pty without a -+ * listener. Otherwise the guest spins forever. -+ * We can revert this if -+ * 1: chardevs can notify frondends -+ * 2: the guest driver does not spin in these cases -+ */ -+ if (!info->is_console) { -+ virtio_serial_throttle_port(port, true); -+ } - port->iov_idx = i; - if (ret > 0) { - port->iov_offset += ret; diff --git a/qemu.spec b/qemu.spec index 75395e2..b03c9c1 100644 --- a/qemu.spec +++ b/qemu.spec @@ -38,7 +38,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 1.0.1 -Release: 4%{?dist} +Release: 5%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD @@ -75,126 +75,131 @@ Source9: ksmtuned.conf Source10: qemu-guest-agent.service Source11: 99-qemu-guest-agent.rules -# USB-redir patches all upstream for 1.1 except for the chardev flowcontrol set -Patch101: 0101-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch -Patch102: 0102-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch -Patch103: 0103-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch -Patch104: 0104-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch -Patch105: 0105-usb-redir-Improve-some-debugging-messages.patch -Patch106: 0106-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch -Patch107: 0107-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch -Patch108: 0108-iohandlers-Add-enable-disable_write_fd_handler-funct.patch -Patch109: 0109-char-Add-framework-for-a-write-unblocked-callback.patch -Patch110: 0110-char-Update-send_all-to-handle-nonblocking-chardev-w.patch -Patch111: 0111-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch -Patch112: 0112-char-Throttle-when-host-connection-is-down.patch -Patch113: 0113-virtio-console-Enable-port-throttling-when-chardev-i.patch -Patch114: 0114-spice-qemu-char.c-add-throttling.patch -Patch115: 0115-spice-qemu-char.c-remove-intermediate-buffer.patch -Patch116: 0116-usb-redir-Add-flow-control-support.patch -Patch117: 0117-virtio-serial-bus-replay-guest_open-on-migration.patch -Patch118: 0118-char-Disable-write-callback-if-throttled-chardev-is-.patch -Patch119: 0119-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch -Patch120: 0120-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch -Patch121: 0121-usb-redir-Fix-printing-of-device-version.patch -Patch122: 0122-usb-redir-Always-clear-device-state-on-filter-reject.patch -Patch123: 0123-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch -Patch124: 0124-usb-redir-Limit-return-values-returned-by-iso-packet.patch -Patch125: 0125-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch -Patch126: 0126-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch -Patch127: 0127-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch -Patch128: 0128-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch -Patch129: 0129-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch -Patch130: 0130-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch -Patch131: 0131-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch -Patch132: 0132-usb-ehci-Any-packet-completion-except-for-NAK-should.patch -Patch133: 0133-usb-ehci-Fix-cerr-tracking.patch -Patch134: 0134-usb-ehci-Remove-dead-nakcnt-code.patch -Patch135: 0135-usb-ehci-Fix-and-simplify-nakcnt-handling.patch -Patch136: 0136-usb-ehci-Remove-dead-isoch_pause-code.patch -Patch137: 0137-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch -Patch138: 0138-usb-add-USB_RET_IOERROR.patch -Patch139: 0139-usb-ehci-fix-reset.patch -Patch140: 0140-usb-ehci-sanity-check-iso-xfers.patch -Patch141: 0141-usb-ehci-frindex-always-is-a-14-bits-counter.patch -Patch142: 0142-usb-ehci-Drop-unused-sofv-value.patch -Patch143: 0143-usb-redir-Notify-our-peer-when-we-reject-a-device-du.patch -Patch144: 0144-usb-redir-An-interface-count-of-0-is-a-valid-value.patch -Patch145: 0145-usb-redir-Reset-device-address-and-speed-on-disconne.patch -Patch146: 0146-usb-redir-Not-finding-an-async-urb-id-is-not-an-erro.patch -Patch147: 0147-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch - -# General bug fixes -Patch202: qemu-virtio-9p-noatime.patch -Patch203: 0203-pci-fix-corrupted-pci-conf-index-register-by-unaligned-write.patch - -# Feature patches, should be in 1.1 before release -Patch301: enable_architectural_PMU_cpuid_leaf.patch -Patch302: qemu_virtio-scsi_support.patch - -# QXL fixes backports, all are upstream for 1.1 -Patch401: 0401-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch -Patch402: 0402-input-send-kbd-mouse-events-only-to-running-guests.patch -Patch403: 0403-qxl-fix-warnings-on-32bit.patch -Patch404: 0404-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch -Patch405: 0405-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch -Patch406: 0406-qxl-make-sure-primary-surface-is-saved-on-migration-.patch -Patch407: 0407-Add-SPICE-support-to-add_client-monitor-command.patch -Patch408: 0408-spice-support-ipv6-channel-address-in-monitor-events.patch -Patch409: 0409-qxl-drop-vram-bar-minimum-size.patch -Patch410: 0410-qxl-move-ram-size-init-to-new-function.patch -Patch411: 0411-qxl-add-user-friendly-bar-size-properties.patch -Patch412: 0412-qxl-fix-spice-sdl-no-cursor-regression.patch -Patch413: 0413-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch -Patch414: 0414-qxl-drop-qxl_spice_update_area_async-definition.patch -Patch415: 0415-qxl-require-spice-0.8.2.patch -Patch416: 0416-qxl-remove-flipped.patch -Patch417: 0417-qxl-introduce-QXLCookie.patch -Patch418: 0418-qxl-make-qxl_render_update-async.patch -Patch419: 0419-spice-use-error_report-to-report-errors.patch -Patch420: 0420-Error-out-when-tls-channel-option-is-used-without-TL.patch -Patch421: 0421-qxl-properly-handle-upright-and-non-shared-surfaces.patch -Patch422: 0422-spice-set-spice-uuid-and-name.patch -Patch423: 0423-monitor-fix-client_migrate_info-error-handling.patch -Patch424: 0424-qxl-init_pipe_signaling-exit-on-failure.patch -Patch425: 0425-qxl-switch-qxl.c-to-trace-events.patch -Patch426: 0426-qxl-qxl_render.c-add-trace-events.patch -Patch427: 0427-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch -Patch428: 0428-spice-fix-broken-initialization.patch -Patch429: 0429-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch -Patch430: 0430-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch -Patch431: 0431-qxl-add-optinal-64bit-vram-bar.patch -Patch432: 0432-qxl-set-default-values-of-vram-_size_mb-to-1.patch -Patch433: 0433-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch -Patch434: 0434-qxl-don-t-assert-on-guest-create_guest_primary.patch +# Upstream USB bits and flow control series +Patch0001: 0001-usb-redir-Clear-iso-irq-error-when-stopping-the-stre.patch +Patch0002: 0002-usb-redir-Dynamically-adjust-iso-buffering-size-base.patch +Patch0003: 0003-usb-redir-Pre-fill-our-isoc-input-buffer-before-send.patch +Patch0004: 0004-usb-redir-Try-to-keep-our-buffer-size-near-the-targe.patch +Patch0005: 0005-usb-redir-Improve-some-debugging-messages.patch +Patch0006: 0006-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch +Patch0007: 0007-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch +Patch0008: 0008-iohandlers-Add-enable-disable_write_fd_handler-funct.patch +Patch0009: 0009-char-Add-framework-for-a-write-unblocked-callback.patch +Patch0010: 0010-char-Update-send_all-to-handle-nonblocking-chardev-w.patch +Patch0011: 0011-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch +Patch0012: 0012-char-Throttle-when-host-connection-is-down.patch +Patch0013: 0013-virtio-console-Enable-port-throttling-when-chardev-i.patch +Patch0014: 0014-spice-qemu-char.c-add-throttling.patch +Patch0015: 0015-spice-qemu-char.c-remove-intermediate-buffer.patch +Patch0016: 0016-usb-redir-Add-flow-control-support.patch +Patch0017: 0017-virtio-serial-bus-replay-guest_open-on-migration.patch +Patch0018: 0018-char-Disable-write-callback-if-throttled-chardev-is-.patch +Patch0019: 0019-usb-ehci-Clear-the-portstatus-powner-bit-on-device-d.patch +Patch0020: 0020-usb-redir-Add-the-posibility-to-filter-out-certain-d.patch +Patch0021: 0021-usb-redir-Fix-printing-of-device-version.patch +Patch0022: 0022-usb-redir-Always-clear-device-state-on-filter-reject.patch +Patch0023: 0023-usb-redir-Let-the-usb-host-know-about-our-device-fil.patch +Patch0024: 0024-usb-redir-Limit-return-values-returned-by-iso-packet.patch +Patch0025: 0025-usb-redir-Return-USB_RET_NAK-when-we-ve-no-data-for-.patch +Patch0026: 0026-usb-ehci-Handle-ISO-packets-failing-with-an-error-ot.patch +Patch0027: 0027-usb-ehci-Never-follow-table-entries-with-the-T-bit-s.patch +Patch0028: 0028-usb-ehci-split-our-qh-queue-into-async-and-periodic-.patch +Patch0029: 0029-usb-ehci-always-call-ehci_queues_rip_unused-for-peri.patch +Patch0030: 0030-usb-ehci-Drop-cached-qhs-when-the-doorbell-gets-rung.patch +Patch0031: 0031-usb-ehci-Rip-the-queues-when-the-async-or-period-sch.patch +Patch0032: 0032-usb-ehci-Any-packet-completion-except-for-NAK-should.patch +Patch0033: 0033-usb-ehci-Fix-cerr-tracking.patch +Patch0034: 0034-usb-ehci-Remove-dead-nakcnt-code.patch +Patch0035: 0035-usb-ehci-Fix-and-simplify-nakcnt-handling.patch +Patch0036: 0036-usb-ehci-Remove-dead-isoch_pause-code.patch +Patch0037: 0037-usb-return-BABBLE-rather-then-NAK-when-we-receive-to.patch +Patch0038: 0038-usb-add-USB_RET_IOERROR.patch +Patch0039: 0039-usb-ehci-fix-reset.patch +Patch0040: 0040-usb-ehci-sanity-check-iso-xfers.patch +Patch0041: 0041-usb-ehci-frindex-always-is-a-14-bits-counter.patch +Patch0042: 0042-usb-ehci-Drop-unused-sofv-value.patch +Patch0043: 0043-usb-redir-Notify-our-peer-when-we-reject-a-device-du.patch +Patch0044: 0044-usb-redir-An-interface-count-of-0-is-a-valid-value.patch +Patch0045: 0045-usb-redir-Reset-device-address-and-speed-on-disconne.patch +Patch0046: 0046-usb-redir-Not-finding-an-async-urb-id-is-not-an-erro.patch +Patch0047: 0047-usb-ehci-Ensure-frindex-writes-leave-a-valid-frindex.patch + +# QXL backports from 1.1 +Patch0101: 0101-qxl-Slot-sanity-check-in-qxl_phys2virt-is-off-by-one.patch +Patch0102: 0102-input-send-kbd-mouse-events-only-to-running-guests.patch +Patch0103: 0103-qxl-fix-warnings-on-32bit.patch +Patch0104: 0104-qxl-don-t-render-stuff-when-the-vm-is-stopped.patch +Patch0105: 0105-qxl-set-only-off-screen-surfaces-dirty-instead-of-th.patch +Patch0106: 0106-qxl-make-sure-primary-surface-is-saved-on-migration-.patch +Patch0107: 0107-Add-SPICE-support-to-add_client-monitor-command.patch +Patch0108: 0108-spice-support-ipv6-channel-address-in-monitor-events.patch +Patch0109: 0109-qxl-drop-vram-bar-minimum-size.patch +Patch0110: 0110-qxl-move-ram-size-init-to-new-function.patch +Patch0111: 0111-qxl-add-user-friendly-bar-size-properties.patch +Patch0112: 0112-qxl-fix-spice-sdl-no-cursor-regression.patch +Patch0113: 0113-sdl-remove-NULL-check-g_malloc0-can-t-fail.patch +Patch0114: 0114-qxl-drop-qxl_spice_update_area_async-definition.patch +Patch0115: 0115-qxl-require-spice-0.8.2.patch +Patch0116: 0116-qxl-remove-flipped.patch +Patch0117: 0117-qxl-introduce-QXLCookie.patch +Patch0118: 0118-qxl-make-qxl_render_update-async.patch +Patch0119: 0119-spice-use-error_report-to-report-errors.patch +Patch0120: 0120-Error-out-when-tls-channel-option-is-used-without-TL.patch +Patch0121: 0121-qxl-properly-handle-upright-and-non-shared-surfaces.patch +Patch0122: 0122-spice-set-spice-uuid-and-name.patch +Patch0123: 0123-monitor-fix-client_migrate_info-error-handling.patch +Patch0124: 0124-qxl-init_pipe_signaling-exit-on-failure.patch +Patch0125: 0125-qxl-switch-qxl.c-to-trace-events.patch +Patch0126: 0126-qxl-qxl_render.c-add-trace-events.patch +Patch0127: 0127-hw-qxl.c-Fix-compilation-failures-on-32-bit-hosts.patch +Patch0128: 0128-spice-fix-broken-initialization.patch +Patch0129: 0129-ui-spice-display.c-Fix-compilation-warnings-on-32-bi.patch +Patch0130: 0130-ui-spice-display-use-uintptr_t-when-casting-qxl-phys.patch +Patch0131: 0131-qxl-add-optinal-64bit-vram-bar.patch +Patch0132: 0132-qxl-set-default-values-of-vram-_size_mb-to-1.patch +Patch0133: 0133-qxl-render-fix-broken-vnc-spice-since-commit-f934493.patch +Patch0134: 0134-qxl-don-t-assert-on-guest-create_guest_primary.patch # Spice volume control backports, all are upstream for 1.1 -Patch501: 0501-audio-add-VOICE_VOLUME-ctl.patch -Patch502: 0502-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch -Patch503: 0503-hw-ac97-remove-USE_MIXER-code.patch -Patch504: 0504-hw-ac97-the-volume-mask-is-not-only-0x1f.patch -Patch505: 0505-hw-ac97-add-support-for-volume-control.patch -Patch506: 0506-audio-spice-add-support-for-volume-control.patch -Patch507: 0507-Do-not-use-pa_simple-PulseAudio-API.patch -Patch508: 0508-configure-pa_simple-is-not-needed-anymore.patch -Patch509: 0509-Allow-controlling-volume-with-PulseAudio-backend.patch -# Fix fedora guest hang with virtio console (bz 837925) -Patch510: %{name}-virtio-console-unconnected-pty.patch -# Fix VNC audio tunnelling (bz 840653) -Patch511: %{name}-fix-vnc-audio.patch -# CVE-2012-2652: Possible symlink attacks with -snapshot (bz 825697, bz -# 824919) -Patch512: %{name}-snapshot-symlink-attack.patch -# Fix systemtap tapsets (bz 831763) -Patch513: %{name}-fix-systemtap.patch +Patch0201: 0201-audio-add-VOICE_VOLUME-ctl.patch +Patch0202: 0202-audio-don-t-apply-volume-effect-if-backend-has-VOICE.patch +Patch0203: 0203-hw-ac97-remove-USE_MIXER-code.patch +Patch0204: 0204-hw-ac97-the-volume-mask-is-not-only-0x1f.patch +Patch0205: 0205-hw-ac97-add-support-for-volume-control.patch +Patch0206: 0206-audio-spice-add-support-for-volume-control.patch +Patch0207: 0207-Do-not-use-pa_simple-PulseAudio-API.patch +Patch0208: 0208-configure-pa_simple-is-not-needed-anymore.patch +Patch0209: 0209-Allow-controlling-volume-with-PulseAudio-backend.patch + +# F17 feature backports +Patch0301: 0301-enable-architectural-PMU-cpuid-leaf-for-kvm.patch +Patch0302: 0302-virtio-scsi-backport.patch +# Remove O_NOATIME for 9p filesystems +Patch0303: 0303-hw-9pfs-Remove-O_NOATIME-flag-from-9pfs-open-calls-i.patch +# Fix booting NetBSD VM (bz #830261) +Patch0304: 0304-pci-fix-corrupted-pci-conf-index-register-by-unalign.patch +# Fix fedora guest hang with virtio console (bz #837925) +Patch0305: 0305-virtio-console-Fix-failure-on-unconnected-pty.patch +# Fix VNC audio tunnelling (bz #840653) +Patch0306: 0306-audio-Unbreak-capturing-in-mixemu-case.patch +# CVE-2012-2652: Possible symlink attacks with -snapshot (bz #825697, bz +# #824919) +Patch0307: 0307-block-prevent-snapshot-mode-TMPDIR-symlink-attack.patch +# Fix systemtap tapsets (bz #831763) +Patch0308: 0308-Fix-systemtap-keyword-collisions.patch # Remove comma from 1.0.1 version number -Patch514: 0001-qemu-1.0.1-VERSION.patch -# CVE-2012-3515 VT100 emulation vulnerability (bz 854600, bz 851252) -Patch515: 0002-console-bounds-check-whenever-changing-the-cursor-du.patch -# Fix slirp crash (bz 845793) -Patch516: 0003-slirp-Fix-requeuing-of-batchq-packets-in-if_start.patch -# CVE-2012-6075: Buffer overflow in e1000 nic (bz 889301, bz 889304) -Patch517: 0001-e1000-Discard-oversized-packets-based-on-SBP-LPE.patch +Patch0309: 0309-qemu-1.0.1-VERSION.patch +# CVE-2012-3515 VT100 emulation vulnerability (bz #854600, bz #851252) +Patch0310: 0310-console-bounds-check-whenever-changing-the-cursor-du.patch +# Fix slirp crash (bz #845793) +Patch0311: 0311-slirp-Fix-requeuing-of-batchq-packets-in-if_start.patch +# CVE-2012-6075: Buffer overflow in e1000 nic (bz #889301, bz #889304) +Patch0312: 0312-e1000-Discard-packets-that-are-too-long-if-SBP-and-L.patch +Patch0313: 0313-e1000-Discard-oversized-packets-based-on-SBP-LPE.patch +# Fix -vga vmware crashes (bz #836260) +Patch0314: 0314-vmware_vga-fix-out-of-bounds-and-invalid-rects-updat.patch +# Fix vhost crash (bz #918272) +Patch0315: 0315-vhost-Fix-size-of-dirty-log-sync-on-resize.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: SDL-devel zlib-devel which texi2html gnutls-devel cyrus-sasl-devel @@ -447,112 +452,131 @@ such as kvm_stat. %prep %setup -q -n qemu-kvm-%{version} -%patch101 -p1 -%patch102 -p1 -%patch103 -p1 -%patch104 -p1 -%patch105 -p1 -%patch106 -p1 -%patch107 -p1 -%patch108 -p1 -%patch109 -p1 -%patch110 -p1 -%patch111 -p1 -%patch112 -p1 -%patch113 -p1 -%patch114 -p1 -%patch115 -p1 -%patch116 -p1 -%patch117 -p1 -%patch118 -p1 -%patch119 -p1 -%patch120 -p1 -%patch121 -p1 -%patch122 -p1 -%patch123 -p1 -%patch124 -p1 -%patch125 -p1 -%patch126 -p1 -%patch127 -p1 -%patch128 -p1 -%patch129 -p1 -%patch130 -p1 -%patch131 -p1 -%patch132 -p1 -%patch133 -p1 -%patch134 -p1 -%patch135 -p1 -%patch136 -p1 -%patch137 -p1 -%patch138 -p1 -%patch139 -p1 -%patch140 -p1 -%patch141 -p1 -%patch142 -p1 -%patch143 -p1 -%patch144 -p1 -%patch145 -p1 -%patch146 -p1 -%patch147 -p1 - -%patch202 -p1 -%patch203 -p1 - -%patch301 -p1 -%patch302 -p1 - -%patch401 -p1 -%patch402 -p1 -%patch403 -p1 -%patch404 -p1 -%patch405 -p1 -%patch406 -p1 -%patch407 -p1 -%patch408 -p1 -%patch409 -p1 -%patch410 -p1 -%patch411 -p1 -%patch412 -p1 -%patch413 -p1 -%patch414 -p1 -%patch415 -p1 -%patch416 -p1 -%patch417 -p1 -%patch418 -p1 -%patch419 -p1 -%patch420 -p1 -%patch421 -p1 -%patch422 -p1 -%patch423 -p1 -%patch424 -p1 -%patch425 -p1 -%patch426 -p1 -%patch427 -p1 -%patch428 -p1 -%patch429 -p1 -%patch430 -p1 -%patch431 -p1 -%patch432 -p1 -%patch433 -p1 -%patch434 -p1 - -%patch501 -p1 -%patch502 -p1 -%patch503 -p1 -%patch504 -p1 -%patch505 -p1 -%patch506 -p1 -%patch507 -p1 -%patch508 -p1 -%patch509 -p1 -%patch510 -p1 -%patch511 -p1 -%patch512 -p1 -%patch513 -p1 -%patch514 -p1 -%patch515 -p1 -%patch516 -p1 -%patch517 -p1 +# Upstream USB bits and flow control series +%patch0001 -p1 +%patch0002 -p1 +%patch0003 -p1 +%patch0004 -p1 +%patch0005 -p1 +%patch0006 -p1 +%patch0007 -p1 +%patch0008 -p1 +%patch0009 -p1 +%patch0010 -p1 +%patch0011 -p1 +%patch0012 -p1 +%patch0013 -p1 +%patch0014 -p1 +%patch0015 -p1 +%patch0016 -p1 +%patch0017 -p1 +%patch0018 -p1 +%patch0019 -p1 +%patch0020 -p1 +%patch0021 -p1 +%patch0022 -p1 +%patch0023 -p1 +%patch0024 -p1 +%patch0025 -p1 +%patch0026 -p1 +%patch0027 -p1 +%patch0028 -p1 +%patch0029 -p1 +%patch0030 -p1 +%patch0031 -p1 +%patch0032 -p1 +%patch0033 -p1 +%patch0034 -p1 +%patch0035 -p1 +%patch0036 -p1 +%patch0037 -p1 +%patch0038 -p1 +%patch0039 -p1 +%patch0040 -p1 +%patch0041 -p1 +%patch0042 -p1 +%patch0043 -p1 +%patch0044 -p1 +%patch0045 -p1 +%patch0046 -p1 +%patch0047 -p1 + +# QXL backports from 1.1 +%patch0101 -p1 +%patch0102 -p1 +%patch0103 -p1 +%patch0104 -p1 +%patch0105 -p1 +%patch0106 -p1 +%patch0107 -p1 +%patch0108 -p1 +%patch0109 -p1 +%patch0110 -p1 +%patch0111 -p1 +%patch0112 -p1 +%patch0113 -p1 +%patch0114 -p1 +%patch0115 -p1 +%patch0116 -p1 +%patch0117 -p1 +%patch0118 -p1 +%patch0119 -p1 +%patch0120 -p1 +%patch0121 -p1 +%patch0122 -p1 +%patch0123 -p1 +%patch0124 -p1 +%patch0125 -p1 +%patch0126 -p1 +%patch0127 -p1 +%patch0128 -p1 +%patch0129 -p1 +%patch0130 -p1 +%patch0131 -p1 +%patch0132 -p1 +%patch0133 -p1 +%patch0134 -p1 + +# Spice volume control backports, all are upstream for 1.1 +%patch0201 -p1 +%patch0202 -p1 +%patch0203 -p1 +%patch0204 -p1 +%patch0205 -p1 +%patch0206 -p1 +%patch0207 -p1 +%patch0208 -p1 +%patch0209 -p1 + +# F17 feature backports +%patch0301 -p1 +%patch0302 -p1 +# Remove O_NOATIME for 9p filesystems +%patch0303 -p1 +# Fix booting NetBSD VM (bz #830261) +%patch0304 -p1 +# Fix fedora guest hang with virtio console (bz #837925) +%patch0305 -p1 +# Fix VNC audio tunnelling (bz #840653) +%patch0306 -p1 +# CVE-2012-2652: Possible symlink attacks with -snapshot (bz #825697, bz +# #824919) +%patch0307 -p1 +# Fix systemtap tapsets (bz #831763) +%patch0308 -p1 +# Remove comma from 1.0.1 version number +%patch0309 -p1 +# CVE-2012-3515 VT100 emulation vulnerability (bz #854600, bz #851252) +%patch0310 -p1 +# Fix slirp crash (bz #845793) +%patch0311 -p1 +# CVE-2012-6075: Buffer overflow in e1000 nic (bz #889301, bz #889304) +%patch0312 -p1 +%patch0313 -p1 +# Fix -vga vmware crashes (bz #836260) +%patch0314 -p1 +# Fix vhost crash (bz #918272) +%patch0315 -p1 %build @@ -789,7 +813,7 @@ rm -rf $RPM_BUILD_ROOT # load kvm modules now, so we can make sure no reboot is needed. # If there's already a kvm module installed, we don't mess with it sh %{_sysconfdir}/sysconfig/modules/kvm.modules || : -udevadm trigger --sysname-match=kvm || : +udevadm trigger --subsystem-match=misc --sysname-match=kvm --action=add || : %endif %post common @@ -993,6 +1017,11 @@ fi %{_mandir}/man1/qemu-img.1* %changelog +* Tue Apr 02 2013 Cole Robinson - 2:1.0.1-5 +- Fix -vga vmware crashes (bz #836260) +- Fix vhost crash (bz #918272) +- Fix kvm module permissions after first install (bz #907215) + * Wed Jan 30 2013 Kyle McMartin - 2:1.0.1-4 - pci: fix unaligned writes to pci config index register (rhbz#830261) (resulted in NetBSD being unable to boot in a VM.) diff --git a/qemu_virtio-scsi_support.patch b/qemu_virtio-scsi_support.patch deleted file mode 100644 index 59f6876..0000000 --- a/qemu_virtio-scsi_support.patch +++ /dev/null @@ -1,1652 +0,0 @@ -diff -ruNp qemu-kvm-1.0/default-configs/pci.mak qemu-kvm-1.0.virtio-scsi/default-configs/pci.mak ---- qemu-kvm-1.0/default-configs/pci.mak 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/default-configs/pci.mak 2012-02-07 14:44:53.424905251 -0600 -@@ -1,5 +1,6 @@ - CONFIG_PCI=y - CONFIG_VIRTIO_PCI=y -+CONFIG_VIRTIO_SCSI=y - CONFIG_VIRTIO=y - CONFIG_USB_UHCI=y - CONFIG_USB_OHCI=y -diff -ruNp qemu-kvm-1.0/default-configs/s390x-softmmu.mak qemu-kvm-1.0.virtio-scsi/default-configs/s390x-softmmu.mak ---- qemu-kvm-1.0/default-configs/s390x-softmmu.mak 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/default-configs/s390x-softmmu.mak 2012-02-07 14:44:53.424905251 -0600 -@@ -1 +1,2 @@ - CONFIG_VIRTIO=y -+CONFIG_VIRTIO_SCSI=y -diff -ruNp qemu-kvm-1.0/dma.h qemu-kvm-1.0.virtio-scsi/dma.h ---- qemu-kvm-1.0/dma.h 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/dma.h 2012-02-07 14:44:53.425905267 -0600 -@@ -17,6 +17,13 @@ - - typedef struct ScatterGatherEntry ScatterGatherEntry; - -+struct QEMUSGList { -+ ScatterGatherEntry *sg; -+ int nsg; -+ int nalloc; -+ size_t size; -+}; -+ - #if defined(TARGET_PHYS_ADDR_BITS) - typedef target_phys_addr_t dma_addr_t; - -@@ -32,13 +39,6 @@ struct ScatterGatherEntry { - dma_addr_t len; - }; - --struct QEMUSGList { -- ScatterGatherEntry *sg; -- int nsg; -- int nalloc; -- dma_addr_t size; --}; -- - void qemu_sglist_init(QEMUSGList *qsg, int alloc_hint); - void qemu_sglist_add(QEMUSGList *qsg, dma_addr_t base, dma_addr_t len); - void qemu_sglist_destroy(QEMUSGList *qsg); -@@ -58,4 +58,10 @@ BlockDriverAIOCB *dma_bdrv_read(BlockDri - BlockDriverAIOCB *dma_bdrv_write(BlockDriverState *bs, - QEMUSGList *sg, uint64_t sector, - BlockDriverCompletionFunc *cb, void *opaque); -+uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg); -+uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg); -+ -+void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, -+ QEMUSGList *sg, enum BlockAcctType type); -+ - #endif -diff -ruNp qemu-kvm-1.0/dma-helpers.c qemu-kvm-1.0.virtio-scsi/dma-helpers.c ---- qemu-kvm-1.0/dma-helpers.c 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/dma-helpers.c 2012-02-07 14:44:53.424905251 -0600 -@@ -196,3 +196,39 @@ BlockDriverAIOCB *dma_bdrv_write(BlockDr - { - return dma_bdrv_io(bs, sg, sector, bdrv_aio_writev, cb, opaque, true); - } -+ -+ -+static uint64_t dma_buf_rw(uint8_t *ptr, int32_t len, QEMUSGList *sg, bool to_dev) -+{ -+ uint64_t resid; -+ int sg_cur_index; -+ -+ resid = sg->size; -+ sg_cur_index = 0; -+ len = MIN(len, resid); -+ while (len > 0) { -+ ScatterGatherEntry entry = sg->sg[sg_cur_index++]; -+ cpu_physical_memory_rw(entry.base, ptr, MIN(len, entry.len), !to_dev); -+ ptr += entry.len; -+ len -= entry.len; -+ resid -= entry.len; -+ } -+ -+ return resid; -+} -+ -+uint64_t dma_buf_read(uint8_t *ptr, int32_t len, QEMUSGList *sg) -+{ -+ return dma_buf_rw(ptr, len, sg, 0); -+} -+ -+uint64_t dma_buf_write(uint8_t *ptr, int32_t len, QEMUSGList *sg) -+{ -+ return dma_buf_rw(ptr, len, sg, 1); -+} -+ -+void dma_acct_start(BlockDriverState *bs, BlockAcctCookie *cookie, -+ QEMUSGList *sg, enum BlockAcctType type) -+{ -+ bdrv_acct_start(bs, cookie, sg->size, type); -+} -diff -ruNp qemu-kvm-1.0/hw/esp.c qemu-kvm-1.0.virtio-scsi/hw/esp.c ---- qemu-kvm-1.0/hw/esp.c 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/esp.c 2012-02-07 14:44:53.425905267 -0600 -@@ -389,7 +389,8 @@ static void esp_do_dma(ESPState *s) - esp_dma_done(s); - } - --static void esp_command_complete(SCSIRequest *req, uint32_t status) -+static void esp_command_complete(SCSIRequest *req, uint32_t status, -+ int32_t resid) - { - ESPState *s = DO_UPCAST(ESPState, busdev.qdev, req->bus->qbus.parent); - -diff -ruNp qemu-kvm-1.0/hw/ide/ahci.c qemu-kvm-1.0.virtio-scsi/hw/ide/ahci.c ---- qemu-kvm-1.0/hw/ide/ahci.c 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/ide/ahci.c 2012-02-07 14:44:53.426905283 -0600 -@@ -425,55 +425,6 @@ static void ahci_reg_init(AHCIState *s) - } - } - --static uint32_t read_from_sglist(uint8_t *buffer, uint32_t len, -- QEMUSGList *sglist) --{ -- uint32_t i = 0; -- uint32_t total = 0, once; -- ScatterGatherEntry *cur_prd; -- uint32_t sgcount; -- -- cur_prd = sglist->sg; -- sgcount = sglist->nsg; -- for (i = 0; len && sgcount; i++) { -- once = MIN(cur_prd->len, len); -- cpu_physical_memory_read(cur_prd->base, buffer, once); -- cur_prd++; -- sgcount--; -- len -= once; -- buffer += once; -- total += once; -- } -- -- return total; --} -- --static uint32_t write_to_sglist(uint8_t *buffer, uint32_t len, -- QEMUSGList *sglist) --{ -- uint32_t i = 0; -- uint32_t total = 0, once; -- ScatterGatherEntry *cur_prd; -- uint32_t sgcount; -- -- DPRINTF(-1, "total: 0x%x bytes\n", len); -- -- cur_prd = sglist->sg; -- sgcount = sglist->nsg; -- for (i = 0; len && sgcount; i++) { -- once = MIN(cur_prd->len, len); -- DPRINTF(-1, "write 0x%x bytes to 0x%lx\n", once, (long)cur_prd->base); -- cpu_physical_memory_write(cur_prd->base, buffer, once); -- cur_prd++; -- sgcount--; -- len -= once; -- buffer += once; -- total += once; -- } -- -- return total; --} -- - static void check_cmd(AHCIState *s, int port) - { - AHCIPortRegs *pr = &s->dev[port].port_regs; -@@ -794,9 +745,8 @@ static void process_ncq_command(AHCIStat - DPRINTF(port, "tag %d aio read %"PRId64"\n", - ncq_tfs->tag, ncq_tfs->lba); - -- bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct, -- (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE, -- BDRV_ACCT_READ); -+ dma_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct, -+ &ncq_tfs->sglist, BDRV_ACCT_READ); - ncq_tfs->aiocb = dma_bdrv_read(ncq_tfs->drive->port.ifs[0].bs, - &ncq_tfs->sglist, ncq_tfs->lba, - ncq_cb, ncq_tfs); -@@ -808,9 +758,8 @@ static void process_ncq_command(AHCIStat - DPRINTF(port, "tag %d aio write %"PRId64"\n", - ncq_tfs->tag, ncq_tfs->lba); - -- bdrv_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct, -- (ncq_tfs->sector_count-1) * BDRV_SECTOR_SIZE, -- BDRV_ACCT_WRITE); -+ dma_acct_start(ncq_tfs->drive->port.ifs[0].bs, &ncq_tfs->acct, -+ &ncq_tfs->sglist, BDRV_ACCT_WRITE); - ncq_tfs->aiocb = dma_bdrv_write(ncq_tfs->drive->port.ifs[0].bs, - &ncq_tfs->sglist, ncq_tfs->lba, - ncq_cb, ncq_tfs); -@@ -1015,12 +964,12 @@ static int ahci_start_transfer(IDEDMA *d - is_write ? "writ" : "read", size, is_atapi ? "atapi" : "ata", - has_sglist ? "" : "o"); - -- if (is_write && has_sglist && (s->data_ptr < s->data_end)) { -- read_from_sglist(s->data_ptr, size, &s->sg); -- } -- -- if (!is_write && has_sglist && (s->data_ptr < s->data_end)) { -- write_to_sglist(s->data_ptr, size, &s->sg); -+ if (has_sglist && size) { -+ if (is_write) { -+ dma_buf_write(s->data_ptr, size, &s->sg); -+ } else { -+ dma_buf_read(s->data_ptr, size, &s->sg); -+ } - } - - /* update number of transferred bytes */ -@@ -1059,14 +1008,9 @@ static int ahci_dma_prepare_buf(IDEDMA * - { - AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma); - IDEState *s = &ad->port.ifs[0]; -- int i; - - ahci_populate_sglist(ad, &s->sg); -- -- s->io_buffer_size = 0; -- for (i = 0; i < s->sg.nsg; i++) { -- s->io_buffer_size += s->sg.sg[i].len; -- } -+ s->io_buffer_size = s->sg.size; - - DPRINTF(ad->port_no, "len=%#x\n", s->io_buffer_size); - return s->io_buffer_size != 0; -@@ -1084,9 +1028,9 @@ static int ahci_dma_rw_buf(IDEDMA *dma, - } - - if (is_write) { -- write_to_sglist(p, l, &s->sg); -+ dma_buf_read(p, l, &s->sg); - } else { -- read_from_sglist(p, l, &s->sg); -+ dma_buf_write(p, l, &s->sg); - } - - /* update number of transferred bytes */ -diff -ruNp qemu-kvm-1.0/hw/lsi53c895a.c qemu-kvm-1.0.virtio-scsi/hw/lsi53c895a.c ---- qemu-kvm-1.0/hw/lsi53c895a.c 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/lsi53c895a.c 2012-02-07 14:44:53.427905299 -0600 -@@ -699,7 +699,7 @@ static int lsi_queue_req(LSIState *s, SC - } - - /* Callback to indicate that the SCSI layer has completed a command. */ --static void lsi_command_complete(SCSIRequest *req, uint32_t status) -+static void lsi_command_complete(SCSIRequest *req, uint32_t status, int32_t resid) - { - LSIState *s = DO_UPCAST(LSIState, dev.qdev, req->bus->qbus.parent); - int out; -diff -ruNp qemu-kvm-1.0/hw/pci.h qemu-kvm-1.0.virtio-scsi/hw/pci.h ---- qemu-kvm-1.0/hw/pci.h 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/pci.h 2012-02-07 14:44:53.427905299 -0600 -@@ -76,6 +76,7 @@ - #define PCI_DEVICE_ID_VIRTIO_BLOCK 0x1001 - #define PCI_DEVICE_ID_VIRTIO_BALLOON 0x1002 - #define PCI_DEVICE_ID_VIRTIO_CONSOLE 0x1003 -+#define PCI_DEVICE_ID_VIRTIO_SCSI 0x1004 - - #define FMT_PCIBUS PRIx64 - -diff -ruNp qemu-kvm-1.0/hw/s390-virtio-bus.c qemu-kvm-1.0.virtio-scsi/hw/s390-virtio-bus.c ---- qemu-kvm-1.0/hw/s390-virtio-bus.c 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/s390-virtio-bus.c 2012-02-07 14:44:53.428905315 -0600 -@@ -158,6 +158,18 @@ static int s390_virtio_serial_init(VirtI - return r; - } - -+static int s390_virtio_scsi_init(VirtIOS390Device *dev) -+{ -+ VirtIODevice *vdev; -+ -+ vdev = virtio_scsi_init((DeviceState *)dev, &dev->scsi); -+ if (!vdev) { -+ return -1; -+ } -+ -+ return s390_virtio_device_init(dev, vdev); -+} -+ - static uint64_t s390_virtio_device_vq_token(VirtIOS390Device *dev, int vq) - { - ram_addr_t token_off; -@@ -370,6 +382,17 @@ static VirtIOS390DeviceInfo s390_virtio_ - }, - }; - -+static VirtIOS390DeviceInfo s390_virtio_scsi = { -+ .init = s390_virtio_scsi_init, -+ .qdev.name = "virtio-scsi-s390", -+ .qdev.alias = "virtio-scsi", -+ .qdev.size = sizeof(VirtIOS390Device), -+ .qdev.props = (Property[]) { -+ DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOS390Device, host_features, scsi), -+ DEFINE_PROP_END_OF_LIST(), -+ }, -+}; -+ - static int s390_virtio_busdev_init(DeviceState *dev, DeviceInfo *info) - { - VirtIOS390DeviceInfo *_info = (VirtIOS390DeviceInfo *)info; -@@ -392,6 +415,7 @@ static void s390_virtio_register(void) - s390_virtio_bus_register_withprop(&s390_virtio_serial); - s390_virtio_bus_register_withprop(&s390_virtio_blk); - s390_virtio_bus_register_withprop(&s390_virtio_net); -+ s390_virtio_bus_register_withprop(&s390_virtio_scsi); - } - device_init(s390_virtio_register); - -diff -ruNp qemu-kvm-1.0/hw/s390-virtio-bus.h qemu-kvm-1.0.virtio-scsi/hw/s390-virtio-bus.h ---- qemu-kvm-1.0/hw/s390-virtio-bus.h 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/s390-virtio-bus.h 2012-02-07 14:44:53.428905315 -0600 -@@ -19,6 +19,7 @@ - - #include "virtio-net.h" - #include "virtio-serial.h" -+#include "virtio-scsi.h" - - #define VIRTIO_DEV_OFFS_TYPE 0 /* 8 bits */ - #define VIRTIO_DEV_OFFS_NUM_VQ 1 /* 8 bits */ -@@ -47,6 +48,7 @@ typedef struct VirtIOS390Device { - uint32_t host_features; - virtio_serial_conf serial; - virtio_net_conf net; -+ VirtIOSCSIConf scsi; - } VirtIOS390Device; - - typedef struct VirtIOS390Bus { -diff -ruNp qemu-kvm-1.0/hw/scsi-bus.c qemu-kvm-1.0.virtio-scsi/hw/scsi-bus.c ---- qemu-kvm-1.0/hw/scsi-bus.c 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/scsi-bus.c 2012-02-07 14:44:53.428905315 -0600 -@@ -5,6 +5,7 @@ - #include "qdev.h" - #include "blockdev.h" - #include "trace.h" -+#include "dma.h" - - static char *scsibus_get_fw_dev_path(DeviceState *dev); - static int scsi_req_parse(SCSICommand *cmd, SCSIDevice *dev, uint8_t *buf); -@@ -50,6 +51,7 @@ static void scsi_dma_restart_bh(void *op - scsi_req_continue(req); - break; - case SCSI_XFER_NONE: -+ assert(!req->sg); - scsi_req_dequeue(req); - scsi_req_enqueue(req); - break; -@@ -512,6 +514,8 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, - } - - req->cmd = cmd; -+ req->resid = req->cmd.xfer; -+ - switch (buf[0]) { - case INQUIRY: - trace_scsi_inquiry(d->id, lun, tag, cmd.buf[1], cmd.buf[2]); -@@ -624,15 +628,25 @@ void scsi_req_build_sense(SCSIRequest *r - req->sense_len = 18; - } - --int32_t scsi_req_enqueue(SCSIRequest *req) -+static void scsi_req_enqueue_internal(SCSIRequest *req) - { -- int32_t rc; -- - assert(!req->enqueued); - scsi_req_ref(req); -+ if (req->bus->info->get_sg_list) { -+ req->sg = req->bus->info->get_sg_list(req); -+ } else { -+ req->sg = NULL; -+ } - req->enqueued = true; - QTAILQ_INSERT_TAIL(&req->dev->requests, req, next); -+} -+ -+int32_t scsi_req_enqueue(SCSIRequest *req) -+{ -+ int32_t rc; - -+ assert (!req->retry); -+ scsi_req_enqueue_internal(req); - scsi_req_ref(req); - rc = req->ops->send_command(req, req->cmd.buf); - scsi_req_unref(req); -@@ -1254,12 +1268,32 @@ void scsi_req_continue(SCSIRequest *req) - Once it completes, calling scsi_req_continue will restart I/O. */ - void scsi_req_data(SCSIRequest *req, int len) - { -+ uint8_t *buf; - if (req->io_canceled) { - trace_scsi_req_data_canceled(req->dev->id, req->lun, req->tag, len); -- } else { -- trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); -+ return; -+ } -+ trace_scsi_req_data(req->dev->id, req->lun, req->tag, len); -+ assert(req->cmd.mode != SCSI_XFER_NONE); -+ if (!req->sg) { -+ req->resid -= len; - req->bus->info->transfer_data(req, len); -+ return; -+ } -+ -+ /* If the device calls scsi_req_data and the HBA specified a -+ * scatter/gather list, the transfer has to happen in a single -+ * step. */ -+ assert(!req->dma_started); -+ req->dma_started = true; -+ -+ buf = scsi_req_get_buf(req); -+ if (req->cmd.mode == SCSI_XFER_FROM_DEV) { -+ req->resid = dma_buf_read(buf, len, req->sg); -+ } else { -+ req->resid = dma_buf_write(buf, len, req->sg); - } -+ scsi_req_continue(req); - } - - void scsi_req_print(SCSIRequest *req) -@@ -1318,7 +1352,7 @@ void scsi_req_complete(SCSIRequest *req, - - scsi_req_ref(req); - scsi_req_dequeue(req); -- req->bus->info->complete(req, req->status); -+ req->bus->info->complete(req, req->status, req->resid); - scsi_req_unref(req); - } - -@@ -1393,3 +1427,100 @@ SCSIDevice *scsi_device_find(SCSIBus *bu - } - return target_dev; - } -+ -+ -+/* SCSI request list. For simplicity, pv points to the whole device */ -+ -+static void put_scsi_requests(QEMUFile *f, void *pv, size_t size) -+{ -+ SCSIDevice *s = pv; -+ SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus); -+ SCSIRequest *req; -+ -+ QTAILQ_FOREACH(req, &s->requests, next) { -+ assert(!req->io_canceled); -+ assert(req->status == -1); -+ assert(req->retry); -+ assert(req->enqueued); -+ -+ qemu_put_sbyte(f, 1); -+ qemu_put_buffer(f, req->cmd.buf, sizeof(req->cmd.buf)); -+ qemu_put_be32s(f, &req->tag); -+ qemu_put_be32s(f, &req->lun); -+ if (bus->info->save_request) { -+ bus->info->save_request(f, req); -+ } -+ if (req->ops->save_request) { -+ req->ops->save_request(f, req); -+ } -+ } -+ qemu_put_sbyte(f, 0); -+} -+ -+static int get_scsi_requests(QEMUFile *f, void *pv, size_t size) -+{ -+ SCSIDevice *s = pv; -+ SCSIBus *bus = DO_UPCAST(SCSIBus, qbus, s->qdev.parent_bus); -+ -+ while (qemu_get_sbyte(f)) { -+ uint8_t buf[SCSI_CMD_BUF_SIZE]; -+ uint32_t tag; -+ uint32_t lun; -+ SCSIRequest *req; -+ -+ qemu_get_buffer(f, buf, sizeof(buf)); -+ qemu_get_be32s(f, &tag); -+ qemu_get_be32s(f, &lun); -+ req = scsi_req_new(s, tag, lun, buf, NULL); -+ if (bus->info->load_request) { -+ req->hba_private = bus->info->load_request(f, req); -+ } -+ if (req->ops->load_request) { -+ req->ops->load_request(f, req); -+ } -+ -+ /* Just restart it later. */ -+ req->retry = true; -+ scsi_req_enqueue_internal(req); -+ -+ /* At this point, the request will be kept alive by the reference -+ * added by scsi_req_enqueue_internal, so we can release our reference. -+ * The HBA of course will add its own reference in the load_request -+ * callback if it needs to hold on the SCSIRequest. -+ */ -+ scsi_req_unref(req); -+ } -+ -+ return 0; -+} -+ -+const VMStateInfo vmstate_info_scsi_requests = { -+ .name = "scsi-requests", -+ .get = get_scsi_requests, -+ .put = put_scsi_requests, -+}; -+ -+const VMStateDescription vmstate_scsi_device = { -+ .name = "SCSIDevice", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT8(unit_attention.key, SCSIDevice), -+ VMSTATE_UINT8(unit_attention.asc, SCSIDevice), -+ VMSTATE_UINT8(unit_attention.ascq, SCSIDevice), -+ VMSTATE_BOOL(sense_is_ua, SCSIDevice), -+ VMSTATE_UINT8_ARRAY(sense, SCSIDevice, SCSI_SENSE_BUF_SIZE), -+ VMSTATE_UINT32(sense_len, SCSIDevice), -+ { -+ .name = "requests", -+ .version_id = 0, -+ .field_exists = NULL, -+ .size = 0, /* ouch */ -+ .info = &vmstate_info_scsi_requests, -+ .flags = VMS_SINGLE, -+ .offset = 0, -+ }, -+ VMSTATE_END_OF_LIST() -+ } -+}; -diff -ruNp qemu-kvm-1.0/hw/scsi-disk.c qemu-kvm-1.0.virtio-scsi/hw/scsi-disk.c ---- qemu-kvm-1.0/hw/scsi-disk.c 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/scsi-disk.c 2012-02-07 14:44:53.429905331 -0600 -@@ -38,6 +38,7 @@ do { fprintf(stderr, "scsi-disk: " fmt , - #include "sysemu.h" - #include "blockdev.h" - #include "block_int.h" -+#include "dma.h" - - #ifdef __linux - #include -@@ -110,12 +111,12 @@ static void scsi_cancel_io(SCSIRequest * - r->req.aiocb = NULL; - } - --static uint32_t scsi_init_iovec(SCSIDiskReq *r) -+static uint32_t scsi_init_iovec(SCSIDiskReq *r, size_t size) - { - SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); - - if (!r->iov.iov_base) { -- r->buflen = SCSI_DMA_BUF_SIZE; -+ r->buflen = size; - r->iov.iov_base = qemu_blockalign(s->qdev.conf.bs, r->buflen); - } - r->iov.iov_len = MIN(r->sector_count * 512, r->buflen); -@@ -123,6 +124,56 @@ static uint32_t scsi_init_iovec(SCSIDisk - return r->qiov.size / 512; - } - -+static void scsi_disk_save_request(QEMUFile *f, SCSIRequest *req) -+{ -+ SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); -+ -+ qemu_put_be64s(f, &r->sector); -+ qemu_put_be32s(f, &r->sector_count); -+ qemu_put_be32s(f, &r->buflen); -+ if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { -+ qemu_put_buffer(f, r->iov.iov_base, r->iov.iov_len); -+ } -+} -+ -+static void scsi_disk_load_request(QEMUFile *f, SCSIRequest *req) -+{ -+ SCSIDiskReq *r = DO_UPCAST(SCSIDiskReq, req, req); -+ -+ qemu_get_be64s(f, &r->sector); -+ qemu_get_be32s(f, &r->sector_count); -+ qemu_get_be32s(f, &r->buflen); -+ if (r->buflen) { -+ scsi_init_iovec(r, r->buflen); -+ if (r->req.cmd.mode == SCSI_XFER_TO_DEV) { -+ qemu_get_buffer(f, r->iov.iov_base, r->iov.iov_len); -+ } -+ } -+ -+ qemu_iovec_init_external(&r->qiov, &r->iov, 1); -+} -+ -+static void scsi_dma_complete(void * opaque, int ret) -+{ -+ SCSIDiskReq *r = (SCSIDiskReq *)opaque; -+ SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev); -+ -+ bdrv_acct_done(s->qdev.conf.bs, &r->acct); -+ -+ if (ret) { -+ if (scsi_handle_rw_error(r, -ret)) { -+ goto done; -+ } -+ } -+ -+ r->sector += r->sector_count; -+ r->sector_count = 0; -+ scsi_req_complete(&r->req, GOOD); -+ -+done: -+ scsi_req_unref(&r->req); -+} -+ - static void scsi_read_complete(void * opaque, int ret) - { - SCSIDiskReq *r = (SCSIDiskReq *)opaque; -@@ -213,10 +264,17 @@ static void scsi_read_data(SCSIRequest * - return; - } - -- n = scsi_init_iovec(r); -- bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ); -- r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n, -- scsi_read_complete, r); -+ if (r->req.sg) { -+ dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_READ); -+ r->req.resid -= r->req.sg->size; -+ r->req.aiocb = dma_bdrv_read(s->qdev.conf.bs, r->req.sg, r->sector, -+ scsi_dma_complete, r); -+ } else { -+ n = scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); -+ bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_READ); -+ r->req.aiocb = bdrv_aio_readv(s->qdev.conf.bs, r->sector, &r->qiov, n, -+ scsi_read_complete, r); -+ } - if (r->req.aiocb == NULL) { - scsi_read_complete(r, -EIO); - } -@@ -290,7 +348,7 @@ static void scsi_write_complete(void * o - if (r->sector_count == 0) { - scsi_req_complete(&r->req, GOOD); - } else { -- scsi_init_iovec(r); -+ scsi_init_iovec(r, SCSI_DMA_BUF_SIZE); - DPRINTF("Write complete tag=0x%x more=%d\n", r->req.tag, r->qiov.size); - scsi_req_data(&r->req, r->qiov.size); - } -@@ -318,21 +376,29 @@ static void scsi_write_data(SCSIRequest - return; - } - -- n = r->qiov.size / 512; -- if (n) { -- if (s->tray_open) { -- scsi_write_complete(r, -ENOMEDIUM); -- return; -- } -+ if (!r->req.sg && !r->qiov.size) { -+ /* Called for the first time. Ask the driver to send us more data. */ -+ scsi_write_complete(r, 0); -+ return; -+ } -+ if (s->tray_open) { -+ scsi_write_complete(r, -ENOMEDIUM); -+ return; -+ } -+ -+ if (r->req.sg) { -+ dma_acct_start(s->qdev.conf.bs, &r->acct, r->req.sg, BDRV_ACCT_WRITE); -+ r->req.resid -= r->req.sg->size; -+ r->req.aiocb = dma_bdrv_write(s->qdev.conf.bs, r->req.sg, r->sector, -+ scsi_dma_complete, r); -+ } else { -+ n = r->qiov.size / 512; - bdrv_acct_start(s->qdev.conf.bs, &r->acct, n * BDRV_SECTOR_SIZE, BDRV_ACCT_WRITE); - r->req.aiocb = bdrv_aio_writev(s->qdev.conf.bs, r->sector, &r->qiov, n, - scsi_write_complete, r); -- if (r->req.aiocb == NULL) { -- scsi_write_complete(r, -ENOMEM); -- } -- } else { -- /* Called for the first time. Ask the driver to send us more data. */ -- scsi_write_complete(r, 0); -+ } -+ if (r->req.aiocb == NULL) { -+ scsi_write_complete(r, -ENOMEM); - } - } - -@@ -1601,6 +1667,8 @@ static const SCSIReqOps scsi_disk_reqops - .write_data = scsi_write_data, - .cancel_io = scsi_cancel_io, - .get_buf = scsi_get_buf, -+ .load_request = scsi_disk_load_request, -+ .save_request = scsi_disk_save_request, - }; - - static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, -@@ -1729,6 +1797,22 @@ static SCSIRequest *scsi_block_new_reque - DEFINE_PROP_STRING("ver", SCSIDiskState, version), \ - DEFINE_PROP_STRING("serial", SCSIDiskState, serial) - -+static const VMStateDescription vmstate_scsi_disk_state = { -+ .name = "scsi-disk", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .minimum_version_id_old = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_SCSI_DEVICE(qdev, SCSIDiskState), -+ VMSTATE_BOOL(media_changed, SCSIDiskState), -+ VMSTATE_BOOL(media_event, SCSIDiskState), -+ VMSTATE_BOOL(eject_request, SCSIDiskState), -+ VMSTATE_BOOL(tray_open, SCSIDiskState), -+ VMSTATE_BOOL(tray_locked, SCSIDiskState), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ - static SCSIDeviceInfo scsi_disk_info[] = { - { - .qdev.name = "scsi-hd", -@@ -1736,6 +1820,7 @@ static SCSIDeviceInfo scsi_disk_info[] = - .qdev.desc = "virtual SCSI disk", - .qdev.size = sizeof(SCSIDiskState), - .qdev.reset = scsi_disk_reset, -+ .qdev.vmsd = &vmstate_scsi_disk_state, - .init = scsi_hd_initfn, - .destroy = scsi_destroy, - .alloc_req = scsi_new_request, -@@ -1751,6 +1836,7 @@ static SCSIDeviceInfo scsi_disk_info[] = - .qdev.desc = "virtual SCSI CD-ROM", - .qdev.size = sizeof(SCSIDiskState), - .qdev.reset = scsi_disk_reset, -+ .qdev.vmsd = &vmstate_scsi_disk_state, - .init = scsi_cd_initfn, - .destroy = scsi_destroy, - .alloc_req = scsi_new_request, -@@ -1766,6 +1852,7 @@ static SCSIDeviceInfo scsi_disk_info[] = - .qdev.desc = "SCSI block device passthrough", - .qdev.size = sizeof(SCSIDiskState), - .qdev.reset = scsi_disk_reset, -+ .qdev.vmsd = &vmstate_scsi_disk_state, - .init = scsi_block_initfn, - .destroy = scsi_destroy, - .alloc_req = scsi_block_new_request, -@@ -1780,6 +1867,7 @@ static SCSIDeviceInfo scsi_disk_info[] = - .qdev.desc = "virtual SCSI disk or CD-ROM (legacy)", - .qdev.size = sizeof(SCSIDiskState), - .qdev.reset = scsi_disk_reset, -+ .qdev.vmsd = &vmstate_scsi_disk_state, - .init = scsi_disk_initfn, - .destroy = scsi_destroy, - .alloc_req = scsi_new_request, -diff -ruNp qemu-kvm-1.0/hw/scsi-generic.c qemu-kvm-1.0.virtio-scsi/hw/scsi-generic.c ---- qemu-kvm-1.0/hw/scsi-generic.c 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/scsi-generic.c 2012-02-07 14:44:53.430905347 -0600 -@@ -59,6 +59,28 @@ typedef struct SCSIGenericReq { - sg_io_hdr_t io_header; - } SCSIGenericReq; - -+static void scsi_generic_save_request(QEMUFile *f, SCSIRequest *req) -+{ -+ SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); -+ -+ qemu_put_sbe32s(f, &r->buflen); -+ if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { -+ assert(!r->req.sg); -+ qemu_put_buffer(f, r->buf, r->req.cmd.xfer); -+ } -+} -+ -+static void scsi_generic_load_request(QEMUFile *f, SCSIRequest *req) -+{ -+ SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); -+ -+ qemu_get_sbe32s(f, &r->buflen); -+ if (r->buflen && r->req.cmd.mode == SCSI_XFER_TO_DEV) { -+ assert(!r->req.sg); -+ qemu_get_buffer(f, r->buf, r->req.cmd.xfer); -+ } -+} -+ - static void scsi_free_request(SCSIRequest *req) - { - SCSIGenericReq *r = DO_UPCAST(SCSIGenericReq, req, req); -@@ -450,6 +472,8 @@ const SCSIReqOps scsi_generic_req_ops = - .write_data = scsi_write_data, - .cancel_io = scsi_cancel_io, - .get_buf = scsi_get_buf, -+ .load_request = scsi_generic_load_request, -+ .save_request = scsi_generic_save_request, - }; - - static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun, -@@ -467,6 +491,7 @@ static SCSIDeviceInfo scsi_generic_info - .qdev.desc = "pass through generic scsi device (/dev/sg*)", - .qdev.size = sizeof(SCSIDevice), - .qdev.reset = scsi_generic_reset, -+ .qdev.vmsd = &vmstate_scsi_device, - .init = scsi_generic_initfn, - .destroy = scsi_destroy, - .alloc_req = scsi_new_request, -diff -ruNp qemu-kvm-1.0/hw/scsi.h qemu-kvm-1.0.virtio-scsi/hw/scsi.h ---- qemu-kvm-1.0/hw/scsi.h 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/scsi.h 2012-02-07 14:44:53.430905347 -0600 -@@ -47,8 +47,11 @@ struct SCSIRequest { - uint32_t tag; - uint32_t lun; - uint32_t status; -+ size_t resid; - SCSICommand cmd; - BlockDriverAIOCB *aiocb; -+ QEMUSGList *sg; -+ bool dma_started; - uint8_t sense[SCSI_SENSE_BUF_SIZE]; - uint32_t sense_len; - bool enqueued; -@@ -78,6 +81,16 @@ struct SCSIDevice - uint64_t max_lba; - }; - -+extern const VMStateDescription vmstate_scsi_device; -+ -+#define VMSTATE_SCSI_DEVICE(_field, _state) { \ -+ .name = (stringify(_field)), \ -+ .size = sizeof(SCSIDevice), \ -+ .vmsd = &vmstate_scsi_device, \ -+ .flags = VMS_STRUCT, \ -+ .offset = vmstate_offset_value(_state, _field, SCSIDevice), \ -+} -+ - /* cdrom.c */ - int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); - int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num); -@@ -91,6 +104,9 @@ struct SCSIReqOps { - void (*write_data)(SCSIRequest *req); - void (*cancel_io)(SCSIRequest *req); - uint8_t *(*get_buf)(SCSIRequest *req); -+ -+ void (*save_request)(QEMUFile *f, SCSIRequest *req); -+ void (*load_request)(QEMUFile *f, SCSIRequest *req); - }; - - typedef int (*scsi_qdev_initfn)(SCSIDevice *dev); -@@ -107,8 +123,12 @@ struct SCSIBusInfo { - int tcq; - int max_channel, max_target, max_lun; - void (*transfer_data)(SCSIRequest *req, uint32_t arg); -- void (*complete)(SCSIRequest *req, uint32_t arg); -+ void (*complete)(SCSIRequest *req, uint32_t arg, int32_t len); - void (*cancel)(SCSIRequest *req); -+ QEMUSGList *(*get_sg_list)(SCSIRequest *req); -+ -+ void (*save_request)(QEMUFile *f, SCSIRequest *req); -+ void *(*load_request)(QEMUFile *f, SCSIRequest *req); - }; - - struct SCSIBus { -diff -ruNp qemu-kvm-1.0/hw/spapr_vscsi.c qemu-kvm-1.0.virtio-scsi/hw/spapr_vscsi.c ---- qemu-kvm-1.0/hw/spapr_vscsi.c 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/spapr_vscsi.c 2012-02-07 14:44:53.430905347 -0600 -@@ -494,7 +494,7 @@ static void vscsi_transfer_data(SCSIRequ - } - - /* Callback to indicate that the SCSI layer has completed a transfer. */ --static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status) -+static void vscsi_command_complete(SCSIRequest *sreq, uint32_t status, int32_t resid) - { - VSCSIState *s = DO_UPCAST(VSCSIState, vdev.qdev, sreq->bus->qbus.parent); - vscsi_req *req = sreq->hba_private; -diff -ruNp qemu-kvm-1.0/hw/usb-msd.c qemu-kvm-1.0.virtio-scsi/hw/usb-msd.c ---- qemu-kvm-1.0/hw/usb-msd.c 2012-02-07 14:44:04.881123501 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/usb-msd.c 2012-02-07 14:44:53.431905363 -0600 -@@ -223,7 +223,7 @@ static void usb_msd_transfer_data(SCSIRe - } - } - --static void usb_msd_command_complete(SCSIRequest *req, uint32_t status) -+static void usb_msd_command_complete(SCSIRequest *req, uint32_t status, int32_t resid) - { - MSDState *s = DO_UPCAST(MSDState, dev.qdev, req->bus->qbus.parent); - USBPacket *p = s->packet; -diff -ruNp qemu-kvm-1.0/hw/virtio.h qemu-kvm-1.0.virtio-scsi/hw/virtio.h ---- qemu-kvm-1.0/hw/virtio.h 2011-12-04 04:38:06.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/virtio.h 2012-02-07 14:44:53.433905395 -0600 -@@ -199,6 +199,8 @@ VirtIODevice *virtio_net_init(DeviceStat - typedef struct virtio_serial_conf virtio_serial_conf; - VirtIODevice *virtio_serial_init(DeviceState *dev, virtio_serial_conf *serial); - VirtIODevice *virtio_balloon_init(DeviceState *dev); -+typedef struct VirtIOSCSIConf VirtIOSCSIConf; -+VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *conf); - #ifdef CONFIG_LINUX - VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf); - #endif -@@ -208,6 +210,7 @@ void virtio_net_exit(VirtIODevice *vdev) - void virtio_blk_exit(VirtIODevice *vdev); - void virtio_serial_exit(VirtIODevice *vdev); - void virtio_balloon_exit(VirtIODevice *vdev); -+void virtio_scsi_exit(VirtIODevice *vdev); - - #define DEFINE_VIRTIO_COMMON_FEATURES(_state, _field) \ - DEFINE_PROP_BIT("indirect_desc", _state, _field, \ -diff -ruNp qemu-kvm-1.0/hw/virtio-pci.c qemu-kvm-1.0.virtio-scsi/hw/virtio-pci.c ---- qemu-kvm-1.0/hw/virtio-pci.c 2012-02-07 14:44:04.850123002 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/virtio-pci.c 2012-02-07 14:44:53.432905379 -0600 -@@ -19,6 +19,7 @@ - #include "virtio-blk.h" - #include "virtio-net.h" - #include "virtio-serial.h" -+#include "virtio-scsi.h" - #include "pci.h" - #include "qemu-error.h" - #include "msix.h" -@@ -855,6 +856,32 @@ static int virtio_balloon_exit_pci(PCIDe - return virtio_exit_pci(pci_dev); - } - -+static int virtio_scsi_init_pci(PCIDevice *pci_dev) -+{ -+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); -+ VirtIODevice *vdev; -+ -+ vdev = virtio_scsi_init(&pci_dev->qdev, &proxy->scsi); -+ if (!vdev) { -+ return -EINVAL; -+ } -+ -+ vdev->nvectors = proxy->nvectors; -+ virtio_init_pci(proxy, vdev); -+ -+ /* make the actual value visible */ -+ proxy->nvectors = vdev->nvectors; -+ return 0; -+} -+ -+static int virtio_scsi_exit_pci(PCIDevice *pci_dev) -+{ -+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); -+ -+ virtio_scsi_exit(proxy->vdev); -+ return virtio_exit_pci(pci_dev); -+} -+ - static PCIDeviceInfo virtio_info[] = { - { - .qdev.name = "virtio-blk-pci", -@@ -940,6 +967,21 @@ static PCIDeviceInfo virtio_info[] = { - }, - .qdev.reset = virtio_pci_reset, - },{ -+ .qdev.name = "virtio-scsi-pci", -+ .qdev.alias = "virtio-scsi", -+ .qdev.size = sizeof(VirtIOPCIProxy), -+ .init = virtio_scsi_init_pci, -+ .exit = virtio_scsi_exit_pci, -+ .vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET, -+ .device_id = PCI_DEVICE_ID_VIRTIO_SCSI, -+ .class_id = PCI_CLASS_STORAGE_SCSI, -+ .revision = 0x00, -+ .qdev.props = (Property[]) { -+ DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), -+ DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOPCIProxy, host_features, scsi), -+ DEFINE_PROP_END_OF_LIST(), -+ }, -+ }, { - /* end of list */ - } - }; -diff -ruNp qemu-kvm-1.0/hw/virtio-pci.h qemu-kvm-1.0.virtio-scsi/hw/virtio-pci.h ---- qemu-kvm-1.0/hw/virtio-pci.h 2012-02-07 14:44:04.850123002 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/virtio-pci.h 2012-02-07 14:44:53.432905379 -0600 -@@ -17,6 +17,7 @@ - - #include "virtio-net.h" - #include "virtio-serial.h" -+#include "virtio-scsi.h" - - /* Performance improves when virtqueue kick processing is decoupled from the - * vcpu thread using ioeventfd for some devices. */ -@@ -40,6 +41,7 @@ typedef struct { - #endif - virtio_serial_conf serial; - virtio_net_conf net; -+ VirtIOSCSIConf scsi; - bool ioeventfd_disabled; - bool ioeventfd_started; - } VirtIOPCIProxy; -diff -ruNp qemu-kvm-1.0/hw/virtio-scsi.c qemu-kvm-1.0.virtio-scsi/hw/virtio-scsi.c ---- qemu-kvm-1.0/hw/virtio-scsi.c 1969-12-31 18:00:00.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/virtio-scsi.c 2012-02-07 14:44:53.432905379 -0600 -@@ -0,0 +1,607 @@ -+/* -+ * Virtio SCSI HBA -+ * -+ * Copyright IBM, Corp. 2010 -+ * Copyright Red Hat, Inc. 2011 -+ * -+ * Authors: -+ * Stefan Hajnoczi -+ * Paolo Bonzini -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2 or later. -+ * See the COPYING file in the top-level directory. -+ * -+ */ -+ -+#include "virtio-scsi.h" -+#include -+#include -+ -+#define VIRTIO_SCSI_VQ_SIZE 128 -+#define VIRTIO_SCSI_CDB_SIZE 32 -+#define VIRTIO_SCSI_SENSE_SIZE 96 -+#define VIRTIO_SCSI_MAX_CHANNEL 0 -+#define VIRTIO_SCSI_MAX_TARGET 255 -+#define VIRTIO_SCSI_MAX_LUN 16383 -+ -+/* Response codes */ -+#define VIRTIO_SCSI_S_OK 0 -+#define VIRTIO_SCSI_S_OVERRUN 1 -+#define VIRTIO_SCSI_S_ABORTED 2 -+#define VIRTIO_SCSI_S_BAD_TARGET 3 -+#define VIRTIO_SCSI_S_RESET 4 -+#define VIRTIO_SCSI_S_BUSY 5 -+#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6 -+#define VIRTIO_SCSI_S_TARGET_FAILURE 7 -+#define VIRTIO_SCSI_S_NEXUS_FAILURE 8 -+#define VIRTIO_SCSI_S_FAILURE 9 -+#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10 -+#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11 -+#define VIRTIO_SCSI_S_INCORRECT_LUN 12 -+ -+/* Controlq type codes. */ -+#define VIRTIO_SCSI_T_TMF 0 -+#define VIRTIO_SCSI_T_AN_QUERY 1 -+#define VIRTIO_SCSI_T_AN_SUBSCRIBE 2 -+ -+/* Valid TMF subtypes. */ -+#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0 -+#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1 -+#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2 -+#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3 -+#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4 -+#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5 -+#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6 -+#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7 -+ -+/* Events. */ -+#define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000 -+#define VIRTIO_SCSI_T_NO_EVENT 0 -+#define VIRTIO_SCSI_T_TRANSPORT_RESET 1 -+#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2 -+ -+/* SCSI command request, followed by data-out */ -+typedef struct { -+ uint8_t lun[8]; /* Logical Unit Number */ -+ uint64_t tag; /* Command identifier */ -+ uint8_t task_attr; /* Task attribute */ -+ uint8_t prio; -+ uint8_t crn; -+ uint8_t cdb[]; -+} QEMU_PACKED VirtIOSCSICmdReq; -+ -+/* Response, followed by sense data and data-in */ -+typedef struct { -+ uint32_t sense_len; /* Sense data length */ -+ uint32_t resid; /* Residual bytes in data buffer */ -+ uint16_t status_qualifier; /* Status qualifier */ -+ uint8_t status; /* Command completion status */ -+ uint8_t response; /* Response values */ -+ uint8_t sense[]; -+} QEMU_PACKED VirtIOSCSICmdResp; -+ -+/* Task Management Request */ -+typedef struct { -+ uint32_t type; -+ uint32_t subtype; -+ uint8_t lun[8]; -+ uint64_t tag; -+} QEMU_PACKED VirtIOSCSICtrlTMFReq; -+ -+typedef struct { -+ uint8_t response; -+} QEMU_PACKED VirtIOSCSICtrlTMFResp; -+ -+/* Asynchronous notification query/subscription */ -+typedef struct { -+ uint32_t type; -+ uint8_t lun[8]; -+ uint32_t event_requested; -+} QEMU_PACKED VirtIOSCSICtrlANReq; -+ -+typedef struct { -+ uint32_t event_actual; -+ uint8_t response; -+} QEMU_PACKED VirtIOSCSICtrlANResp; -+ -+typedef struct { -+ uint32_t event; -+ uint8_t lun[8]; -+ uint32_t reason; -+} QEMU_PACKED VirtIOSCSIEvent; -+ -+typedef struct { -+ uint32_t num_queues; -+ uint32_t seg_max; -+ uint32_t max_sectors; -+ uint32_t cmd_per_lun; -+ uint32_t event_info_size; -+ uint32_t sense_size; -+ uint32_t cdb_size; -+ uint16_t max_channel; -+ uint16_t max_target; -+ uint32_t max_lun; -+} QEMU_PACKED VirtIOSCSIConfig; -+ -+typedef struct { -+ VirtIODevice vdev; -+ DeviceState *qdev; -+ VirtIOSCSIConf *conf; -+ -+ SCSIBus bus; -+ VirtQueue *ctrl_vq; -+ VirtQueue *event_vq; -+ VirtQueue *cmd_vq; -+ uint32_t sense_size; -+ uint32_t cdb_size; -+ bool resetting; -+} VirtIOSCSI; -+ -+typedef struct VirtIOSCSIReq { -+ VirtIOSCSI *dev; -+ VirtQueue *vq; -+ VirtQueueElement elem; -+ QEMUSGList qsgl; -+ SCSIRequest *sreq; -+ union { -+ char *buf; -+ VirtIOSCSICmdReq *cmd; -+ VirtIOSCSICtrlTMFReq *tmf; -+ VirtIOSCSICtrlANReq *an; -+ } req; -+ union { -+ char *buf; -+ VirtIOSCSICmdResp *cmd; -+ VirtIOSCSICtrlTMFResp *tmf; -+ VirtIOSCSICtrlANResp *an; -+ VirtIOSCSIEvent *event; -+ } resp; -+} VirtIOSCSIReq; -+ -+static inline int virtio_scsi_get_lun(uint8_t *lun) -+{ -+ return ((lun[2] << 8) | lun[3]) & 0x3FFF; -+} -+ -+static inline SCSIDevice *virtio_scsi_device_find(VirtIOSCSI *s, uint8_t *lun) -+{ -+ if (lun[0] != 1) { -+ return NULL; -+ } -+ if (lun[2] != 0 && !(lun[2] >= 0x40 && lun[2] < 0x80)) { -+ return NULL; -+ } -+ return scsi_device_find(&s->bus, 0, lun[1], virtio_scsi_get_lun(lun)); -+} -+ -+static void virtio_scsi_complete_req(VirtIOSCSIReq *req) -+{ -+ VirtIOSCSI *s = req->dev; -+ VirtQueue *vq = req->vq; -+ virtqueue_push(vq, &req->elem, req->qsgl.size + req->elem.in_sg[0].iov_len); -+ qemu_sglist_destroy(&req->qsgl); -+ if (req->sreq) { -+ req->sreq->hba_private = NULL; -+ scsi_req_unref(req->sreq); -+ } -+ g_free(req); -+ virtio_notify(&s->vdev, vq); -+} -+ -+static void virtio_scsi_bad_req(void) -+{ -+ error_report("wrong size for virtio-scsi headers"); -+ exit(1); -+} -+ -+static void qemu_sgl_init_external(QEMUSGList *qsgl, struct iovec *sg, -+ target_phys_addr_t *addr, int num) -+{ -+ memset(qsgl, 0, sizeof(*qsgl)); -+ while (num--) { -+ qemu_sglist_add(qsgl, *(addr++), (sg++)->iov_len); -+ } -+} -+ -+static void virtio_scsi_parse_req(VirtIOSCSI *s, VirtQueue *vq, -+ VirtIOSCSIReq *req) -+{ -+ assert(req->elem.out_num && req->elem.in_num); -+ req->vq = vq; -+ req->dev = s; -+ req->sreq = NULL; -+ req->req.buf = req->elem.out_sg[0].iov_base; -+ req->resp.buf = req->elem.in_sg[0].iov_base; -+ -+ if (req->elem.out_num > 1) { -+ qemu_sgl_init_external(&req->qsgl, &req->elem.out_sg[1], -+ &req->elem.out_addr[1], -+ req->elem.out_num - 1); -+ } else { -+ qemu_sgl_init_external(&req->qsgl, &req->elem.in_sg[1], -+ &req->elem.in_addr[1], -+ req->elem.in_num - 1); -+ } -+} -+ -+static VirtIOSCSIReq *virtio_scsi_pop_req(VirtIOSCSI *s, VirtQueue *vq) -+{ -+ VirtIOSCSIReq *req; -+ req = g_malloc(sizeof(*req)); -+ if (!virtqueue_pop(vq, &req->elem)) { -+ g_free(req); -+ return NULL; -+ } -+ -+ virtio_scsi_parse_req(s, vq, req); -+ return req; -+} -+ -+static void virtio_scsi_save_request(QEMUFile *f, SCSIRequest *sreq) -+{ -+ VirtIOSCSIReq *req = sreq->hba_private; -+ -+ qemu_put_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem)); -+} -+ -+static void *virtio_scsi_load_request(QEMUFile *f, SCSIRequest *sreq) -+{ -+ SCSIBus *bus = sreq->bus; -+ VirtIOSCSI *s = container_of(bus, VirtIOSCSI, bus); -+ VirtIOSCSIReq *req; -+ -+ req = g_malloc(sizeof(*req)); -+ qemu_get_buffer(f, (unsigned char*)&req->elem, sizeof(req->elem)); -+ virtio_scsi_parse_req(s, s->cmd_vq, req); -+ -+ scsi_req_ref(sreq); -+ req->sreq = sreq; -+ if (req->sreq->cmd.mode != SCSI_XFER_NONE) { -+ int req_mode = -+ (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV); -+ -+ assert (req->sreq->cmd.mode == req_mode); -+ } -+ return req; -+} -+ -+static void virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req) -+{ -+ SCSIDevice *d = virtio_scsi_device_find(s, req->req.cmd->lun); -+ SCSIRequest *r, *next; -+ DeviceState *qdev; -+ int target; -+ -+ switch (req->req.tmf->subtype) { -+ case VIRTIO_SCSI_T_TMF_ABORT_TASK: -+ case VIRTIO_SCSI_T_TMF_QUERY_TASK: -+ d = virtio_scsi_device_find(s, req->req.cmd->lun); -+ if (!d) { -+ goto fail; -+ } -+ if (d->lun != virtio_scsi_get_lun(req->req.cmd->lun)) { -+ req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN; -+ break; -+ } -+ QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { -+ if (r->tag == req->req.cmd->tag) { -+ break; -+ } -+ } -+ if (r && r->hba_private) { -+ if (req->req.tmf->subtype == VIRTIO_SCSI_T_TMF_ABORT_TASK) { -+ scsi_req_cancel(r); -+ } -+ req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; -+ } else { -+ req->resp.tmf->response = VIRTIO_SCSI_S_OK; -+ } -+ break; -+ -+ case VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET: -+ d = virtio_scsi_device_find(s, req->req.cmd->lun); -+ if (!d) { -+ goto fail; -+ } -+ if (d->lun == virtio_scsi_get_lun(req->req.cmd->lun)) { -+ s->resetting++; -+ qdev_reset_all(&d->qdev); -+ s->resetting--; -+ } -+ break; -+ -+ case VIRTIO_SCSI_T_TMF_ABORT_TASK_SET: -+ case VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET: -+ case VIRTIO_SCSI_T_TMF_QUERY_TASK_SET: -+ d = virtio_scsi_device_find(s, req->req.cmd->lun); -+ if (!d) { -+ goto fail; -+ } -+ if (d->lun != virtio_scsi_get_lun(req->req.cmd->lun)) { -+ req->resp.tmf->response = VIRTIO_SCSI_S_INCORRECT_LUN; -+ break; -+ } -+ req->resp.tmf->response = VIRTIO_SCSI_S_OK; -+ QTAILQ_FOREACH_SAFE(r, &d->requests, next, next) { -+ if (r->hba_private) { -+ if (req->req.tmf->subtype != VIRTIO_SCSI_T_TMF_QUERY_TASK) { -+ scsi_req_cancel(r); -+ } -+ req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_SUCCEEDED; -+ } -+ } -+ break; -+ -+ case VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET: -+ target = req->req.cmd->lun[1]; -+ s->resetting++; -+ QTAILQ_FOREACH(qdev, &s->bus.qbus.children, sibling) { -+ d = DO_UPCAST(SCSIDevice, qdev, qdev); -+ if (d->channel == 0 && d->id == target) { -+ qdev_reset_all(&d->qdev); -+ } -+ } -+ s->resetting--; -+ break; -+ -+ case VIRTIO_SCSI_T_TMF_CLEAR_ACA: -+ default: -+ req->resp.tmf->response = VIRTIO_SCSI_S_FUNCTION_REJECTED; -+ break; -+ } -+ -+ return; -+ -+fail: -+ req->resp.tmf->response = VIRTIO_SCSI_S_BAD_TARGET; -+} -+ -+static void virtio_scsi_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq) -+{ -+ VirtIOSCSI *s = (VirtIOSCSI *)vdev; -+ VirtIOSCSIReq *req; -+ -+ while ((req = virtio_scsi_pop_req(s, vq))) { -+ int out_size, in_size; -+ if (req->elem.out_num < 1 || req->elem.in_num < 1) { -+ virtio_scsi_bad_req(); -+ continue; -+ } -+ -+ out_size = req->elem.out_sg[0].iov_len; -+ in_size = req->elem.in_sg[0].iov_len; -+ if (req->req.tmf->type == VIRTIO_SCSI_T_TMF) { -+ if (out_size < sizeof(VirtIOSCSICtrlTMFReq) || -+ in_size < sizeof(VirtIOSCSICtrlTMFResp)) { -+ virtio_scsi_bad_req(); -+ } -+ virtio_scsi_do_tmf(s, req); -+ -+ } else if (req->req.tmf->type == VIRTIO_SCSI_T_AN_QUERY || -+ req->req.tmf->type == VIRTIO_SCSI_T_AN_SUBSCRIBE) { -+ if (out_size < sizeof(VirtIOSCSICtrlANReq) || -+ in_size < sizeof(VirtIOSCSICtrlANResp)) { -+ virtio_scsi_bad_req(); -+ } -+ req->resp.an->event_actual = 0; -+ req->resp.an->response = VIRTIO_SCSI_S_OK; -+ } -+ virtio_scsi_complete_req(req); -+ } -+} -+ -+static void virtio_scsi_command_complete(SCSIRequest *r, uint32_t status, -+ int32_t resid) -+{ -+ VirtIOSCSIReq *req = r->hba_private; -+ -+ req->resp.cmd->response = VIRTIO_SCSI_S_OK; -+ req->resp.cmd->status = status; -+ if (req->resp.cmd->status == GOOD) { -+ req->resp.cmd->resid = resid; -+ } else { -+ req->resp.cmd->resid = 0; -+ scsi_req_get_sense(r, req->resp.cmd->sense, VIRTIO_SCSI_SENSE_SIZE); -+ } -+ virtio_scsi_complete_req(req); -+} -+ -+static QEMUSGList *virtio_scsi_get_sg_list(SCSIRequest *r) -+{ -+ VirtIOSCSIReq *req = r->hba_private; -+ -+ return &req->qsgl; -+} -+ -+static void virtio_scsi_request_cancelled(SCSIRequest *r) -+{ -+ VirtIOSCSIReq *req = r->hba_private; -+ -+ if (!req) { -+ return; -+ } -+ if (req->dev->resetting) { -+ req->resp.cmd->response = VIRTIO_SCSI_S_RESET; -+ } else { -+ req->resp.cmd->response = VIRTIO_SCSI_S_ABORTED; -+ } -+ virtio_scsi_complete_req(req); -+} -+ -+static void virtio_scsi_fail_cmd_req(VirtIOSCSIReq *req) -+{ -+ req->resp.cmd->response = VIRTIO_SCSI_S_FAILURE; -+ virtio_scsi_complete_req(req); -+} -+ -+static void virtio_scsi_handle_cmd(VirtIODevice *vdev, VirtQueue *vq) -+{ -+ VirtIOSCSI *s = (VirtIOSCSI *)vdev; -+ VirtIOSCSIReq *req; -+ int n; -+ -+ while ((req = virtio_scsi_pop_req(s, vq))) { -+ SCSIDevice *d; -+ int out_size, in_size; -+ if (req->elem.out_num < 1 || req->elem.in_num < 1) { -+ virtio_scsi_bad_req(); -+ } -+ -+ out_size = req->elem.out_sg[0].iov_len; -+ in_size = req->elem.in_sg[0].iov_len; -+ if (out_size < sizeof(VirtIOSCSICmdReq) + s->cdb_size || -+ in_size < sizeof(VirtIOSCSICmdResp) + s->sense_size) { -+ virtio_scsi_bad_req(); -+ } -+ -+ if (req->elem.out_num > 1 && req->elem.in_num > 1) { -+ virtio_scsi_fail_cmd_req(req); -+ continue; -+ } -+ -+ d = virtio_scsi_device_find(s, req->req.cmd->lun); -+ if (!d) { -+ req->resp.cmd->response = VIRTIO_SCSI_S_BAD_TARGET; -+ virtio_scsi_complete_req(req); -+ continue; -+ } -+ req->sreq = scsi_req_new(d, req->req.cmd->tag, -+ virtio_scsi_get_lun(req->req.cmd->lun), -+ req->req.cmd->cdb, req); -+ -+ if (req->sreq->cmd.mode != SCSI_XFER_NONE) { -+ int req_mode = -+ (req->elem.in_num > 1 ? SCSI_XFER_FROM_DEV : SCSI_XFER_TO_DEV); -+ -+ if (req->sreq->cmd.mode != req_mode || -+ req->sreq->cmd.xfer > req->qsgl.size) { -+ req->resp.cmd->response = VIRTIO_SCSI_S_OVERRUN; -+ virtio_scsi_complete_req(req); -+ continue; -+ } -+ } -+ -+ n = scsi_req_enqueue(req->sreq); -+ if (n) { -+ scsi_req_continue(req->sreq); -+ } -+ } -+} -+ -+static void virtio_scsi_get_config(VirtIODevice *vdev, -+ uint8_t *config) -+{ -+ VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; -+ VirtIOSCSI *s = (VirtIOSCSI *)vdev; -+ -+ stl_raw(&scsiconf->num_queues, s->conf->num_queues); -+ stl_raw(&scsiconf->seg_max, 128 - 2); -+ stl_raw(&scsiconf->max_sectors, s->conf->max_sectors); -+ stl_raw(&scsiconf->cmd_per_lun, s->conf->cmd_per_lun); -+ stl_raw(&scsiconf->event_info_size, sizeof(VirtIOSCSIEvent)); -+ stl_raw(&scsiconf->sense_size, s->sense_size); -+ stl_raw(&scsiconf->cdb_size, s->cdb_size); -+ stl_raw(&scsiconf->max_channel, VIRTIO_SCSI_MAX_CHANNEL); -+ stl_raw(&scsiconf->max_target, VIRTIO_SCSI_MAX_TARGET); -+ stl_raw(&scsiconf->max_lun, VIRTIO_SCSI_MAX_LUN); -+} -+ -+static void virtio_scsi_set_config(VirtIODevice *vdev, -+ const uint8_t *config) -+{ -+ VirtIOSCSIConfig *scsiconf = (VirtIOSCSIConfig *)config; -+ VirtIOSCSI *s = (VirtIOSCSI *)vdev; -+ -+ if ((uint32_t) ldl_raw(&scsiconf->sense_size) >= 65536 || -+ (uint32_t) ldl_raw(&scsiconf->cdb_size) >= 256) { -+ error_report("bad data written to virtio-scsi configuration space"); -+ exit(1); -+ } -+ -+ s->sense_size = ldl_raw(&scsiconf->sense_size); -+ s->cdb_size = ldl_raw(&scsiconf->cdb_size); -+} -+ -+static uint32_t virtio_scsi_get_features(VirtIODevice *vdev, -+ uint32_t requested_features) -+{ -+ return requested_features; -+} -+ -+static void virtio_scsi_reset(VirtIODevice *vdev) -+{ -+ VirtIOSCSI *s = (VirtIOSCSI *)vdev; -+ -+ s->sense_size = VIRTIO_SCSI_SENSE_SIZE; -+ s->cdb_size = VIRTIO_SCSI_CDB_SIZE; -+} -+ -+/* The device does not have anything to save beyond the virtio data. -+ * Request data is saved with callbacks from SCSI devices. -+ */ -+static void virtio_scsi_save(QEMUFile *f, void *opaque) -+{ -+ VirtIOSCSI *s = opaque; -+ virtio_save(&s->vdev, f); -+} -+ -+static int virtio_scsi_load(QEMUFile *f, void *opaque, int version_id) -+{ -+ VirtIOSCSI *s = opaque; -+ virtio_load(&s->vdev, f); -+ return 0; -+} -+ -+static struct SCSIBusInfo virtio_scsi_scsi_info = { -+ .tcq = true, -+ .max_channel = VIRTIO_SCSI_MAX_CHANNEL, -+ .max_target = VIRTIO_SCSI_MAX_TARGET, -+ .max_lun = VIRTIO_SCSI_MAX_LUN, -+ -+ .complete = virtio_scsi_command_complete, -+ .cancel = virtio_scsi_request_cancelled, -+ .get_sg_list = virtio_scsi_get_sg_list, -+ .save_request = virtio_scsi_save_request, -+ .load_request = virtio_scsi_load_request, -+}; -+ -+VirtIODevice *virtio_scsi_init(DeviceState *dev, VirtIOSCSIConf *proxyconf) -+{ -+ VirtIOSCSI *s; -+ static int virtio_scsi_id; -+ -+ s = (VirtIOSCSI *)virtio_common_init("virtio-scsi", VIRTIO_ID_SCSI, -+ sizeof(VirtIOSCSIConfig), -+ sizeof(VirtIOSCSI)); -+ -+ s->qdev = dev; -+ s->conf = proxyconf; -+ -+ /* TODO set up vdev function pointers */ -+ s->vdev.get_config = virtio_scsi_get_config; -+ s->vdev.set_config = virtio_scsi_set_config; -+ s->vdev.get_features = virtio_scsi_get_features; -+ s->vdev.reset = virtio_scsi_reset; -+ -+ s->ctrl_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE, -+ virtio_scsi_handle_ctrl); -+ s->event_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE, -+ NULL); -+ s->cmd_vq = virtio_add_queue(&s->vdev, VIRTIO_SCSI_VQ_SIZE, -+ virtio_scsi_handle_cmd); -+ -+ scsi_bus_new(&s->bus, dev, &virtio_scsi_scsi_info); -+ if (!dev->hotplugged) { -+ scsi_bus_legacy_handle_cmdline(&s->bus); -+ } -+ -+ register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1, -+ virtio_scsi_save, virtio_scsi_load, s); -+ -+ return &s->vdev; -+} -+ -+void virtio_scsi_exit(VirtIODevice *vdev) -+{ -+ virtio_cleanup(vdev); -+} -diff -ruNp qemu-kvm-1.0/hw/virtio-scsi.h qemu-kvm-1.0.virtio-scsi/hw/virtio-scsi.h ---- qemu-kvm-1.0/hw/virtio-scsi.h 1969-12-31 18:00:00.000000000 -0600 -+++ qemu-kvm-1.0.virtio-scsi/hw/virtio-scsi.h 2012-02-07 14:44:53.432905379 -0600 -@@ -0,0 +1,36 @@ -+/* -+ * Virtio SCSI HBA -+ * -+ * Copyright IBM, Corp. 2010 -+ * -+ * Authors: -+ * Stefan Hajnoczi -+ * -+ * This work is licensed under the terms of the GNU GPL, version 2. See -+ * the COPYING file in the top-level directory. -+ * -+ */ -+ -+#ifndef _QEMU_VIRTIO_SCSI_H -+#define _QEMU_VIRTIO_SCSI_H -+ -+#include "virtio.h" -+#include "net.h" -+#include "pci.h" -+ -+/* The ID for virtio_scsi */ -+#define VIRTIO_ID_SCSI 8 -+ -+struct VirtIOSCSIConf { -+ uint32_t num_queues; -+ uint32_t max_sectors; -+ uint32_t cmd_per_lun; -+}; -+ -+#define DEFINE_VIRTIO_SCSI_PROPERTIES(_state, _features_field, _conf_field) \ -+ DEFINE_VIRTIO_COMMON_FEATURES(_state, _features_field), \ -+ DEFINE_PROP_UINT32("num_queues", _state, _conf_field.num_queues, 1), \ -+ DEFINE_PROP_UINT32("max_sectors", _state, _conf_field.max_sectors, 0xFFFF), \ -+ DEFINE_PROP_UINT32("cmd_per_lun", _state, _conf_field.cmd_per_lun, 128) -+ -+#endif /* _QEMU_VIRTIO_SCSI_H */ -diff -ruNp qemu-kvm-1.0/Makefile.target qemu-kvm-1.0.virtio-scsi/Makefile.target ---- qemu-kvm-1.0/Makefile.target 2012-02-07 14:44:04.965124855 -0600 -+++ qemu-kvm-1.0.virtio-scsi/Makefile.target 2012-02-07 14:44:53.126900450 -0600 -@@ -205,6 +205,7 @@ obj-y = arch_init.o cpus.o monitor.o mac - obj-$(CONFIG_NO_PCI) += pci-stub.o - obj-$(CONFIG_PCI) += pci.o - obj-$(CONFIG_VIRTIO) += virtio.o virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o -+obj-$(CONFIG_VIRTIO_SCSI) += virtio-scsi.o - obj-y += vhost_net.o - obj-$(CONFIG_VHOST_NET) += vhost.o - obj-$(CONFIG_REALLY_VIRTFS) += 9pfs/virtio-9p-device.o