Index: usr.sbin/bhyve/pci_emul.c =================================================================== --- usr.sbin/bhyve/pci_emul.c +++ usr.sbin/bhyve/pci_emul.c @@ -590,23 +590,47 @@ return (cmd & PCIM_CMD_MEMEN); } +/* Is the registration actually just all 'f's? */ +static bool +addr_is_probe(uint64_t addr, uint64_t size, int type) +{ + switch (type) { + case PCIBAR_IO: + return (addr + size - 1 == 0xffffUL); + case PCIBAR_MEM32: + case PCIBAR_MEM64: + return ((addr & 0xffffffffUL) + size - 1 == 0xffffffffUL); + case PCIBAR_MEMHI64: + return ((addr >> 32) + size - 1 == 0xffffffffUL); + default: + assert(0); + } +} + /* * Update the MMIO or I/O address that is decoded by the BAR register. * * If the pci device has enabled the address space decoding then intercept * the address range decoded by the BAR register. + * + * However, do not intercept the address if we are writing all '1's to the + * BAR register, since that is an attempt to probe the capabilities of + * the device. */ static void update_bar_address(struct pci_devinst *pi, uint64_t addr, int idx, int type) { int decode; + uint64_t size; + + size = pi->pi_bar[idx].size; if (pi->pi_bar[idx].type == PCIBAR_IO) decode = porten(pi); else decode = memen(pi); - if (decode) + if (decode && !addr_is_probe(pi->pi_bar[idx].addr, size, type)) unregister_bar(pi, idx); switch (type) { @@ -619,14 +643,14 @@ pi->pi_bar[idx].addr |= addr; break; case PCIBAR_MEMHI64: - pi->pi_bar[idx].addr &= 0xffffffff; + pi->pi_bar[idx].addr &= 0xffffffffUL; pi->pi_bar[idx].addr |= addr; break; default: assert(0); } - if (decode) + if (decode && !addr_is_probe(pi->pi_bar[idx].addr, size, type)) register_bar(pi, idx); }