Implementing correct inter-module synchronization in Linux kernel
Traditionally IRQ handling in Linux is done in two parts:
So called "upper-half" is actual working in IRQ context (IRQ handler itself). This part must exit as fast as possible. So it basically checks interrupt source and then starts bottom-half.
"Bottom-half". It may be implemented as work queue. It is where actual job is done. It runs in normal context, so it can use blocking functions, etc.
If you only want to wait for IRQ in your worker thread, better to use special object called completion
. It is exactly created for this task.
linux inter driver communication
It seems you want to receive input events from an unrelated module. But you cannot read /dev/input/event*
from kernel space, so you have to options:
- Write a user mode daemon that reads the
/dev/input/event*
and forwards to your driver, maybe with a char device or a sysfs parameter. - Hook on the input driver events from your driver.
Option 1 should be straightforward. I'll elaborate on option 2.
To hook an input device from kernel you use function input_register_handler()
from your module init function (and input_unregister_handler()
from your exit function, of course).
This function takes a struct input_handler
as argument, it has a lot of members, but you probably only need to fill name
, id_table
, connect
, disconnect
and event
.
Then, in your connect
callback you call input_register_handle()
(note the handle
vs handler
names) and input_open_device()
and you will get input events in your event
callback.
Of course, do not forget to undo that work in your disconnect
callback.
There are several instances of this API usage in the kernel, but by far the easier one to read is the evbug
driver: it just dumps all input events into the kernel log.
Communicating between multiple distinct kernel modules (drivers)
It looks like the Linux side has already been answered in comments.
For macOS kexts, the mechanism to use are the OSBundleLibraries
and OSBundleCompatibleVersion
Info.plist properties. The kext exporting symbols must have the OSBundleCompatibleVersion
property set. This must be less than or equal to its CFBundleVersion
and allows you to version your API.
The kext which wishes to import the other kext's symbols must list the exporting kext's bundle identifier in the OSBundleLibraries
dictionary, with the appropriate version number.
Note that linking against another kext will import all of its public symbols, so I strongly recommend making all symbols default-hidden and providing an explicit exports file. To do this, enable "Symbols hidden by default" in the Xcode target settings, create a new .exp (or .exports) file, and declare it in the "Exported Symbols File" setting. At a minimum, you will need to add _kmod_info
to this file. Then add all the symbols you wish to export, one on each line.
C functions and global variables will need to be prefixed with an underscore, C++ functions and static class member variables will need to be mangled in the usual way. You can use *
as a (partial) wildcard, which is sometimes handy for C++ classes with a lot of member functions, for example. The xnu source distribution contains plenty of examples of exports files if you need a reference. You can use the nm
tool to generate a list of all the symbols in your kext, from which you can then pick & choose; this saves you from manually mangling names.
Kexts can't circularly depend on one another. One will need to be the "library," the other the "user" of that library. If they need to interact, you will need to use callbacks, virtual functions, etc.
The "library" kext must be installed in /Library/Extensions (/System/Library/Extensions on OS X 10.8 or earlier) or the user of the library will not find it, potentially even if the library kext is already loaded. If your "user" kext specifies in its OSBundleRequired
property that it may be needed for local or network booting, the libraries it depends on should declare the same or a superset of those conditions, or they may not be appropriately prelinked/kextcached.
Apple does have a small amount of documentation on designing kext libraries too.
How to make communication between user space program and Linux kernel module in order to print a message sent from user program to the kernel
First problem: you never modify message
.
Then, you cannot use directly the user memory in the kernel context
You have to translate it before: copy_from_user is for that.
Your write function could looks like
#define MAX 256
/* here, message is defined as 256 bytes +1 one.
The extra char is here to be compatible with the `%s` formatter */
static char message[MAX+1] ="";
ssize_t exer_write(struct file *pfile, const char __user *buffer, size_t length, loff_t *offset) {
if (length > MAX)
return -EINVAL;
if (copy_from_user(message, buffer, length) != 0)
return -EFAULT;
printk(KERN_INFO "Received %s characters from the user\n", message);
return 0;
}
Structure of two interdependent Linux kernel modules?
I don't see any problem with your proposed solution of having one router.ko module that talks to the actual hardware, and submodules dev_A.ko and dev_B.ko that talk to router.ko. You just need to have router.ko export a "my_register_driver" function, analogous to the existing pci_register_driver function. You would pass in a structure that has an "id" member and a "add_device" function pointer; dev_A.ko would pass in id="A" and add_device=dev_A_add, and similarly for dev_B.ko.
Then when router.ko comes up, it discovers the hardware and creates virtual devices (your own context structure) for A and B. Then when a submodule comes along, router.ko just calls the appropriate add_device methods with the appropriate virtual device. router.ko should also export methods that the dev_A and dev_B modules can use to access the underlying hardware.
For an example of what I have in mind, you can look at the mlx4_core, mlx4_ib and mlx4_en modules in the upstream kernel (I wrote them so I choose this example :). The idea with them is that there is one PCI device that can be used as both an InfiniBand and Ethernet device; so mlx4_ib and mlx4_en both use mlx4_core to discover and access the underlying PCI device. The small bit of code that the sub-drivers use to ask for which devices exist is in drivers/net/mlx4/intf.c.
Also, as far as the existing "Device A" userspace interface, that shouldn't be a problem. You can just implement the same ABI in your dev_A.ko, unless there is some complication you didn't mention.
What options do we have for communication between a user program and a Linux Kernel Module?
Your option 3) is really a sub-option of option 1) - ioctl()
is one way of interacting with a device file (read()
and write()
being the usual ways).
Two other ways worth considering are:
- The
sysfs
filesystem; - Netlink sockets.
Related Topics
Can't Install Using Yum in Rhel 7.1
Reason of a Directory Size Being Zero
Goroutine in Io Wait State for Long Time
How to Make Libusb Library Visible to Another Program
How to Invoke Any Kernel Function
Why Can One Remove/Rename Open Files in Linux
Run Shell Script After Xserver Is Started
Aborting a Blocking Read on Linux
Svn Setup of Existing Directory
Detect If Interface Is in Promiscuous Mode with C
How to Force a Range of Virtual Addresses
Run 'Perf Stat' on The Output of 'Perf Record'
How to Compile a Node C++ Addon So That I Can Use Distribute It on Amazon Aws
How to Enable Hocr Font Info in Tesseract 4
Caputre Opengl Window in X11 with Fast Framerate - Possible