Linux Learning Articles (3) --- Kernel Modules of the Linux Kernel

What is a Linux kernel module? Not much nonsense, let's have a piece of code to feel it first!

kernel programming : module.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

/** 编写内核模块程序所必须的 3 个头文件
    因为内核编程和用户层编程所用的库函数不一样,故头文件也不同
    
    a. 内核头文件的位置 : /usr/src/linux-2.6.x/include/

    b. 用户层头文件的位置 : /usr/include/
**/

MODULE_LICENSE("Dual BSD/GPL");



static int hello_init(void)
{
printk(KERN_ALERT "hello,I am greenbird/n");
return 0;
}

static void hello_exit(void)
{
printk(KERN_ALERT "goodbye,kernel/n");
}

module_init(hello_init);
module_exit(hello_exit);
 
MODULE_AUTHOR("Greenbird");
MODULE_DESCRIPTION("This is a simple module!/n");
MODULE_ALIAS("A simplest module");
————————————————

The previous hellowold program is like this:

以前的c程序(用户层): hello.c

#include<stdio.h>

int main()

{

printf("hello world!/n");


return 0;
}

kernel module

    The kernel module is a socket provided by the Linux kernel to the outside. Its full name is Loadable Kernel Module (LKM), and we refer to it as a module for short. The reason why the Linux kernel provides a module mechanism is because it is a monolithic kernel itself. The biggest advantage of a single core is high efficiency, because all the content is integrated, but its disadvantage is that the scalability and maintainability are relatively poor, and the module mechanism is to make up for this defect. A module is a program with independent functionality that can be compiled independently but not run independently.

    Features of the kernel module: the module itself is not compiled into the kernel image, thereby controlling the size of the kernel; once the module is loaded, it is exactly the same as other parts of the kernel.

Common commands for module development


The following instructions are commonly used in the process of kernel module development. 
1) insmod: insert the module into the kernel, use method: insmod XXX.ko 
2) rmmod: delete the module from the kernel, use method: rmmod XXX.ko 
3) lsmod: list all kernel modules, can be used with grep command In conjunction with. How to use: lsmod | grep XXX 
4) modprobe: modprobe can load specified individual modules, or load a group of dependent modules. modprobe will decide which modules to load based on the dependencies generated by depmod. If an error occurs during loading, modprobe will unload the entire set of modules. Dependencies are obtained by reading /lib/modules/2.6.xx/modules.dep. And this file is created by depmod. 
How to use: modprobe module [module parameters] 
Among them, the parameter module specifies the name of the module to be loaded, and the following parameters will be passed to the kernel when the module is loaded. 
5) modinfo: View module information. How to use: modinfo XXX.ko 
6) tree –a: View the entire tree structure of the current directory. How to use: tree -a

 

 Why does the kernel mode use the printk() function, while the user mode uses the printf() function .

The printk() function directly uses the function tty_write() to write to the terminal. The printf() function calls the write() system call function to write to the standard output device. Therefore, the printk() function cannot be used directly in the user state (such as process 0), but the printk() function can be used directly in the kernel state because it is already a privilege level, so there is no need for a system call to change the privilege level. printk is kernel output, invisible to the terminal. We can take a look at the system log. But we can use the command: cat /var/log/messages, or use the dmesg command to see the output information

 

Two functions that must be present when writing a kernel module:

1> 加载 函数:

static int init_fun(void)

{

// 初始化代码

}

函数实例:

static int hello_init(void)// 不加 void 在调试时会出现报警

{

printk("hello world!/n");

return 0;

}

2> 卸载函数 无返回值

static void cleaup_fun(void)

{

// 释放代码

}

函数实例:

static void hello_exit(void)// 不加 void 会出现报警 , 若改为 static int 也会报错 , 因为出口函数是不能返会值的

{

printk("goodbye!/n");

}

在模块编程中必须要有上面这两个函数;

补充:

注册函数和卸载函数还有另一中写法:

1> 模块加载 函数

static int __init init_fun(void)

{

// 初始化代码

}

函数实例:

static int __init hello_init(void)

{

printk("hello bird/n");

return 0;

}

2> 卸载函数 无返回值

static void __exit cleaup_fun(void)

{

// 释放代码

}

函数实例:

static void __exit exit(void)

{

printk("goodbye!/n");

}

Note:

By comparison, we can find that the main difference between the writing method of the second function and the first function is the addition of __init and __exit prefixes. (init and exit are preceded by two underscores)

So what is the advantage of the second method over the first:

_init and __exit are a macro definition of the Linux kernel, so that the system releases the function after the initialization is completed, and releases the memory it occupies. So its advantages are obvious. So I suggest that you use the second method when writing entry functions and exit functions.

(1) In the linux kernel, all functions marked as __init are placed in the section .init.text when linking. In addition, all __init functions also save a file in the section .initcall.init. A function pointer, the kernel will call these __init functions through these function pointers during initialization, and release the init section (including .init.text, .initcall.init, etc.) after the initialization is completed.

(2) Like __init, __exit can also make the corresponding function automatically reclaim memory after running.

 

Loading modules and unloading modules

1>module_init(hello_init)

a. Tell the kernel where you write the module program to start execution from.

b. The parameter in the module_init() function is the function name of the registered function.

2>module_exit(hello_exit)

a. Tell the kernel where you write the module program and go from there.

The parameter name in b.module_exit() is the function name of the uninstall function.

Note:

We generally perform some initialization in the registration function, such as applying for memory space and registering the device number. Then we have to release the resources we occupy in the unload function.

(1) If the module loading function has registered XXX, then the module unloading function should cancel XXX

(2) If the module loading function dynamically applies for memory, the module unloading function should cancel XXX

(3) If the module loading function has applied for the occupation of hardware resources (interrupts, DMA channels), the module unloading function should release these hardware resources.

(4) If the module loading function has enabled the hardware, the unloading function generally needs to turn off the hardware.

 

 

Statement of Permissions

1> Function instance:

MODULE_LICENSE("Dual BSD/GPL") ;

2> It is optional here, you can not add the system default (but it will alarm)

The module statement describes the permission of the kernel module. If you do not declare LICENSE, you will receive a warning from the kernel when the module is loaded.

In the Linux2.6 kernel, acceptable LICENSE includes "GPL", "GPL v2", "GPL and additional rights", "Dual BSD/GPL", "Dual MPL/GPL", "Proprietary".

 

 

Module declaration and description (can be added or not)

MODULE_AUTHOR("author");// author

MODULE_DESCRIPTION(“description”);//Description

MODULE_VERSION("version_string");// version

MODULE_DEVICE_TABLE("table_info");// device table

For device drivers such as USB and PCI, a MODULE_DEVICE_TABLE is usually created

MODULE_ALIAS("alternate_name");//alias

A complete module programming is done!!!

 

 

Reference: https://blog.csdn.net/tigerjibo/article/details/6010997

 

 

 

 

Guess you like

Origin blog.csdn.net/qq_41899773/article/details/102548263