Writing end to end linux device driver - linux

I am looking forward to learn writing a typical linux device driver. Can anyone guide me how can i learn all the aspects of a typical linux device driver ? The examples i see on internet are way too simple, they just send a "hello world" msg from user space to kernel driver module, and echo back "hello". I want to touch almost all areas in a simple way, one would face in writing a real world driver. Would i need to have a real hardware to go forward to meet my requirement ? Cannot system's memory simulate the hardware peripheral and let me treat it as a hardware and control it vie kernel driver covering good set of operations ? Any examples/guidance for this ?

Take a look at the following example of network driver. It uses QEMU for development and testing.
http://www.codeproject.com/Articles/1087177/Linux-Ethernet-Driver-using-Qemu

Sample drivers usually don't control real hardware. The QEMU answer mentioned here is a good exception I guess.
It depends what type of driver you want to focus on. Most classes of drivers distributed with the kernel have some simpler drivers you can learn from. Nbd for example is great for block subsystem and loop devices:
https://github.com/torvalds/linux/blob/c05c2ec96bb8b7310da1055c7b9d786a3ec6dc0c/drivers/block/nbd.c
Look at the smallest file sizes in a drivers/xyz directory and go up until the code is too complex.

Related

Linux kernel: Find all drivers reachable via syscalls

I am comparing a mainline Linux kernel source with a modified copy of the same source that has many drivers added. A little background: That modified source is an Android kernel source, it contains many drivers added by the vendor, SoC manufacturer, Google etc.
I am trying to identify all drivers added in the modified source that are reachable from userspace via any syscalls. I'm looking for some systematic or ideally automatic way to find all these to avoid the manual work.
For example, char device drivers are of interest, since I could perform some openat, read, write, ioctl and close syscalls on them if there is a corresponding device file. To find new character device drivers, I could first find all new files in the source tree and then grep them for struct file_operations. But besides char drivers, what else is there that I need to look for?
I know that the syscalls mentioned above do some kind of "forwarding" to the respective device driver associated with the file. But are there other syscalls that do this kind of forwarding? I think I would have to focus on all these syscalls, right?
Is there something I can grep for in source files that indicates that syscalls can lead there? How should I go about this to find all these drivers?
Update (narrowing down):
I am targeting specific devices (e.g. Huawei P20 Lite), so I know relevant architecture and hardware. But for the sake of this question, we can just assume that hardware for whatever driver is present. It doesn't really matter in my case if I invoked a driver and it reported back that no corresponding hardware is present, as long as I can invoke the driver.
I only look for the drivers directly reachable via syscalls. By directly reachable I mean drivers designed to have some syscall interface with userspace. Yes, syscalls not aimed at a certain driver may still indirectly trigger code in that driver, but these indirect effects can be neglected.
Maybe some background on my objective clarifies: I want to fuzz-test the found drivers using Syzkaller. For this, I would create descriptions of the syscalls usable to fuzz each driver that Syzkaller parses.
I'm pretty sure there is no way to do this programmatically. Any attempt to do so would hit up against a couple of problems:
The drivers that are called in a given case depend on the hardware. For example, on my laptop, the iwlwifi driver will be reachable via network syscalls, but on a server that driver won't be used.
Virtually any code loaded into the kernel is reachable from some syscall if the hardware is present. Drivers interact with hardware, which in turn either interacts with users, external devices, or networks, and all of these operations are reachable by syscalls. People don't write drivers that don't do anything.
Even drivers that aren't directly reachable by a system call can affect execution. For example, a driver for a true RNG would be able to affect execution by changing the behavior of the system PRNG, even if it weren't accessible by /dev/hwrng.
So for a generic kernel that can run on any hardware of a given architecture, it's going to be pretty hard to exclude any driver from consideration. If your hope is to trace the execution of the code by some programmatic means without actually executing it, then you're going to need to solve the halting problem.
Sorry for the bad news.

