pkgsrc-ng/sysutils/xentools42/patches/patch-qemu-xen-traditional_hw_pass-through.c
2016-01-21 23:42:40 +01:00

763 lines
28 KiB
C

$NetBSD: patch-qemu-xen-traditional_hw_pass-through.c,v 1.2 2015/08/23 16:17:12 spz Exp $
patch for CVE-2015-2756 aka XSA-126 from
http://xenbits.xenproject.org/xsa/xsa126-qemut.patch
patch for CVE-2015-4103 aka XSA-128 from
http://xenbits.xen.org/xsa/xsa128-qemut.patch
patch for CVE-2015-4104 aka XSA-129 from
http://xenbits.xen.org/xsa/xsa129-qemut.patch
patch for CVE-2015-4106 aka XSA-131 from
http://xenbits.xen.org/xsa/xsa131-qemut-4.2-1.patch
http://xenbits.xen.org/xsa/xsa131-qemut-2.patch
http://xenbits.xen.org/xsa/xsa131-qemut-3.patch
http://xenbits.xen.org/xsa/xsa131-qemut-4.patch
http://xenbits.xen.org/xsa/xsa131-qemut-5.patch
http://xenbits.xen.org/xsa/xsa131-qemut-6.patch
http://xenbits.xen.org/xsa/xsa131-qemut-7.patch
http://xenbits.xen.org/xsa/xsa131-qemut-8.patch
avoid duplicate inclusion of pci/header.h and pci/pci.h (also in pass-through.h)
--- qemu-xen-traditional/hw/pass-through.c.orig 2014-01-09 12:44:42.000000000 +0000
+++ qemu-xen-traditional/hw/pass-through.c
@@ -84,8 +84,6 @@
*/
#include "pass-through.h"
-#include "pci/header.h"
-#include "pci/pci.h"
#include "pt-msi.h"
#include "qemu-xen.h"
#include "iomulti.h"
@@ -147,6 +145,10 @@ static uint32_t pt_msgaddr64_reg_init(st
struct pt_reg_info_tbl *reg, uint32_t real_offset);
static uint32_t pt_msgdata_reg_init(struct pt_dev *ptdev,
struct pt_reg_info_tbl *reg, uint32_t real_offset);
+static uint32_t pt_mask_reg_init(struct pt_dev *ptdev,
+ struct pt_reg_info_tbl *reg, uint32_t real_offset);
+static uint32_t pt_pending_reg_init(struct pt_dev *ptdev,
+ struct pt_reg_info_tbl *reg, uint32_t real_offset);
static uint32_t pt_msixctrl_reg_init(struct pt_dev *ptdev,
struct pt_reg_info_tbl *reg, uint32_t real_offset);
static uint32_t pt_header_type_reg_init(struct pt_dev *ptdev,
@@ -178,9 +180,6 @@ static int pt_cmd_reg_read(struct pt_dev
static int pt_bar_reg_read(struct pt_dev *ptdev,
struct pt_reg_tbl *cfg_entry,
uint32_t *value, uint32_t valid_mask);
-static int pt_pmcsr_reg_read(struct pt_dev *ptdev,
- struct pt_reg_tbl *cfg_entry,
- uint16_t *value, uint16_t valid_mask);
static int pt_byte_reg_write(struct pt_dev *ptdev,
struct pt_reg_tbl *cfg_entry,
uint8_t *value, uint8_t dev_value, uint8_t valid_mask);
@@ -285,7 +284,7 @@ static struct pt_reg_info_tbl pt_emu_reg
.offset = PCI_COMMAND,
.size = 2,
.init_val = 0x0000,
- .ro_mask = 0xF880,
+ .res_mask = 0xF880,
.emu_mask = 0x0740,
.init = pt_common_reg_init,
.u.w.read = pt_cmd_reg_read,
@@ -312,7 +311,8 @@ static struct pt_reg_info_tbl pt_emu_reg
.offset = PCI_STATUS,
.size = 2,
.init_val = 0x0000,
- .ro_mask = 0x06FF,
+ .res_mask = 0x0007,
+ .ro_mask = 0x06F8,
.emu_mask = 0x0010,
.init = pt_status_reg_init,
.u.w.read = pt_word_reg_read,
@@ -457,7 +457,7 @@ static struct pt_reg_info_tbl pt_emu_reg
.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,
@@ -493,15 +493,29 @@ static struct pt_reg_info_tbl pt_emu_reg
.u.w.write = pt_word_reg_write,
.u.w.restore = NULL,
},
- /* PCI Power Management Control/Status reg */
+ /* PCI Power Management Control/Status reg (->power_mgmt on) */
{
.offset = PCI_PM_CTRL,
.size = 2,
.init_val = 0x0008,
- .ro_mask = 0xE1FC,
+ .res_mask = 0x00F0,
+ .ro_mask = 0xE10C,
.emu_mask = 0x8100,
.init = pt_pmcsr_reg_init,
- .u.w.read = pt_pmcsr_reg_read,
+ .u.w.read = pt_word_reg_read,
+ .u.w.write = pt_pmcsr_reg_write,
+ .u.w.restore = pt_pmcsr_reg_restore,
+ },
+ /* PCI Power Management Control/Status reg (->power_mgmt off) */
+ {
+ .offset = PCI_PM_CTRL,
+ .size = 2,
+ .init_val = 0x0008,
+ .res_mask = 0x00F0,
+ .ro_mask = 0xE10C,
+ .emu_mask = 0x810B,
+ .init = pt_pmcsr_reg_init,
+ .u.w.read = pt_word_reg_read,
.u.w.write = pt_pmcsr_reg_write,
.u.w.restore = pt_pmcsr_reg_restore,
},
@@ -525,6 +539,16 @@ static struct pt_reg_info_tbl pt_emu_reg
.u.b.restore = NULL,
},
{
+ .offset = PCI_VPD_ADDR,
+ .size = 2,
+ .ro_mask = 0x0003,
+ .emu_mask = 0x0003,
+ .init = pt_common_reg_init,
+ .u.w.read = pt_word_reg_read,
+ .u.w.write = pt_word_reg_write,
+ .u.w.restore = pt_word_reg_restore,
+ },
+ {
.size = 0,
},
};
@@ -567,7 +591,7 @@ static struct pt_reg_info_tbl pt_emu_reg
.offset = PCI_EXP_DEVCAP,
.size = 4,
.init_val = 0x00000000,
- .ro_mask = 0x1FFCFFFF,
+ .ro_mask = 0xFFFFFFFF,
.emu_mask = 0x10000000,
.init = pt_common_reg_init,
.u.dw.read = pt_long_reg_read,
@@ -586,6 +610,17 @@ static struct pt_reg_info_tbl pt_emu_reg
.u.w.write = pt_word_reg_write,
.u.w.restore = pt_word_reg_restore,
},
+ /* Device Status reg */
+ {
+ .offset = PCI_EXP_DEVSTA,
+ .size = 2,
+ .res_mask = 0xFFC0,
+ .ro_mask = 0x0030,
+ .init = pt_common_reg_init,
+ .u.w.read = pt_word_reg_read,
+ .u.w.write = pt_word_reg_write,
+ .u.w.restore = pt_word_reg_restore,
+ },
/* Link Control reg */
{
.offset = PCI_EXP_LNKCTL,
@@ -598,6 +633,16 @@ static struct pt_reg_info_tbl pt_emu_reg
.u.w.write = pt_word_reg_write,
.u.w.restore = pt_word_reg_restore,
},
+ /* Link Status reg */
+ {
+ .offset = PCI_EXP_LNKSTA,
+ .size = 2,
+ .ro_mask = 0x3FFF,
+ .init = pt_common_reg_init,
+ .u.w.read = pt_word_reg_read,
+ .u.w.write = pt_word_reg_write,
+ .u.w.restore = pt_word_reg_restore,
+ },
/* Device Control 2 reg */
{
.offset = 0x28,
@@ -646,8 +691,9 @@ static struct pt_reg_info_tbl pt_emu_reg
.offset = PCI_MSI_FLAGS, // 2
.size = 2,
.init_val = 0x0000,
- .ro_mask = 0xFF8E,
- .emu_mask = 0x007F,
+ .res_mask = 0xFE00,
+ .ro_mask = 0x018E,
+ .emu_mask = 0x017E,
.init = pt_msgctrl_reg_init,
.u.w.read = pt_word_reg_read,
.u.w.write = pt_msgctrl_reg_write,
@@ -660,7 +706,6 @@ static struct pt_reg_info_tbl pt_emu_reg
.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,
@@ -673,7 +718,6 @@ static struct pt_reg_info_tbl pt_emu_reg
.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,
@@ -686,7 +730,6 @@ static struct pt_reg_info_tbl pt_emu_reg
.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,
@@ -699,12 +742,55 @@ static struct pt_reg_info_tbl pt_emu_reg
.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,
.u.w.restore = NULL,
},
+ /* Mask reg (if PCI_MSI_FLAGS_MASK_BIT set, for 32-bit devices) */
+ {
+ .offset = PCI_MSI_MASK_32,
+ .size = 4,
+ .init_val = 0x00000000,
+ .ro_mask = 0xFFFFFFFF,
+ .emu_mask = 0xFFFFFFFF,
+ .init = pt_mask_reg_init,
+ .u.dw.read = pt_long_reg_read,
+ .u.dw.write = pt_long_reg_write,
+ },
+ /* Mask reg (if PCI_MSI_FLAGS_MASK_BIT set, for 64-bit devices) */
+ {
+ .offset = PCI_MSI_MASK_64,
+ .size = 4,
+ .init_val = 0x00000000,
+ .ro_mask = 0xFFFFFFFF,
+ .emu_mask = 0xFFFFFFFF,
+ .init = pt_mask_reg_init,
+ .u.dw.read = pt_long_reg_read,
+ .u.dw.write = pt_long_reg_write,
+ },
+ /* Pending reg (if PCI_MSI_FLAGS_MASK_BIT set, for 32-bit devices) */
+ {
+ .offset = PCI_MSI_MASK_32 + 4,
+ .size = 4,
+ .init_val = 0x00000000,
+ .ro_mask = 0xFFFFFFFF,
+ .emu_mask = 0x00000000,
+ .init = pt_pending_reg_init,
+ .u.dw.read = pt_long_reg_read,
+ .u.dw.write = pt_long_reg_write,
+ },
+ /* Pending reg (if PCI_MSI_FLAGS_MASK_BIT set, for 64-bit devices) */
+ {
+ .offset = PCI_MSI_MASK_64 + 4,
+ .size = 4,
+ .init_val = 0x00000000,
+ .ro_mask = 0xFFFFFFFF,
+ .emu_mask = 0x00000000,
+ .init = pt_pending_reg_init,
+ .u.dw.read = pt_long_reg_read,
+ .u.dw.write = pt_long_reg_write,
+ },
{
.size = 0,
},
@@ -729,7 +815,8 @@ static struct pt_reg_info_tbl pt_emu_reg
.offset = PCI_MSI_FLAGS, // 2
.size = 2,
.init_val = 0x0000,
- .ro_mask = 0x3FFF,
+ .res_mask = 0x3800,
+ .ro_mask = 0x07FF,
.emu_mask = 0x0000,
.init = pt_msixctrl_reg_init,
.u.w.read = pt_word_reg_read,
@@ -1527,10 +1614,10 @@ static void pt_pci_write_config(PCIDevic
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, wp_mask;
uint8_t *ptr_val = NULL;
int emul_len = 0;
- int index = 0;
+ int index = 0, wp_flag = 0;
int ret = 0;
#ifdef PT_DEBUG_PCI_CONFIG_ACCESS
@@ -1600,11 +1687,21 @@ static void pt_pci_write_config(PCIDevic
{
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)
+ {
+ if (!assigned_device->permissive)
+ {
+ wb_mask = 0;
+ wp_flag = 1;
+ }
goto out;
+ }
/* adjust the read and write value to appropriate CFC-CFF window */
read_val <<= ((address & 3) << 3);
@@ -1623,6 +1720,12 @@ static void pt_pci_write_config(PCIDevic
valid_mask = (0xFFFFFFFF >> ((4 - emul_len) << 3));
valid_mask <<= ((find_addr - real_offset) << 3);
ptr_val = ((uint8_t *)&val + (real_offset & 3));
+ wp_mask = reg->emu_mask | reg->ro_mask;
+ if (!assigned_device->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 depend on register size */
switch (reg->size) {
@@ -1671,6 +1774,16 @@ static void pt_pci_write_config(PCIDevic
/* nothing to do with passthrough type register,
* continue to find next byte
*/
+ if (!assigned_device->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 = 1;
+ }
emul_len--;
find_addr++;
}
@@ -1680,8 +1793,28 @@ static void pt_pci_write_config(PCIDevic
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);
+ if (wp_flag && !assigned_device->permissive_warned)
+ {
+ assigned_device->permissive_warned = 1;
+ PT_LOG("Write-back to unknown field 0x%02x (partially) inhibited (0x%0*x)\n",
+ addr, len * 2, wb_mask);
+ PT_LOG("If device %02x:%02x.%o doesn't work, try enabling permissive\n",
+ pci_bus_num(d->bus), PCI_SLOT(d->devfn), PCI_FUNC(d->devfn));
+ PT_LOG("mode (unsafe) and if it helps report the problem to xen-devel\n");
+ }
+ 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);
@@ -2848,6 +2981,7 @@ static uint32_t pt_pmc_reg_init(struct p
return reg->init_val;
}
+/* this function will be called twice (for ->power_mgmt on and off cases) */
/* initialize PCI Power Management Control/Status register */
static uint32_t pt_pmcsr_reg_init(struct pt_dev *ptdev,
struct pt_reg_info_tbl *reg, uint32_t real_offset)
@@ -2855,8 +2989,23 @@ static uint32_t pt_pmcsr_reg_init(struct
PCIDevice *d = &ptdev->dev;
uint16_t cap_ver = 0;
- if (!ptdev->power_mgmt)
- return reg->init_val;
+ switch (reg->emu_mask & (PCI_PM_CTRL_STATE_MASK |
+ PCI_PM_CTRL_NO_SOFT_RESET))
+ {
+ case 0:
+ if (!ptdev->power_mgmt)
+ return PT_INVALID_REG;
+ break;
+ case PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET:
+ if (!ptdev->power_mgmt)
+ return reg->init_val;
+ return PT_INVALID_REG;
+ default:
+ /* exit I/O emulator */
+ PT_LOG("Internal error: Invalid PMCSR emulation mask %04x."
+ " I/O emulator exit.\n", reg->emu_mask);
+ exit(1);
+ }
/* check PCI Power Management support version */
cap_ver = ptdev->pm_state->pmc_field & PCI_PM_CAP_VER_MASK;
@@ -3000,6 +3149,42 @@ static uint32_t pt_msgdata_reg_init(stru
return PT_INVALID_REG;
}
+/* this function will be called twice (for 32 bit and 64 bit type) */
+/* initialize Mask register */
+static uint32_t pt_mask_reg_init(struct pt_dev *ptdev,
+ struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+ uint32_t flags = ptdev->msi->flags;
+ uint32_t offset = reg->offset;
+
+ if (!(flags & PCI_MSI_FLAGS_MASK_BIT))
+ return PT_INVALID_REG;
+
+ if (offset == (flags & PCI_MSI_FLAGS_64BIT ?
+ PCI_MSI_MASK_64 : PCI_MSI_MASK_32))
+ return reg->init_val;
+
+ return PT_INVALID_REG;
+}
+
+/* this function will be called twice (for 32 bit and 64 bit type) */
+/* initialize Pending register */
+static uint32_t pt_pending_reg_init(struct pt_dev *ptdev,
+ struct pt_reg_info_tbl *reg, uint32_t real_offset)
+{
+ uint32_t flags = ptdev->msi->flags;
+ uint32_t offset = reg->offset;
+
+ if (!(flags & PCI_MSI_FLAGS_MASK_BIT))
+ return PT_INVALID_REG;
+
+ if (offset == (flags & PCI_MSI_FLAGS_64BIT ?
+ PCI_MSI_MASK_64 + 4 : PCI_MSI_MASK_32 + 4))
+ return reg->init_val;
+
+ return PT_INVALID_REG;
+}
+
/* initialize Message Control register for MSI-X */
static uint32_t pt_msixctrl_reg_init(struct pt_dev *ptdev,
struct pt_reg_info_tbl *reg, uint32_t real_offset)
@@ -3331,24 +3516,18 @@ static int pt_bar_reg_read(struct pt_dev
}
-/* read Power Management Control/Status register */
-static int pt_pmcsr_reg_read(struct pt_dev *ptdev,
- struct pt_reg_tbl *cfg_entry,
- uint16_t *value, uint16_t valid_mask)
+static uint32_t get_throughable_mask(const struct pt_dev *ptdev,
+ const struct pt_reg_info_tbl *reg,
+ uint32_t valid_mask)
{
- struct pt_reg_info_tbl *reg = cfg_entry->reg;
- uint16_t valid_emu_mask = reg->emu_mask;
-
- if (!ptdev->power_mgmt)
- valid_emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
+ uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
- valid_emu_mask = valid_emu_mask & valid_mask ;
- *value = PT_MERGE_VALUE(*value, cfg_entry->data, ~valid_emu_mask);
+ if (!ptdev->permissive)
+ throughable_mask &= ~reg->res_mask;
- return 0;
+ return throughable_mask & valid_mask;
}
-
/* write byte size emulate register */
static int pt_byte_reg_write(struct pt_dev *ptdev,
struct pt_reg_tbl *cfg_entry,
@@ -3356,14 +3535,13 @@ static int pt_byte_reg_write(struct pt_d
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
uint8_t writable_mask = 0;
- uint8_t throughable_mask = 0;
+ uint8_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
*value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
return 0;
@@ -3376,14 +3554,13 @@ static int pt_word_reg_write(struct pt_d
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
+ uint16_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
*value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
return 0;
@@ -3396,14 +3573,13 @@ static int pt_long_reg_write(struct pt_d
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
uint32_t writable_mask = 0;
- uint32_t throughable_mask = 0;
+ uint32_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
*value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
return 0;
@@ -3416,7 +3592,7 @@ static int pt_cmd_reg_write(struct pt_de
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
+ uint16_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
uint16_t wr_value = *value;
uint16_t emu_mask = reg->emu_mask;
@@ -3430,8 +3606,6 @@ static int pt_cmd_reg_write(struct pt_de
cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~emu_mask & valid_mask;
-
if (*value & PCI_COMMAND_DISABLE_INTx)
{
if (ptdev->msi_trans_en)
@@ -3477,7 +3651,6 @@ static int pt_bar_reg_write(struct pt_de
PCIDevice *d = (PCIDevice *)&ptdev->dev;
PCIIORegion *r;
uint32_t writable_mask = 0;
- uint32_t throughable_mask = 0;
uint32_t bar_emu_mask = 0;
uint32_t bar_ro_mask = 0;
uint32_t new_addr, last_addr;
@@ -3604,8 +3777,7 @@ static int pt_bar_reg_write(struct pt_de
exit:
/* create value for writing to I/O device register */
- throughable_mask = ~bar_emu_mask & valid_mask;
- *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+ *value = PT_MERGE_VALUE(*value, dev_value, 0);
/* After BAR reg update, we need to remap BAR*/
reg_grp_entry = pt_find_reg_grp(ptdev, PCI_COMMAND);
@@ -3632,9 +3804,8 @@ static int pt_exp_rom_bar_reg_write(stru
PCIDevice *d = (PCIDevice *)&ptdev->dev;
PCIIORegion *r;
uint32_t writable_mask = 0;
- uint32_t throughable_mask = 0;
+ uint32_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
uint32_t r_size = 0;
- uint32_t bar_emu_mask = 0;
uint32_t bar_ro_mask = 0;
r = &d->io_regions[PCI_ROM_SLOT];
@@ -3644,7 +3815,6 @@ static int pt_exp_rom_bar_reg_write(stru
PT_GET_EMUL_SIZE(base->bar_flag, r_size);
/* set emulate mask and read-only mask */
- bar_emu_mask = reg->emu_mask;
bar_ro_mask = (reg->ro_mask | (r_size - 1)) & ~PCI_ROM_ADDRESS_ENABLE;
/* modify emulate register */
@@ -3664,7 +3834,6 @@ static int pt_exp_rom_bar_reg_write(stru
r->addr = cfg_entry->data;
/* create value for writing to I/O device register */
- throughable_mask = ~bar_emu_mask & valid_mask;
*value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
/* After BAR reg update, we need to remap BAR*/
@@ -3688,22 +3857,18 @@ static int pt_pmcsr_reg_write(struct pt_
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
PCIDevice *d = &ptdev->dev;
- uint16_t emu_mask = reg->emu_mask;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
+ uint16_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
struct pt_pm_info *pm_state = ptdev->pm_state;
uint16_t read_val = 0;
- if (!ptdev->power_mgmt)
- emu_mask |= PCI_PM_CTRL_STATE_MASK | PCI_PM_CTRL_NO_SOFT_RESET;
-
/* modify emulate register */
- writable_mask = emu_mask & ~reg->ro_mask & valid_mask;
+ writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~emu_mask & valid_mask;
- *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+ *value = PT_MERGE_VALUE(*value, dev_value & ~PCI_PM_CTRL_PME_STATUS,
+ throughable_mask);
if (!ptdev->power_mgmt)
return 0;
@@ -3810,7 +3975,7 @@ static int pt_msgctrl_reg_write(struct p
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
+ uint16_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
uint16_t old_ctrl = cfg_entry->data;
PCIDevice *pd = (PCIDevice *)ptdev;
uint16_t val;
@@ -3821,6 +3986,11 @@ static int pt_msgctrl_reg_write(struct p
/* modify emulate register */
writable_mask = reg->emu_mask & ~reg->ro_mask & valid_mask;
+ /* also emulate MSI_ENABLE bit for MSI-INTx translation */
+ if (ptdev->msi_trans_en) {
+ writable_mask |= PCI_MSI_FLAGS_ENABLE & valid_mask;
+ throughable_mask &= ~PCI_MSI_FLAGS_ENABLE;
+ }
cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
/* update the msi_info too */
ptdev->msi->flags |= cfg_entry->data &
@@ -3828,7 +3998,6 @@ static int pt_msgctrl_reg_write(struct p
/* create value for writing to I/O device register */
val = *value;
- throughable_mask = ~reg->emu_mask & valid_mask;
*value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
/* update MSI */
@@ -3868,12 +4037,6 @@ static int pt_msgctrl_reg_write(struct p
else
ptdev->msi->flags &= ~PCI_MSI_FLAGS_ENABLE;
- /* pass through MSI_ENABLE bit when no MSI-INTx translation */
- if (!ptdev->msi_trans_en) {
- *value &= ~PCI_MSI_FLAGS_ENABLE;
- *value |= val & PCI_MSI_FLAGS_ENABLE;
- }
-
return 0;
}
@@ -3884,7 +4047,6 @@ static int pt_msgaddr32_reg_write(struct
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
uint32_t writable_mask = 0;
- uint32_t throughable_mask = 0;
uint32_t old_addr = cfg_entry->data;
/* modify emulate register */
@@ -3894,8 +4056,7 @@ static int pt_msgaddr32_reg_write(struct
ptdev->msi->addr_lo = cfg_entry->data;
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
- *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+ *value = PT_MERGE_VALUE(*value, dev_value, 0);
/* update MSI */
if (cfg_entry->data != old_addr)
@@ -3914,7 +4075,6 @@ static int pt_msgaddr64_reg_write(struct
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
uint32_t writable_mask = 0;
- uint32_t throughable_mask = 0;
uint32_t old_addr = cfg_entry->data;
/* check whether the type is 64 bit or not */
@@ -3932,8 +4092,7 @@ static int pt_msgaddr64_reg_write(struct
ptdev->msi->addr_hi = cfg_entry->data;
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
- *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+ *value = PT_MERGE_VALUE(*value, dev_value, 0);
/* update MSI */
if (cfg_entry->data != old_addr)
@@ -3953,7 +4112,6 @@ static int pt_msgdata_reg_write(struct p
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
uint16_t old_data = cfg_entry->data;
uint32_t flags = ptdev->msi->flags;
uint32_t offset = reg->offset;
@@ -3974,8 +4132,7 @@ static int pt_msgdata_reg_write(struct p
ptdev->msi->data = cfg_entry->data;
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
- *value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
+ *value = PT_MERGE_VALUE(*value, dev_value, 0);
/* update MSI */
if (cfg_entry->data != old_data)
@@ -3994,7 +4151,7 @@ static int pt_msixctrl_reg_write(struct
{
struct pt_reg_info_tbl *reg = cfg_entry->reg;
uint16_t writable_mask = 0;
- uint16_t throughable_mask = 0;
+ uint16_t throughable_mask = get_throughable_mask(ptdev, reg, valid_mask);
uint16_t old_ctrl = cfg_entry->data;
/* modify emulate register */
@@ -4002,7 +4159,6 @@ static int pt_msixctrl_reg_write(struct
cfg_entry->data = PT_MERGE_VALUE(*value, cfg_entry->data, writable_mask);
/* create value for writing to I/O device register */
- throughable_mask = ~reg->emu_mask & valid_mask;
*value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
/* update MSI-X */
@@ -4206,7 +4362,7 @@ static struct pt_dev * register_real_dev
struct pci_dev *pci_dev;
uint8_t e_device, e_intx;
char *key, *val;
- int msi_translate, power_mgmt;
+ int msi_translate, power_mgmt, permissive = 0;
PT_LOG("Assigning real physical device %02x:%02x.%x ...\n",
r_bus, r_dev, r_func);
@@ -4250,6 +4406,8 @@ static struct pt_dev * register_real_dev
else
PT_LOG("Error: unrecognized value for msitranslate=\n");
}
+ else if (strcmp(key, "permissive") == 0)
+ permissive = 1;
else if (strcmp(key, "power_mgmt") == 0)
{
if (strcmp(val, "0") == 0)
@@ -4287,6 +4445,7 @@ static struct pt_dev * register_real_dev
assigned_device->msi_trans_cap = msi_translate;
assigned_device->power_mgmt = power_mgmt;
assigned_device->is_virtfn = pt_dev_is_virtfn(pci_dev);
+ assigned_device->permissive = permissive;
pt_iomul_init(assigned_device, r_bus, r_dev, r_func);
/* Initialize virtualized PCI configuration (Extended 256 Bytes) */