From 2.4 to 2.6: the impact of changes in the Linux kernel's installable module mechanism on Device Drivers

Source: Internet
Author: User

1. Get the kernel version

When the device driver needs to support different kernel versions at the same time, in the compilation phase, the kernel module needs to know the version of the currently used kernel source code to use the corresponding kernel API. In the 2.4 and 2.6 kernels, the source code header file Linux/version. H is defined as follows:

Linux_version_code: the binary representation of the kernel version. Each of the primary, slave, and revision versions corresponds to one byte;

Kernel_version (Major, minor, release)-the binary version is constructed by the master, slave, and revision versions.

The following code segment is often seen in device drivers that support both the 2.4 and 2.6 kernels:


Listing 1: code segment for determining the kernel version.

#include <linux/version.h>#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)#define LINUX26#endif#ifdef LINUX26/*code in 2.6 kernel*/#else/*code in 2.4 kernel */#endif 

 


2. kernel module Mechanism Changes

2.1 Module Compilation

From 2.4 to 2.6, the compilation, connection process, and makefile Writing of external kernel modules have all changed.

In the 2.4 kernel, only the kernel source code header file is required for module compilation. The module must be defined before Linux/modules. h. The kernel module generated after compilation and connection is suffixed with. O.

2.6 kernel, the kernel source code to be configured for module compilation; the kernel module generated after compilation and connection is suffixed. ko; the compilation process first reads the MAKEFILE file at the top level under the kernel source code directory, and then returns the directory where the module source code is located.


Listing 2: 2. 4. makefile template of the kernel module

#Makefile2.4KVER=$(shell uname -r)KDIR=/lib/modules/$(KVER)/buildOBJS=mymodule.oCFLAGS=-D__KERNEL__ -I$(KDIR)/include -DMODULE     -D__KERNEL_SYSCALLS__ -DEXPORT_SYMTAB  -O2 -fomit-frame-pointer  -Wall  -DMODVERSIONS           -include $(KDIR)/include/linux/modversions.hall: $(OBJS)mymodule.o: file1.o file2.old -r -o $@ $^clean:rm -f *.o

 

At 2.4
In the kernel, The makefile of the kernel module is the same as the makefile of the common user program in terms of structure and syntax, but must be defined in cflags-d1_kernel __-
Dmodule, specify the kernel header file directory-I $ (kdir)/include.
Note that variables are defined in cflags instead of in the module source code file. On the one hand, these predefined variables can be visible to all source code files in the module, and on the other hand, they are equivalent
Predefined variables are defined at the starting position of the source code file. During module compilation, these global predefined variables are generally defined in cflags.


Listing 3: kernel module makefile Template

# Makefile2.6ifneq ($(KERNELRELEASE),)#kbuild syntax. dependency relationshsip of files and target modules are listed here.mymodule-objs := file1.o file2.oobj-m := mymodule.o elsePWD  := $(shell pwd)KVER ?= $(shell uname -r)KDIR := /lib/modules/$(KVER)/buildall:$(MAKE) -C $(KDIR) M=$(PWD) clean:rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versionsendif

 

Kernelrelease is a variable defined in the top-level makefile of the kernel source code. It is executed for the first read.
Kernelrelease is not defined,
Therefore, make will read the content after else execution. If the target of make is clean, directly execute the clean operation and end. -C
$ (Kdir) indicates to jump to the kernel source code directory to read the makefile; m =$ (PWD)
Indicates that the current makefile will be read and executed in the current directory. When returned from the kernel source code directory, kernelrelease is defined and kbuild is also started.
Make will continue to read the content before else by parsing the kbuild syntax statement. The statement before else is the kbuild syntax,
Specify the dependency between each file in the module source code and the name of the target module to be generated. Mymodule-objs: = file1.o
File2.o indicates that mymoudule. O is generated by the connection between file1.o and file2.o. OBJ-M: =
Mymodule. O indicates that the mymodule. O module will be generated after the connection is compiled.

Add, "$ (make)-C $ (kdir) M = $ (PWD)" and "$ (make)-C $ (kdir) subdirs = $ (PWD) "is equivalent, and the latter is an old method of use. We recommend that you use M instead of subdirs. The former is clearer.