Testing a userspace driver that uses VFIO?

I have a possibly-buggy piece of hardware and a possibly-buggy userspace driver for it that relies on the vfio-pci kernel driver. I'd like to test the driver without dealing with the hardware.
I imagine the ideal solution would be something like: run my whole stack except for the hardware (application, userspace driver, VFIO driver) and intercept everything that the VFIO driver decides to send on to the hardware. Then I could verify that the hardware is getting the right info -- resets are happening at the expected time, DMAs are going to the right addresses, etc.
I guess I'm looking for something like a mock device that will let me run userspace code underneath vfio-pci rather than running hardware. Does such a thing exist?
Emulating devices has gotten impressively easy with Qemu. I've often used it to do some Linux kernel research. On Archlinux, the qemu-arch-extra comes with a bunch of machines:
$ qemu-system-arm -machine help
Supported machines are:
[..]
cubieboard cubietech cubieboard
emcraft-sf2 SmartFusion2 SOM kit from Emcraft (M2S010)
highbank Calxeda Highbank (ECX-1000)
imx25-pdk ARM i.MX25 PDK board (ARM926)
integratorcp ARM Integrator/CP (ARM926EJ-S)
kzm ARM KZM Emulation Baseboard (ARM1136)
lm3s6965evb Stellaris LM3S6965EVB
lm3s811evb Stellaris LM3S811EVB
mainstone Mainstone II (PXA27x)
midway Calxeda Midway (ECX-2000)
[and more...]
A good approach for your task would be to write an emulated PCI device for Qemu, and test it there.
There really isn't much to explain about it, given there are plenty of good materials on using and extending Qemu. A quick google search shows a couple good resources. This answer has some super useful hints, and here's a decent tutorial.

Writing hard disk and keyboard driver

