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>

--- a/hw/pass-through.c
+++ b/hw/pass-through.c
@@ -3442,6 +3442,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,
@@ -3449,14 +3458,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;
@@ -3469,14 +3477,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;
@@ -3489,14 +3496,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;
@@ -3509,7 +3515,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 */
@@ -3517,8 +3523,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)
@@ -3564,7 +3568,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;
@@ -3691,8 +3694,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);
@@ -3719,9 +3721,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];
@@ -3731,7 +3732,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 */
@@ -3751,7 +3751,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*/
@@ -3776,7 +3775,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;
 
@@ -3785,7 +3784,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);
 
@@ -3894,7 +3892,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;
@@ -3906,8 +3904,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 &
@@ -3915,10 +3915,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 */
@@ -3972,7 +3968,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 */
@@ -3982,8 +3977,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)
@@ -4002,7 +3996,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 */
@@ -4020,8 +4013,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)
@@ -4041,7 +4033,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;
@@ -4062,8 +4053,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)
@@ -4082,7 +4072,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 */
@@ -4090,7 +4080,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 */
