top | item 46689065

Linux kernel framework for PCIe device emulation, in userspace

239 points| 71bw | 1 month ago |github.com

83 comments

order

tiernano|1 month ago

Hmmm.... Wondering if this could be eventually used to emulate a PCIe card using another device, like a RaspberryPi or something more powerful... Thinking the idea of a card you could stick in a machine, anything from a 1x to 16x slot, that emulates a network card (you could run VPN or other stuff on the card and offload it from the host) or storage (running something with enough power to run ZFS and a few disks, and show to the host as a single disk, allowing ZFS on devices that would not support it). but this is probably not something easy...

cakehonolulu|1 month ago

Hi! Author here! You can technically offload the transactions the real driver on your host does to wherever you want really. PCI is very delay-tolerant and it usually negotiates with the device so I see not much of an issue doing that proven that you can efficiently and performantly manage the throughput throughout the architecture. The thing that kinda makes PCIem special is that you are pretty much free to do whatever you want with the accesses the driver does, you have total freedom. I have made a simple NVME controller (With a 1GB drive I basically malloc'd) which pops up on the local PCI bus (And the regular Linux's nvme block driver attaches to it just fine). You can format it, mount it, create files, folders... it's kinda neat. I also have a simple dumb rasteriser that I made inside QEMU that I wanted to write a driver for, but since it doesn't exist, I used PCIem to help me redirect the driver writes to the QEMU instance hosting the card (Thus was able to run software-rendered DOOM, OpenGL 1.X-based Quake and Half-Life ports).

MisterTea|1 month ago

This kind of stuff is stupid easy on an OS like Plan 9 where you speak a single protocol: 9P. Ethernet devices are abstracted and served by the kernel as a file system explained in ether(3). Since it's all 9P the system doesn't care where the server is running; could be a local in-kernel/user-space server or remote server over ANY 2-way link including TCP, IL, PCIe link, RS232 port, SPI, USB, etc. This means you can mount individual pieces of hardware or networking stacks like ip(3), any 9P server, from other machines to a processes local namespace. Per-process name spaces let you customize the processes view of the file system and hence all its children allowing you to customize each and every programs resource view.

There is interest in getting 9front running on the Octeon chips. This would allow one to run anything they want on an Octeon card (Plan 9 cross platform is first class) so one could boot the card using the hosts root file system, write and test a program on the host, change the objtype env variable to mips/arm, build the binary for the Octeon and then run it on the Octeon using rcpu (like running a command remotely via ssh.) All you need is a working kernel on the Octeon and a host kernel driver and the rest is out of the box.

xerxes901|1 month ago

Something like the stm32mp2 series of MCUs can run Linux and act as a PCIe endpoint you can control from a kernel module on the MCU. So you can program an arbitrary PCIe device that way (although it won’t be setting any speed records, and I think the PHY might be limited to PCIe 1x)

hsbauauvhabzb|1 month ago

… or pcie over ethernet ;)

asdefghyk|1 month ago

Could add one or more (reprograble?) FPGA's for extra? processing power OR reconfiguration ease to such a card ......

I've often wondered why such a card (with FPGA) is not available for retro? computer emulation or simulation ??

wmf|1 month ago

This is what DPUs are for.

hhh|1 month ago

this is what dma cards do

immibis|1 month ago

I recently bought a DMA cheating card because it's secretly just an FPGA PCIe card. Haven't tried to play around with it yet.

Seems unlikely you'd emulate a real PCIe card in software because PCIe is pretty high-speed.

krupan|1 month ago

So just to be clear, you have to boot up the physical machine with a kernel command-line argument to reserve some RAM for this to work? And the amount of RAM you reserve is for BAR memory? If you wanted multiple PCIem devices (can you do that?) you'd need to reserve RAM for each of them?

cakehonolulu|1 month ago

Hi! That's correct. We need a way to have a chunk of what Linux calls "Reserved" memory for the virtual BAR trick. Currently, PCIem only thinks about a single device (Since I first needed to have something that worked in order to check how feasible this all was), but there's planned support for multiple devices that can share a "Reserved" memory pool dynamically so you can have multiple BARs for multiple devices.

Surac|1 month ago

