10007. Nuclear module programming introduction

xiaoxiao2021-03-06  92

What is Module and how to write a Module author: Zhuang Rongcheng does not know when you are, Linux appears this kind of thing, it is indeed, it is a big innovation in Linux. After you have Module, you should write Device Driver is no longer a nightmare. Modifying Kernel is no longer a painful thing. Because you don't need to test Driver every time you re-compile kernel once. That is simply being exhausted. Module allows us to dynamically change KERNEL, load Device Driver, and it can shorten our DRiver developments. In this article, I will tell you the principle of Module and how to write a Module. Module is translated into Chinese is a module, but it doesn't make sense to translate this word. Before talking about the module, I will give an example. I believe that many people have used Redhat. In Redhat, we can perform SNDCONFIG, which can help us the CONFIG sound card. After config, if you can't get your sound card, your sound card will be moved right away, and you don't have to reactivate your computer. What is this doing? Just relying on Module. Module is actually a general procedure. But it can be dynamically contained in the Kernel into part of the Kernel. Module loaded into kernel it has the same power as Kernel. Can Access, any kernel, Data Structure. Have you heard KDebug? It is used to debug kernel. It is first to load itself into the kernel, and the USER SPACE GDB can communicate with this module, know the value of the Data Structure in the Kernel, in addition to the Kernel Module Change the Kernel Data Structure. We know that a program can only have one main when writing the C program. KERNEL itself is actually a program, it itself has main, called Start_kernel (). When we carry a Module into the kernel, it will integrate with kernel and become part of the kernel. Please think about it, can Module MAIN? The answer is obvious, it is NO. Reasons are very simple. A program can only have a main. When using Module, a little thing to remember is Module is a passive role. It is to provide some functions to let others go. There is a variable module_list in Kernel. Whenever the user loads a MODULE to the Kernel, this module will be recorded inside Module_List. When KERNEL wants to use the function provided by this Module, it will go to Search, find Module, and then use the function or variable. Every module can export some function or variables to make others use. In addition, Module can also use the function provided by Module that has been loaded into the kernel. This situation is called Module Stack. For example, Module A uses Module B, which must first load Module B before loading Module A. Otherwise, Module A will not be loaded.

In addition to Module Export, kernel itself will also export some function or variable. Similarly, Module can also use the things of Kernel Export. Since everyone is usually written in the User Space, it will use the Function used by the usual writer to use the Function used in Module when suddenly writes Module. Stypes like Printf. I want to tell you that the function or variable used by Module is written in the module. If you do other Module, it is not provided by kernel. You cannot use the Function provided by general libc or glibc. Things like Printf. This may be where you are careful. (Maybe you can first stay well, then load it into Kernel, I am trying to try, but forgot) I just said that kernel itself will export some function or variable to let Module, but we are not universal, how do we Do you know that KERNEL has an open thing to let us use? Linux offers a command, called Ksyms, you can know Kernel or the Module currently loaded into Kernel provides those Function or Variable. The case is under my system: c0216ba0 drive_info_R744aa133 c01e4a44 boot_cpu_data_R660bd466 c01e4ac0 EISA_bus_R7413793a c01e4ac4 MCA_bus_Rf48a2c4c c010cc34 __verify_write_R203afbeb in the kernel, there is a symbol table is used to record export out of function or variable...... In addition, the Module Export will also record those function. In the above line, it means that KERNEL provides Drive_info Function / Variable. So, we can use it directly in the Kernel, which will automatically do a good job in the LINK. From this, we can know that Module itself is actually some Object Code that has not been LINK. Everything goes to Module after the Module is loaded, the LINK will be completed. Everyone should be able to see some strange strings behind DRIVE_INFO. _R744AA133, this string is based on the result of the current Kernel version. What is the additional string? Linux does not know that since that version, there will be more config options, called SET VERSION NUMBER in Symbols of Module. This is to avoid unstable system. We know that Linux's kernel update is very fast. In the process of the Kernel update, sometimes for efficiency, some old Data Structure or Function changes, and a variable may have a Variable, some of the Function protoy is not the same as the original.

