File xsa131-qemut-4.patch of Package xen.950
xen/pt: split out calculation of throughable mask in PCI config space handling
This is just to avoid having to adjust that calculation later in
multiple places.
Note that including ->ro_mask in get_throughable_mask()'s calculation
is only an apparent (i.e. benign) behavioral change: For r/o fields it
doesn't matter > whether they get passed through - either the same flag
is also set in emu_mask (then there's no change at all) or the field is
r/o in hardware (and hence a write won't change it anyway).
This is a preparatory patch for XSA-131.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
Index: xen-4.4.2-testing/tools/qemu-xen-traditional-dir-remote/hw/pass-through.c
===================================================================
--- xen-4.4.2-testing.orig/tools/qemu-xen-traditional-dir-remote/hw/pass-through.c
+++ xen-4.4.2-testing/tools/qemu-xen-traditional-dir-remote/hw/pass-through.c
@@ -3440,6 +3440,15 @@ static int pt_bar_reg_read(struct pt_dev
}
+static uint32_t get_throughable_mask(const struct pt_dev *ptdev,
+ const struct pt_reg_info_tbl *reg,
+ uint32_t valid_mask)
+{
+ uint32_t throughable_mask = ~(reg->emu_mask | reg->ro_mask);
+
+ 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,
@@ -3447,14 +3456,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;
@@ -3467,14 +3475,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;
@@ -3487,14 +3494,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;
@@ -3507,7 +3513,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;
/* modify emulate register */
@@ -3515,8 +3521,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 = ~reg->emu_mask & valid_mask;
-
if (*value & PCI_COMMAND_DISABLE_INTx)
{
if (ptdev->msi_trans_en)
@@ -3562,7 +3566,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;
@@ -3689,8 +3692,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);
@@ -3717,9 +3719,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];
@@ -3729,7 +3730,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 */
@@ -3749,7 +3749,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*/
@@ -3774,7 +3773,7 @@ static int pt_pmcsr_reg_write(struct pt_
struct pt_reg_info_tbl *reg = cfg_entry->reg;
PCIDevice *d = &ptdev->dev;
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;
@@ -3783,7 +3782,6 @@ static int pt_pmcsr_reg_write(struct pt_
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 & ~PCI_PM_CTRL_PME_STATUS,
throughable_mask);
@@ -3892,7 +3890,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;
@@ -3904,8 +3902,10 @@ 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)
+ 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 &
@@ -3913,10 +3913,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;
- /* don't pass through MSI_ENABLE bit for MSI-INTx translation */
- if (ptdev->msi_trans_en)
- throughable_mask &= ~PCI_MSI_FLAGS_ENABLE;
*value = PT_MERGE_VALUE(*value, dev_value, throughable_mask);
/* update MSI */
@@ -3970,7 +3966,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 */
@@ -3980,8 +3975,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)
@@ -4000,7 +3994,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 */
@@ -4018,8 +4011,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)
@@ -4039,7 +4031,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;
@@ -4060,8 +4051,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)
@@ -4080,7 +4070,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 */
@@ -4088,7 +4078,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 */