Index: usr.sbin/bhyve/pci_emul.h =================================================================== --- usr.sbin/bhyve/pci_emul.h +++ usr.sbin/bhyve/pci_emul.h @@ -159,6 +159,7 @@ struct msix_table_entry *table; /* allocated at runtime */ void *pba_page; int pba_page_offset; + void *table_page; } pi_msix; void *pi_arg; /* devemu-private data */ Index: usr.sbin/bhyve/pci_passthru.c =================================================================== --- usr.sbin/bhyve/pci_passthru.c +++ usr.sbin/bhyve/pci_passthru.c @@ -327,13 +327,14 @@ return (data); } + /* Should make this an assert. */ if (offset < pi->pi_msix.table_offset) return (-1); offset -= pi->pi_msix.table_offset; index = offset / MSIX_TABLE_ENTRY_SIZE; if (index >= pi->pi_msix.table_count) - return (-1); + goto readbar; entry = &pi->pi_msix.table[index]; entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; @@ -360,6 +361,33 @@ } return (data); + +readbar: + if (pi->pi_msix.table_page != NULL && offset < 4096) { + switch(size) { + case 1: + src8 = (uint8_t *)(pi->pi_msix.table_page + offset); + data = *src8; + break; + case 2: + src16 = (uint16_t *)(pi->pi_msix.table_page + offset); + data = *src16; + break; + case 4: + src32 = (uint32_t *)(pi->pi_msix.table_page + offset); + data = *src32; + break; + case 8: + src64 = (uint64_t *)(pi->pi_msix.table_page + offset); + data = *src64; + break; + default: + return (-1); + } + return (data); + } + + return (-1); } static void @@ -406,13 +434,14 @@ return; } + /* Should make this an assert. */ if (offset < pi->pi_msix.table_offset) return; offset -= pi->pi_msix.table_offset; index = offset / MSIX_TABLE_ENTRY_SIZE; if (index >= pi->pi_msix.table_count) - return; + goto writebar; entry = &pi->pi_msix.table[index]; entry_offset = offset % MSIX_TABLE_ENTRY_SIZE; @@ -435,6 +464,31 @@ entry->msg_data, entry->vector_control); } } + +writebar: + if (pi->pi_msix.table_page != NULL && offset < 4096) { + switch(size) { + case 1: + dest8 = (uint8_t *)(pi->pi_msix.table_page + offset); + *dest8 = data; + break; + case 2: + dest16 = (uint16_t *)(pi->pi_msix.table_page + offset); + *dest16 = data; + break; + case 4: + dest32 = (uint32_t *)(pi->pi_msix.table_page + offset); + *dest32 = data; + break; + case 8: + dest64 = (uint64_t *)(pi->pi_msix.table_page + offset); + *dest64 = data; + break; + default: + break; + } + return; + } } static int @@ -470,6 +524,21 @@ start = pi->pi_bar[idx].addr; remaining = pi->pi_bar[idx].size; + /* + * Some device (against better documentation of the spec) + * are mapping other usable address space into the same page + * as the end of the MSI-X tables. + * At least Intel AX200 being one of them apparently. + * Map the page and fall back to it for any reads/writes outside + * the MSI-X table in msix_table_{read,write}. + */ + pi->pi_msix.table_page = mmap(NULL, 4096, PROT_READ | PROT_WRITE, + MAP_SHARED, memfd, sc->psc_bar[idx].addr + table_offset); + if (pi->pi_msix.table_page == MAP_FAILED) { + warn("Failed to map table page for MSI-X on %d/%d/%d", b, s, f); + return (-1); + } + if (pi->pi_msix.pba_bar == pi->pi_msix.table_bar) { pba_offset = pi->pi_msix.pba_offset; pba_size = pi->pi_msix.pba_size;