diff options
| author | Peter Maydell <peter.maydell@linaro.org> | 2015-06-02 16:47:31 +0100 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2015-06-02 16:47:31 +0100 |
| commit | 42d58e7c6760cb9c55627c28ae538e27dcf2f144 (patch) | |
| tree | 432c6332cb6fc1f64ebbf1210218cdfc060bc63f /hw/xen/xen_pt.c | |
| parent | 3fc827d591679f3e262b9d1f8b34528eabfca8c0 (diff) | |
| parent | c25bbf1545a53ac051f9e51d4140e397660c10ae (diff) | |
| download | focaccia-qemu-42d58e7c6760cb9c55627c28ae538e27dcf2f144.tar.gz focaccia-qemu-42d58e7c6760cb9c55627c28ae538e27dcf2f144.zip | |
Merge remote-tracking branch 'remotes/sstabellini/tags/xen-15-06-02-tag' into staging
XSA 128 129 130 131 # gpg: Signature made Tue Jun 2 16:46:38 2015 BST using RSA key ID 70E1AE90 # gpg: Good signature from "Stefano Stabellini <stefano.stabellini@eu.citrix.com>" * remotes/sstabellini/tags/xen-15-06-02-tag: xen/pt: unknown PCI config space fields should be read-only xen/pt: add a few PCI config space field descriptions xen/pt: mark reserved bits in PCI config space fields xen/pt: mark all PCIe capability bits read-only xen/pt: split out calculation of throughable mask in PCI config space handling xen/pt: correctly handle PM status bit xen/pt: consolidate PM capability emu_mask xen/MSI: don't open-code pass-through of enable bit modifications xen/MSI-X: limit error messages xen: don't allow guest to control MSI mask register xen: properly gate host writes of modified PCI CFG contents Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/xen/xen_pt.c')
| -rw-r--r-- | hw/xen/xen_pt.c | 51 |
1 files changed, 47 insertions, 4 deletions
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c index d095c081cc..9afcda8e21 100644 --- a/hw/xen/xen_pt.c +++ b/hw/xen/xen_pt.c @@ -234,11 +234,12 @@ 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; XenPTRegInfo *reg = NULL; + bool wp_flag = false; if (xen_pt_pci_config_access_check(d, addr, len)) { return; @@ -271,10 +272,17 @@ 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 */ if (reg_grp_entry == NULL) { + if (!s->permissive) { + wb_mask = 0; + wp_flag = true; + } goto out; } @@ -295,9 +303,17 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr, uint32_t real_offset = reg_grp_entry->base_offset + reg->offset; uint32_t valid_mask = 0xFFFFFFFF >> ((4 - emul_len) << 3); uint8_t *ptr_val = NULL; + uint32_t wp_mask = reg->emu_mask | reg->ro_mask; valid_mask <<= (find_addr - real_offset) << 3; ptr_val = (uint8_t *)&val + (real_offset & 3); + if (!s->permissive) { + wp_mask |= reg->res_mask; + } + if (wp_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) { + wb_mask &= ~((wp_mask >> ((find_addr - real_offset) << 3)) + << ((len - emul_len) << 3)); + } /* do emulation based on register size */ switch (reg->size) { @@ -339,6 +355,16 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr, } else { /* nothing to do with passthrough type register, * continue to find next byte */ + if (!s->permissive) { + wb_mask &= ~(0xff << ((len - emul_len) << 3)); + /* Unused BARs will make it here, but we don't want to issue + * warnings for writes to them (bogus writes get dealt with + * above). + */ + if (index < 0) { + wp_flag = true; + } + } emul_len--; find_addr++; } @@ -350,10 +376,26 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr, memory_region_transaction_commit(); out: - if (!(reg && reg->no_wb)) { + if (wp_flag && !s->permissive_warned) { + s->permissive_warned = true; + xen_pt_log(d, "Write-back to unknown field 0x%02x (partially) inhibited (0x%0*x)\n", + addr, len * 2, wb_mask); + xen_pt_log(d, "If the device doesn't work, try enabling permissive mode\n"); + xen_pt_log(d, "(unsafe) and if it helps report the problem to xen-devel\n"); + } + 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); @@ -807,6 +849,7 @@ static void xen_pt_unregister_device(PCIDevice *d) static Property xen_pci_passthrough_properties[] = { DEFINE_PROP_PCI_HOST_DEVADDR("hostaddr", XenPCIPassthroughState, hostaddr), + DEFINE_PROP_BOOL("permissive", XenPCIPassthroughState, permissive, false), DEFINE_PROP_END_OF_LIST(), }; |