提交 42d58e7c 编写于 作者: P Peter Maydell

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: NPeter Maydell <peter.maydell@linaro.org>
......@@ -21,10 +21,6 @@
#include "hw/pci/msi.h"
#include "qemu/range.h"
/* Eventually those constants should go to Linux pci_regs.h */
#define PCI_MSI_PENDING_32 0x10
#define PCI_MSI_PENDING_64 0x14
/* PCI_MSI_ADDRESS_LO */
#define PCI_MSI_ADDRESS_LO_MASK (~0x3)
......
......@@ -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(),
};
......
......@@ -101,12 +101,12 @@ struct XenPTRegInfo {
uint32_t offset;
uint32_t size;
uint32_t init_val;
/* reg reserved field mask (ON:reserved, OFF:defined) */
uint32_t res_mask;
/* reg read only field mask (ON:RO/ROS, OFF:other) */
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 */
......@@ -177,6 +177,7 @@ typedef struct XenPTMSIXEntry {
uint32_t data;
uint32_t vector_ctrl;
bool updated; /* indicate whether MSI ADDR or DATA is updated */
bool warned; /* avoid issuing (bogus) warning more than once */
} XenPTMSIXEntry;
typedef struct XenPTMSIX {
uint32_t ctrl_offset;
......@@ -196,6 +197,8 @@ struct XenPCIPassthroughState {
PCIHostDeviceAddress hostaddr;
bool is_virtfn;
bool permissive;
bool permissive_warned;
XenHostPCIDevice real_device;
XenPTRegion bases[PCI_NUM_REGIONS]; /* Access regions */
QLIST_HEAD(, XenPTRegGroup) reg_grps;
......
此差异已折叠。
......@@ -434,11 +434,10 @@ static void pci_msix_write(void *opaque, hwaddr addr,
XenPCIPassthroughState *s = opaque;
XenPTMSIX *msix = s->msix;
XenPTMSIXEntry *entry;
int entry_nr, offset;
unsigned int entry_nr, offset;
entry_nr = addr / PCI_MSIX_ENTRY_SIZE;
if (entry_nr < 0 || entry_nr >= msix->total_entries) {
XEN_PT_ERR(&s->dev, "asked MSI-X entry '%i' invalid!\n", entry_nr);
if (entry_nr >= msix->total_entries) {
return;
}
entry = &msix->msix_entry[entry_nr];
......@@ -460,8 +459,11 @@ static void pci_msix_write(void *opaque, hwaddr addr,
+ PCI_MSIX_ENTRY_VECTOR_CTRL;
if (msix->enabled && !(*vec_ctrl & PCI_MSIX_ENTRY_CTRL_MASKBIT)) {
XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
" already enabled.\n", entry_nr);
if (!entry->warned) {
entry->warned = true;
XEN_PT_ERR(&s->dev, "Can't update msix entry %d since MSI-X is"
" already enabled.\n", entry_nr);
}
return;
}
......
......@@ -298,8 +298,10 @@
#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */
#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */
#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */
#define PCI_MSI_PENDING_32 16 /* Pending bits register for 32-bit devices */
#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */
#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */
#define PCI_MSI_PENDING_64 20 /* Pending bits register for 32-bit devices */
/* MSI-X registers */
#define PCI_MSIX_FLAGS 2
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册