Article directory
foreword
开发板以STM32MP157为例进行实验
.
Everything is difficult at the beginning, and so is writing a driver. This chapter will build the first driver. The relationship between the driver and the module is very close, so the relevant knowledge of the module will be explained in detail here. The prerequisite for the success or failure of module programming is to have a unified kernel version, so here will explain how to upgrade the kernel version. Finally, in order to improve the programming efficiency of programmers, two integrated development environments will be introduced here.
Kernel upgrade for development environment configuration
Building a correct development environment is very important for writing drivers. In the wrong development environment, the written driver cannot run correctly. Especially regarding the kernel version, if the kernel version does not match, the driver cannot run in the system, so the meshing needs to be upgraded. 实际以STM32MP157为例
, the reference tutorial takes ``Fedora Core9 as an example to upgrade the kernel. Pay attention to the distinction. First, explain why the kernel needs to be upgraded.
Why upgrade the kernel
内核时一个提供硬件抽象层、磁盘及文件系统控制、多任务等功能的系统软件。
According to whether the kernel has been modified, the kernel can be divided into 标准内核和厂商内核
two categories, as shown in the figure below.
标准内核源码和标准内核
The standard kernel source code refers to kernel.org
the standard code downloaded from the official website. It is the kernel code built by Linux kernel developers after rigorous testing. The standard kernel is the binary image file obtained after compiling the standard kernel source code, as shown in the left half of the figure above.
厂商内核源码和厂商内核
In some cases, distribution vendors make appropriate changes to the standard kernel source code to optimize the kernel's performance. This modified standard kernel source code is the kernel source code modified by the manufacturer. After compiling the kernel source code modified by the manufacturer, the kernel of the manufacturer's release version will be formed. So, the vendor distribution kernel is a modification and optimization of the standard kernel. Here, 需要注意的是,厂商发行版内核和标准内核对于驱动程序是不兼容的,根据不同内核源码编译的驱动程序是不能互用的。
两者兼容性问题
when building a driver module, the compatibility of the driver with the kernel must be considered. A kernel module built using standard kernel sources is a standard kernel module, which cannot be used in a vendor kernel. The kernel module built using the kernel source code modified by the manufacturer is the manufacturer's kernel module, which cannot be used in the standard kernel. Here, you can check the kernel version used 需要注意的是,即使模块代码相同,标准内核模块和特定厂商的内核模块,其模块格式也是不相同的。
by command.uname -r
kernel upgrade
Although many development boards can use the "package manager tool" to upgrade the kernel, after all, the kernel compiled by the developer has its limitations, and many modules that are not needed by the driver development system are added in it. module is not enabled. Therefore, it is also necessary to learn to manually compile and upgrade by yourself. For example, the steps to upgrade a kernel to linux 2.6.39.4
a kernel upgrade are as follows:
http://www.kernel.org/pub/linux/kernel
Download the kernel source package from abovelinux-2.6.29.4.tar.bz2
.mkdir linux-2.6.29.4
Create a directory in the root directory using- Copy the tarball into the created directory
- Enter the directory to decompress the source package
- Enter the second-level source code directory
- Execute
make menuconfig
configure kernel and save. ——For details, please refer to the characteristics of the manufacturer or development board - Compile the kernel
make
command - Compile the kernel module
make modules
- Install kernel modules
make modules_install
- install kernel
make install
- Use
reboot
restart the computer, select the new kernel to start the system.
After the kernel is upgraded successfully, you canuname -r
check the kernel version by command.
To save time, you can write a shell program. code show as below:
#! /bin/sh
cd /
mkdir linux-2.6.29.4
cp linux-2.6.29.4.tar.bz2 /linux-2.6.29.4/
cd linux-2.6.29.4
tar -xjvf linux-2.6.29.4.tar.bz2
cd linux-2.6.29.4
make menuconfig
make
make modules
make modules_install
make install
reboot
The shell file does not have executable permission, you need to use the command chmod
to make the shell file have executable permission, the command is as follows:
chmod a+x install-new-core
Then execute the shell file to automatically upgrade the kernel, use the following command:
./install-new-core
注意:对内核的升级并不会破坏现有的内核,也不会破坏系统上的文件等资源。内核升级以后,除了性能上的改变外,对用户来说就像什么也没有发生一样
。
Hello world driver
This section will lead readers to write the first driver module, the function of which is to output "Hello World" when loading; output "Goodbye World" when unloading. Although the driver module is simple, it also contains the important components of the driver module. At the beginning of this section, the important components of the module will be introduced.
Composition of the drive module
A driver module is mainly composed of the following parts:
图中的顺序也是源文件中的顺序。不按照这个顺序来编写驱动模块也不会出错,只是大多数开发人员都喜欢这样的顺序规范。
These structures are described below.
1、头文件(必须)
The driver module uses many functions in the kernel, so the necessary header files need to be included. 有两个头文件是所有驱动模块都必须包含的
.
#inlcude <linux/module.h>
#inlcude <linux/init.h>
module.h
The file contains a large number of symbols and function definitions needed to load the module. init.h
Contains the macro definition of the module load function and release function.
2、模块参数(可选)
Module parameters are parameters that need to be passed to the driver module when the driver module is loaded. If a drive module needs to complete two functions, then you can choose which function to use through the module parameters.
3、模块加载函数(必须)
The module loading function is a function that needs to be executed when the module is loaded.
4、模块卸载函数(必须)
The module unload function is the function that needs to be executed when the module is unloaded. The module
5、模块许可声明(必须)
license statement indicates the degree to which the module is supported by the kernel. Modules with permissions will be more valued by developers. Requires MODULE_LICENSE
permission to use that represents the module. The permissions recognized by the kernel are as follows:
MODULE_LICENSE("GPL"); /*任一版本的GNU公告许可权*/
MODULE_LICENSE("GPL v2"); /* GPL版本2许可权*/
MODULE_LICENSE("GPL and additional rights"); /*GPL及其附加许可权*/
MODULE_LICENSE("Dual BSD/GPL"); /*BSD/GPL双重许可权*/
MODULE_LICENSE("Dual MPL/GPL"); /*MPL/GPL双重许可权*/
MODULE_LICENSE("Proprietary"); /*专有许可权*/
If a module does not contain any permissions, it is considered non-compliant. At this time, when the kernel loads such a module, it will receive a warning that the kernel loads a non-standard module. Developers don't like maintaining kernel modules that don't follow the standard permissions.
Take the GPL as an example to illustrate the meaning of license rights. GPL is the abbreviation of General Public License, which means General Public License. The GNU General Public License guarantees your freedom to distribute free software; guarantees that you can receive the source program or get it when you need it; guarantees that you can modify the software or use parts of it in new free software.
Hello World module
Almost any book about programming starts with "Hello World". Now, let's look at the simplest driver module.
#include <linux/init.h> /*定义了一些相关的宏*/
#include <linux/module.h> /*定义了模块需要的*/
static int hello_init(void)
{
printk(KERN_ALERT "Hello World\n"); /*打印 Hello World*/
return 0;
}
static void hello_exit(void)
{
printk(KERNEL_ALERT "Goodbye World\n"); /*打印Goodbye World*/
}
module_init(hello_init); /*指定加载模块函数*/
module_exit(hello_exit); /*指定模块卸载函数*/
MODULE_LICENSE("Dual BSD/GPL"); /*指定许可权为Dual BSD/GPL*/
Source code analysis:
- Lines 1~2 are two necessary header files
- Lines 3~7 are the loading function of the module,
insmod
which will be called when the module is loaded with the command. - Lines 8~11 are the release function of the module, which
rmmod
will be called when the module is uninstalled with the command - Line 12
module_init
is a macro of the kernel module. It is used to declare the loading function of the module, that is,insmod
the function called when the module is loaded using the commandhello_init()
. - Line 13
module_exit
is also a macro of the kernel module. Used to declare the release function of the module, that is,rmmod
the function called when the module is unloaded with the commandhello_exit()
. - Line 14, using
MODULE_LICENSE()
the specification that the code follows, the module code follows the dual specification of BSD and GPL. These specifications define copyright issues in the distribution of modules.
Compile the Hello World module
When compiling the Hello World module, certain conditions need to be met.
1、编译内核模块的条件
Correctly compiling a kernel module meets some important prerequisites:
I. The reader should make sure to use the correct versions of the build tools, module tools, and other necessary tools. Different versions of the kernel require different versions of compilation tools.
II. There should be a kernel source code, and the version of the source code should be consistent with the kernel version currently used by the system.
III. The kernel source code should be compiled at least once, that is, make
the command has been executed.
2、Makefile文件
Compiling the Hello World module requires writing a Makefile
file. Let's take a look at a complete Makefile first, so as to have an overall understanding of the file.
ifeq ($(KERNELRELEASE),)
KERNELDIR ?= /linux-2.6.29.4/linux-2.6.29.4
PWD := $(shell pwd)
modules:
$(MAKE) -C $(KERNELDIR) M= $(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M= $(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
else
obj-m := hello.o
endif
Makefile analysis
- 1 line, to determine
KERNELRELEASE
whether the variable is empty, the variable is a string describing the kernel version. Onlymake
when the current directory where the command is executed is the kernel source code directory, this variable is not a null character. - Lines 2~3 define
KERNELDIR
andPWD
variables.KERNELDIR
Is the kernel path variable, which is the current module path obtainedPWD
by executing the command.pwd
- Line 4 is an identifier, ending with a colon, which identifies a functional option of the Makefile.
- The syntax of line 5
make
is "Make -C kernel path M=module path modules". This statement executes the compilation of the kernel module - The 6-line and 4-line marks have the same meaning.
- Line 7 is to install the module into the path corresponding to the module. When the command is executed
make modules_install
, the command is executed, and it is not executed at other times. - Line 8 is to delete redundant file identifiers
- Line 9 is the command to delete the intermediate files of the compilation process
- Line 11,
意思是将hello.o编译成hello.ko
module. If you want to compile other modules, just changehello.o
inhello
to the file name of the module.
3、Makefile文件的执行过程
The execution process of the Makefile is somewhat complicated. In order to give readers a clear understanding of the execution process of the file, the following figure is used for analysis.
After executing make
the command, the Makefile will be entered. At this time KERNELRELEASE
, the variable is empty, and it is the first to enter the Makefile at this time. After executing 2 or 3 lines of code, make
different logic will be executed according to the parameters of the command, as follows:
make modules_install
command, will execute lines 6 and 7 to install the module into the operating system.make clean
command, which deletes all temporary files in the directorymake
The command will execute 4 or 5 lines to compile the module.$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
The option in the first-C $(KERNELDIR)
will make the compilation enter the kernel source code directory/linux-2.6.29.4/linux-2.6.29.4
, read the Makefile file, and get some information from it, such as variablesKERNELRELEASE
will be assigned here. After reading the Makefile in the kernel source code directory, the compiler willM=$(PWD)
enter the directory where the module is located for the second time according to the options, and execute the Makefile again. When the second Makefile is executed, theKERNELRELEASE
value of the variable is the kernel release version information, that is, it is not empty. At this time, lines 10, 11, and 12 of the code will be executed. The code here indicates the dependencies of each file in the module source code and the name of the target module to be generated. Here, the module is officially compiled.
Module operation
Linux provides modutils
tools for users to manipulate modules. This toolset mainly includes:
insmod
command to load the module. Useinsmod hello.ko
loadablehello.ko
modules. The function is called automatically after the module is loadedhello_init()
. This function prints the "Hello World" message. If you don't see the message in the terminal, the message was sent to/var/log/message
the file. You can usedemsg | tail
the command to view the last few lines of the file. If the module has parameters, the following format can be used to pass parameters to the module:insmod 模块.ko 参数1=值1 参数2=值2 参数3=值3 /*参数之间没有逗号*/
rmmod
command to unload a module.rmmod hello.ko
Execution can unload the module if it is not being usedhello.ko
.modprobe
The command is a relatively advanced load and delete module command, which can solve the dependency problem between modules. Will be introduced later.lsmod
The command lists the loaded module information.insmod hello.ko
You can knowhello.ko
whether the module is loaded by executing this command before and after.modinfo
The command is used to query module-related information, such as author, copyright, etc.
File system changes after the Hello World module is loaded
insmod hello.ko
What happens to the file system when the module is loaded ? The file system stores attribute information about modules. Programmers can know the current state of the module in the system from these attribute information, and these states are very important for development and debugging.
/proc/modules发生变化,在modules文件中会增加如下一行
:
The information in these fields is the module name, memory used, reference count, delimiter, activity status, and address loaded into the kernel.
lsmod
The command /proc/modules
lists the module information currently loaded by the kernel by reading the file. lsmod
Removed some information and made the display more tidy. lsmod
The structure of the execution command is as follows:
/proc/devices文件没有变化,因为hello.ko模块并不是一个设备模块
.
在/sys/module/目录会增加hello这个模块的基本信息
在/sys/module/目录下会增加一个hello目录。该目录中包含了一些以层次结构组织的内核模块的属性信息。使用tree -a hello目录可以得到下面的目录结构
.
Module parameters and communication between modules
In order to increase the flexibility of the module, parameters can be added to the module. Module parameters can control the internal logic of the module. In this way, the module can perform different functions under different circumstances. The module parameters are firstly introduced below.
module parameters
Applications for space can accept user parameters, and device drivers sometimes need to accept parameters. For example, a module can implement two similar functions. At this time, a parameter can be passed to the driver module to determine which function it uses. The parameters need to be specified when loading the module, for example, insmod xxx.ko param=1
you can use "module_param(parameter name, parameter data type, parameter read and write permission)" to define parameters for the module. For example, the following code defines a long integer and an integer parameter:
static long a = 1;
static int b = 1;
module_param(a, long, S_IRUGO);
module_param(b, int , S_IRUGO);
The parameter data type can be byte、short、ushort、int、uint、long、ulong、bool、charp(字符指针类型)
. Careful readers can see that there is no floating-point type among the types of module parameters. This is because the kernel does not perfectly support floating-point operations. When using floating-point numbers in the kernel, there are some trivial things to do besides manually saving and restoring floating-point number registers. As an example to avoid trouble usually do not use floating point numbers in the kernel. In addition, printk()
the function does not support floating point types.
Module file format ELF
Knowing what format the modules are stored on the hard disk is necessary to understand how the modules communicate with each other. You can use file
the command to know the file format hello.ko
used by the module ELF
. The command is as follows:
This command is often used in the development of linux drivers, please pay attention to its usage.
The figure below describes the overall structure of the ELF object file. In the figure, some cumbersome structures of ELF are omitted, and the main structure is extracted to form the basic structure diagram of the ELF file shown in the figure below.
ELF Header
The header is at the very front of the file. It contains the basic attributes describing the entire file, such as ELF file version, target machine model, program entry address, etc..text
Indicates the code segment, which stores the code part of the file..data
Represents the data segment, storing initialized data, etc..Section Table
The table describes the information of all segments contained in the ELF file, such as the segment name of each segment, the length of the segment, the offset in the file, read and write permissions, and other attributes of the segment..symtab
Represents a symbol table. A symbol table is a data structure that maps functions to real memory addresses. It is like a dictionary, which records functions whose addresses cannot be determined during the compilation phase. The symbol table will be assigned a real memory address by the system during the module file loading stage.
Communication between modules
Modules are designed to accomplish a specific task. Its function is relatively simple, in order to enrich the function of the system, so the communication between the modules is often carried out. They can share variables and data structures, and can also call functions provided by each other.
As shown in the figure below, analyze how module 1 calls the function of module 2. In order to clarify this process, we need to start with the loading of module 2.
The loading process of module 2 is as follows:
(1) Use insmod 模块2.ko
loading block 2
(2) The kernel allocates space for module 2, and then loads the code and data of the module into the allocated memory.
(3) The kernel finds that function 1 and function 2 can be exported in the symbol table, so 将其内存地址记录在内核符号表中
.
When module 1 is loaded into the kernel, the system will perform the following operations:
(1) insmod
The command will allocate space for the module, and then load the code and data of the module into the memory. (2) The kernel found some unresolved functions in
the symbol table ( ) of module 1 . symtab
These unanalyzed functions in the figure above are "function 1" and "function 2", and these functions are located in the code of module 2. Therefore, module 1 will find the corresponding function through the kernel symbol table, and fill the function address into the symbol table of module 1.
After passing the loading process of module 1, module 1 can use "function 1" and "function 2" provided by module 2.
Example of communication between modules
This example introduces the communication between modules through two modules. The module add_sub
provides two exported functions add_integer()
and sub_integer()
, which respectively complete the addition and subtraction of two numbers. The module test
is used to debug add_sub
the two methods provided by the module to complete the operation of addition or subtraction.
1、add_sub模块
An addition function and a subtraction function are provided in the module add_sub, and its add_sub.c file is as follows:
#inlcude <linux/init.h>
#include <linux/module.h>
#include "add_sub.h"
long add_integer(int a, int b)
{
return a+b;
}
long sub_integer(int a, int b)
{
return a-b;
}
EXPORT_SYMBOL(add_integer); /*导出加法函数*/
EXPORT_SYMBOL(sub_integer); /*导出减法函数*/
MODULE_LICENSE("Dual BSD/GPL");
This file defines an addition and subtraction function, which 两个函数需要导出到内核符号表
can be called by other modules. EXPORT_SYMBOL
Just export the macro. The function of this macro is to let the kernel know that the function it defines can be used by other functions.
Using EXPORT_SYMBOL
make a function as an exported function is convenient, but not casual. There are millions of lines of code and tens of thousands of functions in a Linux kernel source code, and functions with the same name are likely to appear in modules. Fortunately, the compiler thinks that the functions in the module are private, and the same function name in different modules will not affect the compilation, provided that the export EXPORT_SYMBOL
symbols cannot be used.
In order to test the functionality of the module add_sub, another test module is created here. The test module needs to know which functions are provided by the add_sub module, so a add_sub.h
header file is defined, the code is as follows:
#ifndef _ADD_SUB_H_
#define _ADD_SUB_H_
long add_integer(int a, int b);
long sub_integer(int a, int b);
#endif
2、test模块
The test module is used to test the two methods provided by the add_sub module, and the test module can also accept one AddOrSub
to decide whether to call add_integer()
a function or sub_integer()
a function. When AddOrSub
it is 1, add_integer()
the function is called; when AddOrSub
it is not 1, sub_integer()
the function is called. The code of the test module is as follows:
#include <linux/init.h>
#include <linux/module.h>
#include "add_sub.h" /*不要使用<>包含文件,否则找不到该文件*/
/*定义模块传递的参数a, b*/
static long a = 1;
static long b = 1;
static int AddOrSub = 1;
static int test_init(void) /*模块加载函数*/
{
long result = 0;
printk(KERN_ALERT "test init\n");
if(1==AddOrSub)
{
result=add_integer(a, b);
}
else
{
result=sun_integer(a, b);
}
printk(KERN_ALERT "The %s result is %ld", AddOrSub==1?"Add":
"Sub", result);
return 0;
}
static void test_exit(void) /*模块卸载函数*/
{
printk(KERN_ALERT "test exit\n");
}
module_init(test_init);
module_exit(test_exit);
module_param(a, long, S_IRUGO);
module_param(b, long, S_IRUGO);
module_param(AddOrSub, int, S_IRUGO);
/*描述信息*/
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Jacky Hu");
MODULE_DESCRIPTION("A module for testing module params and EXPORT_SYMBOL");
MODULE_VERSION("V1.0");
3、编译模块
Compile the two modules separately to obtain two module files. add_sub
The Makefile of the module is different from the Makefile of the Hello World module. In add_sub
the Makefile of the module, the variable PRINT_INC
represents add_sub.h
the directory where the file is located, and the file declares the prototypes of the add_integer() function and the sub_integer() function. EXTRA_CFLAGS
The variable indicates the directory that needs to be added when compiling the module. The compiler will find the required header files from these directories. add_sub
The Makefile of the module is as follows:
ifeq($(KERNELRELEASE),)
KERNELDIR ?=/linux-2.6.29.4/linux-2.6.29.4
PWD := $(shell pwd)
PRINT_INC = $(PWD)/../include
EXTRA_CFLAGS += -I $(PRINT_INC)
modules:
$(MAKE) -I $(PRINT_INC) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_version
.PHYONY:modules modules_install clean
else
#called from kernel build system: just declare what our modules are
obj-m := add_sub.o
endif
The Makefile of the test module is shown in the following code. SYMBOL_INC
is the include directory, which contains the add_sub.h
header files. This file defines two functions that are called in the test module. KBUILD_EXTRA_SYMBOLS
Contains add_sub
the symbol table file generated when compiling the module Module.symvers
, which lists add_sub
the address of the function in the module. This symbol table is required when compiling the test module.
obj-m := test.o
KERNELDIR ?= /linux-2.6.29.4/linux-2.6.29.4
PWD := $(shell pwd)
SYMBOL_INC = $(obj)/../include
EXTRA_CFLAGS += -I $(SYMBOL_INC)
KBUILD_EXTRA_SYMBOL=$(obj)/../print/Module.symvers
modules:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
.PHONY:modules modules_install clean
4、测试模块
Before loading the test module, you need to load the add_sub module first, so that the test module can access the export functions provided by the add_sub module. The command is as follows:
use insmod
the load module and pass parameters to the module. Parameters AddOrSub=2
indicate execution. A test directory will be created a-b
under /sys/module/
the directory, in which you can clearly see that there are 3 files under paramters, each representing 3 parameters.
add the module to the kernel
After compiling the module, if you want the module to start together with the system, you need to install the module 静态编译进内核
. To statically compile a module into the kernel, some necessary steps need to be completed.
Add modules to the kernel
To add a driver module to the Linux kernel, three tasks need to be completed:
(1) Write the driver program file
(2) Put the driver program file into the corresponding directory of the Linux kernel source code. If there is no suitable directory, you can create a directory for storage driver files.
(3) Kconfig
Add the project compilation selection corresponding to the new driver in the file in the directory.
(4) Makefile
Add the compilation statement of the new driver to the file in the directory.
Kconfig
Kconfig
There are two files and in the directory of the kernel source tree Makefile
. The files distributed into the directories Kconfig
make up a 分布式的内核配置数据库
, 每个Kconfig文件分别描述了所属目录源文档相关的内核配置菜单
. When configuring the kernel make menuconfig(或xconfig等)
, the menu is read Kconfig
from it , and the user selects it and saves .config
it in the kernel configuration file. When the kernel is compiled, the user's choice is known Makefile
by calling this file in the main directory. The above content shows that Kconfig is the configuration menu corresponding to the kernel. If you want to add a new driver to the kernel source, you need to modify the file. In order to make readers have an intuitive understanding of the file, here is a simple example, this example is the IIC driver. The source code of the I2c device driver is included in the linux-2.6.29.4/drivers/i2c directory, and its directory structure is as follows: This directory contains a Kconfig file, which contains configuration options. This script in the above file configures the options. This option is a tri-state configuration option, which means module . When the option is Y, it means compiling into the kernel; when the option is M, it means compiling as a module; when the option is N, it means not compiling. As shown in the figure below, the "I2C device interface" option is set to M, which means it is compiled as a kernel module. The following content is help information,.config
Kconfig
Kconfig
I2C_CHARDEV
Kconfig
I2C_CHARDEV
tristate
要么编译为内核,要么编译为内核模块
help
在单击“快捷键?”时,会显示帮助信息。
Kconfig syntax
The Kconfig syntax is relatively simple, and its syntax Documentation/kbuild/kconfig-language.txt
is introduced in the file. In summary, the grammar of Kconfig mainly includes the following aspects.
1、主要语法总览
The Kconfig configuration file describes a series of menu entries. Except for help information, each line begins with a keyword, and these keywords are as follows:
config
menuconfig
choice/endchoice
comment
menu/endmenu
if/endif
The first 5 keywords all define a menu option, if/endif
which is a conditional option. Some commonly used menu syntaxes are described below.
2、菜单入口(config)
Most kernel configuration options correspond to a menu in Kconfig, which can be make menuconfig
displayed in , as follows:
config MODVERSIONS
bool "Set version infomation on all module symbols"
depends on MODULES
help
Usually, modules have to be recompiled whenever you switch to a new kernel...
Each line begins with a keyword and can have multiple parameters. config
keyword defines a new configuration option, and the following lines define the properties of that configuration option. Properties can have types, input prompts, dependencies, help information, default values, etc.
Two identical configuration options can appear, but each option can only have one input prompt and the types must not conflict.
Each configuration option must specify a type, including bool、tristate、string、hex和int
, where tristate和string
are the two basic types on which other types are based. A bool type is defined as follows:
The type definition is followed by input prompts that will be displayed in the configuration menu. The following two methods can be used to input prompts:
Method 1:
bool "Neworking support"
Method 2:
bool
prompt "Networking support"
The general syntax for an input prompt is as follows:
prompt <prompt> ["if" <expr>]
where prompt
is a keyword that represents an input prompt. <prompt>
is a prompt message. Optionals if
are used to indicate dependencies for this hint.
The syntax for default values is as follows:
default <expr> [if <expr>]
A configuration option can have multiple default values, but only the first default value is valid. Only config
options may configure default values.
The dependencies are as follows:
depends on <expr>
If multiple dependencies are defined, you can use "&&" to connect to indicate the relationship with. Dependencies can be applied to all other selections in the menu, the following two examples are equivalent.
Example 1:
bool "foo" if BAR #如果定义BAR选项,那么就使能foo选项
default y if BAR #如果定义BAR选项,那么foo的默认值就是y,表示编译入内核
Example 2:
depends on BAR # foo选项的可配置与否,依赖于BAR选项
bool "foo"
default y
depends
The ability to define an config
option, that is, if A depends on B, then in the case where B is configured as Y, A can be Y, M, N; in the case where B is configured as M, A can be M, N ; When B is configured as N, A can only be N, indicating that this function is disabled.
help(或者---help---)
begin
...
end
You can use "help" or "--help-" to define help information. Help information can give hints when developers configure the kernel.
3、菜单结构(menu)
The menu structure is generally used as the parent menu of the menu entry. The position of a menu entry in the menu structure can be determined in two ways. The first way is as follows:
menu "Network device support"
depends on NET
config NETDEVICES
...
endmenu
menu
and endmenu
are the keywords of the menu structure, and the options in it config
are menu entries. Menu entries NETDEVICES
are Network device support
submenus of the menu structure. depends on NET
Is menu
a dependency of the main menu, and only if configured , the menu item NET
can be configured . Network device support
Moreover, all submenu options will inherit the dependencies of the parent menu, for example, the dependencies Network device support
on NET
will be added to NETDEVICES
the dependencies of the configuration options.
The second way is to generate the menu structure by analyzing dependencies. If a menu option depends to some extent on another menu option, it becomes a submenu of that option. If the parent menu option is Y or M, then the submenu is visible; if the parent menu is N, then the submenu is not visible. For example:
config MODULES
bool "Enable loadable module support"
config MODVERSIONS
bool "Set version information on all module symbols"
depends on MODULES
comment "module support disabled"
depends on !MODULES
From the statement "depends on MODULES", it can be seen that MODVERSIONS
it is directly dependent on MODULES
, so MODVERSIONS
it is MODULES
a submenu of MODULES. If MODULES
not N, then MODVERSIONS
it is visible.
4、选择菜单(choice)
A selection menu defines a set of options. The type of this option can only be boolean
or tristate
type. The syntax for this option is as follows:
"choice"
<choice options>
<choice block>
"endchoice"
The menu can be used when a piece of hardware has multiple drivers choice
, and choice
only one driver can be compiled into the kernel by using the menu. choice
Another option that the menu can accept is optional
such that the option is set to N, indicating that the kernel is not selected.
5、注释菜单(comment)
The Comments menu defines comments displayed to the user during configuration. This comment can also be output to a file for viewing. The syntax for comments is as follows:
comment <prompt>
<comment options>
The only attribute that can be defined in annotations is dependencies, other attributes cannot be defined.
Application example: add add_sub module in the kernel
A comprehensive example is explained below, assuming that we are going to add a module to the kernel add_sub
. Considering add_sub
the function of the module, it is decided to add the module to drivers
the directory of the kernel source code. drivers
Add a subdirectory to the directory add_sub_Kconfig
. add_sub
The source code directory of the module add_sub_Kconfig
is as follows:
subdirectories are added to the kernel, and files Kconfig
and Makefile
files for the corresponding directories need to be created in order to configure and compile the module. Kconfig
At the same time, the and files in the parent directory of the subdirectory Makefile
also need to be modified so that Kconfig
the and Makefile
files in the subdirectory can be referenced.
In the newly added add_sub_Kconfig
directory, the following Kconfig
files should be included:
#
# add_sub configuration
#
menu "ADD_SUB" #主菜单
comment "ADD_SUB"
config CONFIG_ADD_SUB #子菜单,添加add_sub模块的功能
boolean "ADD_SUB support"
default y
#子菜单,添加test模块的功能,只有配置CONFIG_ADD_SUB选项时,该菜单才会显示
config CONFIG_TEST
tristate "ADD_SUB test support"
depends on CONFIG_ADD_SUB #依赖CONFIG_ADD_SUB
default y
endmenu
Since ADD_SUB
it is a new function for the kernel, it is first necessary to create a ADD_SUB
menu; then use comment
the display ADD_SUB
to wait for the user to select; then judge whether the user has selected ADD_SUB, if ADD_SUB is selected, then ADD_SUB support will be displayed, and the default setting of this option is Y , which means compiled into the kernel. Next, if ADD_SUB support is configured as Y, that is, the variable CONFIG_ADD_SUB=y, then ADD_SUB test support will be displayed, this option depends on CONFIG_ADD_SUB. Since CONFIG_TEST can be compiled into the kernel or as a kernel module, the option type here is set to tristate
.
In order to make this Kconfig
file work, you need to modify the linux-2.6.29.4/drivers/Kconfig file, and add the following content at the end of the file:
source "drivers/add_sub_Kconfig/Kconfig"
means in the script source
to refer to the new Kconfig file, and the parameter is the relative path name of the Kconfig file. At the same time, in order to enable add_sub
the test
module to be compiled, add_sub_Kconfig
a Makefile needs to be added to the directory. The Makefile is as follows:
obj-$(CONFIG_ADD_SUB) +=add_sub.o
obj-$(CONFIG_TEST) +=test.o
The variables CONFIG_ADD_SUB
and CONFIG_TEST
are Kconfig
the variables defined in the file. The script is based on the value of the configuration variable 构建obj-*列表
. For example , when obj-$(CONFIG_ADD_SUB)
it is equal obj-y
to, it means to build add_sub.o
the module and compile it into the kernel; when obj-$(CONFIG_ADD_SUB)
it is equal obj-n
to, it means not to build add_sub.o
the module; when obj-$(CONFIG_ADD_SUB)
it is equal obj-m
to, it means to compile the module separately and not put it into the kernel.
In order to make the entire add_sub_Kconfig
directory attract the attention of the compiler, add_sub_Kconfig
the Makefile in the parent directory drivers also needs to add the following script:
obj-$(ADD_SUB) +=add_sub_Kconfig/
add_sub_Kconfig
Add obj-$(ADD_SUB)+=add_sub_Kconfig/ in linux-2.6.29.4/drivers/Makefile, so that the user can enter the directory when compiling the kernel . The new add_sub_Kconfig tree directory after adding Kconfig and Makefile files is as follows:
Configure the add_sub module
After the source file of the add_sub module is added to the kernel source code, it needs to be configured before the module can be compiled. The configuration steps are as follows:
(1) Execute the command in the kernel source code directory make menuconfig
.
(2) Select Device Drivers
Options, and then select Select
Options.
(3) Select the ADD_SUB option in the entered interface, which is menu
defined by the menu in the Kconfig file, and then select the Select option.
(4) As shown in the figure below, there are two options, ADD_SUB support and ADD_SUB test support, to choose from. Among them ADD_SUB support
is ADD_SUB test support
the parent option, which ADD_SUB support
can only be ADD_SUB test support
selected when it is selected. The figure *
means selected; if it is empty, it means not selected.
summary
This blog mainly explains how to build a driver. First explained why the kernel should be upgraded. Then the Hello World program is briefly introduced. On this basis, the communication between modules is explained in detail, which are the basis of driver program development. Finally, it explains how to add the module to the kernel and let the module run.