Linux Module Programming

https://blog.51cto.com/widder/1956616

I. Introduction:

1. What is a kernel module?

1> Kernel modules are programs with independent functions. It can be compiled separately, but it cannot be run separately. Its operation must be linked to the kernel as part of the kernel and run in the kernel space.

2> Module programming and kernel version are closely linked, because the function names of some functions will change in different kernel versions. Therefore module programming can also be said to be kernel programming.

3> Features:

The modules themselves are not compiled into the kernel image, thus controlling the size of the kernel;
once loaded, the modules are identical to the rest of the kernel.

2. The difference between user-level programming and kernel module programming

 

2. Having said so much, how to write a kernel module program?

1. Let’s first look at the two simplest function examples, which are also programs that almost all programmers will write when learning a new language: output hello world!

Now we use module programming to output hello world!, and user-level programming to output hello wrold! . Through these two programs, we analyze how to write a kernel module program.

User level programming: hello.c

#include<stdio.h>

int main(void)

{

printf("hello world/n");

}

Kernel programming: module.c

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

MODULE_LICENSE("Dual BSD/GPL");

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

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

module_init(hello_init);
module_exit(hello_exit);
// 可选
MODULE_AUTHOR("Tiger-John");
MODULE_DESCRIPTION("This is a simple example!/n");
MODULE_ALIAS("A simplest example");

2. Specific implementation of kernel module programming

Step 1: First let’s take a look at the header file of the program

#include<linux/kernel.h>

#include<linux/module.h>

#include<linux/init.h>

These three header files are necessary for writing kernel module programs.

Tiger-John Description:

1> Since the library functions used in kernel programming and user-level programming are different, its header files are also different from those used when we write programs in the user-level.

2> Let’s take a look at where their header files are stored in Linux

a. The location of the kernel header file: /usr/src/linux-2.6.x/include/

b. Location of user-level header files: /usr/include/

Now we understand. In fact, the header files and system functions we use when writing kernel module programs are different from those used when layer programming is used.

Step 2: Two functions that are necessary when writing a kernel module:

1> Loading function:

static int init_fun(void)

{

// initialization code

}

Function example:

static int hello_init(void)// If void is not added, an alarm will appear during debugging.

{

printk("hello world!/n");

return 0;

}

2> The unloading function has no return value

static void cleaup_fun(void)

{

// release code

}

Function example:

static void hello_exit(void)// If void is not added, an alarm will occur. If it is changed to static int, an error will also be reported, because the exit function cannot return a value.

{

printk("bye,bye/n");

}

In module programming, the above two functions must be available;

Tiger-John added:

There is another way to write the registration function and uninstallation function:

1>Module loading function

static int __init init_fun(void)

{

// initialization code

}

Function example:

static int __init hello_init(void)

{

printk("hello tiger/n");

return 0;

}

2> The unloading function has no return value

static void __exit cleaup_fun(void)

{

// release code

}

Function example:

static void __exit exit(void)

{

printk("bye bye!/n");

}

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 both preceded by two underscores)

So what are the advantages of the second method over the first one:

_init and __exit are macro definitions of the Linux kernel, which enable the system to release the function and release the memory it occupies after initialization is completed. Therefore its advantages are obvious. Therefore, it is recommended that everyone adopt the second method when writing entry functions and exit functions.

(1) In the Linux kernel, all functions marked as __init are placed in the .init.text section when connecting. In addition, all __init functions also save an Function pointers, 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 enable the corresponding function to automatically reclaim memory after completion.

3 > Now let’s take a look at the printk() function

a. As mentioned above, the library functions we use in kernel programming are different from those in user mode. Printk is a kernel-mode information printing function, and its function is similar to the printf of the standard C library. printk also has information printing levels.

b. Now let’s take a look at the prototype of the printk() function:

int printk(const char *fmt, ...)

Message printing level:

fmt---- Message level:

#define KERN_EMERG "<0>" /* Emergency message, prompted before the system crashes, indicating that the system is unavailable*/

#define KERN_ALERT "<1>" /* Report message indicating that immediate action must be taken*/

#define KERN_CRIT "<2>" /* Critical conditions, usually involving serious hardware or software operation failures*/

#define KERN_ERR "<3>" /* Error conditions, drivers often use KERN_ERR to report hardware errors*/

#define KERN_WARNING "<4>" /* Warning conditions, warning of possible problems*/

#define KERN_NOTICE "<5>" /* Normal but important conditions, used for reminders. Commonly used for security-related messages*/

#define KERN_INFO "<6>" /* Prompt information, such as printing hardware information when the driver starts*/

#define KERN_DEBUG "<7>" /* Debug level message*/

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

The printk() function directly uses the tty_write() function 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 mode (such as process 0). In the kernel mode, since it is already a privileged level, there is no need for a system call to change the privilege level, so the printk() function can be used directly. printk is kernel output and is invisible in 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.

Step 3: Load and unload modules

1>module_init(hello_init)

a. Tell the kernel where to start executing the module program you wrote.

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

2>module_exit(hello_exit)

a. Tell the kernel where to leave the module program you wrote.

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

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

(1) If the module loading function registers XXX, the module unloading function should log out XXX

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

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

(4) If the module loading function turns on the hardware, the hardware is generally turned off in the unloading function.

Step 4: Statement of permissions