From the above comparison, we can see that in makefile writing, In the 2.6 kernel, the kernel module compilation does not need to define complicated cflags, and the file dependencies in the module are concise and clear.


Listing 4: makefile that can work in both the 2.4 and 2.6 kernels

#Makefile for 2.4 & 2.6VERS26=$(findstring 2.6,$(shell uname -r))MAKEDIR?=$(shell pwd)ifeq ($(VERS26),2.6)include $(MAKEDIR)/Makefile2.6elseinclude $(MAKEDIR)/Makefile2.4endif  

 

2.2 version check during module Loading

The Linux kernel has been updated and improved. Modules compiled under the kernel source code of Version A cannot run under the kernel of Version B. Therefore, there must be a mechanism, it is restricted that modules compiled and generated under kernel A are loaded under kernel B.

The 2.4 and 2.6 kernels have undergone fundamental changes in the version check mechanism for the mounted kernel module, but these changes are basically transparent to device-driven developers. To make the version check mechanism take effect during module loading, you only need to define

 

-DMODVERSIONS -include $(KDIR)/include/linux/modversions.h; 

 

In the 2.6 kernel, developers do not need to perform any operations.

However, it is necessary to clarify the version check mechanism of the 2.4 and 2.6 kernels for the loaded modules.

In the 2.4 kernel, run 'cat
/Proc/ksyms you can see that the kernel symbol is followed by a string of verification strings after the name, which is related to the kernel version. Linux/modules
There are many *. Ver files in the directory. These files play the role of adding a verification suffix to the kernel symbol, such as a line in the ksyms. Ver file.
# Define printk _ set_ver (printk ). The Linux/modversions. h file contains all the ver files.
. Therefore, after the module contains the Linux/modversions. h file, the kernel symbol used in the module is actually the kernel symbol with the verification suffix. When loading a module
The check string of the used kernel symbol is inconsistent with the check string of the corresponding kernel symbol exported by the current kernel.
"Invalid module format" is incorrect.

Adding a verification string to the kernel symbol to verify whether the module version matches the kernel version is complicated and wastes kernel space. In addition, with SMP (symmetric multi-processor), preempt (can be preemptible
Kernel) and other mechanisms are introduced and improved in the 2.6 kernel. The module runtime dependency on the kernel depends not only on the kernel version, but also on the Kernel configuration, at this time, whether the verification codes of kernel symbols are consistent cannot become a judgment Module
Sufficient Conditions for loading. 2.6
Vermagic_string is defined in Linux/vermagic. H. vermagic_string not only contains the kernel version number, but also contains the kernel
The GCC version used, SMP, preempt, and other configuration information. When the module is compiled, we can see that "modpost" is displayed on the screen ". In this phase,
Vermagic_string is added to the modinfo segment of the module.
In the kernel source code directory scripts/MoD/modpost. c file, you can see the code of the subsequent processing part of the module. After the module is compiled and generated, use 'modinfo
The mymodule. Ko command can view vermagic and other information of this module. 2.6
The module loader under the kernel stores the kernel version information. When loading the module, the loader compares the saved kernel vermagic with the one saved in The modinfo section of the module.
Whether vermagic information is consistent. Only when the two are consistent can the module be loaded. For example, both Fedora Core 4 and Core 2 use the 2.6 kernel,
The Hello. Ko compiled under fedora core4 is loaded under fedore Core 2, and "invalid module format" is displayed"
Error.

 

#insmod hello.koInvalid module format hello: version magic '2.6.11-1.1369_FC4 686 REGPARM 4KSTACKS gcc-4.0' should be '2.6.5-1.358 686 REGPARM 4KSTACKS gcc-3.3'

 

2.3 initialization and exit of the module

In kernel 2.6, the kernel module must call the macro module_init and module_exit () to register the initialization and exit functions. At 2.4
In the kernel, if the initialization function is named init_module () and the exit function is named cleanup_module (), you do not need to use module_init
And module_exit macro. We recommend that you use the module_init and module_exit macros to enable code to work in both the 2.4 and 2.6 kernels.


