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 <fei1.li@intel.com>
This commit is contained in:
Fei Li 2022-10-13 15:35:55 +08:00 committed by acrnsi-robot
parent 8d734dd915
commit 7c940207d2
1 changed files with 30 additions and 15 deletions

View File

@ -27,6 +27,7 @@
*/
#include <asm/guest/vm.h>
#include <asm/io.h>
#include <errno.h>
#include <vpci.h>
#include <asm/guest/ept.h>
@ -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;