1> Function example:

MODULE_LICENSE("Dual BSD/GPL") ;

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

The module declaration describes the permissions of the kernel module. If LICENSE is not declared, 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".

Part 5: Declaration and description of the module (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 USB, PCI and other device drivers, a MODULE_DEVICE_TABLE is usually created

MODULE_ALIAS("alternate_name"); // Alias

Tiger-John:Summary

After the above five steps (actually only the first four steps), a complete module programming is completed.

Step 6: Commonly used module programming commands:

1>In Linux systems, use the lsmod command to obtain all modules loaded in the system and the dependencies between modules

2>You can also use cat /proc/modules to view loaded module information

3>The information about loaded modules in the kernel also exists in the /sys/module directory. After loading hello.ko, the kernel will contain the /sys/module/hello directory, which also contains a refcnt file and a sections directory. You can see the relationship between them by running tree -a in the /sys/module/hello directory.

4>Use the modinfo <module name> command to obtain module information, including the author of the module, module description, parameters supported by a certain block, and vermagic.

However, we have already said this before. Compilation between kernel programming and user-level programming

The links are also different. So how do we compile, link, and run the module program?

Now let's continue to learn how to write Makefile files:

3. The use of make and the preparation of Makefile

1. What is Makefile, make

1>Makefile is a script, which is mainly used for compilation of multiple files.

2> The make program can maintain interdependent source files, but when some files change, it can automatically identify

And only the corresponding files are automatically compiled

2. How to write Makefile

The Makefile file consists of five parts: display rules including rule variable definitions, makefile indicators and comments.

The prototype of a Make rule is:

Target... : Depends on..

Order

...

Shell commands can be used in makefiles, such as pwd, uname

Simple makefile:

obj-m := hello.o

kernel_path=/usr/src/linux-headers-$(shell uname -r)

all:

make -C $(kernel_path) M=$(PWD) modules

clean:

make -C $(kernel_path) M=$(PWD) clean

obj-m:= hello.o // Generate the target of hello module

kernel_path // Define the kernel source file directory

all :

make -C $(kernel_path) M=$(PWD) modules

//The parameters for generating the kernel module are the kernel source code directory and the directory where the module is located.

clean:

make -C $(kernel_path) M=$(PWD) clean

// Clear generated module files and intermediate files

Tiger-John explains:

1>The line below all and clean must be separated by table characters before make, and cannot be separated by spaces, otherwise a compilation error will occur.

2>After -C, the directory of the Linux kernel source code is specified, and after M=, the directory where hello.c and Makefile are located is specified.

3.Makefile example:

1 obj-m:=module.o
2
3
4 CURRENT_PATH :=$(shell pwd)
5 VERSION_NUM :=$(shell uname -r)
6 LINUX_PATH :=/usr/src/linux-headers-$(VERSION_NUM)
7
8 all :
9 make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules
10 clean :
11 make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean

----------------------------------------------------------------------

After the above module programming and Makefile programming, we can compile, link and run our program.

4. Operation process of kernel module

1> Enter make in the console to compile and link

2> After correct, enter sudo insmod module.ko in the console (load module)

3> Enter dmesg in the console to view the results

4> Enter rmmod tiger (uninstall module) on the console

5> Enter dmesg to view the results

(Or use cat /var/log/messages to view the system log file)

6>make clean (remove intermediate generated files)

----------------------------------------------------------------------

Now let's practice it in general and experience it. The joy of writing kernel module programs

module.c

1 #include<linux/kernel.h>
2 #include<linux/init.h>
3 #include<linux/module.h>
4 MODULE_LICENSE("Dual BSD/GPL");
5
6 static int __init hello_init(void)
7 {
8 printk("Hello world/n");
9 return 0;
10 }
11
12 static void __exit hello_exit(void)
13 {
14 printk("Bye Corne/n");
15
16 }
17 module_init(hello_init);
18 module_exit(hello_exit);

Makefile

1 obj-m:=module.o
2
3
4 CURRENT_PATH :=$(shell pwd)
5 VERSION_NUM :=$(shell uname -r)
6 LINUX_PATH :=/usr/src/linux-headers-$(VERSION_NUM)
7
8 all :
9 make -C $(LINUX_PATH) M=$(CURRENT_PATH) modules
10 clean :
11 make -C $(LINUX_PATH) M=$(CURRENT_PATH) clean

Type make in the terminal

think@ubuntu:~/work/moudule/mokua_biancheng$ make
make -C /usr/src/linux-headers-2.6.32-25-generic M=/home/think/work/moudule/mokua_biancheng modules
make[1]: Entering directory `/usr/src/linux-headers-2.6.32-25-generic'
Building modules, stage 2.
MODPOST 1 modules
make[1]: Leaving directory `/usr/src/linux-headers-2.6. 32-25-generic'
think@ubuntu:~/work/moudule/mokua_biancheng$

think@ubuntu:~/work/module/mokua_biancheng$ sudo insmod module.ko

think@ubuntu:~/work/moudule/mokua_biancheng$ dmesg

[19011.002597] Hello world

When the program has no errors, we can see the results of the program running when we enter dmesg.
----------------------------------
Linux Module Programming
https://blog.51cto.com/widder/ 1956616

おすすめ

転載: blog.csdn.net/gaotihong/article/details/127576142