VMSI: This patch
simulates the MSIx table read operation
Signed-off-by:
Liu Yuan <yuan.b.liu@xxxxxxxxx>
Signed-off-by:
Eddie Dong <eddie.dong@xxxxxxxxx>
diff -r
114f860872fb xen/arch/x86/hvm/vmsi.c
---
a/xen/arch/x86/hvm/vmsi.c
+++
b/xen/arch/x86/hvm/vmsi.c
@@ -158,7 +158,10
@@ struct msixtbl_entry
unsigned long gtable; /* gpa of msix table
*/
unsigned long table_len;
unsigned long table_flags[MAX_MSIX_TABLE_ENTRIES / BITS_PER_LONG + 1];
-
+#define
MAX_MSIX_ACC_ENTRIES 3
+
struct {
+
uint32_t msi_ad[3]; /* Shadow of address low, high and data
*/
+
} gentries[MAX_MSIX_ACC_ENTRIES];
struct rcu_head rcu;
};
@@ -205,6 +208,7
@@ static int msixtbl_read(
unsigned long offset;
struct msixtbl_entry *entry;
void *virt;
+
int nr_entry, index;
int r = X86EMUL_UNHANDLEABLE;
rcu_read_lock();
@@ -212,14
+216,22 @@ static int msixtbl_read(
if ( len != 4 )
goto out;
-
offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
-
if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET)
-
goto out;
-
-
entry = msixtbl_find_entry(v, address);
virt = msixtbl_addr_to_virt(entry, address);
if ( !virt )
goto out;
+
+
offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
+
entry = msixtbl_find_entry(v, address);
+
if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET){
+
nr_entry = (address - entry->gtable) / PCI_MSIX_ENTRY_SIZE;
+
index = offset / sizeof(uint32_t);
+
if (nr_entry < MAX_MSIX_ACC_ENTRIES) {
+
*pval = entry->gentries[nr_entry].msi_ad[index];
+
readl(virt); /* Linux kernel needs this to flush the write */
+
r = X86EMUL_OKAY;
+
}
+
goto out;
+
}
*pval = readl(virt);
r = X86EMUL_OKAY;
@@ -235,7 +247,7
@@ static int msixtbl_write(struct vcpu *v,
unsigned long offset;
struct msixtbl_entry *entry;
void *virt;
-
int nr_entry;
+
int nr_entry, index;
int r = X86EMUL_UNHANDLEABLE;
rcu_read_lock();
@@ -249,6 +261,10
@@ static int msixtbl_write(struct vcpu *v,
offset = address & (PCI_MSIX_ENTRY_SIZE - 1);
if ( offset != PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET)
{
+
if (nr_entry < MAX_MSIX_ACC_ENTRIES) {
+
index = offset / sizeof(uint32_t);
+
entry->gentries[nr_entry].msi_ad[index] = val;
+
}
set_bit(nr_entry, &entry->table_flags);
goto out;
}