Listing 5: initialization and exit templates for modules in the 2.4 and 2.6 kernels

#include <linux/module.h>  /* Needed by all modules */#include <linux/init.h>    /* Needed for init&exit macros */static int mod_init_func(void){/*code here*/return 0;}static void mod_exit_func(void){/*code here*/}module_init(mod_init_func);module_exit(mod_exit_func);

 

Note that the initialization and exit functions must be defined before the macro module_init and module_exit functions are used. Otherwise, a compilation error occurs.

2.4 module usage count

When a module is used, it cannot be detached. 2.4 In the kernel, the module itself is managed through the mod_inc_use_count and mod_dec_use_count macros.
The Count used by the user. 2.6 The Kernel provides a more robust and flexible module counting management interface try_module_get (& module) and
Module_put (& module) replaces the module in 2.4 with the count management macro; the module's count usage does not have to be managed by itself, and the module's count usage considerations
The impact of SMP and preempt mechanisms.

Int try_module_get (struct module * module): used to increase the module usage count. If the return value is 0, the call fails. The expected module is not loaded or is being detached.

Void module_put (struct module * module): reduces the module usage count.

The introduction and use of try_module_get and module_put are closely related to the device model in the 2.6 kernel. The module is used to manage hardware devices. The 2.6 kernel defines the struct module * owner domain for different types of devices to point to the module that manages the device. For example, the definition of a character device:

 

struct cdev {struct kobject kobj;struct module *owner;struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;};

 

From the perspective of device usage, when you need to enable or start using a device, use try_module_get (Dev-> owner) to add
The usage count of the owner module. When you disable or stop using this device, use module_put (Dev-> owner) to reduce the usage of the owner module that manages this device.
Count. In this way, when the device is in use, the module managing the device cannot be detached; the module can only be detached when the device is no longer in use.

In the 2.6 kernel, developers who write drivers for specific devices do not need to use try_module_get and module_put, because the drive
The device owner module is usually used to support the owner module of a specific device. The counting manager module of this device is implemented based on a lower-level code in the kernel, such as a bus driver or a core module shared by such devices.
Device driver development.


Kernel symbol output by the module 2.5

2.4 In the kernel, non-static global variables and functions in the module are output to the kernel space after the module is loaded by default.

2.6
In the kernel, by default, non-static global variables and functions in the module are not output to the kernel space after the module is loaded. You need to explicitly call the macro export_symbol to output them. So in 2.6
In the kernel module, the call of the export_no_symbols macro is meaningless and is a null operation. In a device driver that supports both the 2.4 and 2.6 kernels, you can use the following code segment to output the module
The kernel symbol of the block.


Listing 6: Output kernel symbolic code segments of both 2.4 and 2.6 are supported.

#include <linux/module.h>#ifndef LINUX26EXPORT_NO_SYMBOLS;#endifEXPORT_SYMBOL(var);EXPORT_SYMBOL(func);

 

Note that to use export_symbol in the 2.4 kernel, you must define export_symtab in cflags; otherwise, the compilation will fail.

From the perspective of good code style, it is best to explicitly declare the global variables and functions used by other files in the module to be static without being output to the kernel space, the kernel symbol to be output is prefixed with the module name.

After the module is loaded, the kernel symbols output by the module can be viewed through/proc/ksyms and/proc/kallsyms in the 2.4 kernel.


2.6 command line input parameters of the module

When loading the kernel module, you can pass some parameters to the module, such as 'modprobe modname Var = value'. Otherwise, VAR uses the default value defined in the module.

