The Device Driver Environment (DDE) is a wrapper library that maps the interface expected by in-kernel Linux device drivers to the device driver interface provided by a certain host system. This approach allows generic reuse of Linux device drivers in another operating system and was originally developed for reusing Linux drivers in the context of L4-based microkernels.
On this page you find our implementation of a DDE that allows running Linux kernel drivers in Linux user space without requiring any modifications to the driver source code itself. Below you will find a download tarball as well as instructions on compiling the source code and running an example device driver.
To compile and link DDEKit-Linux and the E1000E example application, a few libraries are required. These prerequisites are listed here, with a description why they are required. These libraries may be installed using the packet management of your Linux distribution.
Unzip the tarball after downloading
$> tar xjf ddekit-linux.tar.bz2
Build DDEKit/Linux
$> cd ddekit-linux/ddekit-linux
$> make
Build DDE/Linux2.6
$> cd ../dde-linux2.6
$> mkdir build
$> make O=build config
[accept defaults and exit]
$> make O=build
Build the E1000E example driver
$> cd ../e1000e_example
[edit Makefile; modify DDE_BUILD variable to point to
the build dir created for DDE/Linux2.6]
$> make
To run the example NIC driver, you need a suitable NIC in the first place. We tested the driver with an Intel 82573E Gigabit Ethernet Controller. In general, any other device supported by the e1000e driver should work. It is important to note, that the device comply with the PCI specification, version 2.3, which means it needs to possess an Interrupt Disable Bit in the PCI command register and an Interrupt Status Bit in the PCI status register. If you are unsure, consult your NIC's datasheet.
In the case of the 82753E, the desired information is listed in what Intel calls the PCIe* GbE Controllers Open Source Software Developer's Manual", which can be downloaded from their website. The PCI interface is described in Chapter 4, Section 7 ("Physical Layer"). The Interrupt Disable and Status Bits in PCI config space are described on pages 101 and 102 respectively.
After compiling all components as described above, you'll need to load the UIO kernel modules. Please use the modules supplied with DDEKit/Linux, because they incorporate a couple of changes, which are not included in the official tree. Patching and re-compiling modules is not very convenient on most Linux distributions, so we decided to supply the full module source, to build the module out of tree.
The UIO modules need to be loaded in order: uio_dma, uio, uio_pci_generic. However, module dependencies should be resolved automagically. If necessary, you'll need to unload the original uio and uio_pci_generic modules first.
Once the modules are loaded, unbind your NIC from its driver and unload the driver
module. This can be done by writing the BDF address of the device into the sysfs unbind
attribute of your device driver. In case of an e1000e driver, the command might look like this:
$> lspci
[...]
01:00.0 Ethernet controller: Intel Corporation 82573E Gigabit Ethernet Controller (Copper) (rev 03)
[...]
echo -n 0000:01:00.0 > /sys/bus/pci/drivers/e1000e/unbind
At a later point in time you can use the same method to unbind from uio_pci_generic as well.
Now you can start the user-space driver:
$> sudo ./e1000.elf -d 01:00.0
The -d parameter tells DDEKit/Linux to which device it should bind. The parameter is a BDF address
that uniquely identifies the device.
You will need root privileges to bind the driver to the device and get access to the DMA-mapping pseudo
device as well as the UIO device. By adjusting the access rights to these files, you may also run the
application without root privileges.
The concepts around DDE have evolved through a series of works in our group. If you are interested in this work in more detail, you might want to have a look at the following papers: