Module Loading, Hello World (Slideshow)¶
Kernel Driver Anatomy¶
Built-in vs. loadable module
Built-in driver is statically linked into the kernel (part of the kernel image itself)
Loadable module is much like a shared library in userspace
Initialization on module load
Deinitialization on module unload
Usually used to
(Un)register the module in its subsystem
Create/delete device nodes
Depends on subsystem initialization policy though: for example, PCI and USB have a
probe()
driver method.
Built-In vs. Loadable Module¶
Detail: huge difference, binary-code-wise
Conceptually:
Built-in drivers initialized at kernel boot (deinitialized at shutdown)
Loadable modules initialized at load time (deinitialized at unload)
Minimum Module Source¶
#include <linux/printk.h>
#include <linux/module.h>
static int hello_init(void)
{
printk(KERN_DEBUG "hello init\n");
return 0;
}
static void hello_exit(void)
{
printk(KERN_DEBUG "hello exit\n");
}
module_init(hello_init);
module_exit(hello_exit);
Gotchas: init()
and exit()
¶
init()
returns 0 on successOn error, returns negative value of userspace’s
errno
E.g.,
return -EINVAL
EINVAL
is the most unspecific, one for all, errors
Careful when
init()
fails in the middle⟶ partial initialization
⟶ before returning,
init()
must revert what is did so far
If
init()
succeeds, thenexit()
is supposed to revert everything thatinit()
didIf
init()
fails, the module is not loaded (and thusexit()
is not called)
Module Build¶
Fundamentally different ways to build a module:
In tree: part of the kernel source tree
Maintained as part of the kernel
Kernel’s internal API/ABI is by definition not stable ⟶ all drivers should ideally be part of the kernel
Not always possible: commercial, exotic, simply unwanted upstream, …
Out of tree: not part of the kernel tree
Maintained by third parties
The remainder assumes we are building an external module
Whole story here
Minimum Makefile
, Building¶
obj-m += hello.o
How to build
Makefile
andhello.c
in the same directory… which is the currect working directory
$ make -C /path/to/kernel/tree M=$(pwd) modules
make: Entering directory '/path/to/kernel/tree'
CC [M] /tmp/hello.o
MODPOST /tmp/Module.symvers
WARNING: modpost: missing MODULE_LICENSE() in /tmp/hello.o
CC [M] /tmp/hello.mod.o
LD [M] /tmp/hello.ko
make: Leaving directory '/path/to/kernel/tree'
Modules: Load/Unload Commands¶
|
Lists all loaded modules |
|
|
Inserts module by file name (e.g.
|
|
|
Inserts module by module name (e.g.
|
|
|
|
Modules: Dependency (and other) Databases¶
Question: How does modprobe
know?
$ ls -1 /lib/modules/$(uname -r)/modules.*
/lib/modules/5.9.16-200.fc33.x86_64/modules.dep
/lib/modules/5.9.16-200.fc33.x86_64/modules.dep.bin
/lib/modules/5.9.16-200.fc33.x86_64/modules.softdep
/lib/modules/5.9.16-200.fc33.x86_64/modules.symbols
/lib/modules/5.9.16-200.fc33.x86_64/modules.symbols.bin
... many more omitted ...
⟶ Databases must be rebuilt after changes to
/lib/modules/$(uname -r)
# depmod -a