From: Jan Beulich Date: Tue, 2 Jun 2015 15:43:07 +0000 (+0000) Subject: xen: properly gate host writes of modified PCI CFG contents X-Git-Tag: qemu-xen-4.5.1~12 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=8d3b4a8f8075d7e96a9bece8d8371c95b7be5f5a;p=qemu-upstream-4.5-testing.git xen: properly gate host writes of modified PCI CFG contents The old logic didn't work as intended when an access spanned multiple fields (for example a 32-bit access to the location of the MSI Message Data field with the high 16 bits not being covered by any known field). Remove it and derive which fields not to write to from the accessed fields' emulation masks: When they're all ones, there's no point in doing any host write. This fixes a secondary issue at once: We obviously shouldn't make any host write attempt when already the host read failed. This is XSA-128. Signed-off-by: Jan Beulich Reviewed-by: Stefano Stabellini --- diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index 6bc518c38..fb27d755b 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -234,7 +234,7 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr, int index = 0; XenPTRegGroup *reg_grp_entry = NULL; int rc = 0; - uint32_t read_val = 0; + uint32_t read_val = 0, wb_mask; int emul_len = 0; XenPTReg *reg_entry = NULL; uint32_t find_addr = addr; @@ -271,6 +271,9 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr, if (rc < 0) { XEN_PT_ERR(d, "pci_read_block failed. return value: %d.\n", rc); memset(&read_val, 0xff, len); + wb_mask = 0; + } else { + wb_mask = 0xFFFFFFFF >> ((4 - len) << 3); } /* pass directly to the real device for passthrough type register group */ @@ -298,6 +301,11 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr, valid_mask <<= (find_addr - real_offset) << 3; ptr_val = (uint8_t *)&val + (real_offset & 3); + if (reg->emu_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) { + wb_mask &= ~((reg->emu_mask + >> ((find_addr - real_offset) << 3)) + << ((len - emul_len) << 3)); + } /* do emulation based on register size */ switch (reg->size) { @@ -350,10 +358,19 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr, memory_region_transaction_commit(); out: - if (!(reg && reg->no_wb)) { + for (index = 0; wb_mask; index += len) { /* unknown regs are passed through */ - rc = xen_host_pci_set_block(&s->real_device, addr, - (uint8_t *)&val, len); + while (!(wb_mask & 0xff)) { + index++; + wb_mask >>= 8; + } + len = 0; + do { + len++; + wb_mask >>= 8; + } while (wb_mask & 0xff); + rc = xen_host_pci_set_block(&s->real_device, addr + index, + (uint8_t *)&val + index, len); if (rc < 0) { XEN_PT_ERR(d, "pci_write_block failed. return value: %d.\n", rc); diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h index 942dc60cc..52ceb856f 100644 --- a/hw/xen/xen_pt.h +++ b/hw/xen/xen_pt.h @@ -105,8 +105,6 @@ struct XenPTRegInfo { uint32_t ro_mask; /* reg emulate field mask (ON:emu, OFF:passthrough) */ uint32_t emu_mask; - /* no write back allowed */ - uint32_t no_wb; xen_pt_conf_reg_init init; /* read/write function pointer * for double_word/word/byte size */ diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c index c4c031935..fd732819c 100644 --- a/hw/xen/xen_pt_config_init.c +++ b/hw/xen/xen_pt_config_init.c @@ -1281,7 +1281,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = { .init_val = 0x00000000, .ro_mask = 0x00000003, .emu_mask = 0xFFFFFFFF, - .no_wb = 1, .init = xen_pt_common_reg_init, .u.dw.read = xen_pt_long_reg_read, .u.dw.write = xen_pt_msgaddr32_reg_write, @@ -1293,7 +1292,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = { .init_val = 0x00000000, .ro_mask = 0x00000000, .emu_mask = 0xFFFFFFFF, - .no_wb = 1, .init = xen_pt_msgaddr64_reg_init, .u.dw.read = xen_pt_long_reg_read, .u.dw.write = xen_pt_msgaddr64_reg_write, @@ -1305,7 +1303,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = { .init_val = 0x0000, .ro_mask = 0x0000, .emu_mask = 0xFFFF, - .no_wb = 1, .init = xen_pt_msgdata_reg_init, .u.w.read = xen_pt_word_reg_read, .u.w.write = xen_pt_msgdata_reg_write, @@ -1317,7 +1314,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = { .init_val = 0x0000, .ro_mask = 0x0000, .emu_mask = 0xFFFF, - .no_wb = 1, .init = xen_pt_msgdata_reg_init, .u.w.read = xen_pt_word_reg_read, .u.w.write = xen_pt_msgdata_reg_write,