136 lines
5.1 KiB
Diff
136 lines
5.1 KiB
Diff
|
From 5c83b2f5b4b956e91dd6e5711f14df7ab800aefb Mon Sep 17 00:00:00 2001
|
||
|
From: Jan Beulich <jbeulich@suse.com>
|
||
|
Date: Tue, 2 Jun 2015 15:07:00 +0000
|
||
|
Subject: [PATCH] xen: properly gate host writes of modified PCI CFG contents
|
||
|
|
||
|
The old logic didn't work as intended when an access spanned multiple
|
||
|
fields (for example a 32-bit access to the location of the MSI Message
|
||
|
Data field with the high 16 bits not being covered by any known field).
|
||
|
Remove it and derive which fields not to write to from the accessed
|
||
|
fields' emulation masks: When they're all ones, there's no point in
|
||
|
doing any host write.
|
||
|
|
||
|
This fixes a secondary issue at once: We obviously shouldn't make any
|
||
|
host write attempt when already the host read failed.
|
||
|
|
||
|
This is XSA-128.
|
||
|
|
||
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||
|
Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
|
||
|
---
|
||
|
hw/xen/xen_pt.c | 25 +++++++++++++++++++++----
|
||
|
hw/xen/xen_pt.h | 2 --
|
||
|
hw/xen/xen_pt_config_init.c | 4 ----
|
||
|
3 files changed, 21 insertions(+), 10 deletions(-)
|
||
|
|
||
|
diff --git a/hw/xen/xen_pt.c b/hw/xen/xen_pt.c
|
||
|
index d095c08..8923582 100644
|
||
|
--- a/hw/xen/xen_pt.c
|
||
|
+++ b/hw/xen/xen_pt.c
|
||
|
@@ -234,7 +234,7 @@ 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;
|
||
|
@@ -271,6 +271,9 @@ 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 */
|
||
|
@@ -298,6 +301,11 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
|
||
|
|
||
|
valid_mask <<= (find_addr - real_offset) << 3;
|
||
|
ptr_val = (uint8_t *)&val + (real_offset & 3);
|
||
|
+ if (reg->emu_mask == (0xFFFFFFFF >> ((4 - reg->size) << 3))) {
|
||
|
+ wb_mask &= ~((reg->emu_mask
|
||
|
+ >> ((find_addr - real_offset) << 3))
|
||
|
+ << ((len - emul_len) << 3));
|
||
|
+ }
|
||
|
|
||
|
/* do emulation based on register size */
|
||
|
switch (reg->size) {
|
||
|
@@ -350,10 +358,19 @@ static void xen_pt_pci_write_config(PCIDevice *d, uint32_t addr,
|
||
|
memory_region_transaction_commit();
|
||
|
|
||
|
out:
|
||
|
- if (!(reg && reg->no_wb)) {
|
||
|
+ 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);
|
||
|
diff --git a/hw/xen/xen_pt.h b/hw/xen/xen_pt.h
|
||
|
index 942dc60..52ceb85 100644
|
||
|
--- a/hw/xen/xen_pt.h
|
||
|
+++ b/hw/xen/xen_pt.h
|
||
|
@@ -105,8 +105,6 @@ struct XenPTRegInfo {
|
||
|
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 */
|
||
|
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
|
||
|
index 95a51db..dae0519 100644
|
||
|
--- a/hw/xen/xen_pt_config_init.c
|
||
|
+++ b/hw/xen/xen_pt_config_init.c
|
||
|
@@ -1279,7 +1279,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||
|
.init_val = 0x00000000,
|
||
|
.ro_mask = 0x00000003,
|
||
|
.emu_mask = 0xFFFFFFFF,
|
||
|
- .no_wb = 1,
|
||
|
.init = xen_pt_common_reg_init,
|
||
|
.u.dw.read = xen_pt_long_reg_read,
|
||
|
.u.dw.write = xen_pt_msgaddr32_reg_write,
|
||
|
@@ -1291,7 +1290,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||
|
.init_val = 0x00000000,
|
||
|
.ro_mask = 0x00000000,
|
||
|
.emu_mask = 0xFFFFFFFF,
|
||
|
- .no_wb = 1,
|
||
|
.init = xen_pt_msgaddr64_reg_init,
|
||
|
.u.dw.read = xen_pt_long_reg_read,
|
||
|
.u.dw.write = xen_pt_msgaddr64_reg_write,
|
||
|
@@ -1303,7 +1301,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||
|
.init_val = 0x0000,
|
||
|
.ro_mask = 0x0000,
|
||
|
.emu_mask = 0xFFFF,
|
||
|
- .no_wb = 1,
|
||
|
.init = xen_pt_msgdata_reg_init,
|
||
|
.u.w.read = xen_pt_word_reg_read,
|
||
|
.u.w.write = xen_pt_msgdata_reg_write,
|
||
|
@@ -1315,7 +1312,6 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||
|
.init_val = 0x0000,
|
||
|
.ro_mask = 0x0000,
|
||
|
.emu_mask = 0xFFFF,
|
||
|
- .no_wb = 1,
|
||
|
.init = xen_pt_msgdata_reg_init,
|
||
|
.u.w.read = xen_pt_word_reg_read,
|
||
|
.u.w.write = xen_pt_msgdata_reg_write,
|
||
|
--
|
||
|
2.2.1
|
||
|
|