190 lines
6.9 KiB
Diff
190 lines
6.9 KiB
Diff
|
From 7611dae8a69f0f1775ba1a9a942961c2aa10d88e 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: don't allow guest to control MSI mask register
|
||
|
|
||
|
It's being used by the hypervisor. For now simply mimic a device not
|
||
|
capable of masking, and fully emulate any accesses a guest may issue
|
||
|
nevertheless as simple reads/writes without side effects.
|
||
|
|
||
|
This is XSA-129.
|
||
|
|
||
|
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
||
|
Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
|
||
|
---
|
||
|
hw/pci/msi.c | 4 --
|
||
|
hw/xen/xen_pt_config_init.c | 98 ++++++++++++++++++++++++++++++++++++++++-----
|
||
|
include/hw/pci/pci_regs.h | 2 +
|
||
|
3 files changed, 90 insertions(+), 14 deletions(-)
|
||
|
|
||
|
diff --git a/hw/pci/msi.c b/hw/pci/msi.c
|
||
|
index c111dba..f9c0484 100644
|
||
|
--- a/hw/pci/msi.c
|
||
|
+++ b/hw/pci/msi.c
|
||
|
@@ -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)
|
||
|
|
||
|
diff --git a/hw/xen/xen_pt_config_init.c b/hw/xen/xen_pt_config_init.c
|
||
|
index dae0519..68b8f22 100644
|
||
|
--- a/hw/xen/xen_pt_config_init.c
|
||
|
+++ b/hw/xen/xen_pt_config_init.c
|
||
|
@@ -1016,13 +1016,9 @@ static XenPTRegInfo xen_pt_emu_reg_pm[] = {
|
||
|
*/
|
||
|
|
||
|
/* Helper */
|
||
|
-static bool xen_pt_msgdata_check_type(uint32_t offset, uint16_t flags)
|
||
|
-{
|
||
|
- /* check the offset whether matches the type or not */
|
||
|
- bool is_32 = (offset == PCI_MSI_DATA_32) && !(flags & PCI_MSI_FLAGS_64BIT);
|
||
|
- bool is_64 = (offset == PCI_MSI_DATA_64) && (flags & PCI_MSI_FLAGS_64BIT);
|
||
|
- return is_32 || is_64;
|
||
|
-}
|
||
|
+#define xen_pt_msi_check_type(offset, flags, what) \
|
||
|
+ ((offset) == ((flags) & PCI_MSI_FLAGS_64BIT ? \
|
||
|
+ PCI_MSI_##what##_64 : PCI_MSI_##what##_32))
|
||
|
|
||
|
/* Message Control register */
|
||
|
static int xen_pt_msgctrl_reg_init(XenPCIPassthroughState *s,
|
||
|
@@ -1134,7 +1130,45 @@ static int xen_pt_msgdata_reg_init(XenPCIPassthroughState *s,
|
||
|
uint32_t offset = reg->offset;
|
||
|
|
||
|
/* check the offset whether matches the type or not */
|
||
|
- if (xen_pt_msgdata_check_type(offset, flags)) {
|
||
|
+ if (xen_pt_msi_check_type(offset, flags, DATA)) {
|
||
|
+ *data = reg->init_val;
|
||
|
+ } else {
|
||
|
+ *data = XEN_PT_INVALID_REG;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/* this function will be called twice (for 32 bit and 64 bit type) */
|
||
|
+/* initialize Mask register */
|
||
|
+static int xen_pt_mask_reg_init(XenPCIPassthroughState *s,
|
||
|
+ XenPTRegInfo *reg, uint32_t real_offset,
|
||
|
+ uint32_t *data)
|
||
|
+{
|
||
|
+ uint32_t flags = s->msi->flags;
|
||
|
+
|
||
|
+ /* check the offset whether matches the type or not */
|
||
|
+ if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
|
||
|
+ *data = XEN_PT_INVALID_REG;
|
||
|
+ } else if (xen_pt_msi_check_type(reg->offset, flags, MASK)) {
|
||
|
+ *data = reg->init_val;
|
||
|
+ } else {
|
||
|
+ *data = XEN_PT_INVALID_REG;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+/* this function will be called twice (for 32 bit and 64 bit type) */
|
||
|
+/* initialize Pending register */
|
||
|
+static int xen_pt_pending_reg_init(XenPCIPassthroughState *s,
|
||
|
+ XenPTRegInfo *reg, uint32_t real_offset,
|
||
|
+ uint32_t *data)
|
||
|
+{
|
||
|
+ uint32_t flags = s->msi->flags;
|
||
|
+
|
||
|
+ /* check the offset whether matches the type or not */
|
||
|
+ if (!(flags & PCI_MSI_FLAGS_MASKBIT)) {
|
||
|
+ *data = XEN_PT_INVALID_REG;
|
||
|
+ } else if (xen_pt_msi_check_type(reg->offset, flags, PENDING)) {
|
||
|
*data = reg->init_val;
|
||
|
} else {
|
||
|
*data = XEN_PT_INVALID_REG;
|
||
|
@@ -1222,7 +1256,7 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s,
|
||
|
uint32_t offset = reg->offset;
|
||
|
|
||
|
/* check the offset whether matches the type or not */
|
||
|
- if (!xen_pt_msgdata_check_type(offset, msi->flags)) {
|
||
|
+ if (!xen_pt_msi_check_type(offset, msi->flags, DATA)) {
|
||
|
/* exit I/O emulator */
|
||
|
XEN_PT_ERR(&s->dev, "the offset does not match the 32/64 bit type!\n");
|
||
|
return -1;
|
||
|
@@ -1267,7 +1301,7 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||
|
.size = 2,
|
||
|
.init_val = 0x0000,
|
||
|
.ro_mask = 0xFF8E,
|
||
|
- .emu_mask = 0x007F,
|
||
|
+ .emu_mask = 0x017F,
|
||
|
.init = xen_pt_msgctrl_reg_init,
|
||
|
.u.w.read = xen_pt_word_reg_read,
|
||
|
.u.w.write = xen_pt_msgctrl_reg_write,
|
||
|
@@ -1316,6 +1350,50 @@ static XenPTRegInfo xen_pt_emu_reg_msi[] = {
|
||
|
.u.w.read = xen_pt_word_reg_read,
|
||
|
.u.w.write = xen_pt_msgdata_reg_write,
|
||
|
},
|
||
|
+ /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
|
||
|
+ {
|
||
|
+ .offset = PCI_MSI_MASK_32,
|
||
|
+ .size = 4,
|
||
|
+ .init_val = 0x00000000,
|
||
|
+ .ro_mask = 0xFFFFFFFF,
|
||
|
+ .emu_mask = 0xFFFFFFFF,
|
||
|
+ .init = xen_pt_mask_reg_init,
|
||
|
+ .u.dw.read = xen_pt_long_reg_read,
|
||
|
+ .u.dw.write = xen_pt_long_reg_write,
|
||
|
+ },
|
||
|
+ /* Mask reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
|
||
|
+ {
|
||
|
+ .offset = PCI_MSI_MASK_64,
|
||
|
+ .size = 4,
|
||
|
+ .init_val = 0x00000000,
|
||
|
+ .ro_mask = 0xFFFFFFFF,
|
||
|
+ .emu_mask = 0xFFFFFFFF,
|
||
|
+ .init = xen_pt_mask_reg_init,
|
||
|
+ .u.dw.read = xen_pt_long_reg_read,
|
||
|
+ .u.dw.write = xen_pt_long_reg_write,
|
||
|
+ },
|
||
|
+ /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 32-bit devices) */
|
||
|
+ {
|
||
|
+ .offset = PCI_MSI_MASK_32 + 4,
|
||
|
+ .size = 4,
|
||
|
+ .init_val = 0x00000000,
|
||
|
+ .ro_mask = 0xFFFFFFFF,
|
||
|
+ .emu_mask = 0x00000000,
|
||
|
+ .init = xen_pt_pending_reg_init,
|
||
|
+ .u.dw.read = xen_pt_long_reg_read,
|
||
|
+ .u.dw.write = xen_pt_long_reg_write,
|
||
|
+ },
|
||
|
+ /* Pending reg (if PCI_MSI_FLAGS_MASKBIT set, for 64-bit devices) */
|
||
|
+ {
|
||
|
+ .offset = PCI_MSI_MASK_64 + 4,
|
||
|
+ .size = 4,
|
||
|
+ .init_val = 0x00000000,
|
||
|
+ .ro_mask = 0xFFFFFFFF,
|
||
|
+ .emu_mask = 0x00000000,
|
||
|
+ .init = xen_pt_pending_reg_init,
|
||
|
+ .u.dw.read = xen_pt_long_reg_read,
|
||
|
+ .u.dw.write = xen_pt_long_reg_write,
|
||
|
+ },
|
||
|
{
|
||
|
.size = 0,
|
||
|
},
|
||
|
diff --git a/include/hw/pci/pci_regs.h b/include/hw/pci/pci_regs.h
|
||
|
index 56a404b..57e8c80 100644
|
||
|
--- a/include/hw/pci/pci_regs.h
|
||
|
+++ b/include/hw/pci/pci_regs.h
|
||
|
@@ -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
|
||
|
--
|
||
|
2.2.1
|
||
|
|