How would I go about implementing my own file descriptor?
Say if I have a kernel module controlling some hardware and I want to expose the ability to communicate with this hardware to the userspace via read() and write(). Don't want to use IOCTL or netlink or other userspace-kernelspace methods. Would I need to recompile the kernel or can I do it just by writing a kernel module.
I understand that creating the file descriptor will require a mechanism for userspace to tell the kernelspace to create an entry in the task's files struct (ie a function equivalent to open(), eventfd() timerfd(), socket()). That I can implement via IOCTL (so that I wont have to recompile the kernel), but how do I hack into read() and write() - I have patched them using LD_PRELOAD before, is that the only way? Don't want to recompile the kernel!
I am not sure I understand all of your questions. Nonetheless:
you can definitely have this as a kernel module;
you probably want to create a character device (second part of your question);
for the char device you can implement the system calls you need; if you only want to have read and write - no problem;
Look at the chapter three (and others) of this book.
konrad.kruczynski is right!
use a character device as the userspace mechanism to communicate with your hardware, and create a device in /dev filesystem such as /dev/hardware_type_A.
then compile && load your module in the kernel, then if all your code is good, then the kernel will create a character device in /dev/ with name /dev/hardware_type_A.
then you can use read, write, open, close calls just like you use with the other devices or the files to control your hardware.
IF you really say that you dont want to control it over ioctl, then you must need a new protocol that sends data using write and your driver unpacks that data and controls the hardware on behalf of your program in user.
Related
I'm trying to implement an echo TCP server as a loadable kernel module.
Should I use sock_create, or sock_create_kern?
Should I use accept, or kernel_accept?
I mean it does make sense that I should use kernel_accept for example; but I don't know why. Can't I use normal sockets in the kernel?
The problem is, you are trying to shoehorn an user space application into the kernel.
Sockets (and files and so on) are things the kernel provides to userspace applications via the kernel-userspace API/ABI. Some, but not all, also have an in-kernel callable, for cases when another kernel thingy wishes to use something provided to userspace.
Let's look at the Linux kernel implementation of the socket() or accept() syscalls, in net/socket.c in the kernel sources; look for SYSCALL_DEFINE3(socket, and SYSCALL_DEFINE3(accept,, SYSCALL_DEFINE4(recv,, and so on.
(I recommend you use e.g. Elixir Cross Referencer to find specific identifiers in the Linux kernel sources, then look up the actual code in one of the official kernel Git trees online; that's what I do, anyway.)
Note how pointer arguments have a __user qualifier: this means the data pointed to must reside in user space, and that the functions will eventually use copy_from_user()/copy_to_user() to retrieve or set the data. Furthermore, the operations access the file descriptor table, which is part of the process context: something that normally only exist for userspace processes.
Essentially, this means your kernel module must create an userspace "process" (enough of one to satisfy the requirements of crossing the userspace-kernel boundary when using kernel interfaces) to "hold" the memory and file descriptors, at minimum. It is a lot of work, and in the end, it won't be any more performant than an userspace application would be. (Linux kernel developers have worked on this for literally decades. There are some proprietary operating systems where doing stuff in "kernel space" may be faster, but that is not so in Linux. The cost to do things in userspace is some context switches, and possibly some memory copies (for the transferred data).)
In particular, the TCP/IP and UDP/IP interfaces (see e.g. net/ipv4/udp.c for UDP/IPv4) do not seem to have any interface for kernel-side buffers (other than directly accessing the rx/tx socket buffers, which are in kernel memory).
You have probably heard of TUX web server, a subsystem patch to the Linux kernel by Ingo Molnár. Even that is not a "kernel module server", but more like a subsystem that an userspace process can use to implement a server that runs mostly in kernel space.
The idea of a kernel module that provides a TCP/IP and/or UDP/IP server, is simply like trying to use a hammer to drive in screws. It will work, after a fashion, but the results won't be pretty.
However, for the particular case of an echo server, it just might be possible to bolt it on top of IPv4 (see net/ipv4/) and/or IPv6 (see net/ipv6/) similar to ICMP packets (net/ipv4/icmp.c, net/ipv6/icmp.c). I would consider this route if and only if you intend to specialize in kernel-side networking stuff, as otherwise everything you'd learn doing this is very specialized and not that useful in practice.
If you need to implement something kernel-side for an exercise or something, I'd recommend steering away from "application"-type ideas (services or similar).
Instead, I would warmly recommend developing a character device driver, possibly implementing some kind of inter-process communications layer, preferably bus-style (i.e., one sender, any number of recipients). Something like that has a number of actual real-world use cases (both hardware drivers, as well as stranger things like kdbus-type stuff), so anything you'd learn doing that would be real-world applicable.
(In fact, an echo character device -- which simply outputs whatever is written to it -- is an excellent first target. Although LDD3 is for Linux kernel 2.6.10, it should be an excellent read for anyone diving into Linux kernel development. If you use a more recent kernel, just remember that the example code might not compile as-is, and you might have to do some research wrt. Linux kernel Git repos and/or a kernel source cross referencer like Elixir above.)
In short sockets are just a mechanism that enable two processes to talk, localy or remotely.
If you want to send some data from kernel to userspace you have to use kernel sockets sock_create_kern() with it's family of functions.
What would be the benefit of TCP echo server as kernel module?
It makes sense only if your TCP server provides data which is otherwise not accessible from userspace, e.g. read some post-mortem NVRAM which you can't read normally and to send it to rsyslog via socket.
I would like to write a FreeBSD kernel module that could accept some arbitrary interrupts and upon receiving these interrupt, output some data to an arbitrary device. Currently, I'm facing several issues:
How would I acquire interrupts through a specific IRQ? On Linux there is the request_irq() call but it seems there's no similar API for FreeBSD... Say, I want to be able to detect all the keyboard interrupt through my kernel module (the keyboard is on irq1), how would I do that? (On Linux it is possible through calling free_irq(1, NULL) and request_irq(1, ...), correct me if I'm wrong though).
Is it possible at all to write to a device file under /dev through a kernel module? I've read the question Example for reading text files in FreeBSD kernel module; following this example I was able to do read/write on regular files, but not a device file under /dev (the "device" was a pseudo "echo device", the classical one used in char device examples). I was able to open the file though.
I do understand that it is considered as a bad practice to do file I/O's in kernel, but I could not think any other way... If anyone has a better solution please tell me. (i.e. write to a device through its device_t node?)
The reason I was doing this in a kernel is that I really need all interrupts to be hit, and running it in the user space has the risk of missing interrupts due to kernel threads preempting user threads (the interrupts could come very frequent).
I would also appreciate if anyone could provide me with some other ideas on how to implement this program (basically, the idea is a kernel module that could do the job of a microcontroller...)
You can register an IRQ handler with bus_setup_intr.
Normally, what one would do in this situation is to have a driver collect the interrupts and any other useful data, and export it through a device, and then a (real-time maybe?) process in user-space can read from one device, do whatever it needs to do, and write to the other device.
When writing a device driver, I use the function device_create(), which creates a file in /dev linked to the functions registered through fops.
The problem is, once I insmod this module, I can't fprintf to write to the /dev file. A page domain fault occurs. I can still write to a normal file, so I imagine that I don't have permission to write to the file in /dev. Is there anything I can do to set the file as writable within the kernel module while calling device_create() so I wouldn't need to externally set it?
If I read this right, you have a userspace program doing fopen + fprintf on a device file backed by your custom driver. On use, the kernel crashes.
First of all the use of FILE abstraction (given with fopen and fprintf) is extremely sketchy when applied to device drivers. Since it does internal buffering, you never know for sure what data actually hits the driver and in what chunks. Use the standard file descriptors directly instead (open + write).
Now, the suspicion that there is a permission problem cannot be right. If the open routine of your driver is reached, the kernel already determined you have necessary privileges. Similarly, if the write routine is reached the file was already opened, so we know you have permissions to use it. But even if there was a permission problem of some kind, a page domain fault is definitely not valid for the kernel to encounter in response.
Given the quality of the question I would argue you are too new to programming to play with this stuff and would recommend sticking to userspace for the time being.
Take a look at init/initramfs.c where there are sample uses of syscalls by the kernel. Include linux/syscalls.h and just use sys_chmod. It works like the userspace variant. This can be applied to pretty much any system call.(Not that it's a good idea to use socket in the kernel)
I wish to mock a memory mapped device in C in order to do effective unit testing of a device wrapping library (in Linux).
Now, I know I can mmap a file descriptor into userspace which could in principle represent a mock of said device.
So, AFAICT, my question comes down to this: Is it possible in userspace to create a file descriptor on which mmap can act, with the reading and writing being handled by suitable callbacks?
Alternatively, perhaps this is a solved problem and there is a known kernel driver that can be hooked into?
Considering it's a Linux system, you can implement a very simple FUSE filesystem with just one file on it. The kernel can handle it from there.
The main issue is that you can expect the kernel to not flush every write. There's a msync() call to flush all outstanding writes, though, but your System Under Test isn't going to call that. However, I think you can get away with opening the file descriptor using O_DIRECT | O_DSYNC
I am trying to implement "simple file-system" for my personal experience. For this, I have created a block device driver with which I will perform read/write operations in unit of blocks. Now my question is how should I perform open, read, write and close operation on the block device from the user application.
What I am actually looking for is a function with which I can open the block device /dev/sbd and it returns the struct block_device, if successful. And for the read/write functions, I can issue request to block device struct request with parameters as "buffer, sectore_number, numbe_of_sectors".
Till now I only got block_read() and block_write() functions. But it seems that they are BSD specific. And I am using Debain.
Anyone having idea about it?
Thanks.
I've been doing something similar writing a application level file system that works with files or devices. What you are writing is not really a device driver as device drivers are directly handled/used by the kernel. A user application has no way to access one directly. Regardless, I want to point you to the function calls open(2), read(2), write(2), close(2) (manual page section 2 for all of them). You will need the unistd.h header file to use these. You can set your read/write size as a multiple of your block size when calling read and write. But in the end, you are still going through the kernel.
EDIT: Upon further examination and comments, the device driver really is in the kernel. Normally, there is no direct connection between a driver and an application as there are several layers of code within the kernel to abstract the device so it looks the same like everything else to the application.
There are two ways around this. One is to establish one or more system calls in the system call tree to expose the read/write routines of the device driver to the application. Another idea that I had was to use the ioctl (I/O Control) system call to perform this, but this call is meant to control the actual device. For example, the hard disk uses read and write commands to transfer data, but to talk to the hard drive to get information about it, such as what the last LBA is or get its identity, you would use IOCTL to do that.
Hope this helps.