Loadable kernel modules are normally written in C. In this video, explore a simple skeleton for a loadable kernel module.
- [Instructor] Now we can look more closely at module code. Fun stuff. So we want to talk about header files you need, header files in general for the kernel. we want to talk about an initialization function for your module, an exit or cleanup function for your module, and then we'll look at a skeleton of a complete kernel loadable module. So, like any C program, you're going to have some headers. Remember that kernel code uses headers only from the kernel source directory. Kernel code does not use headers from user include. Those are for userspace. The Linux kernel source tree has lots of header files. I counted about 13,000 header files. For modules, perhaps the most important is module.h in the Linux subdirectory. I counted how many files included that and I counted 8,696. So there's a lot of modules in the Linux kernel source tree. You want a function to be called when your module gets started. You register what function that is by using a macro called module_init. So the function that you registered there will be called when you intmod modprobe your module, or if your module is statically linked when the kernel gets to it during boot time. Authors often include the string init in the name of their function, and maybe even module. It used to be common that folks would call their function init_module. One of the key things that you're init function should do is register callbacks, say, functions to be called later on when something does something with your driver, like tries to read from your device, and maybe allocate some other resources. An example of using the module_init macro comes from the e1000 network driver, where they have a function called e1000_init_module And we see the decoration for that function. It has no parameters passed to it, type is void there, it returns an int, that's whether the function was successful or not, or something about what happened when the function ran. And then we also see, in this case, they use the attribute __init. That tells the linker that this function is part of the initialization for the kernel. This affects when the module is statically linked. That means this function is put in the initialization area and that whole space is freed up when their kernel, during boot, is done with all the initialization. To register a function to be called. when your module is removed, you use the module_exit macro. Now, modules aren't ever removed if they're statically linked, so this is just for dynamically loaded modules. I want to tell you that doing this function correctly can be a challenge. Generally, you want to undo everything you did in the init, but also anything that your model did during its whole lifetime, that's not going to get cleaned up. That means, for example, if you allocate it some memory, it's common in the Linux kernel to not have garbage collection for things, so it's really your responsibility to clean this stuff up. If you registered pointers to some part of your module, pointers to functions or something, somewhere in the kernel, you got to undo that. If you don't undo that and pointers to your module remain, and then you have your module removed all cleaned up and those functions are gone, if that pointer into your module is ever used again, boom! You're probably going to panic your kernel. So we see, you register that function to be called with the module_exit macro, and we see a prototype here, the e1000_exit_module function. The exit functions take no parameters and also have no return type, so you don't know anything about whether the function worked or not. So here we have a skeleton of a complete Linux module. This code could be compiled, create a .ko, and loaded. We see we include the linux/module.h header file. We need that for the macros, for example. then we have init_function that does a printk, that will just show up on the console or in a log. We'll look more at that later. And we see our init function returns zero. You need to return a value. If you return a negative value, that indicates that your init function was unsuccessful. An unsuccessful init will mean your module's not loaded. Intmod or modprobe will print an error message and the module is not loaded, so there's nothing to RM mod. A non-negative value is success, including zero. And then you have a cleanup function. There's another printk, and notice, no return value. Then we register our functions with the macros module_init and module_exit, and then we register the license for our module using the module license, and we specify GPL, and we found out before that doing that opens up a lot more API to our module. So we looked at some good stuff here. Now you know what a module looks like.