Linux Kernel module Analysis

Source: Internet
Author: User

From: http://blog.csdn.net/linweig/article/details/5085487

LinuxMonolithic Kernel)That is, most of the functions of the operating system are calledKernelAnd run in privileged mode. It correspondsMicro KernelDifferent, the latter only runs the basic functions (inter-process communication [IPC], scheduling, Basic Input/Output [I/O], and memory management) as the kernel, other functions (drivers, network stacks, and file systems) are excluded from privileged spaces. Therefore, you may think that Linux is a completely static kernel, but the opposite is true. Linux Kernel module (lkm) can be used to dynamically change Linux at runtime.

Dynamically changeableIt is a new lkm that can load new features to the kernel, remove a feature from the kernel, or even use other lkm. The advantage of lkm is that it can minimize the memory usage of the kernel and only load the required elements (this is an important feature of the embedded system ).

Linux is not the only (or the first) single kernel that can be dynamically changed. Berkeley Software Distribution (BSD) variants, Sun Solaris, older kernels (such as OpenVMS), and other popular operating systems (such as Microsoft Windows and Apple Mac OS X) all supported modules.

What is lkm like? We know that it will be a KO extension after compilation, but what it is like. We can see that the general module template.

/*
* Hello. c Hello, world! As a kernel module
*/

# Include <Linux/init. h>
# Include <Linux/module. h>
# Include <Linux/kernel. h>

/*
* Hello_init the init function, called when the module is loaded.
* Returns zero if successfully loaded, nonzero otherwise.
*/
Static int hello_init (void)
{
Printk (kern_alert "I bear a charmed life./N ");
Return 0;
}

/*
* Hello_exit the exit function, called when the module is removed.
*/
Static void hello_exit (void)
{
Printk (kern_alert "Out, out, brief candle! /N ");
}

Module_init (hello_init );
Module_exit (hello_exit );

Module_license ("GPL ");
Module_author ("Shakespeare ");

The module is not a driver, but a Linux kernel extension mechanism. The driver is based on this mechanism and should be understood theoretically.

This is the basic template of a module. After compilation, a ko is generated. Note that the compilation process is very different from that of other applications, the reason is that what it generates is a completely independent elf.

Lkm is fundamentally different from the elements directly compiled into the kernel or typical program. A typical program has a main function. The lkm contains the entry and exit functions (in version 2.6, you can name these functions as needed ). When a module is inserted into the kernel, the entry function is called. When a module is deleted from the kernel, the exit function is called. Because the entry and exit functions are user-defined, they existmodule_initAndmodule_exitMacro, used to define which function these functions belong. Lkm also contains a set of necessary macros and a set of optional macros for defining the module license, module author, module description, and so on.

The Linux kernel of version 2.6 provides a new and simpler method for building lkm. When building lkm, you can use a typical user tool management module (though changed internally): Standardinsmod(Install lkm ),rmmod(Delete lkm ),modprobe(insmodAndrmmod),depmod(Used to create module dependencies) andmodinfo(Used to find the module macro value ).

Lkm is only a special executable and linkable format (ELF) object file. Generally, object files must be linked to parse their symbols and results in executable files. Since the lkm must be loaded to the kernel before the lkm can parse the symbols, the lkm is still an elf object. You can use the standard Object tool on lkm (in version 2.6, the kernel object has a suffix. Ko,). For example, if you useobjdumpUtility, you will find some familiar sections, such. Text(Description ),. Data(Initialized data) and. BSS(Block start symbol or uninitialized data ).

You can also find other sections in the module that support dynamic features .. Init. text section includesmodule_initCode,. Exit. text section containsmodule_exitCode (see figure 2 ).. The modinfo section contains various macro texts that indicate the module license, author, and description.

In the user space,insmod(Insert module) Start the module loading process.insmodCommand to define the module to be loaded and callinit_moduleThe user space system calls and starts the loading process. 2.6 kernel versioninsmodAfter the command is modified, it becomes very simple (70 lines of code) and can execute more work in the kernel.insmodNot all necessary symbolic parsing (Processingkerneld), It only usesinit_moduleThe function copies the module binary file to the kernel, and then the kernel completes the remaining tasks.

init_moduleThe function enters the kernel to reach the kernel function through the system call layer.sys_init_module(See figure 3 ). This is the main function for Loading modules. It uses many other functions to perform difficult work. Similarly,rmmodThe command causesdelete_moduleRunsystem callAnddelete_moduleWill eventually enter the kernel and callsys_delete_moduleDelete A module from the kernel.

During module loading and unloading, the module subsystem maintains a set of simple state variables used to represent module operations. When a module is loaded, the status isMODULE_STATE_COMING. If the module is loaded and available, the status isMODULE_STATE_LIVE. In addition, when the module is detached, the status isMODULE_STATE_GOING.

