Joseph Mayer wrote: > Is there some way I can implement PCI drivers in userland in OpenBSD? > > On a quick Internet search, see some discussion for Linux and NetBSD > e.g. [1] however nothing in OpenBSD. > > I may be interested in operating some PCI device manually from my own > program (run as root or user) in OpenBSD, and I can see this being of > interest to others also, asking therefore.
As others have mentioned, poking at PCI configuration space and raw physical memory from userspace is wildly insecure. However, contrary to popular belief, you can in fact poke at devices from userspace on OpenBSD. The primary user of this special ability is the X server, which has a plethora of userspace drivers for graphics cards. (It's almost as dangerous as the inteldrm(4) mess!) While you really really don't want to do this in production, it's handy for experimenting with PCI devices on a development machine. Without further ado, here's how to do it: 1. Use the 'machdep memory' command in the bootloader to carve out a hole in the system's physical memory map. 2. Set the kern.securelevel sysctl to -1. (Told you it's a bad idea.) 3. Set the machdep.allowaperture systel to 2. 4. Become root. 5. Open /dev/pci%d to access PCI bus number %d, and issue PCIOCREAD/ PCIOCWRITE ioctls to access PCI configuration space. See pci(4) for details and the pcidump(8) source for usage examples. 6. Map the device's base address register(s) to somewhere in physical memory space that isn't in use, such as your memory hole. 7. Open /dev/xf86 and mmap() the section of physical address space that you have mapped your device at. As long as the kernel hasn't "claimed" those addresses (i.e. you're mapping the memory hole that you created at boot time) the mmap() will succeed. See xf86(4) for a bit more explanation. Once you've been successful at exploring your shiny new PCI device, and understand how it works, you can write a proper kernel driver for it so that it can actually be used on a normal system and by non-root users. Normal systems run at securelevel=1 (or 2) for good reason, and ideally are also running with machdep.allowaperture=0. (I shall now don my flameproof suit.) Cheers -Andrew