|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-4.0-testing] x86/vMSI: miscellaneous fixes
# HG changeset patch
# User Jan Beulich <jbeulich@xxxxxxxx>
# Date 1331204417 0
# Node ID c41ab909f08eef8ecf9cfa975e991a767695aed8
# Parent c62e9965b3950a423b5e5dc2fb9b9495d535dc35
x86/vMSI: miscellaneous fixes
This addresses a number of problems in msixtbl_{read,write}():
- address alignment was not checked, allowing for memory corruption in
the hypervisor (write case) or returning of hypervisor private data
to the guest (read case)
- the interrupt mask bit was permitted to be written by the guest
(while Xen's interrupt flow control routines need to control it)
- MAX_MSIX_TABLE_{ENTRIES,PAGES} were pointlessly defined to plain
numbers (making it unobvious why they have these values, and making
the latter non-portable)
- MAX_MSIX_TABLE_PAGES was also off by one (failing to account for a
non-zero table offset); this was also affecting host MSI-X code
- struct msixtbl_entry's table_flags[] was one element larger than
necessary due to improper open-coding of BITS_TO_LONGS()
- msixtbl_read() unconditionally accessed the physical table, even
though the data was only needed in a quarter of all cases
- various calculations were done unnecessarily for both of the rather
distinct code paths in msixtbl_read()
Additionally it is unclear on what basis MAX_MSIX_ACC_ENTRIES was
chosen to be 3.
Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
Committed-by: Keir Fraser <keir@xxxxxxx>
xen-unstable changeset: 24535:fb81b807c154
xen-unstable date: Mon Jan 23 09:35:17 2012 +0000
---
diff -r c62e9965b395 -r c41ab909f08e xen/arch/x86/hvm/vmsi.c
--- a/xen/arch/x86/hvm/vmsi.c Wed Mar 07 09:09:05 2012 +0000
+++ b/xen/arch/x86/hvm/vmsi.c Thu Mar 08 11:00:17 2012 +0000
@@ -157,7 +157,7 @@
struct pci_dev *pdev;
unsigned long gtable; /* gpa of msix table */
unsigned long table_len;
- unsigned long table_flags[MAX_MSIX_TABLE_ENTRIES / BITS_PER_LONG + 1];
+ unsigned long table_flags[BITS_TO_LONGS(MAX_MSIX_TABLE_ENTRIES)];
struct rcu_head rcu;
};
@@ -179,17 +179,14 @@
static void __iomem *msixtbl_addr_to_virt(
struct msixtbl_entry *entry, unsigned long addr)
{
- int idx, nr_page;
+ unsigned int idx, nr_page;
- if ( !entry )
+ if ( !entry || !entry->pdev )
return NULL;
nr_page = (addr >> PAGE_SHIFT) -
(entry->gtable >> PAGE_SHIFT);
- if ( !entry->pdev )
- return NULL;
-
idx = entry->pdev->msix_table_idx[nr_page];
if ( !idx )
return NULL;
@@ -207,11 +204,11 @@
void *virt;
int r = X86EMUL_UNHANDLEABLE;
+ if ( len != 4 || (address & 3) )
+ return r;
+
rcu_read_lock();
- if ( len != 4 )
- goto out;
-
offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET)
goto out;
@@ -235,14 +232,14 @@
unsigned long offset;
struct msixtbl_entry *entry;
void *virt;
- int nr_entry;
+ unsigned int nr_entry;
int r = X86EMUL_UNHANDLEABLE;
+ if ( len != 4 || (address & 3) )
+ return r;
+
rcu_read_lock();
- if ( len != 4 )
- goto out;
-
entry = msixtbl_find_entry(v, address);
nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE;
@@ -261,9 +258,22 @@
if ( !virt )
goto out;
+ /* Do not allow the mask bit to be changed. */
+#if 0 /* XXX
+ * As the mask bit is the only defined bit in the word, and as the
+ * host MSI-X code doesn't preserve the other bits anyway, doing
+ * this is pointless. So for now just discard the write (also
+ * saving us from having to determine the matching irq_desc).
+ */
+ spin_lock_irqsave(&desc->lock, flags);
+ orig = readl(virt);
+ val &= ~PCI_MSIX_VECTOR_BITMASK;
+ val |= orig & PCI_MSIX_VECTOR_BITMASK;
writel(val, virt);
+ spin_unlock_irqrestore(&desc->lock, flags);
+#endif
+
r = X86EMUL_OKAY;
-
out:
rcu_read_unlock();
return r;
diff -r c62e9965b395 -r c41ab909f08e xen/include/asm-x86/msi.h
--- a/xen/include/asm-x86/msi.h Wed Mar 07 09:09:05 2012 +0000
+++ b/xen/include/asm-x86/msi.h Thu Mar 08 11:00:17 2012 +0000
@@ -127,12 +127,6 @@
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
-#define PCI_MSIX_ENTRY_SIZE 16
-#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0
-#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4
-#define PCI_MSIX_ENTRY_DATA_OFFSET 8
-#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12
-
#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
#define msi_upper_address_reg(base) (base + PCI_MSI_ADDRESS_HI)
diff -r c62e9965b395 -r c41ab909f08e xen/include/xen/pci.h
--- a/xen/include/xen/pci.h Wed Mar 07 09:09:05 2012 +0000
+++ b/xen/include/xen/pci.h Thu Mar 08 11:00:17 2012 +0000
@@ -11,6 +11,8 @@
#include <xen/types.h>
#include <xen/list.h>
#include <xen/spinlock.h>
+#include <xen/pci_regs.h>
+#include <asm/page.h>
/*
* The PCI interface treats multi-function devices as independent
@@ -29,8 +31,10 @@
#define PCI_BDF(b,d,f) ((((b) & 0xff) << 8) | PCI_DEVFN(d,f))
#define PCI_BDF2(b,df) ((((b) & 0xff) << 8) | ((df) & 0xff))
-#define MAX_MSIX_TABLE_ENTRIES 2048
-#define MAX_MSIX_TABLE_PAGES 8
+#define MAX_MSIX_TABLE_ENTRIES (PCI_MSIX_FLAGS_QSIZE + 1)
+#define MAX_MSIX_TABLE_PAGES PFN_UP(MAX_MSIX_TABLE_ENTRIES * \
+ PCI_MSIX_ENTRY_SIZE + \
+ (~PCI_MSIX_FLAGS_BIRMASK & (PAGE_SIZE -
1)))
struct pci_dev_info {
unsigned is_extfn;
unsigned is_virtfn;
diff -r c62e9965b395 -r c41ab909f08e xen/include/xen/pci_regs.h
--- a/xen/include/xen/pci_regs.h Wed Mar 07 09:09:05 2012 +0000
+++ b/xen/include/xen/pci_regs.h Thu Mar 08 11:00:17 2012 +0000
@@ -302,6 +302,13 @@
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
#define PCI_MSIX_FLAGS_MASKALL (1 << 14)
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
+
+#define PCI_MSIX_ENTRY_SIZE 16
+#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0
+#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4
+#define PCI_MSIX_ENTRY_DATA_OFFSET 8
+#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12
+
#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
/* CompactPCI Hotswap Register */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |