Page MenuHomeFreeBSD

bhyve: allow passthrough of sub-page MMIO BARs
Needs ReviewPublic

Authored by wanpengqian_gmail.com on Aug 19 2025, 2:29 PM.
Tags
None
Referenced Files
Unknown Object (File)
Tue, Oct 21, 8:17 PM
Unknown Object (File)
Fri, Oct 17, 4:34 PM
Unknown Object (File)
Wed, Oct 15, 3:46 AM
Unknown Object (File)
Sat, Oct 11, 8:03 AM
Unknown Object (File)
Fri, Oct 10, 8:16 AM
Unknown Object (File)
Fri, Oct 10, 8:16 AM
Unknown Object (File)
Fri, Oct 10, 2:11 AM
Unknown Object (File)
Thu, Oct 9, 9:06 PM

Details

Reviewers
jhb
markj
corvink
Group Reviewers
bhyve
Summary

Historically, bhyve rejected devices whose MMIO BAR size was not
page-aligned, effectively prohibiting passthrough of BARs smaller than
PAGE_SIZE. Some devices legitimately expose sub-page BARs (e.g., <4K),
and they can be safely passed through as long as the mapping is made on
a page boundary and any page sharing is validated.

This change allows passthrough of MMIO BARs smaller than PAGE_SIZE by:

  • mapping the containing page (page-aligned base) while remembering the BAR's offset within that page, and
  • checking whether the hosting page is shared with any other device (and failing with a clear error if a conflict is detected).

I/O BARs (PCIBAR_IO) remain unaffected.

Behavioral changes:

  • Previously: bhyve aborted with "base/size not page aligned" on sub-page MMIO BARs.
  • Now: sub-page MMIO BARs are accepted; if the enclosing page is shared with another device, bhyve refuses passthrough with a descriptive message.
Test Plan
  • Pass a device with an MMIO BAR <4K; guest enumerates the device (lspci -vv) and it functions normally.
  • Verify IO BAR devices still bypass page-alignment checks.
  • Boot and functional tests on stable/14 AMD64 host.

Signed-off-by: Wanpeng Qian <wanpengqian@gmail.com>

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Passed
Unit
No Test Coverage
Build Status
Buildable 66344
Build 63227: arc lint + arc unit

Event Timeline

usr.sbin/bhyve/pci_passthru.c
579–584

I'm pretty sure that there's already a macro for this. Haven't searched for it on my own yet.

678–680

Why do you push every single page? Wouldn't it be sufficient to track the start and end address of each BAR?

698

Why do we have to track it? I expect this to be called once on ppt_init, so no need to skip this on subsequent calls.

I'm not sure but it might be possible to use an RB tree [1] to simplify creating a list, sorting it and searching for elements (RB_NFIND).

[1] https://man.freebsd.org/cgi/man.cgi?query=tree&sektion=3&apropos=0&manpath=FreeBSD+14.3-RELEASE+and+Ports

usr.sbin/bhyve/pci_passthru.c
678–680

Good point, per-page pushing would blow up for large BARs. Our goal here is only to handle sub-4 KiB BAR corner cases. I’ll guard this path with if (length < PAGE_SIZE) (and add a comment), so we don’t expand large BARs page-by-page. If/when we need large BAR coverage, we’ll switch that path to an interval set instead of per-page entries.

698

If we move this into ppt_init, we’d pay the cost unconditionally. The map is only needed when a device has a BAR < 4 KiB, so building it lazily and guarding with g_occ_built avoids doing the work when it isn’t needed. We call build_occ_map() only on the sub-4 KiB path, so subsequent calls are skipped.