If this situation occurs, it may be a 2.0.33 version of Module to get a 2.2.1 version of Kernel use. If the original Module uses the variables provided by 2.0.33 kernel call A, but it has been 2.2.1 due to certain The reason must be set to NULL. That when this module is used on 2.2.1 Kernel, if it does not check A's value, it will cause the system's error. Maybe it will not die throughout the system, but this module is definitely hard to play its function. For this reason, Linux is in compile module, putting the Kernel version number Encode to each exported function and variable. So, maybe we should not speak KERNEL to provide Drive_info, and it should be said that Kernel provides Driver_info_r744aa133 to let us use. This maybe you will be appreciated. That is to say, Kernel thinks that it provides this thing, instead of driver_info. So, we can find that someone is loading Module, the system has always told you that a Function cannot resolved. This is because Kernel does not have the function you want, or it is the fact that the function used in your module is not the same as the result of kernel eNCode. So you can't resolve. Solution, what is to be turned off in the Kernel, or you have a typical type that Module Compile is a way. Someone will want to say, if the Kernel determines that the Function name it provides is called Driver_INFO_R744AA133, when we write the program, it is changed to Driver_info_r744AA133. The answer is YES. However, if each function must be written like this, don't you feel very annoying? To mention, when we write Driver, many people will use Printk. This is the function provided by Kernel. Its function is very similar to Printf. The usage is almost the same. It is very easy to use when Debug. If we use a hundred printk in Module, it is also what we have to play a hundred times of printk_rdd132261? Of course, the smart people will think of using #define printkprintk_rdd132261. So, Linux is very considerate to help us do this. If you open the options of the Set Version, you can go to / usr / src / linux / include / linux / modules. There are many .. Ver files under this directory. These files are actually used to do #define. Let's take a look at the file in Ksyms.ver, there is such a line: #define printk _set_ver (printk) set_ver is a MacRo, which is used to add Version Number after printk. Interested friends can watch this Macro written by themselves. With these VER files, we can use the names such as Printk directly in Module. And these VER files will automatically help us do the action of #define. However, we can find a lot of VER files in this directory.

Sometimes, how do we know that the Function we want to call is defined in that VER file? Linux helps us do one thing. /usr/src/linux/include/linux/modversions.h This file has already added all VER files. So in our Module as long as INCLUDE file, the issue of that name is solved. However, here, we advise you one thing, don't put the modversions.h in the module in Module, if you want, then add the following number: #ifdef modversions #include #ENDIF The reason for joining these three lines is that this module is in the system without setting the Kernel Version, incorre the models. You can try it, when you turn off the set version of the option, Modversions.h and Modules are not seen. If there is no three lines above, the compile will not pass. So in general, modversions.h we will choose to pass to GCC during Compile. Just like this. GCC -C -D__kernel__ -dmodule -dmodversions main.c / -include usr / src / linux / include / linux / modversions.h In this Command Line, we saw -D__kernel__, this is to define __kernel__ this constant. Many Header File related to Kernel must define this constant to include. So it is recommended that you prefer it to define it. There is also a -dmodversions. I just forgotten this constant. Just now, however, to solve the fucntion or variable name Encode is to include Modversions.h, in addition to this, you must also define modversions this constant. Another is Module this constant. In fact, as long as you want to write Module, you must define this variable. And you still have to include Module.h this file, because _Set_Ver is defined here. Telling here, I believe that you should have some understanding of Module, and you will not be confused by Module Unresolved, and there should be something to solve. Just talking about the name Encode issues encountered on the function of others. However, if our own Module wants to use some things to make other modules. Very simple. On Default, all Global Variable and Function in your Module will be considered to go out for Export. So if you have 10 Global Variable in your module, you can find this ten variable will be out of Export via Ksyms. This is of course a very convenient thing, but you know, sometimes we don't want to put all the variable exports at all. If you have a Module, you have no trouble, how to do our Variable? So, in many times, we It will only limit several necessary things export going out.

