User space kernel driver
During memory pressure, the kernel will kill random user-space programs, but never kill kernel threads. User-space programs may be swapped out, which could lead to your device being unavailable for several seconds.
Kernel code can not be swapped out. Running code in user-space requires several context switches. These waste a "lot" of CPU time. If your device is a baud modem, nobody will notice. But if it's a gigabit Ethernet card, and every packet has to go to your userspace driver before it gets to the real user, the system will have major bottlenecks. User space programs are also "harder" to use because you have to install that user-space software, which often has many library dependencies. Kernel modules "just work".
I used to work for a company that made USB dongles that talked a particular protocol. We could have written a full kernel driver, but instead just wrote our program on top of libUSB.
The advantages: The program was portable between Linux, Mac, Win. No worrying about our code vs the GPL. The disadvantages: If the device needed to data to the PC and get a response quickly, there is no guarantee that would happen. For example, if we needed a real-time control loop on the PC, it would be harder to have bounded response times. Maybe not entirely impossible on Linux. If there is a way to do it in userspace, I would try that first. It will automatically be called by the built-in handler.
Each driver provides attributes that are used to read or write variables. These attributes are accessible through sysfs files. A custom kernel driver module can add its own attributes to the device owned by the uio driver, but not added to the UIO device itself at this time.
This might change in the future if it would be found to be useful. Please note that this directory might be a symlink, and not a real directory. Any userspace code that accesses it must be able to handle this. Each UIO device can make one or more memory regions available for memory mapping.
These directories will only appear if the size of the mapping is not 0. From userspace, the different mappings are distinguished by adjusting the offset parameter of the mmap call. To map the memory of mapping N, you have to use N times the page size as your offset:. Sometimes there is hardware with memory-like regions that can not be mapped with the technique described here, but there are still ways to access them from userspace.
The most common example are x86 ioports. On x86 systems, userspace can access these ioports using ioperm , iopl , inb , outb , and similar functions. Without information about the port regions a hardware has to offer, it becomes difficult for the userspace part of the driver to find out which ports belong to which UIO device. It only exists if the driver wants to pass information about one or more port regions to userspace. The following paragraphs explain the different sections of this file. This structure tells the framework the details of your driver, Some of the members are required, others are optional.
Usually, your device will have one or more memory regions that can be mapped to user space. It is used by the UIO framework to set up sysfs files for this mapping. Simply leave it alone. Sometimes, your device can have one or more port regions which can not be mapped to userspace. But if there are other possibilities for userspace to access these ports, it makes sense to make information about the ports available in sysfs.
It is used internally by the UIO framework to set up sysfs files for this region. What you need to do in your interrupt handler depends on your hardware and on how you want to handle it.
You should try to keep the amount of code in your kernel interrupt handler low. If your hardware requires no action that you have to perform after each interrupt, then your handler can be empty. If, on the other hand, your hardware needs some action to be performed after each interrupt, then you must do it in your kernel module. Note that you cannot rely on the userspace part of your driver.
Your userspace program can terminate at any time, possibly leaving your hardware in a state where proper interrupt handling is still required. With this technique you could avoid loss of data if your userspace program misses an interrupt. A note on shared interrupts: Your driver should support interrupt sharing whenever this is possible.
It is possible if and only if your driver can detect whether your hardware has triggered the interrupt or not. During user-mode debugging, the current process determines the meaning of virtual addresses. For more information, see Controlling Processes and Threads.
In kernel mode, you can set breakpoints in user space with the bp , bu , and ba commands or with the Breakpoints dialog box.
You must first use the process context to specify the user-mode process that owns that address space by using. Breakpoints in user space are always associated with the process whose process context was active when the breakpoints were set. If a user-mode debugger is debugging this process and if a kernel debugger is debugging the computer that the process is running on, this breakpoint breaks into the user-mode debugger, even though the breakpoint was actually set from the kernel debugger. You can break into the system from the kernel debugger at this point, or use the.
It is available here:. With lsuio you can quickly check if your kernel module is loaded and which attributes it exports. Have a look at the manpage for details. The source code of lsuio can serve as an example for getting information about an UIO device. The parameter offset of the mmap call has a special meaning for UIO devices: It is used to select which mapping of your device you want to map.
A drawback of this technique is that memory is always mapped beginning with its start address. After you successfully mapped your devices memory, you can access it like an ordinary array. Usually, you will perform some initialization. A read will always block until an interrupt occurs. There is only one legal value for the count parameter of read , and that is the size of a signed 32 bit integer 4.
Any other value for count causes read to fail. The signed 32 bit integer read is the interrupt count of your device. If the value is one more than the value you read the last time, everything is OK. If the difference is greater than one, you missed interrupts. It can work with any device compliant to PCI 2.
Using this, you only need to write the userspace driver, removing the need to write a hardware-specific kernel module. Since the driver does not declare any device ids, it will not get loaded automatically and will not automatically bind to any devices, you must load it and allocate id to the driver yourself. For example:. You can verify that the device has been bound to the driver by looking for it in sysfs, for example like the following:.
Note that the generic driver will not bind to old PCI 2. If binding the device failed, run the following command:. All devices compliant to PCI 2. This prevents the device from generating further interrupts until the bit is cleared.
The userspace driver should clear this bit before blocking and waiting for more interrupts. Userspace driver can use pci sysfs interface, or the libpci library that wraps it, to talk to the device and to re-enable interrupts by writing to the command register. For example, to use the network device class GUID:.
When host rescinds a device, the interrupt file descriptor is marked down and any reads of the interrupt file descriptor will return -EIO. Similar to a closed socket or disconnected serial device. The Linux Kernel 5. Hardware that is ideally suited for an UIO driver fulfills all of the following: The device has memory that can be mapped.
The device usually generates interrupts. The device does not fit into one of the standard kernel subsystems. The following standard attributes are provided by the UIO framework: name : The name of your device. You should also make sure that the memory mapping you need exists and has the size you expect.
0コメント