I am a complete newbie to operating system and aiming to write my own kernel.
I understand that i will have to write my own device drivers as well.
How do i start with writing my driver?
The tasks of project are as follows.
1.Defining GDT in assembly language
2.Creating boot sector
3.Interrupt handling
4.Screen Driver
5.Keyboard driver
6.Hard disk driver
7.File system
8.I/O programming
9.Physical memory management
Also is it possible to do this in 3 months ( team of 2 )
As you know (or about to find out) OSes are extremely complicated and interconnected. For example, how are you going to have a working Keyboard driver before you have implemented interrupt handling?
It sounds like your question actually is: "How do I start writing my own OS?" You start by reading "Required Knowledge," "Beginner Mistakes," and "Getting Started" on osdev.
Good luck, and it is going to take a long time... especially if you are learning as you go (which is okay, since your goal is learning and not to make a commercial OS).
Edit: Modifying the Linux kernel is a good way to learn about the internals of an OS. It will let you focus on individual aspects (such as just writing a keyboard driver) and your work environment will be sane. Depending on what you want to do, you will be able to further ease development by creating a kernel module instead directly modifying the kernel.
Define your project and its scope
Set up your work environment (my suggestion, run Ubuntu Server in QEMU)
Learn how to either boot a custom kernel or use the module system
Get to work!
You can try looking into contributing to minix (http://www.minix3.org/)
There are a loads of things that are needed to be done .Have a look at (http://wiki.minix3.org/Wishlist).

How can I get edge events via GPIO on Linux without a busy-loop?

I'm working an a system with embedded Linux (Kernel 2.6.31).
It is a AT91SAM9G20 chip inside, and some of the Pins are forwarded to the outside.
Now I want to use them as GPIO Inputs.
I read the gpio.txt documentation about using the GPIOs via filesystem, and that works very well 'til here. I connected some switches to the gpio-pins and I can see the result in /sys/class/gpio/gpioX/value. But now I'd like to react on a change without busy-waiting in a loop. (i.e echo "Switch1 was pressed").
I guess I need interrupts here, but I couldn't find out how to use them without writing my own kernel driver. I'm relatively new to Linux and C (I normally program in Java), so I'd like to handle the Interrupts via sysfs too. But my problem is, that there is no "edge"-file in my GPIO directory (I guess because this is only since Kernel version 2.6.33+). Is that right? Instead of "edge" I've got a uevent file in there, which is not described in gpio.txt.
In the gpio.txt documentation there was a Standard Kernel Driver mentioned: "gpio_keys". Is it possible to use this for my problem?
I guess it would be better to work with this driver than allowing a userspace program to manipulate kernel tasks.
I found a lot of codesnippets for writing my own driver, but I wasn't even able to find out which of the 600 gpio.h files to include, and how to refer to the library (cross compiler couldn't find the gpio.h file).
Sorry for newbie questions, I hope you could give me some advices.
Thanks in advance
See this for an example on how to do that. Basically, the thing you're missing is the usage of the select or poll system calls.

how to access sound card in linux using nasm

hello i want to know how i can access sound card from nasm assembly program using int 0x80.
and also what values should i put in the registers when to access the sound card.
is there any manual or something that has details about the arguments that we have to pass to the kernel to access the sound card or other hardware devices, please if anyone know please tell me.
i had done alot of searching and well there alot of c libraries and ALSA and OSS and stuff like that, but what i would like is that if any one know of some resources about learning from the basics up about assembly program interfacing with the hardware.
and if any one could give me a small code listing as to how the access is done i would be very thankful.
As you've observed, the interface between user-space and kernel space in Linux is INT 0x80.
In Unix, as a matter of philosophy, (almost) everything is a file, thus sound cards are treated as "Character Files." The kernel syscalls are as per the POSIX specification - so "open","close","ioctl","read","write".
Access to the soundcard is done through the driver interface, as a file under "/dev/". Some sample documentation is at OSS documentation, but I'm not sure if its current.
To observe this communication, you can use 'strace' to see what system calls are being used by any existing application.
You will likely see a sequence like:
open("/dev/dsp", ... )
ioctl()
write()
...
write()
close()
Usually you'd get to "open" through the C library, but since you want to skip that, you can find the syscalls a few ways - one way would be
objdump -d /usr/lib/libc.a
For example, you can find that open is syscall 0x5 by looking for <__libc_open>:
You'll notice that eax is 5, and the rest of the parameters are in ebx, ecx and edx.
(The usage and parameters are also listed on Linux Syscalls )
This is what sound card drivers do. They have to be custom written for each sound card, in order to implement a common API which can be used by the O/S or applications. The same goes for other hardware devices. Hardware manufacturers tend to be less than open about how to access their stuff at this level (for one thing).
Not that I'm a Linux expert, but this is a fairly fundamental issue with all O/S's.
From user mode, this won't work - you won't have direct access to the sound hardware.
If you create a kernel-mode driver, you'd be able to directly poke the sound card hardware, but at this point I think most vendors have different implementations and don't follow a consistent standard. Newer sound cards might still be Adlib & SoundBlaster 16 compatible - this was the hardware standard WAY back when games were targetting DOS and directly used the hardware, but I wouldn't be surprised if this is no longer valid. A quick search should yield ways to directly access the interface for these legacy cards. Alternatively, you could run DOS inside of a virtual machine and access the hardware - most virtual machines emulate this level of sound card.
Depending what you're trying to do, you're probably better off using an existing library to handle the interface to the sound card, unless you aim to write a sound card driver, which I doubt, and that would be best done in C on linux.
Portaudio is one (free) one that's relatively easy to use. one example lib using portaudio with a C interface (I'm the author of wwviaudio).
FMOD seems to be big with the game programming guys, though it's not free.
sdl mixer is another one that's big with the linux game developers.
JACK is big in the linux pro-audio world. (think ardour -- the linux answer to Protools.)
There's no sense in trying to talk to the audio hardware directly from user space.

Resources