Kernel (not very sure) before 2.2.1 can help us with Register_symTab. However, the updated version is now coming out. So, here, I will introduce KERNEL 2.2.1. A macro is provided in Kernel 2.2.1 called Export_Symbol, which is used to help us choose Variable or Function for Export. For example, I want to export a Variable called Full, then I will write to the module: export_symbol; will automatically go out of Full Export, you can discover this variable from Ksyms, you can go out of Export. Be careful before using Export_Symbol, you must define an export_symtab this constant in the GCC, otherwise Parser Error will occur when compile. So, if you use export_symbol, that gcc should be under: gcc -c -d__kernel__ -dmodule -dmodversions -dexport_symtab / main.c -include /usr/src/linux/include/linux/modversions.h If we don't want Export any Things, then we just need to export_no_symbols in Module; Use export_no_symbols to use not to define any constant. In fact, if you use the old version of Register_Symbol, you will feel better to use the new version. At least I think it is. Because using register_symbol, you must first define your Symbol_Table, it feels a bit trouble. When we use export_symbol to take some function or variable export, we use Ksyma -a to see some results. We have found that export_symbol (full) is indeed coming out: c882200 full [my_module] c01b8e08 pci_find_slot_r454463b5.. However, the result is nothing to do with our imagination, take care of it, it should be Full_Rxxxxxx. Ah, how can I appear Full? Strange, there is there? In fact, the problem is that we don't have the name of the Function or Variable's name of the Module EXPORT. Think about if it is in Module. After we join the DEFINE FULL FULL_RXXXXXX, we re-compile Module once again. After using kernel, you can find that ksyms -a is displayed is C8822200 full_rxxxxxxx [my_module] c01b8e08 pci_find_slot_r454463b5....... That is not to say, we have to go to each of the Variable and Function to do define actions? Of course not 啰. Remember, when we told the Function of Kernel Export, we told the file of Include, so that we don't have to do DEFINE.

Now, we also use the .ver file to help us, so that our Module Export can automatically join the systemation of the Kernel Version. That is, something that turns full_rxxxxxx. A Command is provided in Linux, called Genksyms, which is used to help us produce this .ver file. It will read the Source Code from stdin and check if there is a Variable or Function of Export in the Source Code. If so, it will automatically generate some define for every export. These Define is what we said before. After we have these Define, as long as you join these define in our Module, the Function or Variable that export will become the same. Suppose our programs are placed in a file called Main.c, we can use the following ways to generate these define. GCC -E -D__genksyms__ main.c | Genksyms -k 2.2.1> main.ver gcc's -e parameter refers to the result of PreProcessing results. That is to say, some of the results of some defludes are expanded. -D__genksyms__ is necessary. If you don't define this constant, you will not see any results. It is because Genksyms is read from StdIns, so the result of GCC is passed to Genksyms via pipeline. -k 2.2.1 means that the Kernel version currently used is 2.2.1. If your Kernel version is different, you must specify your kernel version. The resulting define will be placed in main.ver. After generating the main.ver file, in main.c, it comes in, it is OK. It is necessary to tell you that using the module generated in this way, its export comes outgoing, via main.ver's Define change. So if you want others to use it, you must open main.ver, otherwise, others can't use something you exported. Tell this lot, I believe that you should know how Module is in Kernel, and you should know what sometimes Module will not load. In addition, you should also know how to make your Module Export also have the information of the kernel version of INFORMATION. Next, you have to talk to you, how to write a Module. In fact, writing a Module is simple. If you understand what I said above. Then I will talk again, use an example, I believe everyone will. To write a module, you must provide two functions. These two functions are used for INSMOD and RMMOD. They are init_module (), and clenup_module (). INT init_module (); void cleanup_module (); I believe everyone knows that I can use Insmod this Command in Linux to load a Module. For example, I have a Module called Hello.o, which can use the Insmod Hello.o to load the Hello this module into the kernel.

