l What is a kernel module?
1. Kernel module is a kind of non-link, can not run independently of the target file, is actually running in the kernel space program. Links are loaded into the kernel as part of the kernel to access common symbols (functions and variables) of the kernel
2. Kernel modules allow the operating system kernel to be loaded and executed when needed and uninstalled by the operating system when it is not needed. They extend the functionality of the operating system kernel without the need to reboot the system
3. If there is no kernel module, we have to recompile the kernel image of the single kernel operating system again and again to add new features, which also means a bloated kernel.
L Advantages and disadvantages of the module mechanism
Pros: 1. Reduce kernel image size and increase system flexibility
2. Save development time; Modify the kernel without recompiling the entire kernel
3. Once the target code of the module is linked into the kernel, the kernel target code of the function and the static link is completely equivalent
Cons: 1. There is a certain loss to the system performance
2. Improper use can cause system crashes
Hello World Module
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
static int __init hello_init (void)
{
PRINTK ("<1>hello world\n");
return 0;
}
static void __exit hello_exit (void)
{
PRINTK (kern_alert "Hello module exit\n");
}
Module_init (Hello_init);
Module_exit (Hello_exit);
Module_license ("GPL");
Module_author ("Luzheng");
Module_description ("This is my first module");
L __init and __exit macros
1. If the module is compiled into the kernel instead of being dynamically loaded, the use of __init will discard the function and reclaim the occupied memory after the module initialization is complete
2. If the module is compiled into the kernel, the __EXIT macro ignores the "cleanup finishing" function
3. These macros are defined in the header file linux/init.h to free up kernel-occupied memory. For example, the information that you see at startup, "Freeint unused kernel memory:236k freed", is the printing information that the kernel releases when these functions occupy space.
L Makefile
Ifneq ($ (kernelrelease),)
Obj-m + = hello.o
# Obj-m + = STARTSTOP.O
# Startstop-objs: = START.O STOP.O/* Compile two files into one module */
Else
Kerneldir =/lib/modules/$ (Shell uname-r)/build/* Define the kernel path */
PWD: = $ (Shell pwd)/* means compiled in the current directory */
Default
$ (make)-C $ (Kerneldir) m=$ (PWD) modules
endif
Clean
RM Hello.ko HELLO.MOD.C HELLO.MOD.O hello.o MODULE.SYMVERS-RF
L PRINTK
The kernel outputs information through PRINTK () with a log level, which is controlled by adding an integer with angle brackets before the string output by PRINTK (), such as PRINTK ("<6>hello, world!/n");. The kernel provides eight different log levels, with corresponding macros in the linux/kernel.h.
#define Kern_emerg "<0>"/*system is unusable emergency message, prompted before the system crashes, indicating that the system is not available */
#define Kern_alert "<1>"/*action must be taken immediately report message that action must be taken immediately */
#define KERN_CRIT "<2>"/* Critical conditions critical conditions, usually involving severe hardware or software operation failure */
#define KERN_ERR "<3>"/* Error conditions errors condition, drivers commonly use this to report hardware errors */
#define Kern_warning "<4>"/* warningconditions warning condition to warn of possible problems
#define Kern_notice "<5>"/*normal but significant normal but important conditions for reminders */
#define KERN_INFO "<6>"/* Informational prompt information, such as when the driver starts, print hardware information */
#define KERN_DEBUG "<7>"/*debug-level messages Debug Level message */
So PRINTK () can be used this way: PRINTK (kern_info "Hello, world!/n");.
The default level for PRINTK () that does not specify a log level is Default_message_loglevel, which is defined in KERNEL/PRINTK.C as an integer 4, which corresponds to kern_warning.
The/PROC/SYS/KERNEL/PRINTK displays 4 values (which can be modified by echo), indicating the current console log level, the default message log level for which the log level is not explicitly specified, the minimum (maximum) allowed settings for the console log level, and the default logging level at boot time. When the message log level in PRINTK () is less than the current console log level, the PRINTK information (with the/n character) is displayed on the console. However, no matter what the current console log level is, you can always view it through/proc/kmsg (or using DMESG). Additionally, if SYSLOGD or KLOGD is configured and running, the PRINTK information that is not displayed on the console is appended to the/var/log/messages.log.
Char myname[] = "chinacodec/n";
PRINTK (kern_info "Hello, World%s!/n", myname);
L Write kernel programs need to be aware
1. Kernel programming cannot access C library
2. Kernel programming must use gun C
3. Kernel programming lacks a memory protection mechanism like user space
4. Floating point numbers are difficult to use when kernel programming
5. The kernel has only a small fixed-length stack
6. Because the kernel supports asynchronous interrupts, preemption, and SMP, you must always be aware of synchronization and concurrency
7. Consider the importance of portability
L Kernel module parameters
Linux2.6 allows the user to pass parameters to the kernel module when insmod, it mainly uses the Module_param macro definition to implement this function.
The definition of Module_param can be found in the Include/linux/moduleparam.h file, and its prototype is:
Module_param (name, type, perm);
Module_param_array (name, type, nump,perm);
Where Module_param is used to pass variable arguments, Module_param_array is used to pass array parameters.
Name is the variable name defined in the module, type is the variable, and perm is the permission mask used to make an auxiliary SYSFS entry.
Nump is the number of incoming arrays, which is an int pointer.
The types of parameters that Module_param supports pass are:
BOOL: Boolean type
Invbool: A Boolean (True or False) value (the related variable should be of type int). The Invbool type reverses the value, so the truth becomes false and vice versa.
Charp: A character pointer value. The memory is assigned to the user-supplied string, so the pointer is set.
int: Shaping
Long: Plastic
Short: Shorter shaping
UINT: Unsigned shaping
ULONG: unsigned long shaping
ushort: unsigned short shaping
The basic variable-length integer value. The unsigned value begins with U.
The Perm field is a permission value that represents the properties of the file node that this parameter corresponds to in the Sysfs file system. You should use the values defined in <linux/stat.h>. This value controls who can access the representation of these module parameters in Sysfs. When perm is 0 o'clock, this parameter does not exist for the corresponding file node under Sysfs file system. Otherwise, after the module is loaded, a directory named after this module name will appear under the/sys/module/directory with the given permissions:
Permissions are defined in Include/linux/stat.h
Like what:
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_iroth 00004
#define S_iwoth 00002
#define S_ixoth 00001
Using the S_irugo parameter can be read by everyone, but cannot be changed; s_irugo| S_IWUSR allows root to change parameters. Note that if a parameter is SYSFS modified, the parameter values that your module sees also change, but your module does not have any other notifications. You should not make the module parameters writable unless you are ready to detect the change and react accordingly.
Let's take a look at an example of the experiment:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
///////////////////////////////////////////////////////////
Module_license ("Dual BSD/GPL");
Char *msg_buf = "Hello world!";
int n_arr[] = {1,2,3,4,5};
int n = 7;
Module_param (n, int, s_irusr);
Module_param_array (N_arr, int, &n, s_irusr);
Module_param (Msg_buf, Charp, S_IRUSR);
///////////////////////////////////////////////////////////
static __init int hello_init (void)
{
int i;
PRINTK ("%s/n", msg_buf);
for (i=0; i<n; i++)
{
PRINTK ("n_arr[%d]=%d/n", I, n_arr[i]);
}
return 0;
}
///////////////////////////////////////////////////////////
static __exit void Hello_exit (void)
{
PRINTK ("Goodbye, kernel!/n");
}
Module_init (Hello_init);
Module_exit (Hello_exit);
To run the command:
sudo insmod HELLO.KOMSG_BUF=VERYCD
You can then use DMESG to view the output of the PRINTK:
[35983.685059] VeryCD
[35983.685067] N_arr[0]=1
[35983.685072] n_arr[1]=2
[35983.685075] N_arr[2]=3
[35983.685079] N_arr[3]=4
[35983.685083] N_arr[4]=5
[35983.685087] N_arr[5]=7
[35983.685091] N_arr[6]=1
It can be seen that the length of the implementation of the N_arr should be 5, and N is 7, the driver is not detected inside, N_arr[5],n_arr[6] has crossed the border,,,
But when it insmod, it detects the length of the N_arr,
Enter the command:
sudo insmod Hello.ko msg_buf=verycd n_arr=1,2,3,4,5,6
But the hint is wrong:
Insmod:error inserting ' Hello.ko ':-1 Invalid parameters
Because the array length of the N_arr is 5, when the input array length is less than or equal to 5, the Insmod can load the module successfully,
sudo insmod Hello.ko msg_buf=verycd n_arr=1,2,3
[36315.732903] VeryCD
[36315.732908] N_arr[0]=1
[36315.732909] n_arr[1]=2
[36315.732911] N_arr[2]=3
As you can see, the value of Nump in Module_param_array is the actual input array parameter length.
Then when the kernel module is loaded with Insmod and the data parameters are passed, the length of the array is automatically detected and the Insmod succeeds if the input array length is less than the module's array length.
L Kernel module Static compilation
- Copy. c Files to/drivers/char/
- Modify the Kconfig file under/drivers/char
Add the following code to the Kconfig:
- Go back to the root of the kernel makemenuconfig, and find that it has been added
Compile into a module and select <M> or write obj-m + = hello.o in the next step
- Modify the makefile file under/drivers/char and add the following
obj-$ (Config_hello) + = hello.o
Of course, the premise is that your hello.c must be in the current directory.
- Compiling the kernel
Kernel Module Basics