adopt 《 teach-by-doing Linux drive 1- Modular programming 》 Learning from , We've learned how to load a module into the kernel , Now let's learn how to pass parameters between modules .

One 、 Pass parameters to the module

When we load a module into Linux Kernel time ,Linux The kernel allows you to pass some parameters to this module . The advantage of this design is , Let's make our module more flexible , We can accomplish different functions by passing different parameters to it .

for example : Let's write a modular program , To complete the hardware interrupt operation . stay Linux Operating system , Each interrupt has an interrupt number . If we write the interrupt number dead in the module , Then our module can only respond to specific interrupts . If we pass the interrupt number as a parameter to our module , Then our module can complete the operation of different interrupts .

How to pass parameters to the module ? It's simple ,Linux The kernel is ready for us , We just need to call the corresponding interface .
(1) It's in the module , Declare a variable ( Global variables ), It is used to receive the parameters passed by the user when loading the module
The file location is as follows :linux-3.14\include\linux\ Moduleparam.h

 The function prototype :module_param(name,type,perm) Parameters :
@name The name of the variable used to receive the parameter
@type Data type of parameter
@perm Specify parameter access .

 Insert picture description here

Parameters of each module , It's going to end up in sysfs File system , That is to say, in the end, it will be in the system
/sys/module/ Module name /parameters/ You can see the file named by the parameter name under the path . The permissions of this file are the permissions specified here . If perm The value of is 0, It's in sysfs The file system does not generate the file corresponding to the parameter .

Typical use cases :
We can do it in modules (test.ko) Write the following code inside , Receive the parameters passed by the user when loading the module

static unsigned int var=0;module_param(var,uint,0400);

When loading a module , Pass parameters :

insmod test.ko var=100

Finally, the global variables in the module var The value is 100 了 .
If I want to pass a string to the module , How do I do that ?

static char *string;module_param(string,charp,0400);

When loading a module , Pass parameters :

insmod test.ko string="PENG";

Someone might ask , Does this code have bug, Because of you. string A pointer is a wild pointer .
In fact, the kernel will automatically allocate space for strings passed by users , And then use string The pointer holds the first address of the string in memory .

(2) Make the name of the variable inside the module different from the parameter name passed when loading the module
The function prototype :

module_param_named(name_out,name_in,type,perm); Parameters :
@name_out When loading modules , Parameter name
@name_in The name of the variable inside the module
@type  Parameter type
@perm  Access right 

Typical use cases :

static int var =0;module_param_named(var_out,var,int,0400);

When loading a module , Pass parameters :

insmod test.ko var_out=100

var_out It's module variables var The name on the outside , here var The value of is 100

(3) When loading a module , Pass the string to a global character array of the module
The function prototype :

module_param_string(name,string,len,perm); Parameters :
@name When loading modules , Parameter name
@string The name of the character array inside the module
@len  The size of the character array inside the module
@perm  Access right 

Typical use cases :

static int buffer[LEN];module_param_string(buffer_out,buffer,LEN,0400);

When loading a module , Pass parameters :

insmod test.ko buffer_out="hello word"

Um. , When loading a module , The kernel puts "hello word" The character serial port is copied to buffer Array .
(4) When loading a module , Pass parameters to an array of modules
The function prototype :

module_param_arry(name,type,num_point,perm); Parameters :
@name  The array name of the module , Is also an externally specified parameter name
@type The data type of the module array
@num_point It is used to obtain the number of parameters passed by the user when loading the module ,NULL: Don't care about the number of parameters passed by the user
@perm  Access right 

Typical use cases :

static int my_arry[3];int num;module_param_arry(my_arry,int,&num,0400);

When loading a module , Pass parameters :( Multiple parameters with ”,“ separate )

insmod test.ko my_arr=1,2,3

Be careful : When the above interfaces are called ,perm The specified permissions do not allow normal users to have write permissions , Otherwise the compilation will report an error

(5) Specify a description information function prototype for each variable receiving user parameters in the module :

MODULE_PARM_DESC(name,describe); Parameters
@name  Variable name
@describe A string describing information 

Now let's achieve the following :
 Insert picture description here  Insert picture description here

The test results are as follows :
 Insert picture description here

At the same time in the directory /sys/module/hello/parameters Next generation of the corresponding file node , The file permissions are one-to-one corresponding to those defined in the code :
 Insert picture description here

The content of all nodes can be used cat Command view
 Insert picture description here

Switch to administrator mode , Can pass echo Command modification has W Permission file :

 Insert picture description here

Two 、 Module symbol export

(1) What are symbols ?
The symbols here mainly refer to global variables and functions .
(2) Why export symbols ?

Linux The kernel uses the modular form to manage the kernel code . Each module in the kernel is independent of each other , in other words A Global variables and functions of modules ,B Modules are inaccessible .
Sometimes , When we write some module code , Some functions have been realized by others , At this point, we thought that if only we could call the function interface that they have already implemented . So how can we do that ? The symbol is exported , That is to say, you can export the function interfaces and global variables that you implement , For other modules .
stay Linux In the world of the kernel , If a module has been statically compiled into the kernel , Then the symbols it exports will appear in the global kernel symbol table . stay Ubuntu 14.04 In the system ,Linux The global symbol table of the kernel is in /usr/src/linux-headers-3.2.0-29-generic-pae/Module.symvers In the file . If you open this file , You can see that the content is :
Addr-------> Symbol name ------> Module name ------> The macro that exports the symbol
 Insert picture description here

(3) How to export symbols ?
Linux The kernel provides us with two macros :

EXPORT_SYMBOL(name);EXPORT_SYMBOL_GPL(name);

Any of the above macro definitions makes the given symbol available outside the module .GPL Version of the macro definition can only make symbols pair to GPL Licensed modules are available . Symbols must be output in the global part of the module file , Outside of any function , Because a macro definition extends to a declaration of a variable that is intended for a particular purpose and is expected to be globally accessible .
(4) Module compile time , How to find symbols to use ?

  • a. In the symbol table of this module , Looking for symbols ( Function or variable implementation )
  • b. Look for... In the kernel global symbol table
  • c. In the module Directory Module.symvers Looking in the file

Case presentation

modular A Export global variables global_var And the function show Two symbols for the module B Use .
A modular

#include <linux/init.h>#include <linux/module.h>static int global_var = 100;static void show(void){printk("show():  global_var =%d \n",global_var);}static int hello_init(void){printk("module b :global_var=%d\n",global_var);return 0;}static void hello_exit(void){printk("hello_exit \n");return;}EXPORT_SYMBOL(global_var);EXPORT_SYMBOL(show);MODULE_AUTHOR("PENG");MODULE_LICENSE("GPL");module_init(hello_init);module_exit(hello_exit); #include <linux/init.h>

B modular

#include <linux/module.h>extern int global_var;extern  void show(void);static int hello_init(void){printk("module a: global_var= %d\n",global_var);show();return 0;}static void hello_exit(void){printk("hello_exit \n");return;}MODULE_AUTHOR("PENG");MODULE_LICENSE("GPL");module_init(hello_init);module_exit(hello_exit);

Debugging steps :

  • 1. Compiler module A, Then load the module A, In the module A After compiling , In its current directory, you'll see a Module.symvers file , Here is our module A Exported symbols .
  • 2. Put the module A Compile generated Module.symvers Copy the file to the module B Under the table of contents , Then compile the module B, Load module B.
  • 3. adopt dmesg View the information printed by the module .
    The printed information is as follows :
     Insert picture description here