I. Introduction to the Linux kernel module
The overall structure of the Linux kernel is very large, and it contains many components. How can we include all the required parts in the kernel?
One way is to compile all required functions into the kernel. This will cause two problems. One is that the generated kernel will be very large, and the other is that if we want to add or delete features in the existing kernel, We have to re-compile the kernel, work efficiency will be very low, and if the compilation module is not perfect, it is likely to cause the kernel crash.
Linux provides another mechanism to solve this problem. This kind of set is called a module, and the compiled kernel itself does not contain all functions. When these functions need to be used, the corresponding code can be dynamically loaded into the kernel.
Ii. Module features:
1) The module itself is not compiled into the kernel, thus controlling the kernel size.
2) Once a module is loaded, it is exactly the same as other parts in the kernel.
Note: The module is not a necessary form of driver: the driver is not necessarily a module, and some drivers are directly compiled into the kernel. At the same time, the module is not all a driver, for example, some small algorithms we write can be compiled into the kernel as modules, but they are not drivers. Just like a pancake is not necessarily a circle, and not all circles are a pancake.
Iii. Simplest module Analysis
1) The following is a simple module example.
# Include <Linux/init. h>/* printk () */# include <Linux/module. h>/* _ init _ exit */static int _ init hello_init (void)/* when loading a function by using the insmod command, automatically run the */{printk (kern_info "Hello world enter \ n"); Return 0;} static void _ exit hello_exit (void)/* module to uninstall the function, when the rmmod command is run, the system will automatically execute */{printk (kern_info "Hello World exit \ n");} module_init (hello_init); module_exit (hello_exit ); module_author ("dengwei");/* module author, optional */module_license ("dual BSD/GPL");/* module license, which describes the permission of the kernel module, required */module_description ("a simple hello World module");/* module description, optional */module_alias ("a simplest module");/* module description, optional */
2) The makefile to compile the above modules is as follows:
OBJ-M: = hello. O // target file # module-objs: = file1.o file. O // when the module contains multiple files, add the kdir: =/usr/src/Linux // kernel path and change it to your own kernel path according to the actual situation, embedded to embedded, PC's specified PC path PWD: = $ (shell PWD) // Module source file path all: $ (make)-C $ (kdir) subdirs = $ (PWD) Modules @ rM-RF *. mod. * @ rM-RF. *. CMD @ rM-RF *. o @ rM-RF module. * clean: Rm-RF *. ko
The: Hello. Ko file will be compiled.
Use insmodhello. Ko to insert the module into the kernel, and then use dmesg to see the output prompt.
Common module operations:
Insmod XXX. Ko loads a specified Module
Lsmod lists all modules in the current system
Rmmod XXX uninstall the specified module (note that there is no. Ko suffix)
Dmesg uses this command to view system logs when the print level is lower than the default output level
3) program structure of the Linux kernel module
1. Module loading function:
Linux Kernel Modules are generally declared as _ init. The typical form of module loading functions is as follows:
static int __init myModule_init(void){/* Module init code */PRINTK("myModule_init\n");return 0;}module_init(myModule_init);
The name of the module-loaded function can be obtained at will, but must be specified in the form of "module_init (function name;
The insmod command is executed to initialize resources required by the module, such as memory space and hardware devices;
It returns an integer value. If Initialization is successful, 0 should be returned, and a negative number will be returned if initialization fails.
2. unmount a function
The typical form of uninstalling a function is as follows:
static void __exit myModule_exit(void){/* Module exit code */PRINTK("myModule_exit\n");return;}module_exit(myModule_exit);
The module uninstallation function is executed when the module is detached. No value is returned. It must be specified in the form of "module_exit (function name.
The uninstall module has the opposite functions as the load function:
If the loaded function registers XXX, the unmounted function should deregister XXX.
If the loaded function has applied for memory space, the unmounted function should release the corresponding memory space.
If the load function requests some hardware resources (interrupt, DMA, I/0 port, I/O memory, etc.), the unmount function should release the corresponding hardware resources.
If hardware is enabled for the function to be loaded, the hardware should be disabled for the function to be detached.
Here, _ init and _ exit are two macros provided by the system, indicating that the modified function will automatically recycle the memory after the call is complete, that is, the kernel considers this function to be executed only once, and the resources it occupies will be released.
3. Module declaration and description
In the Linux kernel module, we can use module_author, module_description, module_version, module_table, and module_alia to describe the author, description, version, device table number, and alias of the module.
MODULE_AUTHOR("dengwei");MODULE_LICENSE("Dual BSD/GPL");MODULE_DESCRIPTION("A simple Hello World Module");MODULE_ALIAS("a simplest module");
IV. Other features of related modules
1) module parameters:
We can use module_param (parameter name, parameter type, parameter read/write attribute) to define a parameter for the module, for example:
static char *string_test = “this is a test”;static num_test = 1000; module_param (num_test,int,S_IRUGO);module_param (steing_test,charp,S_ITUGO);
When loading a module, you can pass parameters to the module in the form of "insmod Module name parameter = parameter value". If this parameter is not passed, the parameter uses the default parameter value.
The parameter types can be byte, short, ushort, Int, uint, long, ulong, CHARP, bool;
Permission: defined in Linux/STAT. h to control the access permission. s_irugo indicates that all users are read-only;
After a module is loaded, a directory named after this module appears under sys/module,When the read/write permission is set to zero, this parameter does not exist in the file nodes in the sysfs file system,When the read/write permission is not set to zero: The parameters directory exists in the directory of this module, which contains a series of file nodes named after parameters. The permission value of these file nodes is passed to module_param () "parameter read/write permissions", and the content of this file is the parameter value.
In addition, the module can also have an array of parameters in the form of: "module_param_array (array name, array type, number leader, parameter read/write permission, etc )", when you do not need to save the actual number of input array elements, you can set "number leaders" to 0.
When running insmod, use commas to separate the input array elements.
The following is an actual example to illustrate the process of passing parameters in the module.
#include <linux/module.h> /*module_init()*/#include <linux/kernel.h>/* printk() */#include <linux/init.h>/* __init __exit */#define DEBUG//open debug message#ifdef DEBUG#define PRINTK(fmt, arg...)printk(KERN_WARNING fmt, ##arg)#else#define PRINTK(fmt, arg...)printk(KERN_DEBUG fmt, ##arg)#endifstatic char *string_test="default paramater";static int num_test=1000;static int __init hello_init(void){ PRINTK("\nthe string_test is : %s\n",string_test); PRINTK("the num_test is : %d\n",num_test); return 0;}static void __exit hello_exit(void){ PRINTK(" input paramater module exit\n ");}module_init(hello_init);module_exit(hello_exit);module_param(num_test,int,S_IRUGO);module_param(string_test,charp,S_IRUGO);MODULE_AUTHOR("dengwei");MODULE_LICENSE("GPL");
When insmod hello_param.ko is executed, run dmesg to view kernel output information:
Hello World enterthe test string is: this is a testthe test num is :1000
Execute insmod hello_param.ko num_test = 2000 string_test = "edit by dengwei" and run dmesg to view the kernel output information:
Hello World enterthe test string is: edit by dengweithe test num is :2000
2) Mutual reference of export modules and symbols
The "/proc/kallsyms" file in Linux corresponds to the kernel symbol table, which records the memory address of the symbol and symbol. The module can use the following macros to export to the kernel symbol table.
Export_symbol (symbol name); Any module can
Export_symbol_gpl (symbol name); used only for modules containing GPL permission
The exported symbols can be used by other modules. Just declare them before using them.
The following is a simple example: export the Add sub symbol to the kernel symbol table, so that other modules can use the Function
#include <linux/module.h> /*module_init()*/#include <linux/kernel.h>/* printk() */#include <linux/init.h>/* __init __exit */ int add_test(int a ,int b) { return a + b; } int sub_test(int a,int b) { return a - b; } EXPORT_SYMBOL(add_test);EXPORT_SYMBOL(sub_test);MODULE_AUTHOR("dengwei");MODULE_LICENSE("GPL");
Run CAT/proc/kallsyms | grep test to find the following information, indicating that the module is indeed loaded into the kernel table.
f88c9008 r __ksymtab_sub_integar [export_symb]f88c9020 r __kstrtab_sub_integar [export_symb]f88c9018 r __kcrctab_sub_integar [export_symb]f88c9010 r __ksymtab_add_integar [export_symb]f88c902c r __kstrtab_add_integar [export_symb]f88c901c r __kcrctab_add_integar [export_symb]f88c9000 T add_tes [export_symb]f88c9004 T sub_tes [export_symb]13db98c9 a __crc_sub_integar [export_symb]e1626dee a __crc_add_integar [export_symb]
This symbol can be referenced in other modules.
#include <linux/module.h> /*module_init()*/#include <linux/kernel.h>/* printk() */#include <linux/init.h>/* __init __exit */#define DEBUG//open debug message#ifdef DEBUG#define PRINTK(fmt, arg...)printk(KERN_WARNING fmt, ##arg)#else#define PRINTK(fmt, arg...)printk(KERN_DEBUG fmt, ##arg)#endifextern int add_test(int a ,int b); extern int sub_test(int a,int b); static int __init hello_init(void){int a,b; a = add_test(10,20); b = sub_test(30,20); PRINTK("the add test result is %d",a); PRINTK("the sub test result is %d\n",b); return 0;}static void __exit hello_exit(void){ PRINTK(" Hello World exit\n ");}module_init(hello_init);module_exit(hello_exit);MODULE_AUTHOR("dengwei");MODULE_LICENSE("GPL");