From f5f190ba99193995d6c186ded3b7fc2457fdf515fed174973147e33acf985e84 Mon Sep 17 00:00:00 2001 From: Bruce Rogers Date: Fri, 10 Jun 2016 15:24:43 +0000 Subject: [PATCH] Accepting request 400970 from home:bfrogers:branches:Virtualization Submit includes numerous security fixes, patches which help fulfill FATE regarding xen pv-usb. and a fix openQA is needing. OBS-URL: https://build.opensuse.org/request/show/400970 OBS-URL: https://build.opensuse.org/package/show/Virtualization/qemu?expand=0&rev=299 --- ...-scsi-megasas-use-appropriate-proper.patch | 34 + ...-scsi-megasas-check-read_queue_head-.patch | 36 + ...-scsi-megasas-null-terminate-bios-ve.patch | 32 + ...-vmsvga-move-fifo-sanity-checks-to-v.patch | 73 ++ ...-vmsvga-don-t-process-more-than-1024.patch | 45 + ...-block-iscsi-avoid-potential-overflo.patch | 37 + ...-scsi-esp-check-TI-buffer-index-befo.patch | 71 + 0056-xen-introduce-dummy-system-device.patch | 104 ++ ...-xen-write-information-about-support.patch | 219 ++++ 0058-xen-add-pvUSB-backend.patch | 1165 +++++++++++++++++ ...-usb-Fix-conditions-that-xen-usb.c-i.patch | 28 + ...-vnc-add-configurable-keyboard-delay.patch | 129 ++ qemu-linux-user.changes | 18 + qemu-linux-user.spec | 24 + qemu-testsuite.changes | 31 + qemu-testsuite.spec | 24 + qemu.changes | 31 + qemu.spec | 24 + 18 files changed, 2125 insertions(+) create mode 100644 0049-scsi-megasas-use-appropriate-proper.patch create mode 100644 0050-scsi-megasas-check-read_queue_head-.patch create mode 100644 0051-scsi-megasas-null-terminate-bios-ve.patch create mode 100644 0052-vmsvga-move-fifo-sanity-checks-to-v.patch create mode 100644 0053-vmsvga-don-t-process-more-than-1024.patch create mode 100644 0054-block-iscsi-avoid-potential-overflo.patch create mode 100644 0055-scsi-esp-check-TI-buffer-index-befo.patch create mode 100644 0056-xen-introduce-dummy-system-device.patch create mode 100644 0057-xen-write-information-about-support.patch create mode 100644 0058-xen-add-pvUSB-backend.patch create mode 100644 0059-usb-Fix-conditions-that-xen-usb.c-i.patch create mode 100644 0060-vnc-add-configurable-keyboard-delay.patch diff --git a/0049-scsi-megasas-use-appropriate-proper.patch b/0049-scsi-megasas-use-appropriate-proper.patch new file mode 100644 index 00000000..bd8d974c --- /dev/null +++ b/0049-scsi-megasas-use-appropriate-proper.patch @@ -0,0 +1,34 @@ +From d884938c3eab2ca005180941c1dacf6e95f630cc Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Wed, 25 May 2016 16:01:29 +0530 +Subject: [PATCH] scsi: megasas: use appropriate property buffer size + +When setting MegaRAID SAS controller properties via MegaRAID +Firmware Interface(MFI) commands, a user supplied size parameter +is used to set property value. Use appropriate size value to avoid +OOB access issues. + +Reported-by: Li Qiang +Signed-off-by: Prasad J Pandit +Message-Id: <1464172291-2856-2-git-send-email-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit 1b85898025c4cd95dce673d15e67e60e98e91731) +[BR:CVE-2016-5106 BSC#982018] +Signed-off-by: Bruce Rogers +--- + hw/scsi/megasas.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index a63a581..dcbd3e1 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -1446,7 +1446,7 @@ static int megasas_dcmd_set_properties(MegasasState *s, MegasasCmd *cmd) + dcmd_size); + return MFI_STAT_INVALID_PARAMETER; + } +- dma_buf_write((uint8_t *)&info, cmd->iov_size, &cmd->qsg); ++ dma_buf_write((uint8_t *)&info, dcmd_size, &cmd->qsg); + trace_megasas_dcmd_unsupported(cmd->index, cmd->iov_size); + return MFI_STAT_OK; + } diff --git a/0050-scsi-megasas-check-read_queue_head-.patch b/0050-scsi-megasas-check-read_queue_head-.patch new file mode 100644 index 00000000..c3e815d4 --- /dev/null +++ b/0050-scsi-megasas-check-read_queue_head-.patch @@ -0,0 +1,36 @@ +From 09b7b3b4bf5463c411a0e4f442db3cf09ec33cbe Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Wed, 25 May 2016 17:55:10 +0530 +Subject: [PATCH] scsi: megasas: check 'read_queue_head' index value + +While doing MegaRAID SAS controller command frame lookup, routine +'megasas_lookup_frame' uses 'read_queue_head' value as an index +into 'frames[MEGASAS_MAX_FRAMES=2048]' array. Limit its value +within array bounds to avoid any OOB access. + +Reported-by: Li Qiang +Signed-off-by: Prasad J Pandit +Message-Id: <1464179110-18593-1-git-send-email-ppandit@redhat.com> +Reviewed-by: Alexander Graf +Signed-off-by: Paolo Bonzini +(cherry picked from commit b60bdd1f1ee1616b7a9aeeffb4088e1ce2710fb2) +[BR: CVE-2016-5107 BSC#982019] +Signed-off-by: Bruce Rogers +--- + hw/scsi/megasas.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index dcbd3e1..96aee1c 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -650,7 +650,9 @@ static int megasas_init_firmware(MegasasState *s, MegasasCmd *cmd) + pa_hi = le32_to_cpu(initq->pi_addr_hi); + s->producer_pa = ((uint64_t) pa_hi << 32) | pa_lo; + s->reply_queue_head = ldl_le_pci_dma(pcid, s->producer_pa); ++ s->reply_queue_head %= MEGASAS_MAX_FRAMES; + s->reply_queue_tail = ldl_le_pci_dma(pcid, s->consumer_pa); ++ s->reply_queue_tail %= MEGASAS_MAX_FRAMES; + flags = le32_to_cpu(initq->flags); + if (flags & MFI_QUEUE_FLAG_CONTEXT64) { + s->flags |= MEGASAS_MASK_USE_QUEUE64; diff --git a/0051-scsi-megasas-null-terminate-bios-ve.patch b/0051-scsi-megasas-null-terminate-bios-ve.patch new file mode 100644 index 00000000..c2d35556 --- /dev/null +++ b/0051-scsi-megasas-null-terminate-bios-ve.patch @@ -0,0 +1,32 @@ +From 81ed91f0c8e7ba89afd4718129065c920b3923f0 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Tue, 7 Jun 2016 16:44:03 +0530 +Subject: [PATCH] scsi: megasas: null terminate bios version buffer + +While reading information via 'megasas_ctrl_get_info' routine, +a local bios version buffer isn't null terminated. Add the +terminating null byte to avoid any OOB access. + +Reported-by: Li Qiang +Reviewed-by: Peter Maydell +Signed-off-by: Prasad J Pandit +Signed-off-by: Paolo Bonzini +(cherry picked from commit 844864fbae66935951529408831c2f22367a57b6) +[BR: CVE-2016-5337 BSC#983961] +Signed-off-by: Bruce Rogers +--- + hw/scsi/megasas.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c +index 96aee1c..893448b 100644 +--- a/hw/scsi/megasas.c ++++ b/hw/scsi/megasas.c +@@ -773,6 +773,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd) + + ptr = memory_region_get_ram_ptr(&pci_dev->rom); + memcpy(biosver, ptr + 0x41, 31); ++ biosver[31] = 0; + memcpy(info.image_component[1].name, "BIOS", 4); + memcpy(info.image_component[1].version, biosver, + strlen((const char *)biosver)); diff --git a/0052-vmsvga-move-fifo-sanity-checks-to-v.patch b/0052-vmsvga-move-fifo-sanity-checks-to-v.patch new file mode 100644 index 00000000..fbdb2a52 --- /dev/null +++ b/0052-vmsvga-move-fifo-sanity-checks-to-v.patch @@ -0,0 +1,73 @@ +From 5f76584dd7ee7b300a52f57e5a66b667cd3d5faa Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 30 May 2016 09:09:18 +0200 +Subject: [PATCH] vmsvga: move fifo sanity checks to vmsvga_fifo_length +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Sanity checks are applied when the fifo is enabled by the guest +(SVGA_REG_CONFIG_DONE write). Which doesn't help much if the guest +changes the fifo registers afterwards. Move the checks to +vmsvga_fifo_length so they are done each time qemu is about to read +from the fifo. + +Fixes: CVE-2016-4454 +Cc: qemu-stable@nongnu.org +Cc: P J P +Reported-by: 李强 +Signed-off-by: Gerd Hoffmann +Message-id: 1464592161-18348-2-git-send-email-kraxel@redhat.com +(cherry picked from commit 521360267876d3b6518b328051a2e56bca55bef8) +[BR: CVE-2016-4454 BSC#982222] +Signed-off-by: Bruce Rogers +--- + hw/display/vmware_vga.c | 28 +++++++++++++++------------- + 1 file changed, 15 insertions(+), 13 deletions(-) + +diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c +index 0c63fa8..63a7c05 100644 +--- a/hw/display/vmware_vga.c ++++ b/hw/display/vmware_vga.c +@@ -555,6 +555,21 @@ static inline int vmsvga_fifo_length(struct vmsvga_state_s *s) + if (!s->config || !s->enable) { + return 0; + } ++ ++ /* Check range and alignment. */ ++ if ((CMD(min) | CMD(max) | CMD(next_cmd) | CMD(stop)) & 3) { ++ return 0; ++ } ++ if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) { ++ return 0; ++ } ++ if (CMD(max) > SVGA_FIFO_SIZE) { ++ return 0; ++ } ++ if (CMD(max) < CMD(min) + 10 * 1024) { ++ return 0; ++ } ++ + num = CMD(next_cmd) - CMD(stop); + if (num < 0) { + num += CMD(max) - CMD(min); +@@ -1005,19 +1020,6 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value) + case SVGA_REG_CONFIG_DONE: + if (value) { + s->fifo = (uint32_t *) s->fifo_ptr; +- /* Check range and alignment. */ +- if ((CMD(min) | CMD(max) | CMD(next_cmd) | CMD(stop)) & 3) { +- break; +- } +- if (CMD(min) < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo) { +- break; +- } +- if (CMD(max) > SVGA_FIFO_SIZE) { +- break; +- } +- if (CMD(max) < CMD(min) + 10 * 1024) { +- break; +- } + vga_dirty_log_stop(&s->vga); + } + s->config = !!value; diff --git a/0053-vmsvga-don-t-process-more-than-1024.patch b/0053-vmsvga-don-t-process-more-than-1024.patch new file mode 100644 index 00000000..767555d9 --- /dev/null +++ b/0053-vmsvga-don-t-process-more-than-1024.patch @@ -0,0 +1,45 @@ +From 29983512d22362d394c01377fd9b0974865da1b4 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 30 May 2016 09:09:21 +0200 +Subject: [PATCH] vmsvga: don't process more than 1024 fifo commands at once +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +vmsvga_fifo_run is called in regular intervals (on each display update) +and will resume where it left off. So we can simply exit the loop, +without having to worry about how processing will continue. + +Fixes: CVE-2016-4453 +Cc: qemu-stable@nongnu.org +Cc: P J P +Reported-by: 李强 +Signed-off-by: Gerd Hoffmann +Message-id: 1464592161-18348-5-git-send-email-kraxel@redhat.com +(cherry picked from commit 4e68a0ee17dad7b8d870df0081d4ab2e079016c2) +[BR: CVE-2016-4453 BSC#982223] +Signed-off-by: Bruce Rogers +--- + hw/display/vmware_vga.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/display/vmware_vga.c b/hw/display/vmware_vga.c +index 63a7c05..3bd4c52 100644 +--- a/hw/display/vmware_vga.c ++++ b/hw/display/vmware_vga.c +@@ -596,13 +596,13 @@ static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s) + static void vmsvga_fifo_run(struct vmsvga_state_s *s) + { + uint32_t cmd, colour; +- int args, len; ++ int args, len, maxloop = 1024; + int x, y, dx, dy, width, height; + struct vmsvga_cursor_definition_s cursor; + uint32_t cmd_start; + + len = vmsvga_fifo_length(s); +- while (len > 0) { ++ while (len > 0 && --maxloop > 0) { + /* May need to go back to the start of the command if incomplete */ + cmd_start = s->cmd->stop; + diff --git a/0054-block-iscsi-avoid-potential-overflo.patch b/0054-block-iscsi-avoid-potential-overflo.patch new file mode 100644 index 00000000..75406855 --- /dev/null +++ b/0054-block-iscsi-avoid-potential-overflo.patch @@ -0,0 +1,37 @@ +From 30f011dc5ea3328e6bef4923f60e03a5664425f9 Mon Sep 17 00:00:00 2001 +From: Peter Lieven +Date: Tue, 24 May 2016 10:59:28 +0200 +Subject: [PATCH] block/iscsi: avoid potential overflow of acb->task->cdb + +at least in the path via virtio-blk the maximum size is not +restricted. + +Cc: qemu-stable@nongnu.org +Signed-off-by: Peter Lieven +Message-Id: <1464080368-29584-1-git-send-email-pl@kamp.de> +Signed-off-by: Paolo Bonzini +(cherry picked from commit a6b3167fa0e825aebb5a7cd8b437b6d41584a196) +[BR: CVE-2016-5126 BSC#982285] +Signed-off-by: Bruce Rogers +--- + block/iscsi.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/block/iscsi.c b/block/iscsi.c +index 302baf8..172e6cf 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -837,6 +837,13 @@ static BlockAIOCB *iscsi_aio_ioctl(BlockDriverState *bs, + return &acb->common; + } + ++ if (acb->ioh->cmd_len > SCSI_CDB_MAX_SIZE) { ++ error_report("iSCSI: ioctl error CDB exceeds max size (%d > %d)", ++ acb->ioh->cmd_len, SCSI_CDB_MAX_SIZE); ++ qemu_aio_unref(acb); ++ return NULL; ++ } ++ + acb->task = malloc(sizeof(struct scsi_task)); + if (acb->task == NULL) { + error_report("iSCSI: Failed to allocate task for scsi command. %s", diff --git a/0055-scsi-esp-check-TI-buffer-index-befo.patch b/0055-scsi-esp-check-TI-buffer-index-befo.patch new file mode 100644 index 00000000..eb747886 --- /dev/null +++ b/0055-scsi-esp-check-TI-buffer-index-befo.patch @@ -0,0 +1,71 @@ +From e53e6fe07906e619b25fc1eb120b7a07b541bcb8 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Mon, 6 Jun 2016 22:04:43 +0530 +Subject: [PATCH] scsi: esp: check TI buffer index before read/write + +The 53C9X Fast SCSI Controller(FSC) comes with internal 16-byte +FIFO buffers. One is used to handle commands and other is for +information transfer. Three control variables 'ti_rptr', +'ti_wptr' and 'ti_size' are used to control r/w access to the +information transfer buffer ti_buf[TI_BUFSZ=16]. In that, + +'ti_rptr' is used as read index, where read occurs. +'ti_wptr' is a write index, where write would occur. +'ti_size' indicates total bytes to be read from the buffer. + +While reading/writing to this buffer, index could exceed its +size. Add check to avoid OOB r/w access. + +Reported-by: Huawei PSIRT +Reported-by: Li Qiang +Signed-off-by: Prasad J Pandit +Message-Id: <1465230883-22303-1-git-send-email-ppandit@redhat.com> +Signed-off-by: Paolo Bonzini +(cherry picked from commit ff589551c8e8e9e95e211b9d8daafb4ed39f1aec) +[BR: CVE-2016-5338 BSC#983982] +Signed-off-by: Bruce Rogers +--- + hw/scsi/esp.c | 20 +++++++++----------- + 1 file changed, 9 insertions(+), 11 deletions(-) + +diff --git a/hw/scsi/esp.c b/hw/scsi/esp.c +index 591c817..3adb685 100644 +--- a/hw/scsi/esp.c ++++ b/hw/scsi/esp.c +@@ -400,19 +400,17 @@ uint64_t esp_reg_read(ESPState *s, uint32_t saddr) + trace_esp_mem_readb(saddr, s->rregs[saddr]); + switch (saddr) { + case ESP_FIFO: +- if (s->ti_size > 0) { ++ if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { ++ /* Data out. */ ++ qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n"); ++ s->rregs[ESP_FIFO] = 0; ++ esp_raise_irq(s); ++ } else if (s->ti_rptr < s->ti_wptr) { + s->ti_size--; +- if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { +- /* Data out. */ +- qemu_log_mask(LOG_UNIMP, +- "esp: PIO data read not implemented\n"); +- s->rregs[ESP_FIFO] = 0; +- } else { +- s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; +- } ++ s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; + esp_raise_irq(s); + } +- if (s->ti_size == 0) { ++ if (s->ti_rptr == s->ti_wptr) { + s->ti_rptr = 0; + s->ti_wptr = 0; + } +@@ -456,7 +454,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) + } else { + trace_esp_error_fifo_overrun(); + } +- } else if (s->ti_size == TI_BUFSZ - 1) { ++ } else if (s->ti_wptr == TI_BUFSZ - 1) { + trace_esp_error_fifo_overrun(); + } else { + s->ti_size++; diff --git a/0056-xen-introduce-dummy-system-device.patch b/0056-xen-introduce-dummy-system-device.patch new file mode 100644 index 00000000..c848af37 --- /dev/null +++ b/0056-xen-introduce-dummy-system-device.patch @@ -0,0 +1,104 @@ +From 6eaa3deb4b8e3f101f9b4487b786c34394486d72 Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Thu, 12 May 2016 16:13:39 +0200 +Subject: [PATCH] xen: introduce dummy system device + +Introduce a new dummy system device serving as parent for virtual +buses. This will enable new pv backends to introduce virtual buses +which are removable again opposed to system buses which are meant +to stay once added. + +Signed-off-by: Juergen Gross +Acked-by: Anthony PERARD +Reviewed-by: Wei Liu +Message-id: 1463062421-613-2-git-send-email-jgross@suse.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 9432e53a5bc88681b2d3aec4dac9db07c5476d1b) +[BR: FATE#316612] +Signed-off-by: Bruce Rogers +--- + hw/xenpv/xen_machine_pv.c | 40 ++++++++++++++++++++++++++++++++++++++++ + include/hw/xen/xen_backend.h | 1 + + 2 files changed, 41 insertions(+) + +diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c +index fc13535..48d5bc6 100644 +--- a/hw/xenpv/xen_machine_pv.c ++++ b/hw/xenpv/xen_machine_pv.c +@@ -25,10 +25,15 @@ + #include "qemu/osdep.h" + #include "hw/hw.h" + #include "hw/boards.h" ++#include "hw/sysbus.h" + #include "hw/xen/xen_backend.h" + #include "xen_domainbuild.h" + #include "sysemu/block-backend.h" + ++#define TYPE_XENSYSDEV "xensysdev" ++ ++DeviceState *xen_sysdev; ++ + static void xen_init_pv(MachineState *machine) + { + DriveInfo *dinfo; +@@ -67,6 +72,9 @@ static void xen_init_pv(MachineState *machine) + break; + } + ++ xen_sysdev = qdev_create(NULL, TYPE_XENSYSDEV); ++ qdev_init_nofail(xen_sysdev); ++ + xen_be_register("console", &xen_console_ops); + xen_be_register("vkbd", &xen_kbdmouse_ops); + xen_be_register("vfb", &xen_framebuffer_ops); +@@ -101,6 +109,38 @@ static void xen_init_pv(MachineState *machine) + xen_init_display(xen_domid); + } + ++static int xen_sysdev_init(SysBusDevice *dev) ++{ ++ return 0; ++} ++ ++static Property xen_sysdev_properties[] = { ++ {/* end of property list */}, ++}; ++ ++static void xen_sysdev_class_init(ObjectClass *klass, void *data) ++{ ++ DeviceClass *dc = DEVICE_CLASS(klass); ++ SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); ++ ++ k->init = xen_sysdev_init; ++ dc->props = xen_sysdev_properties; ++} ++ ++static const TypeInfo xensysdev_info = { ++ .name = TYPE_XENSYSDEV, ++ .parent = TYPE_SYS_BUS_DEVICE, ++ .instance_size = sizeof(SysBusDevice), ++ .class_init = xen_sysdev_class_init, ++}; ++ ++static void xenpv_register_types(void) ++{ ++ type_register_static(&xensysdev_info); ++} ++ ++type_init(xenpv_register_types); ++ + static void xenpv_machine_init(MachineClass *mc) + { + mc->desc = "Xen Para-virtualized PC"; +diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h +index c839eeb..b4b4ff0 100644 +--- a/include/hw/xen/xen_backend.h ++++ b/include/hw/xen/xen_backend.h +@@ -60,6 +60,7 @@ extern xc_interface *xen_xc; + extern xenforeignmemory_handle *xen_fmem; + extern struct xs_handle *xenstore; + extern const char *xen_protocol; ++extern DeviceState *xen_sysdev; + + /* xenstore helper functions */ + int xenstore_write_str(const char *base, const char *node, const char *val); diff --git a/0057-xen-write-information-about-support.patch b/0057-xen-write-information-about-support.patch new file mode 100644 index 00000000..c72441ca --- /dev/null +++ b/0057-xen-write-information-about-support.patch @@ -0,0 +1,219 @@ +From 40f5afa5ebaf4b6fba5a4d002a013d4e5aae7156 Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Thu, 12 May 2016 16:13:40 +0200 +Subject: [PATCH] xen: write information about supported backends + +Add a Xenstore directory for each supported pv backend. This will allow +Xen tools to decide which backend type to use in case there are +multiple possibilities. + +The information is added under +/local/domain//device-model//backends +before the "running" state is written to Xenstore. Using a directory +for each backend enables us to add parameters for specific backends +in the future. + +This interface is documented in the Xen source repository in the file +docs/misc/qemu-backends.txt + +In order to reuse the Xenstore directory creation already present in +hw/xen/xen_devconfig.c move the related functions to +hw/xen/xen_backend.c where they fit better. + +Signed-off-by: Juergen Gross +Acked-by: Anthony PERARD +Reviewed-by: Wei Liu +Message-id: 1463062421-613-3-git-send-email-jgross@suse.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 637c53ffcb891ce8876183e6b593b8f0c3763ab1) +[BR: FATE#316612] +Signed-off-by: Bruce Rogers +--- + hw/xen/xen_backend.c | 63 ++++++++++++++++++++++++++++++++++++++++++++ + hw/xen/xen_devconfig.c | 52 ++---------------------------------- + include/hw/xen/xen_backend.h | 2 ++ + 3 files changed, 67 insertions(+), 50 deletions(-) + +diff --git a/hw/xen/xen_backend.c b/hw/xen/xen_backend.c +index 60575ad..c63f9df 100644 +--- a/hw/xen/xen_backend.c ++++ b/hw/xen/xen_backend.c +@@ -42,11 +42,36 @@ struct xs_handle *xenstore = NULL; + const char *xen_protocol; + + /* private */ ++struct xs_dirs { ++ char *xs_dir; ++ QTAILQ_ENTRY(xs_dirs) list; ++}; ++static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = ++ QTAILQ_HEAD_INITIALIZER(xs_cleanup); ++ + static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs); + static int debug = 0; + + /* ------------------------------------------------------------- */ + ++static void xenstore_cleanup_dir(char *dir) ++{ ++ struct xs_dirs *d; ++ ++ d = g_malloc(sizeof(*d)); ++ d->xs_dir = dir; ++ QTAILQ_INSERT_TAIL(&xs_cleanup, d, list); ++} ++ ++void xen_config_cleanup(void) ++{ ++ struct xs_dirs *d; ++ ++ QTAILQ_FOREACH(d, &xs_cleanup, list) { ++ xs_rm(xenstore, 0, d->xs_dir); ++ } ++} ++ + int xenstore_write_str(const char *base, const char *node, const char *val) + { + char abspath[XEN_BUFSIZE]; +@@ -75,6 +100,30 @@ char *xenstore_read_str(const char *base, const char *node) + return ret; + } + ++int xenstore_mkdir(char *path, int p) ++{ ++ struct xs_permissions perms[2] = { ++ { ++ .id = 0, /* set owner: dom0 */ ++ }, { ++ .id = xen_domid, ++ .perms = p, ++ } ++ }; ++ ++ if (!xs_mkdir(xenstore, 0, path)) { ++ xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", path); ++ return -1; ++ } ++ xenstore_cleanup_dir(g_strdup(path)); ++ ++ if (!xs_set_permissions(xenstore, 0, path, perms, 2)) { ++ xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", path); ++ return -1; ++ } ++ return 0; ++} ++ + int xenstore_write_int(const char *base, const char *node, int ival) + { + char val[12]; +@@ -726,6 +775,20 @@ err: + + int xen_be_register(const char *type, struct XenDevOps *ops) + { ++ char path[50]; ++ int rc; ++ ++ if (ops->backend_register) { ++ rc = ops->backend_register(); ++ if (rc) { ++ return rc; ++ } ++ } ++ ++ snprintf(path, sizeof(path), "device-model/%u/backends/%s", xen_domid, ++ type); ++ xenstore_mkdir(path, XS_PERM_NONE); ++ + return xenstore_scan(type, xen_domid, ops); + } + +diff --git a/hw/xen/xen_devconfig.c b/hw/xen/xen_devconfig.c +index 1f30fe4..b7d290d 100644 +--- a/hw/xen/xen_devconfig.c ++++ b/hw/xen/xen_devconfig.c +@@ -5,54 +5,6 @@ + + /* ------------------------------------------------------------- */ + +-struct xs_dirs { +- char *xs_dir; +- QTAILQ_ENTRY(xs_dirs) list; +-}; +-static QTAILQ_HEAD(xs_dirs_head, xs_dirs) xs_cleanup = QTAILQ_HEAD_INITIALIZER(xs_cleanup); +- +-static void xen_config_cleanup_dir(char *dir) +-{ +- struct xs_dirs *d; +- +- d = g_malloc(sizeof(*d)); +- d->xs_dir = dir; +- QTAILQ_INSERT_TAIL(&xs_cleanup, d, list); +-} +- +-void xen_config_cleanup(void) +-{ +- struct xs_dirs *d; +- +- QTAILQ_FOREACH(d, &xs_cleanup, list) { +- xs_rm(xenstore, 0, d->xs_dir); +- } +-} +- +-/* ------------------------------------------------------------- */ +- +-static int xen_config_dev_mkdir(char *dev, int p) +-{ +- struct xs_permissions perms[2] = {{ +- .id = 0, /* set owner: dom0 */ +- },{ +- .id = xen_domid, +- .perms = p, +- }}; +- +- if (!xs_mkdir(xenstore, 0, dev)) { +- xen_be_printf(NULL, 0, "xs_mkdir %s: failed\n", dev); +- return -1; +- } +- xen_config_cleanup_dir(g_strdup(dev)); +- +- if (!xs_set_permissions(xenstore, 0, dev, perms, 2)) { +- xen_be_printf(NULL, 0, "xs_set_permissions %s: failed\n", dev); +- return -1; +- } +- return 0; +-} +- + static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev, + char *fe, char *be, int len) + { +@@ -66,8 +18,8 @@ static int xen_config_dev_dirs(const char *ftype, const char *btype, int vdev, + snprintf(be, len, "%s/backend/%s/%d/%d", dom, btype, xen_domid, vdev); + free(dom); + +- xen_config_dev_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE); +- xen_config_dev_mkdir(be, XS_PERM_READ); ++ xenstore_mkdir(fe, XS_PERM_READ | XS_PERM_WRITE); ++ xenstore_mkdir(be, XS_PERM_READ); + return 0; + } + +diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h +index b4b4ff0..63364f7 100644 +--- a/include/hw/xen/xen_backend.h ++++ b/include/hw/xen/xen_backend.h +@@ -28,6 +28,7 @@ struct XenDevOps { + int (*free)(struct XenDevice *xendev); + void (*backend_changed)(struct XenDevice *xendev, const char *node); + void (*frontend_changed)(struct XenDevice *xendev, const char *node); ++ int (*backend_register)(void); + }; + + struct XenDevice { +@@ -63,6 +64,7 @@ extern const char *xen_protocol; + extern DeviceState *xen_sysdev; + + /* xenstore helper functions */ ++int xenstore_mkdir(char *path, int p); + int xenstore_write_str(const char *base, const char *node, const char *val); + int xenstore_write_int(const char *base, const char *node, int ival); + int xenstore_write_int64(const char *base, const char *node, int64_t ival); diff --git a/0058-xen-add-pvUSB-backend.patch b/0058-xen-add-pvUSB-backend.patch new file mode 100644 index 00000000..64e07155 --- /dev/null +++ b/0058-xen-add-pvUSB-backend.patch @@ -0,0 +1,1165 @@ +From 12492549d007b13f9b23b16a5bb7a156918cf299 Mon Sep 17 00:00:00 2001 +From: Juergen Gross +Date: Thu, 12 May 2016 16:13:41 +0200 +Subject: [PATCH] xen: add pvUSB backend + +Add a backend for para-virtualized USB devices for xen domains. + +The backend is using host-libusb to forward USB requests from a +domain via libusb to the real device(s) passed through. + +Signed-off-by: Juergen Gross +Acked-by: Anthony PERARD +Message-id: 1463062421-613-4-git-send-email-jgross@suse.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 816ac92ef769f9ffc534e49a1bb6177bddce7aa2) +[BR: FATE#316612] +Signed-off-by: Bruce Rogers +--- + hw/usb/Makefile.objs | 4 + + hw/usb/xen-usb.c | 1080 ++++++++++++++++++++++++++++++++++++++++++ + hw/xenpv/xen_machine_pv.c | 3 + + include/hw/xen/xen_backend.h | 3 + + include/hw/xen/xen_common.h | 2 + + 5 files changed, 1092 insertions(+) + create mode 100644 hw/usb/xen-usb.c + +diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs +index 2717027..98b5c9d 100644 +--- a/hw/usb/Makefile.objs ++++ b/hw/usb/Makefile.objs +@@ -38,3 +38,7 @@ common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o + + # usb pass-through + common-obj-y += $(patsubst %,host-%.o,$(HOST_USB)) ++ ++ifeq ($(CONFIG_USB_LIBUSB),y) ++common-obj-$(CONFIG_XEN_BACKEND) += xen-usb.o ++endif +diff --git a/hw/usb/xen-usb.c b/hw/usb/xen-usb.c +new file mode 100644 +index 0000000..664df04 +--- /dev/null ++++ b/hw/usb/xen-usb.c +@@ -0,0 +1,1080 @@ ++/* ++ * xen paravirt usb device backend ++ * ++ * (c) Juergen Gross ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; under version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, see . ++ * ++ * Contributions after 2012-01-13 are licensed under the terms of the ++ * GNU GPL, version 2 or (at your option) any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include "qemu/osdep.h" ++#include "qemu-common.h" ++#include "qemu/config-file.h" ++#include "hw/sysbus.h" ++#include "hw/usb.h" ++#include "hw/xen/xen_backend.h" ++#include "monitor/qdev.h" ++#include "qapi/qmp/qbool.h" ++#include "qapi/qmp/qint.h" ++#include "qapi/qmp/qstring.h" ++#include "sys/user.h" ++ ++#include ++#include ++ ++/* ++ * Check for required support of usbif.h: USBIF_SHORT_NOT_OK was the last ++ * macro added we rely on. ++ */ ++#ifdef USBIF_SHORT_NOT_OK ++ ++#define TR(xendev, lvl, fmt, args...) \ ++ { \ ++ struct timeval tv; \ ++ \ ++ gettimeofday(&tv, NULL); \ ++ xen_be_printf(xendev, lvl, "%8ld.%06ld xen-usb(%s):" fmt, \ ++ tv.tv_sec, tv.tv_usec, __func__, ##args); \ ++ } ++#define TR_BUS(xendev, fmt, args...) TR(xendev, 2, fmt, ##args) ++#define TR_REQ(xendev, fmt, args...) TR(xendev, 3, fmt, ##args) ++ ++#define USBBACK_MAXPORTS USBIF_PIPE_PORT_MASK ++#define USB_DEV_ADDR_SIZE (USBIF_PIPE_DEV_MASK + 1) ++ ++/* USB wire protocol: structure describing control request parameter. */ ++struct usbif_ctrlrequest { ++ uint8_t bRequestType; ++ uint8_t bRequest; ++ uint16_t wValue; ++ uint16_t wIndex; ++ uint16_t wLength; ++}; ++ ++struct usbback_info; ++struct usbback_req; ++ ++struct usbback_stub { ++ USBDevice *dev; ++ USBPort port; ++ unsigned int speed; ++ bool attached; ++ QTAILQ_HEAD(submit_q_head, usbback_req) submit_q; ++}; ++ ++struct usbback_req { ++ struct usbback_info *usbif; ++ struct usbback_stub *stub; ++ struct usbif_urb_request req; ++ USBPacket packet; ++ ++ unsigned int nr_buffer_segs; /* # of transfer_buffer segments */ ++ unsigned int nr_extra_segs; /* # of iso_frame_desc segments */ ++ ++ QTAILQ_ENTRY(usbback_req) q; ++ ++ void *buffer; ++ void *isoc_buffer; ++ struct libusb_transfer *xfer; ++}; ++ ++struct usbback_hotplug { ++ QSIMPLEQ_ENTRY(usbback_hotplug) q; ++ unsigned port; ++}; ++ ++struct usbback_info { ++ struct XenDevice xendev; /* must be first */ ++ USBBus bus; ++ void *urb_sring; ++ void *conn_sring; ++ struct usbif_urb_back_ring urb_ring; ++ struct usbif_conn_back_ring conn_ring; ++ int num_ports; ++ int usb_ver; ++ bool ring_error; ++ QTAILQ_HEAD(req_free_q_head, usbback_req) req_free_q; ++ QSIMPLEQ_HEAD(hotplug_q_head, usbback_hotplug) hotplug_q; ++ struct usbback_stub ports[USBBACK_MAXPORTS]; ++ struct usbback_stub *addr_table[USB_DEV_ADDR_SIZE]; ++ QEMUBH *bh; ++}; ++ ++static struct usbback_req *usbback_get_req(struct usbback_info *usbif) ++{ ++ struct usbback_req *usbback_req; ++ ++ if (QTAILQ_EMPTY(&usbif->req_free_q)) { ++ usbback_req = g_new0(struct usbback_req, 1); ++ } else { ++ usbback_req = QTAILQ_FIRST(&usbif->req_free_q); ++ QTAILQ_REMOVE(&usbif->req_free_q, usbback_req, q); ++ } ++ return usbback_req; ++} ++ ++static void usbback_put_req(struct usbback_req *usbback_req) ++{ ++ struct usbback_info *usbif; ++ ++ usbif = usbback_req->usbif; ++ memset(usbback_req, 0, sizeof(*usbback_req)); ++ QTAILQ_INSERT_HEAD(&usbif->req_free_q, usbback_req, q); ++} ++ ++static int usbback_gnttab_map(struct usbback_req *usbback_req) ++{ ++ unsigned int nr_segs, i, prot; ++ uint32_t ref[USBIF_MAX_SEGMENTS_PER_REQUEST]; ++ struct usbback_info *usbif = usbback_req->usbif; ++ struct XenDevice *xendev = &usbif->xendev; ++ struct usbif_request_segment *seg; ++ void *addr; ++ ++ nr_segs = usbback_req->nr_buffer_segs + usbback_req->nr_extra_segs; ++ if (!nr_segs) { ++ return 0; ++ } ++ ++ if (nr_segs > USBIF_MAX_SEGMENTS_PER_REQUEST) { ++ xen_be_printf(xendev, 0, "bad number of segments in request (%d)\n", ++ nr_segs); ++ return -EINVAL; ++ } ++ ++ for (i = 0; i < nr_segs; i++) { ++ if ((unsigned)usbback_req->req.seg[i].offset + ++ (unsigned)usbback_req->req.seg[i].length > PAGE_SIZE) { ++ xen_be_printf(xendev, 0, "segment crosses page boundary\n"); ++ return -EINVAL; ++ } ++ } ++ ++ if (usbback_req->nr_buffer_segs) { ++ prot = PROT_READ; ++ if (usbif_pipein(usbback_req->req.pipe)) { ++ prot |= PROT_WRITE; ++ } ++ for (i = 0; i < usbback_req->nr_buffer_segs; i++) { ++ ref[i] = usbback_req->req.seg[i].gref; ++ } ++ usbback_req->buffer = xengnttab_map_domain_grant_refs(xendev->gnttabdev, ++ usbback_req->nr_buffer_segs, xendev->dom, ref, prot); ++ ++ if (!usbback_req->buffer) { ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < usbback_req->nr_buffer_segs; i++) { ++ seg = usbback_req->req.seg + i; ++ addr = usbback_req->buffer + i * PAGE_SIZE + seg->offset; ++ qemu_iovec_add(&usbback_req->packet.iov, addr, seg->length); ++ } ++ } ++ ++ if (!usbif_pipeisoc(usbback_req->req.pipe)) { ++ return 0; ++ } ++ ++ /* ++ * Right now isoc requests are not supported. ++ * Prepare supporting those by doing the work needed on the guest ++ * interface side. ++ */ ++ ++ if (!usbback_req->nr_extra_segs) { ++ xen_be_printf(xendev, 0, "iso request without descriptor segments\n"); ++ return -EINVAL; ++ } ++ ++ prot = PROT_READ | PROT_WRITE; ++ for (i = 0; i < usbback_req->nr_extra_segs; i++) { ++ ref[i] = usbback_req->req.seg[i + usbback_req->req.nr_buffer_segs].gref; ++ } ++ usbback_req->isoc_buffer = xengnttab_map_domain_grant_refs( ++ xendev->gnttabdev, usbback_req->nr_extra_segs, xendev->dom, ref, prot); ++ ++ if (!usbback_req->isoc_buffer) { ++ return -ENOMEM; ++ } ++ ++ return 0; ++} ++ ++static int usbback_init_packet(struct usbback_req *usbback_req) ++{ ++ struct XenDevice *xendev = &usbback_req->usbif->xendev; ++ USBPacket *packet = &usbback_req->packet; ++ USBDevice *dev = usbback_req->stub->dev; ++ USBEndpoint *ep; ++ unsigned int pid, ep_nr; ++ bool sok; ++ int ret = 0; ++ ++ qemu_iovec_init(&packet->iov, USBIF_MAX_SEGMENTS_PER_REQUEST); ++ pid = usbif_pipein(usbback_req->req.pipe) ? USB_TOKEN_IN : USB_TOKEN_OUT; ++ ep_nr = usbif_pipeendpoint(usbback_req->req.pipe); ++ sok = !!(usbback_req->req.transfer_flags & USBIF_SHORT_NOT_OK); ++ if (usbif_pipectrl(usbback_req->req.pipe)) { ++ ep_nr = 0; ++ sok = false; ++ } ++ ep = usb_ep_get(dev, pid, ep_nr); ++ usb_packet_setup(packet, pid, ep, 0, 1, sok, true); ++ ++ switch (usbif_pipetype(usbback_req->req.pipe)) { ++ case USBIF_PIPE_TYPE_ISOC: ++ TR_REQ(xendev, "iso transfer %s: buflen: %x, %d frames\n", ++ (pid == USB_TOKEN_IN) ? "in" : "out", ++ usbback_req->req.buffer_length, ++ usbback_req->req.u.isoc.nr_frame_desc_segs); ++ ret = -EINVAL; /* isoc not implemented yet */ ++ break; ++ ++ case USBIF_PIPE_TYPE_INT: ++ TR_REQ(xendev, "int transfer %s: buflen: %x\n", ++ (pid == USB_TOKEN_IN) ? "in" : "out", ++ usbback_req->req.buffer_length); ++ break; ++ ++ case USBIF_PIPE_TYPE_CTRL: ++ packet->parameter = *(uint64_t *)usbback_req->req.u.ctrl; ++ TR_REQ(xendev, "ctrl parameter: %lx, buflen: %x\n", packet->parameter, ++ usbback_req->req.buffer_length); ++ break; ++ ++ case USBIF_PIPE_TYPE_BULK: ++ TR_REQ(xendev, "bulk transfer %s: buflen: %x\n", ++ (pid == USB_TOKEN_IN) ? "in" : "out", ++ usbback_req->req.buffer_length); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++static void usbback_do_response(struct usbback_req *usbback_req, int32_t status, ++ int32_t actual_length, int32_t error_count) ++{ ++ struct usbback_info *usbif; ++ struct usbif_urb_response *res; ++ struct XenDevice *xendev; ++ unsigned int notify; ++ ++ usbif = usbback_req->usbif; ++ xendev = &usbif->xendev; ++ ++ TR_REQ(xendev, "id %d, status %d, length %d, errcnt %d\n", ++ usbback_req->req.id, status, actual_length, error_count); ++ ++ if (usbback_req->packet.iov.iov) { ++ qemu_iovec_destroy(&usbback_req->packet.iov); ++ } ++ ++ if (usbback_req->buffer) { ++ xengnttab_unmap(xendev->gnttabdev, usbback_req->buffer, ++ usbback_req->nr_buffer_segs); ++ usbback_req->buffer = NULL; ++ } ++ ++ if (usbback_req->isoc_buffer) { ++ xengnttab_unmap(xendev->gnttabdev, usbback_req->isoc_buffer, ++ usbback_req->nr_extra_segs); ++ usbback_req->isoc_buffer = NULL; ++ } ++ ++ res = RING_GET_RESPONSE(&usbif->urb_ring, usbif->urb_ring.rsp_prod_pvt); ++ res->id = usbback_req->req.id; ++ res->status = status; ++ res->actual_length = actual_length; ++ res->error_count = error_count; ++ res->start_frame = 0; ++ usbif->urb_ring.rsp_prod_pvt++; ++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&usbif->urb_ring, notify); ++ ++ if (notify) { ++ xen_be_send_notify(xendev); ++ } ++ ++ usbback_put_req(usbback_req); ++} ++ ++static void usbback_do_response_ret(struct usbback_req *usbback_req, ++ int32_t status) ++{ ++ usbback_do_response(usbback_req, status, 0, 0); ++} ++ ++static int32_t usbback_xlat_status(int status) ++{ ++ switch (status) { ++ case USB_RET_SUCCESS: ++ return 0; ++ case USB_RET_NODEV: ++ return -ENODEV; ++ case USB_RET_STALL: ++ return -EPIPE; ++ case USB_RET_BABBLE: ++ return -EOVERFLOW; ++ case USB_RET_IOERROR: ++ return -EPROTO; ++ } ++ ++ return -ESHUTDOWN; ++} ++ ++static void usbback_packet_complete(USBPacket *packet) ++{ ++ struct usbback_req *usbback_req; ++ int32_t status; ++ ++ usbback_req = container_of(packet, struct usbback_req, packet); ++ ++ QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); ++ ++ status = usbback_xlat_status(packet->status); ++ usbback_do_response(usbback_req, status, packet->actual_length, 0); ++} ++ ++static void usbback_set_address(struct usbback_info *usbif, ++ struct usbback_stub *stub, ++ unsigned int cur_addr, unsigned int new_addr) ++{ ++ if (cur_addr) { ++ usbif->addr_table[cur_addr] = NULL; ++ } ++ if (new_addr) { ++ usbif->addr_table[new_addr] = stub; ++ } ++} ++ ++static bool usbback_cancel_req(struct usbback_req *usbback_req) ++{ ++ bool ret = false; ++ ++ if (usb_packet_is_inflight(&usbback_req->packet)) { ++ usb_cancel_packet(&usbback_req->packet); ++ ret = true; ++ } ++ return ret; ++} ++ ++static void usbback_process_unlink_req(struct usbback_req *usbback_req) ++{ ++ struct usbback_info *usbif; ++ struct usbback_req *unlink_req; ++ unsigned int id, devnum; ++ int ret; ++ ++ usbif = usbback_req->usbif; ++ ret = 0; ++ id = usbback_req->req.u.unlink.unlink_id; ++ TR_REQ(&usbif->xendev, "unlink id %d\n", id); ++ devnum = usbif_pipedevice(usbback_req->req.pipe); ++ if (unlikely(devnum == 0)) { ++ usbback_req->stub = usbif->ports + ++ usbif_pipeportnum(usbback_req->req.pipe); ++ if (unlikely(!usbback_req->stub)) { ++ ret = -ENODEV; ++ goto fail_response; ++ } ++ } else { ++ if (unlikely(!usbif->addr_table[devnum])) { ++ ret = -ENODEV; ++ goto fail_response; ++ } ++ usbback_req->stub = usbif->addr_table[devnum]; ++ } ++ ++ QTAILQ_FOREACH(unlink_req, &usbback_req->stub->submit_q, q) { ++ if (unlink_req->req.id == id) { ++ if (usbback_cancel_req(unlink_req)) { ++ usbback_do_response_ret(unlink_req, -EPROTO); ++ } ++ break; ++ } ++ } ++ ++fail_response: ++ usbback_do_response_ret(usbback_req, ret); ++} ++ ++/* ++ * Checks whether a request can be handled at once or should be forwarded ++ * to the usb framework. ++ * Return value is: ++ * 0 in case of usb framework is needed ++ * 1 in case of local handling (no error) ++ * The request response has been queued already if return value not 0. ++ */ ++static int usbback_check_and_submit(struct usbback_req *usbback_req) ++{ ++ struct usbback_info *usbif; ++ unsigned int devnum; ++ struct usbback_stub *stub; ++ struct usbif_ctrlrequest *ctrl; ++ int ret; ++ uint16_t wValue; ++ ++ usbif = usbback_req->usbif; ++ stub = NULL; ++ devnum = usbif_pipedevice(usbback_req->req.pipe); ++ ctrl = (struct usbif_ctrlrequest *)usbback_req->req.u.ctrl; ++ wValue = le16_to_cpu(ctrl->wValue); ++ ++ /* ++ * When the device is first connected or resetted, USB device has no ++ * address. In this initial state, following requests are sent to device ++ * address (#0), ++ * ++ * 1. GET_DESCRIPTOR (with Descriptor Type is "DEVICE") is sent, ++ * and OS knows what device is connected to. ++ * ++ * 2. SET_ADDRESS is sent, and then device has its address. ++ * ++ * In the next step, SET_CONFIGURATION is sent to addressed device, and ++ * then the device is finally ready to use. ++ */ ++ if (unlikely(devnum == 0)) { ++ stub = usbif->ports + usbif_pipeportnum(usbback_req->req.pipe) - 1; ++ if (!stub->dev || !stub->attached) { ++ ret = -ENODEV; ++ goto do_response; ++ } ++ ++ switch (ctrl->bRequest) { ++ case USB_REQ_GET_DESCRIPTOR: ++ /* ++ * GET_DESCRIPTOR request to device #0. ++ * through normal transfer. ++ */ ++ TR_REQ(&usbif->xendev, "devnum 0 GET_DESCRIPTOR\n"); ++ usbback_req->stub = stub; ++ return 0; ++ case USB_REQ_SET_ADDRESS: ++ /* ++ * SET_ADDRESS request to device #0. ++ * add attached device to addr_table. ++ */ ++ TR_REQ(&usbif->xendev, "devnum 0 SET_ADDRESS\n"); ++ usbback_set_address(usbif, stub, 0, wValue); ++ ret = 0; ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ goto do_response; ++ } ++ ++ if (unlikely(!usbif->addr_table[devnum])) { ++ ret = -ENODEV; ++ goto do_response; ++ } ++ usbback_req->stub = usbif->addr_table[devnum]; ++ ++ /* ++ * Check special request ++ */ ++ if (ctrl->bRequest != USB_REQ_SET_ADDRESS) { ++ return 0; ++ } ++ ++ /* ++ * SET_ADDRESS request to addressed device. ++ * change addr or remove from addr_table. ++ */ ++ usbback_set_address(usbif, usbback_req->stub, devnum, wValue); ++ ret = 0; ++ ++do_response: ++ usbback_do_response_ret(usbback_req, ret); ++ return 1; ++} ++ ++static void usbback_dispatch(struct usbback_req *usbback_req) ++{ ++ int ret; ++ unsigned int devnum; ++ struct usbback_info *usbif; ++ ++ usbif = usbback_req->usbif; ++ ++ TR_REQ(&usbif->xendev, "start req_id %d pipe %08x\n", usbback_req->req.id, ++ usbback_req->req.pipe); ++ ++ /* unlink request */ ++ if (unlikely(usbif_pipeunlink(usbback_req->req.pipe))) { ++ usbback_process_unlink_req(usbback_req); ++ return; ++ } ++ ++ if (usbif_pipectrl(usbback_req->req.pipe)) { ++ if (usbback_check_and_submit(usbback_req)) { ++ return; ++ } ++ } else { ++ devnum = usbif_pipedevice(usbback_req->req.pipe); ++ usbback_req->stub = usbif->addr_table[devnum]; ++ ++ if (!usbback_req->stub || !usbback_req->stub->attached) { ++ ret = -ENODEV; ++ goto fail_response; ++ } ++ } ++ ++ QTAILQ_INSERT_TAIL(&usbback_req->stub->submit_q, usbback_req, q); ++ ++ usbback_req->nr_buffer_segs = usbback_req->req.nr_buffer_segs; ++ usbback_req->nr_extra_segs = usbif_pipeisoc(usbback_req->req.pipe) ? ++ usbback_req->req.u.isoc.nr_frame_desc_segs : 0; ++ ++ ret = usbback_init_packet(usbback_req); ++ if (ret) { ++ xen_be_printf(&usbif->xendev, 0, "invalid request\n"); ++ ret = -ESHUTDOWN; ++ goto fail_free_urb; ++ } ++ ++ ret = usbback_gnttab_map(usbback_req); ++ if (ret) { ++ xen_be_printf(&usbif->xendev, 0, "invalid buffer, ret=%d\n", ret); ++ ret = -ESHUTDOWN; ++ goto fail_free_urb; ++ } ++ ++ usb_handle_packet(usbback_req->stub->dev, &usbback_req->packet); ++ if (usbback_req->packet.status != USB_RET_ASYNC) { ++ usbback_packet_complete(&usbback_req->packet); ++ } ++ return; ++ ++fail_free_urb: ++ QTAILQ_REMOVE(&usbback_req->stub->submit_q, usbback_req, q); ++ ++fail_response: ++ usbback_do_response_ret(usbback_req, ret); ++} ++ ++static void usbback_hotplug_notify(struct usbback_info *usbif) ++{ ++ struct usbif_conn_back_ring *ring = &usbif->conn_ring; ++ struct usbif_conn_request req; ++ struct usbif_conn_response *res; ++ struct usbback_hotplug *usb_hp; ++ unsigned int notify; ++ ++ if (!usbif->conn_sring) { ++ return; ++ } ++ ++ /* Check for full ring. */ ++ if ((RING_SIZE(ring) - ring->rsp_prod_pvt - ring->req_cons) == 0) { ++ xen_be_send_notify(&usbif->xendev); ++ return; ++ } ++ ++ usb_hp = QSIMPLEQ_FIRST(&usbif->hotplug_q); ++ QSIMPLEQ_REMOVE_HEAD(&usbif->hotplug_q, q); ++ ++ RING_COPY_REQUEST(ring, ring->req_cons, &req); ++ ring->req_cons++; ++ ring->sring->req_event = ring->req_cons + 1; ++ ++ res = RING_GET_RESPONSE(ring, ring->rsp_prod_pvt); ++ res->id = req.id; ++ res->portnum = usb_hp->port; ++ res->speed = usbif->ports[usb_hp->port - 1].speed; ++ ring->rsp_prod_pvt++; ++ RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(ring, notify); ++ ++ if (notify) { ++ xen_be_send_notify(&usbif->xendev); ++ } ++ ++ TR_BUS(&usbif->xendev, "hotplug port %d speed %d\n", usb_hp->port, ++ res->speed); ++ ++ g_free(usb_hp); ++ ++ if (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) { ++ qemu_bh_schedule(usbif->bh); ++ } ++} ++ ++static void usbback_bh(void *opaque) ++{ ++ struct usbback_info *usbif; ++ struct usbif_urb_back_ring *urb_ring; ++ struct usbback_req *usbback_req; ++ RING_IDX rc, rp; ++ unsigned int more_to_do; ++ ++ usbif = opaque; ++ if (usbif->ring_error) { ++ return; ++ } ++ ++ if (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) { ++ usbback_hotplug_notify(usbif); ++ } ++ ++ urb_ring = &usbif->urb_ring; ++ rc = urb_ring->req_cons; ++ rp = urb_ring->sring->req_prod; ++ xen_rmb(); /* Ensure we see queued requests up to 'rp'. */ ++ ++ if (RING_REQUEST_PROD_OVERFLOW(urb_ring, rp)) { ++ rc = urb_ring->rsp_prod_pvt; ++ xen_be_printf(&usbif->xendev, 0, "domU provided bogus ring requests " ++ "(%#x - %#x = %u). Halting ring processing.\n", ++ rp, rc, rp - rc); ++ usbif->ring_error = true; ++ return; ++ } ++ ++ while (rc != rp) { ++ if (RING_REQUEST_CONS_OVERFLOW(urb_ring, rc)) { ++ break; ++ } ++ usbback_req = usbback_get_req(usbif); ++ ++ RING_COPY_REQUEST(urb_ring, rc, &usbback_req->req); ++ usbback_req->usbif = usbif; ++ ++ usbback_dispatch(usbback_req); ++ ++ urb_ring->req_cons = ++rc; ++ } ++ ++ RING_FINAL_CHECK_FOR_REQUESTS(urb_ring, more_to_do); ++ if (more_to_do) { ++ qemu_bh_schedule(usbif->bh); ++ } ++} ++ ++static void usbback_hotplug_enq(struct usbback_info *usbif, unsigned port) ++{ ++ struct usbback_hotplug *usb_hp; ++ ++ usb_hp = g_new0(struct usbback_hotplug, 1); ++ usb_hp->port = port; ++ QSIMPLEQ_INSERT_TAIL(&usbif->hotplug_q, usb_hp, q); ++ usbback_hotplug_notify(usbif); ++} ++ ++static void usbback_portid_remove(struct usbback_info *usbif, unsigned port) ++{ ++ USBPort *p; ++ ++ if (!usbif->ports[port - 1].dev) { ++ return; ++ } ++ ++ p = &(usbif->ports[port - 1].port); ++ snprintf(p->path, sizeof(p->path), "%d", 99); ++ ++ object_unparent(OBJECT(usbif->ports[port - 1].dev)); ++ usbif->ports[port - 1].dev = NULL; ++ usbif->ports[port - 1].speed = USBIF_SPEED_NONE; ++ usbif->ports[port - 1].attached = false; ++ usbback_hotplug_enq(usbif, port); ++ ++ TR_BUS(&usbif->xendev, "port %d removed\n", port); ++} ++ ++static void usbback_portid_add(struct usbback_info *usbif, unsigned port, ++ char *busid) ++{ ++ unsigned speed; ++ char *portname; ++ USBPort *p; ++ Error *local_err = NULL; ++ QDict *qdict; ++ QemuOpts *opts; ++ ++ if (usbif->ports[port - 1].dev) { ++ return; ++ } ++ ++ portname = strchr(busid, '-'); ++ if (!portname) { ++ xen_be_printf(&usbif->xendev, 0, "device %s illegal specification\n", ++ busid); ++ return; ++ } ++ portname++; ++ p = &(usbif->ports[port - 1].port); ++ snprintf(p->path, sizeof(p->path), "%s", portname); ++ ++ qdict = qdict_new(); ++ qdict_put(qdict, "driver", qstring_from_str("usb-host")); ++ qdict_put(qdict, "hostbus", qint_from_int(atoi(busid))); ++ qdict_put(qdict, "hostport", qstring_from_str(portname)); ++ opts = qemu_opts_from_qdict(qemu_find_opts("device"), qdict, &local_err); ++ if (local_err) { ++ goto err; ++ } ++ usbif->ports[port - 1].dev = USB_DEVICE(qdev_device_add(opts, &local_err)); ++ if (!usbif->ports[port - 1].dev) { ++ goto err; ++ } ++ QDECREF(qdict); ++ snprintf(p->path, sizeof(p->path), "%d", port); ++ speed = usbif->ports[port - 1].dev->speed; ++ switch (speed) { ++ case USB_SPEED_LOW: ++ speed = USBIF_SPEED_LOW; ++ break; ++ case USB_SPEED_FULL: ++ speed = USBIF_SPEED_FULL; ++ break; ++ case USB_SPEED_HIGH: ++ speed = (usbif->usb_ver < USB_VER_USB20) ? ++ USBIF_SPEED_NONE : USBIF_SPEED_HIGH; ++ break; ++ default: ++ speed = USBIF_SPEED_NONE; ++ break; ++ } ++ if (speed == USBIF_SPEED_NONE) { ++ xen_be_printf(&usbif->xendev, 0, "device %s wrong speed\n", busid); ++ object_unparent(OBJECT(usbif->ports[port - 1].dev)); ++ usbif->ports[port - 1].dev = NULL; ++ return; ++ } ++ usb_device_reset(usbif->ports[port - 1].dev); ++ usbif->ports[port - 1].speed = speed; ++ usbif->ports[port - 1].attached = true; ++ QTAILQ_INIT(&usbif->ports[port - 1].submit_q); ++ usbback_hotplug_enq(usbif, port); ++ ++ TR_BUS(&usbif->xendev, "port %d attached\n", port); ++ return; ++ ++err: ++ QDECREF(qdict); ++ snprintf(p->path, sizeof(p->path), "%d", 99); ++ xen_be_printf(&usbif->xendev, 0, "device %s could not be opened\n", busid); ++} ++ ++static void usbback_process_port(struct usbback_info *usbif, unsigned port) ++{ ++ char node[8]; ++ char *busid; ++ ++ snprintf(node, sizeof(node), "port/%d", port); ++ busid = xenstore_read_be_str(&usbif->xendev, node); ++ if (busid == NULL) { ++ xen_be_printf(&usbif->xendev, 0, "xenstore_read %s failed\n", node); ++ return; ++ } ++ ++ /* Remove portid, if the port is not connected. */ ++ if (strlen(busid) == 0) { ++ usbback_portid_remove(usbif, port); ++ } else { ++ usbback_portid_add(usbif, port, busid); ++ } ++ ++ g_free(busid); ++} ++ ++static void usbback_disconnect(struct XenDevice *xendev) ++{ ++ struct usbback_info *usbif; ++ struct usbback_req *req, *tmp; ++ unsigned int i; ++ ++ TR_BUS(xendev, "start\n"); ++ ++ usbif = container_of(xendev, struct usbback_info, xendev); ++ ++ xen_be_unbind_evtchn(xendev); ++ ++ if (usbif->urb_sring) { ++ xengnttab_unmap(xendev->gnttabdev, usbif->urb_sring, 1); ++ usbif->urb_sring = NULL; ++ } ++ if (usbif->conn_sring) { ++ xengnttab_unmap(xendev->gnttabdev, usbif->conn_sring, 1); ++ usbif->conn_sring = NULL; ++ } ++ ++ for (i = 0; i < usbif->num_ports; i++) { ++ if (!usbif->ports[i].dev) { ++ continue; ++ } ++ QTAILQ_FOREACH_SAFE(req, &usbif->ports[i].submit_q, q, tmp) { ++ usbback_cancel_req(req); ++ } ++ } ++ ++ TR_BUS(xendev, "finished\n"); ++} ++ ++static int usbback_connect(struct XenDevice *xendev) ++{ ++ struct usbback_info *usbif; ++ struct usbif_urb_sring *urb_sring; ++ struct usbif_conn_sring *conn_sring; ++ int urb_ring_ref; ++ int conn_ring_ref; ++ unsigned int i; ++ ++ TR_BUS(xendev, "start\n"); ++ ++ usbif = container_of(xendev, struct usbback_info, xendev); ++ ++ if (xenstore_read_fe_int(xendev, "urb-ring-ref", &urb_ring_ref)) { ++ xen_be_printf(xendev, 0, "error reading urb-ring-ref\n"); ++ return -1; ++ } ++ if (xenstore_read_fe_int(xendev, "conn-ring-ref", &conn_ring_ref)) { ++ xen_be_printf(xendev, 0, "error reading conn-ring-ref\n"); ++ return -1; ++ } ++ if (xenstore_read_fe_int(xendev, "event-channel", &xendev->remote_port)) { ++ xen_be_printf(xendev, 0, "error reading event-channel\n"); ++ return -1; ++ } ++ ++ usbif->urb_sring = xengnttab_map_grant_ref(xendev->gnttabdev, xendev->dom, ++ urb_ring_ref, ++ PROT_READ | PROT_WRITE); ++ usbif->conn_sring = xengnttab_map_grant_ref(xendev->gnttabdev, xendev->dom, ++ conn_ring_ref, ++ PROT_READ | PROT_WRITE); ++ if (!usbif->urb_sring || !usbif->conn_sring) { ++ xen_be_printf(xendev, 0, "error mapping rings\n"); ++ usbback_disconnect(xendev); ++ return -1; ++ } ++ ++ urb_sring = usbif->urb_sring; ++ conn_sring = usbif->conn_sring; ++ BACK_RING_INIT(&usbif->urb_ring, urb_sring, XC_PAGE_SIZE); ++ BACK_RING_INIT(&usbif->conn_ring, conn_sring, XC_PAGE_SIZE); ++ ++ xen_be_bind_evtchn(xendev); ++ ++ xen_be_printf(xendev, 1, "urb-ring-ref %d, conn-ring-ref %d, " ++ "remote port %d, local port %d\n", urb_ring_ref, ++ conn_ring_ref, xendev->remote_port, xendev->local_port); ++ ++ for (i = 1; i <= usbif->num_ports; i++) { ++ if (usbif->ports[i - 1].dev) { ++ usbback_hotplug_enq(usbif, i); ++ } ++ } ++ ++ return 0; ++} ++ ++static void usbback_backend_changed(struct XenDevice *xendev, const char *node) ++{ ++ struct usbback_info *usbif; ++ unsigned int i; ++ ++ TR_BUS(xendev, "path %s\n", node); ++ ++ usbif = container_of(xendev, struct usbback_info, xendev); ++ for (i = 1; i <= usbif->num_ports; i++) { ++ usbback_process_port(usbif, i); ++ } ++} ++ ++static int usbback_init(struct XenDevice *xendev) ++{ ++ struct usbback_info *usbif; ++ ++ TR_BUS(xendev, "start\n"); ++ ++ usbif = container_of(xendev, struct usbback_info, xendev); ++ ++ if (xenstore_read_be_int(xendev, "num-ports", &usbif->num_ports) || ++ usbif->num_ports < 1 || usbif->num_ports > USBBACK_MAXPORTS) { ++ xen_be_printf(xendev, 0, "num-ports not readable or out of bounds\n"); ++ return -1; ++ } ++ if (xenstore_read_be_int(xendev, "usb-ver", &usbif->usb_ver) || ++ (usbif->usb_ver != USB_VER_USB11 && usbif->usb_ver != USB_VER_USB20)) { ++ xen_be_printf(xendev, 0, "usb-ver not readable or out of bounds\n"); ++ return -1; ++ } ++ ++ usbback_backend_changed(xendev, "port"); ++ ++ TR_BUS(xendev, "finished\n"); ++ ++ return 0; ++} ++ ++static void xen_bus_attach(USBPort *port) ++{ ++ struct usbback_info *usbif; ++ ++ usbif = port->opaque; ++ TR_BUS(&usbif->xendev, "\n"); ++ usbif->ports[port->index].attached = true; ++ usbback_hotplug_enq(usbif, port->index + 1); ++} ++ ++static void xen_bus_detach(USBPort *port) ++{ ++ struct usbback_info *usbif; ++ ++ usbif = port->opaque; ++ TR_BUS(&usbif->xendev, "\n"); ++ usbif->ports[port->index].attached = false; ++ usbback_hotplug_enq(usbif, port->index + 1); ++} ++ ++static void xen_bus_child_detach(USBPort *port, USBDevice *child) ++{ ++ struct usbback_info *usbif; ++ ++ usbif = port->opaque; ++ TR_BUS(&usbif->xendev, "\n"); ++} ++ ++static void xen_bus_complete(USBPort *port, USBPacket *packet) ++{ ++ struct usbback_info *usbif; ++ ++ usbif = port->opaque; ++ TR_REQ(&usbif->xendev, "\n"); ++ usbback_packet_complete(packet); ++} ++ ++static USBPortOps xen_usb_port_ops = { ++ .attach = xen_bus_attach, ++ .detach = xen_bus_detach, ++ .child_detach = xen_bus_child_detach, ++ .complete = xen_bus_complete, ++}; ++ ++static USBBusOps xen_usb_bus_ops = { ++}; ++ ++static void usbback_alloc(struct XenDevice *xendev) ++{ ++ struct usbback_info *usbif; ++ USBPort *p; ++ unsigned int i, max_grants; ++ ++ usbif = container_of(xendev, struct usbback_info, xendev); ++ ++ usb_bus_new(&usbif->bus, sizeof(usbif->bus), &xen_usb_bus_ops, xen_sysdev); ++ for (i = 0; i < USBBACK_MAXPORTS; i++) { ++ p = &(usbif->ports[i].port); ++ usb_register_port(&usbif->bus, p, usbif, i, &xen_usb_port_ops, ++ USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL | ++ USB_SPEED_MASK_HIGH); ++ snprintf(p->path, sizeof(p->path), "%d", 99); ++ } ++ ++ QTAILQ_INIT(&usbif->req_free_q); ++ QSIMPLEQ_INIT(&usbif->hotplug_q); ++ usbif->bh = qemu_bh_new(usbback_bh, usbif); ++ ++ /* max_grants: for each request and for the rings (request and connect). */ ++ max_grants = USBIF_MAX_SEGMENTS_PER_REQUEST * USB_URB_RING_SIZE + 2; ++ if (xengnttab_set_max_grants(xendev->gnttabdev, max_grants) < 0) { ++ xen_be_printf(xendev, 0, "xengnttab_set_max_grants failed: %s\n", ++ strerror(errno)); ++ } ++} ++ ++static int usbback_free(struct XenDevice *xendev) ++{ ++ struct usbback_info *usbif; ++ struct usbback_req *usbback_req; ++ struct usbback_hotplug *usb_hp; ++ unsigned int i; ++ ++ TR_BUS(xendev, "start\n"); ++ ++ usbback_disconnect(xendev); ++ usbif = container_of(xendev, struct usbback_info, xendev); ++ for (i = 1; i <= usbif->num_ports; i++) { ++ usbback_portid_remove(usbif, i); ++ } ++ ++ while (!QTAILQ_EMPTY(&usbif->req_free_q)) { ++ usbback_req = QTAILQ_FIRST(&usbif->req_free_q); ++ QTAILQ_REMOVE(&usbif->req_free_q, usbback_req, q); ++ g_free(usbback_req); ++ } ++ while (!QSIMPLEQ_EMPTY(&usbif->hotplug_q)) { ++ usb_hp = QSIMPLEQ_FIRST(&usbif->hotplug_q); ++ QSIMPLEQ_REMOVE_HEAD(&usbif->hotplug_q, q); ++ g_free(usb_hp); ++ } ++ ++ qemu_bh_delete(usbif->bh); ++ ++ for (i = 0; i < USBBACK_MAXPORTS; i++) { ++ usb_unregister_port(&usbif->bus, &(usbif->ports[i].port)); ++ } ++ ++ usb_bus_release(&usbif->bus); ++ ++ TR_BUS(xendev, "finished\n"); ++ ++ return 0; ++} ++ ++static void usbback_event(struct XenDevice *xendev) ++{ ++ struct usbback_info *usbif; ++ ++ usbif = container_of(xendev, struct usbback_info, xendev); ++ qemu_bh_schedule(usbif->bh); ++} ++ ++struct XenDevOps xen_usb_ops = { ++ .size = sizeof(struct usbback_info), ++ .flags = DEVOPS_FLAG_NEED_GNTDEV, ++ .init = usbback_init, ++ .alloc = usbback_alloc, ++ .free = usbback_free, ++ .backend_changed = usbback_backend_changed, ++ .initialise = usbback_connect, ++ .disconnect = usbback_disconnect, ++ .event = usbback_event, ++}; ++ ++#else /* USBIF_SHORT_NOT_OK */ ++ ++static int usbback_not_supported(void) ++{ ++ return -EINVAL; ++} ++ ++struct XenDevOps xen_usb_ops = { ++ .backend_register = usbback_not_supported, ++}; ++ ++#endif +diff --git a/hw/xenpv/xen_machine_pv.c b/hw/xenpv/xen_machine_pv.c +index 48d5bc6..f68cf48 100644 +--- a/hw/xenpv/xen_machine_pv.c ++++ b/hw/xenpv/xen_machine_pv.c +@@ -80,6 +80,9 @@ static void xen_init_pv(MachineState *machine) + xen_be_register("vfb", &xen_framebuffer_ops); + xen_be_register("qdisk", &xen_blkdev_ops); + xen_be_register("qnic", &xen_netdev_ops); ++#ifdef CONFIG_USB_LIBUSB ++ xen_be_register("qusb", &xen_usb_ops); ++#endif + + /* configure framebuffer */ + if (xenfb_enabled) { +diff --git a/include/hw/xen/xen_backend.h b/include/hw/xen/xen_backend.h +index 63364f7..6e18a46 100644 +--- a/include/hw/xen/xen_backend.h ++++ b/include/hw/xen/xen_backend.h +@@ -101,6 +101,9 @@ extern struct XenDevOps xen_kbdmouse_ops; /* xen_framebuffer.c */ + extern struct XenDevOps xen_framebuffer_ops; /* xen_framebuffer.c */ + extern struct XenDevOps xen_blkdev_ops; /* xen_disk.c */ + extern struct XenDevOps xen_netdev_ops; /* xen_nic.c */ ++#ifdef CONFIG_USB_LIBUSB ++extern struct XenDevOps xen_usb_ops; /* xen-usb.c */ ++#endif + + void xen_init_display(int domid); + +diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h +index bd65e67..d010cee 100644 +--- a/include/hw/xen/xen_common.h ++++ b/include/hw/xen/xen_common.h +@@ -49,6 +49,8 @@ typedef xc_gnttab xengnttab_handle; + #define xengnttab_unmap(h, a, n) xc_gnttab_munmap(h, a, n) + #define xengnttab_map_grant_refs(h, c, d, r, p) \ + xc_gnttab_map_grant_refs(h, c, d, r, p) ++#define xengnttab_map_domain_grant_refs(h, c, d, r, p) \ ++ xc_gnttab_map_domain_grant_refs(h, c, d, r, p) + + #define xenforeignmemory_open(l, f) xen_xc + diff --git a/0059-usb-Fix-conditions-that-xen-usb.c-i.patch b/0059-usb-Fix-conditions-that-xen-usb.c-i.patch new file mode 100644 index 00000000..14fc7855 --- /dev/null +++ b/0059-usb-Fix-conditions-that-xen-usb.c-i.patch @@ -0,0 +1,28 @@ +From 9ddd9862dbc30107d2315f0b858e32cd0c90db8a Mon Sep 17 00:00:00 2001 +From: Bruce Rogers +Date: Fri, 10 Jun 2016 07:12:15 -0600 +Subject: [PATCH] usb: Fix conditions that xen-usb.c is used + +When non-x86 arch targets are built on x86 we have a mismatched +between what is built in support of xen. xen-usb.c is conditioned +upon CONFIG_USB_LIBUSB and CONFIG_XEN_BACKEND, but it relies on +an external reference that is instead controlled by CONFIG_XEN. +Add a dependency on CONFIG_XEN as well. +[BR: FATE#316612] +Signed-off-by: Bruce Rogers +--- + hw/usb/Makefile.objs | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/Makefile.objs b/hw/usb/Makefile.objs +index 98b5c9d..2db2fa1 100644 +--- a/hw/usb/Makefile.objs ++++ b/hw/usb/Makefile.objs +@@ -39,6 +39,6 @@ common-obj-$(CONFIG_USB_REDIR) += redirect.o quirks.o + # usb pass-through + common-obj-y += $(patsubst %,host-%.o,$(HOST_USB)) + +-ifeq ($(CONFIG_USB_LIBUSB),y) ++ifeq ($(CONFIG_XEN)$(CONFIG_USB_LIBUSB),yy) + common-obj-$(CONFIG_XEN_BACKEND) += xen-usb.o + endif diff --git a/0060-vnc-add-configurable-keyboard-delay.patch b/0060-vnc-add-configurable-keyboard-delay.patch new file mode 100644 index 00000000..4b6f0642 --- /dev/null +++ b/0060-vnc-add-configurable-keyboard-delay.patch @@ -0,0 +1,129 @@ +From 464539abcc33f2d8465dead1555de169b87239b9 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 1 Jun 2016 08:22:30 +0200 +Subject: [PATCH] vnc: add configurable keyboard delay + +Limits the rate kbd events from the vnc server are forwarded to the +guest, so input devices which are typically low-bandwidth can keep +up even on bulky input. + +v2: update documentation too. +v3: spell fixes. + +Signed-off-by: Gerd Hoffmann +Tested-by: Yang Hongyang +Message-id: 1464762150-25817-1-git-send-email-kraxel@redhat.com +(cherry picked from commit c5ce83334465ee5acb6789a2f22d125273761c9e) +[BR: BSC#974914] +Signed-off-by: Bruce Rogers +--- + qemu-options.hx | 8 ++++++++ + ui/vnc.c | 13 +++++++++++-- + ui/vnc.h | 1 + + 3 files changed, 20 insertions(+), 2 deletions(-) + +diff --git a/qemu-options.hx b/qemu-options.hx +index 32b25a5..3bcd98f 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -1410,6 +1410,14 @@ everybody else. 'ignore' completely ignores the shared flag and + allows everybody connect unconditionally. Doesn't conform to the rfb + spec but is traditional QEMU behavior. + ++@item key-delay-ms ++ ++Set keyboard delay, for key down and key up events, in milliseconds. ++Default is 1. Keyboards are low-bandwidth devices, so this slowdown ++can help the device and guest to keep up and not lose events in case ++events are arriving in bulk. Possible causes for the latter are flaky ++network connections, or scripts for automated testing. ++ + @end table + ETEXI + +diff --git a/ui/vnc.c b/ui/vnc.c +index ab65db9..1bee07f 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -1639,6 +1639,7 @@ static void reset_keys(VncState *vs) + for(i = 0; i < 256; i++) { + if (vs->modifiers_state[i]) { + qemu_input_event_send_key_number(vs->vd->dcl.con, i, false); ++ qemu_input_event_send_key_delay(vs->vd->key_delay_ms); + vs->modifiers_state[i] = 0; + } + } +@@ -1648,9 +1649,9 @@ static void press_key(VncState *vs, int keysym) + { + int keycode = keysym2scancode(vs->vd->kbd_layout, keysym) & SCANCODE_KEYMASK; + qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, true); +- qemu_input_event_send_key_delay(0); ++ qemu_input_event_send_key_delay(vs->vd->key_delay_ms); + qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false); +- qemu_input_event_send_key_delay(0); ++ qemu_input_event_send_key_delay(vs->vd->key_delay_ms); + } + + static int current_led_state(VncState *vs) +@@ -1802,6 +1803,7 @@ static void do_key_event(VncState *vs, int down, int keycode, int sym) + + if (qemu_console_is_graphic(NULL)) { + qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, down); ++ qemu_input_event_send_key_delay(vs->vd->key_delay_ms); + } else { + bool numlock = vs->modifiers_state[0x45]; + bool control = (vs->modifiers_state[0x1d] || +@@ -1923,6 +1925,7 @@ static void vnc_release_modifiers(VncState *vs) + continue; + } + qemu_input_event_send_key_number(vs->vd->dcl.con, keycode, false); ++ qemu_input_event_send_key_delay(vs->vd->key_delay_ms); + } + } + +@@ -3298,6 +3301,9 @@ static QemuOptsList qemu_vnc_opts = { + .name = "lock-key-sync", + .type = QEMU_OPT_BOOL, + },{ ++ .name = "key-delay-ms", ++ .type = QEMU_OPT_NUMBER, ++ },{ + .name = "sasl", + .type = QEMU_OPT_BOOL, + },{ +@@ -3536,6 +3542,7 @@ void vnc_display_open(const char *id, Error **errp) + #endif + int acl = 0; + int lock_key_sync = 1; ++ int key_delay_ms; + + if (!vs) { + error_setg(errp, "VNC display not active"); +@@ -3658,6 +3665,7 @@ void vnc_display_open(const char *id, Error **errp) + + reverse = qemu_opt_get_bool(opts, "reverse", false); + lock_key_sync = qemu_opt_get_bool(opts, "lock-key-sync", true); ++ key_delay_ms = qemu_opt_get_number(opts, "key-delay-ms", 1); + sasl = qemu_opt_get_bool(opts, "sasl", false); + #ifndef CONFIG_VNC_SASL + if (sasl) { +@@ -3790,6 +3798,7 @@ void vnc_display_open(const char *id, Error **errp) + } + #endif + vs->lock_key_sync = lock_key_sync; ++ vs->key_delay_ms = key_delay_ms; + + device_id = qemu_opt_get(opts, "display"); + if (device_id) { +diff --git a/ui/vnc.h b/ui/vnc.h +index 81a3261..6568bca 100644 +--- a/ui/vnc.h ++++ b/ui/vnc.h +@@ -155,6 +155,7 @@ struct VncDisplay + DisplayChangeListener dcl; + kbd_layout_t *kbd_layout; + int lock_key_sync; ++ int key_delay_ms; + QemuMutex mutex; + + QEMUCursor *cursor; diff --git a/qemu-linux-user.changes b/qemu-linux-user.changes index 1d7859bc..6c7169a5 100644 --- a/qemu-linux-user.changes +++ b/qemu-linux-user.changes @@ -1,3 +1,21 @@ +------------------------------------------------------------------- +Fri Jun 10 13:35:11 UTC 2016 - brogers@suse.com + +- Patch queue updated from git://github.com/openSUSE/qemu.git opensuse-2.6 +* Patches added: + 0049-scsi-megasas-use-appropriate-proper.patch + 0050-scsi-megasas-check-read_queue_head-.patch + 0051-scsi-megasas-null-terminate-bios-ve.patch + 0052-vmsvga-move-fifo-sanity-checks-to-v.patch + 0053-vmsvga-don-t-process-more-than-1024.patch + 0054-block-iscsi-avoid-potential-overflo.patch + 0055-scsi-esp-check-TI-buffer-index-befo.patch + 0056-xen-introduce-dummy-system-device.patch + 0057-xen-write-information-about-support.patch + 0058-xen-add-pvUSB-backend.patch + 0059-usb-Fix-conditions-that-xen-usb.c-i.patch + 0060-vnc-add-configurable-keyboard-delay.patch + ------------------------------------------------------------------- Thu May 26 16:23:33 UTC 2016 - brogers@suse.com diff --git a/qemu-linux-user.spec b/qemu-linux-user.spec index b57f0cf0..91751ffb 100644 --- a/qemu-linux-user.spec +++ b/qemu-linux-user.spec @@ -73,6 +73,18 @@ Patch0045: 0045-esp-check-dma-length-before-reading.patch Patch0046: 0046-scsi-pvscsi-check-command-descripto.patch Patch0047: 0047-scsi-mptsas-infinite-loop-while-fet.patch Patch0048: 0048-vga-add-sr_vbe-register-set.patch +Patch0049: 0049-scsi-megasas-use-appropriate-proper.patch +Patch0050: 0050-scsi-megasas-check-read_queue_head-.patch +Patch0051: 0051-scsi-megasas-null-terminate-bios-ve.patch +Patch0052: 0052-vmsvga-move-fifo-sanity-checks-to-v.patch +Patch0053: 0053-vmsvga-don-t-process-more-than-1024.patch +Patch0054: 0054-block-iscsi-avoid-potential-overflo.patch +Patch0055: 0055-scsi-esp-check-TI-buffer-index-befo.patch +Patch0056: 0056-xen-introduce-dummy-system-device.patch +Patch0057: 0057-xen-write-information-about-support.patch +Patch0058: 0058-xen-add-pvUSB-backend.patch +Patch0059: 0059-usb-Fix-conditions-that-xen-usb.c-i.patch +Patch0060: 0060-vnc-add-configurable-keyboard-delay.patch # Please do not add patches manually here, run update_git.sh. # this is to make lint happy Source300: qemu-rpmlintrc @@ -174,6 +186,18 @@ run cross-architecture builds. %patch0046 -p1 %patch0047 -p1 %patch0048 -p1 +%patch0049 -p1 +%patch0050 -p1 +%patch0051 -p1 +%patch0052 -p1 +%patch0053 -p1 +%patch0054 -p1 +%patch0055 -p1 +%patch0056 -p1 +%patch0057 -p1 +%patch0058 -p1 +%patch0059 -p1 +%patch0060 -p1 %build ./configure --prefix=%_prefix --sysconfdir=%_sysconfdir \ diff --git a/qemu-testsuite.changes b/qemu-testsuite.changes index 1601e283..35b9d8ea 100644 --- a/qemu-testsuite.changes +++ b/qemu-testsuite.changes @@ -1,3 +1,34 @@ +------------------------------------------------------------------- +Fri Jun 10 13:35:06 UTC 2016 - brogers@suse.com + +- Address various security/stability issues +* Patch queue updated from git://github.com/openSUSE/qemu.git opensuse-2.6 +* Fix OOB access in megasas emulated device (CVE-2016-5106 bsc#982018) + 0049-scsi-megasas-use-appropriate-proper.patch +* Fix OOB access in megasas emulated device (CVE-2016-5107 bsc#982019) + 0050-scsi-megasas-check-read_queue_head-.patch +* Fix OOB access in megasas emulated device (CVE-2016-5337 bsc#983961) + 0051-scsi-megasas-null-terminate-bios-ve.patch +* Correct the vmvga fifo access checks (CVE-2016-4454 bsc#982222) + 0052-vmsvga-move-fifo-sanity-checks-to-v.patch +* Fix potential DoS issue in vmvga processing (CVE-2016-4453 bsc#982223) + 0053-vmsvga-don-t-process-more-than-1024.patch +* Fix heap buffer overflow flaw when iscsi protocol is used + (CVE-2016-5126 bsc#982285) + 0054-block-iscsi-avoid-potential-overflo.patch +* Fix OOB access in 53C9X emulation (CVE-2016-5338 bsc#983982) + 0055-scsi-esp-check-TI-buffer-index-befo.patch +- Add support to qemu for pv-usb under Xen (fate#316612) + 0056-xen-introduce-dummy-system-device.patch + 0057-xen-write-information-about-support.patch + 0058-xen-add-pvUSB-backend.patch + 0059-usb-Fix-conditions-that-xen-usb.c-i.patch +- Provide ability to rate limit keyboard events from the vnc server. + This is part of the solution to an issue affecting openQA testing, + where characters are lost, resulting in unexpected failures + (bsc#974914) + 0060-vnc-add-configurable-keyboard-delay.patch + ------------------------------------------------------------------- Fri Jun 3 17:29:41 UTC 2016 - brogers@suse.com diff --git a/qemu-testsuite.spec b/qemu-testsuite.spec index 38db3d92..2f65d5a7 100644 --- a/qemu-testsuite.spec +++ b/qemu-testsuite.spec @@ -114,6 +114,18 @@ Patch0045: 0045-esp-check-dma-length-before-reading.patch Patch0046: 0046-scsi-pvscsi-check-command-descripto.patch Patch0047: 0047-scsi-mptsas-infinite-loop-while-fet.patch Patch0048: 0048-vga-add-sr_vbe-register-set.patch +Patch0049: 0049-scsi-megasas-use-appropriate-proper.patch +Patch0050: 0050-scsi-megasas-check-read_queue_head-.patch +Patch0051: 0051-scsi-megasas-null-terminate-bios-ve.patch +Patch0052: 0052-vmsvga-move-fifo-sanity-checks-to-v.patch +Patch0053: 0053-vmsvga-don-t-process-more-than-1024.patch +Patch0054: 0054-block-iscsi-avoid-potential-overflo.patch +Patch0055: 0055-scsi-esp-check-TI-buffer-index-befo.patch +Patch0056: 0056-xen-introduce-dummy-system-device.patch +Patch0057: 0057-xen-write-information-about-support.patch +Patch0058: 0058-xen-add-pvUSB-backend.patch +Patch0059: 0059-usb-Fix-conditions-that-xen-usb.c-i.patch +Patch0060: 0060-vnc-add-configurable-keyboard-delay.patch # Please do not add QEMU patches manually here. # Run update_git.sh to regenerate this queue. @@ -710,6 +722,18 @@ This package provides a service file for starting and stopping KSM. %patch0046 -p1 %patch0047 -p1 %patch0048 -p1 +%patch0049 -p1 +%patch0050 -p1 +%patch0051 -p1 +%patch0052 -p1 +%patch0053 -p1 +%patch0054 -p1 +%patch0055 -p1 +%patch0056 -p1 +%patch0057 -p1 +%patch0058 -p1 +%patch0059 -p1 +%patch0060 -p1 %if %{build_x86_fw_from_source} pushd roms/seabios diff --git a/qemu.changes b/qemu.changes index 1601e283..35b9d8ea 100644 --- a/qemu.changes +++ b/qemu.changes @@ -1,3 +1,34 @@ +------------------------------------------------------------------- +Fri Jun 10 13:35:06 UTC 2016 - brogers@suse.com + +- Address various security/stability issues +* Patch queue updated from git://github.com/openSUSE/qemu.git opensuse-2.6 +* Fix OOB access in megasas emulated device (CVE-2016-5106 bsc#982018) + 0049-scsi-megasas-use-appropriate-proper.patch +* Fix OOB access in megasas emulated device (CVE-2016-5107 bsc#982019) + 0050-scsi-megasas-check-read_queue_head-.patch +* Fix OOB access in megasas emulated device (CVE-2016-5337 bsc#983961) + 0051-scsi-megasas-null-terminate-bios-ve.patch +* Correct the vmvga fifo access checks (CVE-2016-4454 bsc#982222) + 0052-vmsvga-move-fifo-sanity-checks-to-v.patch +* Fix potential DoS issue in vmvga processing (CVE-2016-4453 bsc#982223) + 0053-vmsvga-don-t-process-more-than-1024.patch +* Fix heap buffer overflow flaw when iscsi protocol is used + (CVE-2016-5126 bsc#982285) + 0054-block-iscsi-avoid-potential-overflo.patch +* Fix OOB access in 53C9X emulation (CVE-2016-5338 bsc#983982) + 0055-scsi-esp-check-TI-buffer-index-befo.patch +- Add support to qemu for pv-usb under Xen (fate#316612) + 0056-xen-introduce-dummy-system-device.patch + 0057-xen-write-information-about-support.patch + 0058-xen-add-pvUSB-backend.patch + 0059-usb-Fix-conditions-that-xen-usb.c-i.patch +- Provide ability to rate limit keyboard events from the vnc server. + This is part of the solution to an issue affecting openQA testing, + where characters are lost, resulting in unexpected failures + (bsc#974914) + 0060-vnc-add-configurable-keyboard-delay.patch + ------------------------------------------------------------------- Fri Jun 3 17:29:41 UTC 2016 - brogers@suse.com diff --git a/qemu.spec b/qemu.spec index 17da0df5..bdb5bdf8 100644 --- a/qemu.spec +++ b/qemu.spec @@ -114,6 +114,18 @@ Patch0045: 0045-esp-check-dma-length-before-reading.patch Patch0046: 0046-scsi-pvscsi-check-command-descripto.patch Patch0047: 0047-scsi-mptsas-infinite-loop-while-fet.patch Patch0048: 0048-vga-add-sr_vbe-register-set.patch +Patch0049: 0049-scsi-megasas-use-appropriate-proper.patch +Patch0050: 0050-scsi-megasas-check-read_queue_head-.patch +Patch0051: 0051-scsi-megasas-null-terminate-bios-ve.patch +Patch0052: 0052-vmsvga-move-fifo-sanity-checks-to-v.patch +Patch0053: 0053-vmsvga-don-t-process-more-than-1024.patch +Patch0054: 0054-block-iscsi-avoid-potential-overflo.patch +Patch0055: 0055-scsi-esp-check-TI-buffer-index-befo.patch +Patch0056: 0056-xen-introduce-dummy-system-device.patch +Patch0057: 0057-xen-write-information-about-support.patch +Patch0058: 0058-xen-add-pvUSB-backend.patch +Patch0059: 0059-usb-Fix-conditions-that-xen-usb.c-i.patch +Patch0060: 0060-vnc-add-configurable-keyboard-delay.patch # Please do not add QEMU patches manually here. # Run update_git.sh to regenerate this queue. @@ -710,6 +722,18 @@ This package provides a service file for starting and stopping KSM. %patch0046 -p1 %patch0047 -p1 %patch0048 -p1 +%patch0049 -p1 +%patch0050 -p1 +%patch0051 -p1 +%patch0052 -p1 +%patch0053 -p1 +%patch0054 -p1 +%patch0055 -p1 +%patch0056 -p1 +%patch0057 -p1 +%patch0058 -p1 +%patch0059 -p1 +%patch0060 -p1 %if %{build_x86_fw_from_source} pushd roms/seabios