From 7c940207d28d50f56cf5eb6e2c7ea987d5c3a4c8 Mon Sep 17 00:00:00 2001 From: Fei Li Date: Thu, 13 Oct 2022 15:35:55 +0800 Subject: [PATCH] hv: vpci: fix pass-thru pcie device may access MSI-X BAR Now ACRN would traps MSI-X Table Structure access and does MSI-X interrupt remapping for pass-thru PCIe devices. ACRN does this trap by unmmapping the address ranges where the MSI-X Table Structure locates in granularity of 4K pages. So there may have other registers (non-MSI-X structures) in these trapped pages However, the guest may access these registers (non-MSI-X structures) in these trapped pages, which needs to be forwarded to the physical device. This patch forwards the access to real hardware for pass-thru PCIe devices. Tracked-On: #8255 Signed-off-by: Fei Li --- hypervisor/dm/vpci/vmsix.c | 45 +++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/hypervisor/dm/vpci/vmsix.c b/hypervisor/dm/vpci/vmsix.c index 213a33af2..e39c3818a 100644 --- a/hypervisor/dm/vpci/vmsix.c +++ b/hypervisor/dm/vpci/vmsix.c @@ -27,6 +27,7 @@ */ #include +#include #include #include #include @@ -98,32 +99,46 @@ uint32_t rw_vmsix_table(struct pci_vdev *vdev, struct io_request *io_req) struct msix_table_entry *entry; uint32_t entry_offset, table_offset, index = CONFIG_MAX_MSIX_TABLE_NUM; uint64_t offset; + void *hva; - /* Must be full DWORD or full QWORD aligned. */ - if ((mmio->size == 4U) || (mmio->size == 8U)) { + if ((mmio->size <= 8U) && mem_aligned_check(mmio->address, mmio->size)) { offset = mmio->address - vdev->msix.mmio_gpa; if (msixtable_access(vdev, (uint32_t)offset)) { + /* Must be full DWORD or full QWORD aligned. */ + if ((mmio->size == 4U) || (mmio->size == 8U)) { - table_offset = (uint32_t)(offset - vdev->msix.table_offset); - index = table_offset / MSIX_TABLE_ENTRY_SIZE; + table_offset = (uint32_t)(offset - vdev->msix.table_offset); + index = table_offset / MSIX_TABLE_ENTRY_SIZE; - entry = &vdev->msix.table_entries[index]; - entry_offset = table_offset % MSIX_TABLE_ENTRY_SIZE; + entry = &vdev->msix.table_entries[index]; + entry_offset = table_offset % MSIX_TABLE_ENTRY_SIZE; - if (mmio->direction == ACRN_IOREQ_DIR_READ) { - (void)memcpy_s(&mmio->value, (size_t)mmio->size, - (void *)entry + entry_offset, (size_t)mmio->size); + if (mmio->direction == ACRN_IOREQ_DIR_READ) { + (void)memcpy_s(&mmio->value, (size_t)mmio->size, + (void *)entry + entry_offset, (size_t)mmio->size); + } else { + (void)memcpy_s((void *)entry + entry_offset, (size_t)mmio->size, + &mmio->value, (size_t)mmio->size); + } } else { - (void)memcpy_s((void *)entry + entry_offset, (size_t)mmio->size, - &mmio->value, (size_t)mmio->size); + pr_err("%s, Only DWORD and QWORD are permitted", __func__); } } else { - if (mmio->direction == ACRN_IOREQ_DIR_READ) { - mmio->value = 0UL; + if (vdev->pdev != NULL) { + hva = hpa2hva(vdev->msix.mmio_hpa + (mmio->address - vdev->msix.mmio_gpa)); + stac(); + if (mmio->direction == ACRN_IOREQ_DIR_READ) { + mmio->value = mmio_read(hva, mmio->size); + } else { + mmio_write(hva, mmio->size, mmio->value); + } + clac(); + } else { + if (mmio->direction == ACRN_IOREQ_DIR_READ) { + mmio->value = 0UL; + } } } - } else { - pr_err("%s, Only DWORD and QWORD are permitted", __func__); } return index;