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#
hello.c##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
errnoE.g.,
return -EINVALEINVALis 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#
Makefile#obj-m += hello.o
How to build
Makefileandhello.cin 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