[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [qemu-xen-4.2-testing] xen: properly gate host writes of modified PCI CFG contents



commit 7b85a1e9cdef8de686780a6e3506448ceca37572
Author:     Jan Beulich <jbeulich@xxxxxxxx>
AuthorDate: Wed Jun 10 14:17:22 2015 +0100
Commit:     Ian Jackson <Ian.Jackson@xxxxxxxxxxxxx>
CommitDate: Wed Jun 10 14:17:22 2015 +0100

    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 <jbeulich@xxxxxxxx>
    Reviewed-by: Stefano Stabellini <stefano.stabellini@xxxxxxxxxxxxx>
---
 hw/pass-through.c |   31 +++++++++++++++++++++++--------
 hw/pass-through.h |    2 --
 2 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/hw/pass-through.c b/hw/pass-through.c
index 1e06aba..ada7697 100644
--- a/hw/pass-through.c
+++ b/hw/pass-through.c
@@ -454,7 +454,7 @@ static struct pt_reg_info_tbl pt_emu_reg_header0_tbl[] = {
         .offset     = PCI_INTEL_OPREGION,
         .size       = 4,
         .init_val   = 0,
-        .no_wb      = 1,
+        .emu_mask   = 0xFFFFFFFF,
         .u.dw.read   = pt_intel_opregion_read,
         .u.dw.write  = pt_intel_opregion_write,
         .u.dw.restore  = NULL,
@@ -657,7 +657,6 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = {
         .init_val   = 0x00000000,
         .ro_mask    = 0x00000003,
         .emu_mask   = 0xFFFFFFFF,
-        .no_wb      = 1,
         .init       = pt_common_reg_init,
         .u.dw.read  = pt_long_reg_read,
         .u.dw.write = pt_msgaddr32_reg_write,
@@ -670,7 +669,6 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = {
         .init_val   = 0x00000000,
         .ro_mask    = 0x00000000,
         .emu_mask   = 0xFFFFFFFF,
-        .no_wb      = 1,
         .init       = pt_msgaddr64_reg_init,
         .u.dw.read  = pt_long_reg_read,
         .u.dw.write = pt_msgaddr64_reg_write,
@@ -683,7 +681,6 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = {
         .init_val   = 0x0000,
         .ro_mask    = 0x0000,
         .emu_mask   = 0xFFFF,
-        .no_wb      = 1,
         .init       = pt_msgdata_reg_init,
         .u.w.read   = pt_word_reg_read,
         .u.w.write  = pt_msgdata_reg_write,
@@ -696,7 +693,6 @@ static struct pt_reg_info_tbl pt_emu_reg_msi_tbl[] = {
         .init_val   = 0x0000,
         .ro_mask    = 0x0000,
         .emu_mask   = 0xFFFF,
-        .no_wb      = 1,
         .init       = pt_msgdata_reg_init,
         .u.w.read   = pt_word_reg_read,
         .u.w.write  = pt_msgdata_reg_write,
@@ -1524,7 +1520,7 @@ static void pt_pci_write_config(PCIDevice *d, uint32_t 
address, uint32_t val,
     uint32_t find_addr = address;
     uint32_t real_offset = 0;
     uint32_t valid_mask = 0xFFFFFFFF;
-    uint32_t read_val = 0;
+    uint32_t read_val = 0, wb_mask;
     uint8_t *ptr_val = NULL;
     int emul_len = 0;
     int index = 0;
@@ -1597,7 +1593,10 @@ static void pt_pci_write_config(PCIDevice *d, uint32_t 
address, uint32_t val,
     {
         PT_LOG("Error: pci_read_block failed. return value[%d].\n", ret);
         memset((uint8_t *)&read_val, 0xff, len);
+        wb_mask = 0;
     }
+    else
+        wb_mask = 0xFFFFFFFF >> ((4 - len) << 3);
 
     /* pass directly to libpci for passthrough type register group */
     if (reg_grp_entry == NULL)
@@ -1620,6 +1619,11 @@ static void pt_pci_write_config(PCIDevice *d, uint32_t 
address, uint32_t val,
             valid_mask = (0xFFFFFFFF >> ((4 - emul_len) << 3));
             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 depend on register size */
             switch (reg->size) {
@@ -1677,8 +1681,19 @@ static void pt_pci_write_config(PCIDevice *d, uint32_t 
address, uint32_t val,
     val >>= ((address & 3) << 3);
 
 out:
-    if (!(reg && reg->no_wb)) {  /* unknown regs are passed through */
-        ret = pci_write_block(pci_dev, address, (uint8_t *)&val, len);
+    for (index = 0; wb_mask; index += len) {
+        /* unknown regs are passed through */
+        while (!(wb_mask & 0xff)) {
+            index++;
+            wb_mask >>= 8;
+        }
+        len = 0;
+        do {
+            len++;
+            wb_mask >>= 8;
+        } while (wb_mask & 0xff);
+        ret = pci_write_block(pci_dev, address + index,
+                              (uint8_t *)&val + index, len);
 
         if (!ret)
             PT_LOG("Error: pci_write_block failed. return value[%d].\n", ret);
diff --git a/hw/pass-through.h b/hw/pass-through.h
index d7d837c..2f11a80 100644
--- a/hw/pass-through.h
+++ b/hw/pass-through.h
@@ -372,8 +372,6 @@ struct pt_reg_info_tbl {
     uint32_t ro_mask;
     /* reg emulate field mask (ON:emu, OFF:passthrough) */
     uint32_t emu_mask;
-    /* no write back allowed */
-    uint32_t no_wb;
     /* emul reg initialize method */
     conf_reg_init init;
     union {
--
generated by git-patchbot for /home/xen/git/qemu-xen-4.2-testing.git

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.