From 2.4 to 2.6: the impact of changes in the Linux Kernel load module mechanism on Device Drivers

Source: Internet
Author: User

Introduction: from 2.4 to 2.6, the Linux kernel has greatly changed in terms of the module mechanism, device model, and some core APIs that can be loaded, device Driver developers are faced with the task of porting a driver from 2.4 to 2.6 kernel, or enabling the driver to support both 2.4 and 2.6 kernels. From the perspective of the device driver developer, the driver is composed of one or more external kernel modules that can be loaded. In this article, we will discuss the impact of the module Mechanism Changes in the 2.6 kernel on the compilation of the device driver program, compared with kernel 2.4 and 2.6 in terms of kernel module compilation, load version check, initialization and exit, module usage count, output kernel symbol, command line input parameters, and license Declaration difference; it also summarizes a series of templates that enable the device driver to support both the 2.4 and 2.6 kernels.
Labels in this article: from 2.4, the kernel, the impact of changes in the kernel-loaded module mechanism on the device driver (makefile), to 2.6: linux
 
 
Mark this article!
 
 
Released on: February 1, February 09, 2006
Level: elementary
Access status: 3751 views
Suggestion: 0 (add comments)

 
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

Back to Top
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.4
KVER = $ (shell uname-r)
KDIR =/lib/modules/$ (KVER)/build
OBJS = mymodule. o
CFLAGS =-d1_kernel _-I $ (KDIR)/include-DMODULE
-D1_kernel_syscils _-DEXPORT_SYMTAB
-O2-fomit-frame-pointer-Wall-DMODVERSIONS
-Include $ (KDIR)/include/linux/modversions. h
All: $ (OBJS)
Mymodule. o: file1.o file2.o
Ld-r-o $ @ $ ^
Clean:
Rm-f *. o

In the 2.4 kernel, The Makefile of the kernel module is the same in structure and syntax as the Makefile of a common user program, but the-D__KERNEL__-DMODULE must be defined in CFLAGS, specify the kernel header file directory-I $ (KDIR)/include. Note that the reason for defining variables in CFLAGS is not defined in the module source code file. On the one hand, these predefined variables can be visible to all source code files in the module, on the other hand, it is equivalent to defining these predefined variables 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.6
Ifneq ($ (KERNELRELEASE ),)
# Kbuild syntax. dependency relationshsip of files and target modules are listed here.
Mymodule-objs: = file1.o file2.o
Obj-m: = mymodule. o
Else
PWD: = $ (shell pwd)
KVER? = $ (Shell uname-r)
KDIR: =/lib/modules/$ (KVER)/build
All:
$ (MAKE)-C $ (KDIR) M = $ (PWD)
Clean:
Rm-rf. *. cmd *. o *. mod. c *. ko. tmp_versions
Endif

KERNELRELEASE is a variable defined in the top-level Makefile of the kernel source code. When this Makefile is read for the first time, KERNELRELEASE is not defined, so make will read the content after else is executed. If the target of make is clean, directly execute the clean operation and end. When the target of make is all,-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 the kernel source code directory is returned, KERNELRELEASE has been defined, and kbuild is also started to parse the kbuild syntax statement. make will continue to read the content before else. The preceding content of else is a statement in the kbuild syntax, which specifies 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.6
VERS26 = $ (findstring 2.6, $ (shell uname-r ))
MAKEDIR? = $ (Shell pwd)
Ifeq ($ (VERS26), 2.6)
Include $(MAKEDIR)/Makefile2.6
Else
Include $(MAKEDIR)/Makefile2.4
Endif
 

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 after the name, which is related to the kernel version. There are many linux/modules directories in the kernel source code header file *. server files, which are used to add verification suffixes to kernel symbols, such as ksyms. the ver file contains a line # 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, if the verification string of the kernel symbol used in the module is inconsistent with the verification string of the corresponding kernel symbol exported by the current running kernel, that is, the current kernel space does not have the kernel symbol used by the module, and the "Invalid module format" error will occur.
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 seize the kernel) and other mechanisms are introduced and improved in the 2.6 kernel. The dependency on the kernel during module running depends not only on the kernel version, but also on the Kernel configuration, at this time, the consistency of the kernel symbol Verification Code cannot be a sufficient condition for determining whether the module can be loaded. In the 2.6 kernel, VERMAGIC_STRING is defined in linux/vermagic. h. VERMAGIC_STRING not only contains the kernel version number, but also contains the gcc version used by the kernel, 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 section of the module. The script \ mod \ modpost. c file in the kernel source code directory shows the code for subsequent processing by the module. After the module is compiled and generated, run the 'modinfo mymodule. ko' command to view vermagic and other information about the module. 2.6 The module loader in the kernel stores kernel version information, the loader compares the stored kernel vermagic with the vermagic information saved in The modinfo segment of the module. 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. If hello ore Core 2 is used to load the hello. ko compiled under Fedora Core4, the "invalid module format" error will occur.

