mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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>
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
+47
-4
@@ -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(),
|
||||
};
|
||||
|
||||
|
||||
+5
-2
@@ -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;
|
||||
|
||||
+156
-79
File diff suppressed because it is too large
Load Diff
+7
-5
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user