Next we will analyze how such an elf file is added to the kernel:

Now let's look at the internal functions when loading the module. When kernel functions are calledsys_init_moduleTo check whether the caller has the right to perform this operation.capableFunction completed ). Then, callload_moduleFunction, which loads the module to the kernel and performs necessary debugging (This will be discussed later ).load_moduleThe function returns a module reference pointing to the latest loaded module. This module is loaded to the list of all modules with dual links in the system, and the notifier list is used to notify the thread waiting for the module status to change. Finallyinit()Function to update the module status, indicating that the module has been loaded and available.

/* This is where the real work happens */
Asmlinkage long
Sys_init_module (void _ User * umod,
Unsigned long Len,
Const char _ User * uargs)
{
Struct module * MOD;
Int ret = 0;

/* Must have permission */
If (! Capable (cap_sys_module ))
Return-eperm;

/* Only one module load at a time, please */
If (mutex_lock_interruptible (& module_mutex )! = 0)
Return-eintr;

/* Do all the hard work */
MoD = load_module (umod, Len, uargs );
If (is_err (MOD )){
Mutex_unlock (& module_mutex );
Return ptr_err (MOD );
}

/* Drop lock so they can recurse */
Mutex_unlock (& module_mutex );

Blocking_notifier_call_chain (& module_policy_list,
Module_state_coming, MoD );

/* Start the module */
If (mod-> Init! = NULL)
Ret = do_one_initcall (mod-> init );
If (Ret <0 ){
/* Init routine failed: abort. Try to protect us from
Buggy refcounters .*/
Mod-> state = module_state_going;
Synchronize_sched ();
Module_put (MOD );
Blocking_notifier_call_chain (& module_policy_list,
Module_state_going, MoD );
Mutex_lock (& module_mutex );
Free_module (MOD );
Mutex_unlock (& module_mutex );
Wake_up (& module_wq );
Return ret;
}
If (Ret> 0 ){
Printk (kern_warning "% s: '% s'-> init suspiciously returned % d ,"
"It shoshould follow 0/-E Convention/N"
Kern_warning "% s: loading module anyway.../N ",
_ FUNC __, mod-> name, RET,
_ FUNC __);
Dump_stack ();
}

/* Now it's a first class citizen! Wake up anyone waiting for it .*/
Mod-> state = module_state_live;
Wake_up (& module_wq );

Mutex_lock (& module_mutex );
/* Drop initial reference .*/
Module_put (MOD );
Unwind_remove_table (mod-> unwind_info, 1 );
Module_free (mod, mod-> module_init );
Mod-> module_init = NULL;
Mod-> init_size = 0;
Mod-> init_text_size = 0;
Mutex_unlock (& module_mutex );

Return 0;
}

The internal details of the loaded module are the parsing and operations of the elf module.load_moduleThe function (in./Linux/kernel/module. c) first allocates a temporary memory to accommodate the entire elf module. Thencopy_from_userThe function reads the elf module from the user space to the temporary memory. As an elf object, this file has a unique structure and is easy to parse and verify.

The code of this function is long, and the implementation is the parsing of a module to find out each section. If you are interested, you can look at the source code of the Linux kernel.

The next step is to perform a set of health checks on the loaded elf image (is it a valid ELF file? Is it suitable for the current architecture? And so on ). After the health check is completed, the elf image will be parsed, and a set of convenient variables will be created for each segment header to simplify subsequent access. Because the elf object offset is based on 0 (unless reassigned), these convenience variables include the relative offset to the temporary memory block. The elf field header is verified during variable creation to ensure a valid module is loaded.

Any Optional module parameters are loaded from the user space to another allocated kernel memory block (step 1), and the module status is updated, indicating that the module has been loaded (MODULE_STATE_COMING). If you need per-CPU data (this is determined when you check the segment header), allocate per-CPU blocks.

In the previous step, the module segment is loaded to the kernel (temporary) memory and you know which segment should be kept and which can be deleted. Step 7 allocate the final location for the module in the memory and move the necessary segments (SHF_ALLOC, Or the segments that occupy memory during execution ). Then execute another allocation. The size is the size required by the necessary segments of the module. Iterate each segment in the temporary elf block and copy the segment to be executed to the new block. Next, we need to perform some additional maintenance. At the same time, you can also parse the symbols in the kernel (compiled into the kernel image) or temporary symbols (exported from other modules ).

Then, iterate the new module for each remaining segment and perform the re-locating. This step is related to the architecture and therefore relies on the Helper function defined for the architecture (./Linux/ARCH/<arch>/kernel/module. C. Finally, refresh the instruction cache (because the temporary. Text Segment is used), execute some extra maintenance (release the temporary module memory and set the system file), and finally return the moduleload_module.

Related Article

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.