1. What is a Kernel Driver?
Kernel drivers are programs that run in Linux kernel space, managed and controlled directly by the kernel. They are primarily responsible for interacting with hardware and providing hardware access interfaces to upper-level user programs. Examples include: network card drivers, graphics card drivers, USB device drivers, disk drivers, etc.
Simple understanding:
User Program ←→ System Call ←→ Kernel Driver ←→ Hardware Device
- Kernel Driver = Bridge between hardware and operating system
2. What is a Kernel Module?
Kernel Module is a piece of functional code that can be separately compiled and loaded into the kernel on demand. Kernel modules include not only driver modules but also file systems, network protocols, extended features, etc.
Linux kernel has two main code integration methods:
- Built-in: Code is directly compiled into the kernel image, loaded at boot, cannot be dynamically unloaded.
- Module: Compiled as a separate
.kofile, can be dynamically loaded/unloaded at runtime using commands likeinsmod,modprobe, more flexible.
Most hardware drivers are made in the form of "kernel modules" for better flexibility.
3. Relationship between Kernel Drivers and Kernel Modules
- Kernel drivers have two existence forms: Built-in Drivers and Module Drivers (driver modules).
- The underlying essence is all " kernel code ", only different in integration method and usage management.
| Category | Load Time | Can be Unloaded | File Form | Typical Commands |
|---|---|---|---|---|
| Built-in Driver | At boot | No | No independent file | Compiled into kernel, kernel image loads at boot |
| Module Driver | Dynamic or at boot | Yes | .ko | insmod, modprobe, rmmod |
Summary:
During development, we usually use module driver form for easier debugging and upgrades.
4. Built-in Driver Testing
In the previous section, we wrote our first driver and generated a hello_world.ko file, which is in kernel module form.
This time, let's try to convert this driver into a kernel driver, a built-in driver. First, we need to find a suitable directory in the kernel directory and add our source code there.
1. Add Source Code to Kernel
Create a 02_kernel_helloworld/ folder, the specific path is:
TaishanPi-3-Linux/kernel-6.1/drivers/02_kernel_helloworld
Copy the hello_world.c from the previous section to the 02_kernel_helloworld/ directory:
Continue to create a new Makefile in the 02_kernel_helloworld/ directory with the following content:
obj-y += hello_world.oThis time it's very simple, we'll explain the reason in detail later.
We need to find the parent directory's TaishanPi-3-Linux/kernel-6.1/drivers/Makefile file and add a line:
obj-y += 02_kernel_helloworld/Similar to nesting dolls, layer after layer, each layer referencing the next.
2. Compile Kernel
Refer to this document for compiling kernel separately Debian12 Standalone Kernel Compilation
./build.sh kernelThe appearance of .o files indicates the source files have been compiled.
3. Flash Kernel for Testing
Refer to Scattered Image Flashing to flash TaishanPi-3-Linux/kernel-6.1/boot.img kernel image separately.
After booting, enter the system and run the following command to search for all statements related to hello in the logs:
dmesg | grep -E helloThis indicates the driver has been included in the kernel image, no need for manual driver loading.
5. Explanation
When adding kernel drivers, the Makefile statements we created are very simple, and we also need to add them to the parent Makefile.
This is because built-in drivers have a different compilation method than module drivers.
For module drivers (generating ko files):
obj-m += hello_world.oFor built-in kernel drivers, simply use:
obj-y += hello_world.oDifference Analysis:
obj-m: Tells the kernel build system that the object file should be compiled as a module (.ko), can be dynamically loaded/unloaded.obj-y: Tells the kernel build system that the object file should be compiled and linked as part of the kernel, no independent module generated.
Built-in drivers are compiled directly into the kernel image, the compiler used is determined by top-level configuration files. Each directory's Makefile needs to recursively notify "this directory's content needs to be compiled", so the outer Makefile must also add a line:
obj-y += 02_kernel_helloworld/This way, the kernel build system recursively enters the 02_kernel_helloworld directory to process the hello_world.c source file.
6. Kernel Source Directory Structure and Integration Process
Linux kernel uses a layered recursive compilation method, directory structure and Makefile recursively reference each other like "nesting dolls":
kernel-6.1/
└── drivers/
├── Makefile # Outer summary
└── 02_kernel_helloworld/
├── Makefile
└── hello_world.c2
3
4
5
6
- Top-level Makefile (
kernel-6.1/drivers/Makefile) is responsible for collecting all subdirectories and source files that need to be compiled. - Subdirectory Makefile (like
02_kernel_helloworld/Makefile) is responsible for specifying the specific compilation targets of this directory. - During compilation, the kernel recursively finds and compiles all specified files, then links them into the kernel image.
This mechanism facilitates flexible integration and management of various driver functions, and is easy to maintain and upgrade.