that is a huge win if you are developing drivers or even real hardware. it allows to iterate on protokols just with the press of a button

cakehonolulu|1 month ago

Indeed, the project has gone through a few iterations already (It was first a monolithic kernel module that required a secondary module to call into the API and whatnot). I've went towards a more userspace-friendly usage mainly so that you can iterate your changes much, much faster. Creating the synthetic PCI device is as easy as opening the userspace shim you program, it'll then appear on your bus. When you want to test new changes, you close the shim normally (Effectively removing it from the bus) and you can do this process as many times as needed.

asimovDev|1 month ago

Could you explain in layman terms how it would help with developing PCIE hardware / drivers? I can immediately imagine something like writing more robust unit tests and maybe developing barebones drivers before you get access to actual hardware, but that's where my imagination runs out of fuel.

iamoutoftouch|1 month ago

How is that better than emulating the device in QEMU or with something like libvfio-user (which also works on top of QEMU)?

cakehonolulu|1 month ago

I feel like libfvio-user is a cool project and works perfectly fine, that is, if you want to have the device on the host's userspace but exposed to a VM (QEMU, in this case).

PCIem kinda does that, but it's down a level; in terms of, it basically pops the device on your host PCI bus, which lets real, unmodified drivers to interact with the userspace implementation of your card, no QEMU, no VM, no hypervisors.

Not saying that you can then, for instance, forward all the accesses to QEMU (Some people/orgs already have their cards defined in QEMU so it'd be a bit pointless to redefine the same stuff over and over, right?) so they're free to basically glue their QEMU stuff to PCIem in case they want to try the driver directly on the host but maintaining the functional emulation on QEMU. PCIem takes care of abstracting the accesses and whatnot with an API that tries to mimick that the cool people over at KVM do.

throwaway132448|1 month ago

Tangential question: PCIe is a pretty future-proof technology to learn/invest in, right? As in, it is very unlikely to become obsolete in the next 5-10 years (like USB)?

pjc50|1 month ago

Neither of those is going to be obsolete in 5 years. Might get rebadged and a bunch of extensions, but there's such a huge install base that rapid change is unlikely. Neither Firewire nor Thunderbolt unseated USB.

CupricTea|1 month ago

PCIe is probably the most future proof technology we have right now. Even if it is upheaveled at the hardware level, from the software perspective it just exposes a device's arbitrary registers to some memory mapped location. Software drivers for PCIe devices will continue to work the same.

neocron|1 month ago

Might as well be replaced by optical connectors next years, but who knows in advance. Currently there is no competition

checker659|1 month ago

Curious what you mean by learning? Learning about TLPs? Learning about FPGA DMA Engines like XDMA? Learning about PCIe switches / retimers? Learning about `lspci`?

GrowingSideways|1 month ago

PCIe expertise will certainly outlive anyone on this forum.

agent013|1 month ago

I've been burned before by driver bugs that only manifested under very specific timing conditions or malformed responses from the device, tnx

cakehonolulu|1 month ago

Anytime, hopefully it fits your needs and helps you not spend more time than needed tracing issues like this. Thanks for the comment!

_lunix|1 month ago

very interesting work! I've been exploring a different idea on the side, using SPDK+libvfio-user [0] to emulate PCIe devices inside QEMU, which doesn't require a kernel module but it's a bit less flexible than this approach.

[0] https://movementarian.org/blog/posts/2025-08-27-vfio-user-cl...

cakehonolulu|1 month ago

Highly interesting! I kinda wanted not to rely on QEMU as a default "end" for the emulation (As in, I want the end user to be able to choose whatever userspace shim/transport layer/thing they want), but for some of my tests I did forward accesses to QEMU itself (And worked wonders). Thanks for that link! Super cool stuff!

JoshTriplett|1 month ago

Any plans to upstream the kernel-side support?

cakehonolulu|1 month ago

I'd love to! Sure sounds like the natural next step for this.

petabyt|1 month ago

vhci-hcd for USB has been so useful for usb development. Especially for testing usb driver code in CI.

brcmthrowaway|1 month ago

How would I do this under macOS?

cakehonolulu|1 month ago

Unfortunately not with PCIem... I don't know how the XNU kernel does PCIe stuff; maybe something can be done there with a Kext module but no idea.