# Insmod hello. ko
Invalid module format
Hello: version magic '2. 6.11-1.1369 _ FC4 686 REGPARM 4 KSTACKS gcc-4.0'
Shocould be '2. 6.5-1.358 686 REGPARM 4 KSTACKS 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. In the 2.4 kernel, if the initialization function is named init_module () and the exit function is named cleanup_module (), you do not need to use the module_init and module_exit macros. 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 uses the MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros to manage its own counts. 2.6 The Kernel provides a more robust and flexible module counting management interface try_module_get (& module) and module_put (& module) to replace the module in section 2.4 with a counting management macro; the use of the module does not have to be managed by itself, and the impact of SMP and PREEMPT mechanisms on the use of the management module is considered.
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 increase the use count of the owner module that manages the device; when you disable or stop using this device, use module_put (dev-> owner) to reduce the use count of the owner module that manages this device. 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 driver written by the developer is usually the owner module that supports a specific device, the counting manager of the device owner module simplifies device driver development by implementing more underlying code in the kernel, such as bus drivers or core modules shared by such devices.
Back to Top
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, the 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 for output. Therefore, in the 2.6 kernel module, the call of the EXPORT_NO_SYMBOLS macro is meaningless and is a null operation. In device drivers that support both the 2.4 and 2.6 kernels, you can use the following code segment to output the kernel symbol of the module.

Listing 6: Output kernel symbolic code segments of both 2.4 and 2.6 are supported.
# Include <linux/module. h>
# Ifndef LINUX26
EXPORT_NO_SYMBOLS;
# Endif
EXPORT_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.
Back to Top
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) defined in linux/module. h 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 are used to indicate the number range of array elements that can 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)

The type can be byte, short, ushort, int, uint, long, ulong, charp, bool or invbool, and is no longer in the 2.4 kernel string format, during module compilation, the type stated here is compared with the type defined in 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 system that is more powerful than proc in memory. 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 the perm value is 0, this parameter does not exist in the file node of the sysfs file system. After the module is loaded, the directory named after this module appears under the/sys/module/directory. If this module has a command line parameter whose perm Is not 0, the parameters directory will appear under the directory of this module, which contains a series of file nodes named after the parameter name, 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, the variable name must be assigned to nump; from 2.6.10, 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 LINUX26
Int tuner_c = 1;
# Endif
# Ifdef LINUX26
MODULE_PARM (debug, "I ");
MODULE_PARM (mode, "s ");
MODULE_PARM (tuner, "1-4i ");
# Else
Module_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 );
# Else
Module_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 use the MODULE_LICENSE macro to declare the license for this module. Otherwise, the module will receive a warning that the kernel is contaminated with "kernel tainted. From linux/module. the valid licenses accepted by the kernel include "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, the request_module interface for loading the kernel module is request_module (const char * module_name) in 2.4, and request_module (const char * fmt,...) in 2.6 ,...). In the 2.6 kernel, the driver developer can call

Request_module ("msp3400 ");
Request_module ("char-major-% 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.

Author "programmer"

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.