Observe / etc / modules should see the name of Hello this Module. If you want to remove the Hello Module, you can use the RMMOD Hello. InSmod After loading Module, you will call the init_module () provided by Module. If the transmission is successful, the module will be loaded. If it fails, the load will fail. Generally speaking, what we do in init_module () is some initialization work. For example, your module requires a memory, then you can do Kmalloc's actions in init_module (). I want to be Often. Cleanup_module () is something to do when Module is to be removed. What is going on is, it is some kind of work, and it is better than the way to remove the previous Kmalloc's memory. Since Module is used in Kernel, you may use your module, or even some Process will use your module, in order to avoid Module, it is removed, each module has A use count. How many process or modules are used to record currently using this module. When Module's use count does not equal 0, Module will not be removed. That is, when module's use count does not equal 0, cleanup_module () is not called. Here, I want to introduce three macro, which is related to Module's use count. MOD_INC_USE_COUNT MOD_DEC_USE_COUNT MOD_IN_USE MOD_INC_USE_COUNT is used to increase module's use count, and mod_dec_use_count is used to reduce module's Use Count. As for mod_in_use, it is used to check that this module is not used. That is to check if the USE COUNT is 0. Module's use count must be MAINTAIN by writing modules. The system does not automatically add Use Count to one or minus one. Everything has to be controlled by yourself. There is an example below, but does not introduce these three Macro usage methods. If there is an opportunity in the future, I will introduce these three macro usage. This example is very simple. In fact, it is only to demonstrate how to use init_module () and cleanup_module () to write a module. Of course, these two function simply constitute the basic conditions of Module. As for the functionality to be provided in Module, it is to see the needs of each person. Main.c #define module #include #include int full; export_symbol; / * Out of Full Export * / int init_module (void) {printk ("< 5> Module Is Loaded / N "); Return 0;} void cleanup_module (void) {printk (" <5> Module is unloaded / n ");} About Printk is like this, it is a print provided by Kernel Message Function. Kernel has an export this function. So you can use it freely. Its usage is almost exactly the same as Printf.

The beginning of the message is <5>, in fact, not see these three characters. It can also be anything in <4>, <3>, <7> and so on. This is PrioiRTY or Level representing this message. <5> indicates the message related to Kernel. Main.ver: It is generated using Genksyms. GCC -E -D__genksyms__ main.c | gENKSYMS -K 2.2.1> main.ver Next, that is to put main.c compile into main.o gcc -d__kernel__dmodversions -dexport_symtab -c / -i / usr / src / Linux / include / linux -include / /usr/src/linux/include/linux/modversions.h / -include ./main.ver main.c is good. Main.o has successfully compile, now the next command, insmod main.o Check if there is a main this module in the Proc / Modules. If there is, it is said that the MAIN this module has been loaded to Kernel. Next, let's take a look at the results of Full EXPORT. ksyms results showed Address Symbol Defined by c40220e0 full_R355b84b2 [main] c401d04c ne_probe [ne] c401a04c ei_open [8390] c401a094 ei_close [8390] c401a504 ei_interrupt [8390] c401af1c [8390] c401af80 NS8390_init [8390] can be seen ethdev_init full_R355b84b2, that we Successfully adds the Full's name to the Kernel Version's information. When we don't need this Module, we can next Command, RMMOD MAIN is such that Main will be removed. Check if you can find that MAIN is invisible. You can now look at / var / log / message file, you should find two lines Apr 12 14:19:05 host kernel: module is loaded apr 12 14:39:29 host kernel: module is unloaded two lines PRINTK is printed. About Module's introduction has been here. In fact, it is very simple to use Module. For those who want to develop Driver or increase the new features of Kernel, use Module not to be a convenient way. I hope this article can help you. Zhuang Rongcheng (J.c. Chuang), CJC86 @ cs.ccu.edu.tw

Excerpt from:

http://linuxfab.cx

转载请注明原文地址:https://www.9cbs.com/read-106055.html

New Post(0)