In kernel 2.4, the macro module_parm (VAR, type) is defined in Linux/module. h)
It is used to pass command line parameters to the module. VaR is the variable name that accepts the parameter value. type is a string in the following format: [Min [-Max] {B, H, I, L, s }. Min and Max
It indicates the range of the number of elements allowed to be input when the parameter is of the array type; B: byte; H: short; I: int; L: long; s: string.

In the 2.6 kernel, macro module_parm (VAR, type) is no longer supported. The following macro is defined in the header file Linux/moduleparam. h:

 

module_param(name, type, perm)module_param_array(name, type, nump, perm)

 

Type can be byte, short, ushort, Int, uint, long, ulong, CHARP, bool or
Invbool, which no longer uses the string format in the 2.4 kernel. During module compilation, the type stated here is compared with the type defined by the variable to determine whether it is consistent.

Perm indicates the attributes of this parameter in the file node corresponding to the sysfs file system. 2.6 The kernel uses the sysfs file system, which is a file that is more powerful than proc in memory.
Component System. Sysfs file systems can be dynamic and real-time, reflecting the hardware, drivers, and other States in the current system at an organized level. When perm is 0, this parameter does not exist in the sysfs file system.
File nodes. After the module is loaded/
The directory named after this module appears. If this module has a command line parameter whose perm Is not 0, the parameters directory appears under the directory of this module, which contains a series of parameters
File node. The permission value of these files is equal to perm, and the file content is the parameter value.

Nump is the pointer to the variable that saves the number of input array elements. If you do not need to save the number of actually entered array elements, you can set it to null. From 2.6.0 to 2.6.10
Version, the variable name must be assigned to nump; from 2.6.10
At the beginning of the version, the reference of the variable must be assigned to nump, which is easier for developers to understand. When loading a module, use commas to separate the input array elements.


Listing 7: module input parameter templates for 2.4 and 2.6 kernels

#include <linux/module.h>#ifdef LINUX26#include <linux/moduleparam.h>#endif int debug = 0;char *mode = "800x600";int tuner[4] = {1, 1, 1, 1};#ifdef LINUX26int tuner_c = 1;  #endif #ifdef LINUX26MODULE_PARM(debug, "i");MODULE_PARM(mode, "s");MODULE_PARM(tuner,"1-4i");#elsemodule_param(debug, int, 0644);module_param(mode, charp, 0644);#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)module_param_array(tuner, int, &tuner_c, 0644);#elsemodule_param_array(tuner, int, tuner_c, 0644);#endif #endif

 

After the module compilation and generation, you can enter 'modprobe my_module mode = 1024x768 DEBUG = 1 tuner = 'when loading the module '.

In Linux/moduleparam. H, the following definitions are also defined:

 

module_param_array_named(name, array, type, nump, perm)module_param_call(name, set, get, arg, perm)module_param_named(name, value, type, perm)

 

For more information about these macros, see Linux/moduleparam. H. Note that in the 2.6 kernel, The module_param macros use lower-case names.

2.7 module license statement

Starting from version 2.4.10 kernel, the module must declare the license of this module through the module_license macro; otherwise, the kernel will be corrupted when loading this module.
Warning of "kernel tainted. From the Linux/module. h file, we can see that the license accepted by the kernel is "GPL", "GPL
V2 "," GPL and additional rights "," dual BSD/GPL "," dual
Mpl/GPL "," proprietary ".

In a device driver that supports both the 2.4 and 2.6 kernels, the module can declare its own license as follows.


Listing 8: module license declaration template for 2.4 and 2.6 kernels

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)MODULE_LICENSE("GPL");#endif

 

Conclusion 2.8

In addition, there are some module mechanisms in the 2.6 kernel, which are not often used by driver developers. For example, if the request_module interface for loading the kernel module is in 2.4
The value is request_module (const char * module_name). In the 2.6 kernel, the value is request_module (const
Char * FMT ,...). In the 2.6 kernel, the driver developer can call

 

request_module("msp3400");request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev));

 

This is a more flexible way to load other kernel modules.

The 2.6 kernel also provides the module_alias (alias) macro in Linux/module. The module can call this macro to define one or more of its specific terms. In the 2.4 kernel, the user can only define the alias for the module in/etc/modules. conf.

From the above comparison, we can see that the changes in the module management mechanism can be loaded from 2.4 to 2.6 kernel make the development of device drivers more concise, flexible, and robust.

 

References

  • Porting device drivers to the 2.6 kernel

About the author


Author: Zhou ting, software engineer, S3 graphics Shanghai R & D center, working direction: video decoding. Email: moting9@hotmail.com
.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.