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)
Related
I have been reading about system calls and how they work in Linux. I still have more reading to do but one thing that nothing I have read has answered is, WHY do we need system calls?
I understand that system calls are requests from user space program for the kernel to do something, but my question is basically: Why can't the user space program do the thing itself? Why doesn't Glibc do the actual operation instead of just being a wrapper for a system call?
For example, if I call fopen() in my program, why does glibc call the open system call? Why doesn't glibc just do the operation itself?
I understand that it would mean that glibc developers would have a lot more work and that they would have to have an intimate knowledge of Linux, but isn't glibc already very closely related to Linux kernel?
Also, I understand the system call functions are run in ring 0 in the CPU...but what's really the point of that? If I execute a program, I am giving it express permission to run, so what security is added by separating what code can be run in different contexts since you are giving it all permission anyway?
Why doesn't glibc just do the operation itself?
Well that is more less the ways things went in good old MS/DOS systems: no separation between kernel code and user code, and user code could happily directly access the hardware.
This just has 2 major problems:
It works (rather) fine on a single user and not multi tasking system, but as soon as multiple programs can simultaneously run in a system, you have to synchronize hardware accesses and memory usage => those are the parts dedicated to the kernel
There is no protection of the system from a poorly coded program. In a modern OS, an erroneous program can crash, but the system itself should survive. In MS/DOS a program crash usually ended in a system reboot.
For those reasons, all modern OS (except maybe some lightweight embedded ones) use isolation between different user processes and the kernel. And that just mean that you need a way to allow a user mode process to require a privileged action (reading or writing a physical disk is) from the kernel: that is exactly what system calls are made for.
Why doesn't glibc just do the operation itself?
Short answer: Because it can't.
Long answer:
A program running in Linux can run in two modes : UserLand or KernelLand.
The Kernel Land has every rights and can do everything, including talking with hardware, or providing userspace callbacks. For instance, when you call fopen(), the kernel does all the dirty talking with your filesystem (ext4 for instance), the caching, everything down to talking with the SATA Controller to access data on the hard-drive.
GLibc could do that using the device exposed by the kernel in /dev, but that would mean recoding from scratch all the filesystems layers, the sockets, the firewalling...
The kernel just provides easy usable API for programmers to have elevated rights and communicate with the devices. That's how Linux (and most modern OS) is made.
What security is added by separating what code can be run in different contexts since you are giving it all permission anyway?
The permissions are managed by the kernel. If you don't have syscall, you don't have permissions. Or should the program you run check their own permission? Once again, it would be reinventing the wheel every time.
If the code generated by a C implementation were the only thing that were going to be running on the target system (as it would be for many freestanding implementations, and for a very small number of hosted implementations) and if implementation knew precisely what hardware it would be running upon (true of some freestanding implementations, but seldom true for hosted ones), its runtime library might be able to perform operations like "fopen" by directly communicating with the storage hardware. It is rare, however, for either condition to apply, much less both of them.
If multiple programs will be using storage device, it will generally be necessary that they either coordinate their actions somehow or else that sequences of operations performed by different programs do not overlap, and that every program "forget" anything it thinks it knows about the state of storage any time another program might have written to it.
Otherwise, suppose a disk contains a single file and program #1 uses "fopen" to open it for reading. Each directory sector holds 8 entries, so the program would read the first directory sector and observe that slot #0 identifies the file of interest while #1-#7 are blank.
Now suppose program #2 uses "fopen" to create a file for writing. It would read the directory sector, observe that slots #1-#7 are blank, and rewrite the directory sector with information about the new file in slot #1.
Finally, suppose program #1 wants to write a file. If it doesn't know about program #2, it might reasonably believe it knows what the directory contains (it had read it earlier, and has no reason to believe it's changed), place information about the new file in slot #1, and replace the directory sector on disk with its new version, obliterating the entry written by program #2.
Having both programs route their operations through an operating system ensures that when program #2 wants to create its file, it can exploit the fact that it had just read the directory for program #1 (and thus doesn't need to reread it). More importantly, when program #1 goes to write a file, the operating system will know that the directory contains the file written by program #2, and will thus ensure that the new file gets placed in slot #2.
Contrary to what other answers say, even microcomputer C implementations running on platforms like MS-DOS essentially always relied upon the OS for file I/O. Some would include their own console I/O routines because the ones in MS-DOS were about four times as slow as they should have been, but the need for coordination when using file I/O meant that very few programs would try to do it themselves.
1- You don't wanna deal with low-level hardware communications. At least most people don't. Each of them has hundreds of commands.
2- Make a simple mistake and your CPU/RAM or I/O device might be useless forever.
3- When you are part of a network, you can share resources. The system calls and kernel keeps your co-worker from damaging your hard disk.
Another consideration is that the OS kernel needs to provide an abstraction for the myriad different types of hardware via a uniform API - without which you'd invariably be making device specific calls in your program.
While the previously-idle disk spins up for two seconds, or the networked disk gets connected for thirty seconds, what is the library going to do?
The full answer to your question is very broad but let me take a simple example based upon your question about fopen.
Let us say that we have a large system that has hundred or thousands of users. One of those users is, say the HR department with files containing confidential information about employees.
If that disk could be accessed at will in user mode, then any person on the system could open any file on the system, including those with confidential information.
In other words operating systems managed SHARED resources. These include disk, CPU, and memory. If these could be controlled in user mode, there would be no way to ensure that these were shared equitably.
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.
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.
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.