Analysis of Linux driver kernel loading module process

Publisher:upsilon30Latest update time:2024-08-20 Source: cnblogs Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

The Linux kernel supports dynamic loading of modules: for example, insmod first_drv.ko, so that the module can be loaded into the kernel space for application calls. Now briefly describe the process of insmod first_drv.ko


1. insmod is also a user process


2. The insmod process reads the name of the module to be linked from the command line: first_drv.ko


3. The insmod process determines the location of the file where the module object code is located in the system directory tree, that is, the location of the first_drv.ko file


4. The insmod process reads the file containing the module target code from the storage area where the file system is located


5. insmod calls the init_module system call. The function will enter the kernel to reach the kernel function sys_init_module, and then the sys_init_module function will copy the module binary file to the kernel, and then the kernel will complete the rest of the tasks.


The following content is reproduced from https://blog.csdn.net/chrovery/article/details/51088425


1. Introduction

When some modules compiled now are insmoded on the system, various errors may be reported. The causes of these errors can be found by carefully reading the kernel source code. The insmod part of the 2.6 kernel and before mainly relied on the modutils source code package, and basically completed the work at the user level. The loading process is referred to the previous article. The practice after the 2.6 kernel is to incorporate most of the original user-level operations into the kernel for processing, which is much less than before in terms of logic and code volume. It is connected to the kernel through the insmod command in busybox. If you understand this set of source code, you will not encounter various errors when loading modules. You can write some patch code to correct the items that the kernel needs to check, such as vermagic and crc, etc.


2. Related Structure


1. Module Dependencies

struct module_use {

struct list_head source_list;

struct list_head target_list;

struct module *source, *target;

};


2. Module status

enum module_state {

MODULE_STATE_LIVE, /* Normal state. */

MODULE_STATE_COMING, /* Full formed, running module_init. */

MODULE_STATE_GOING, /* Going away. */

MODULE_STATE_UNFORMED, /* Still setting it up. */

};


3. Module Count

struct module_ref {

unsigned long incs;

unsigned long decs;

} __attribute((aligned(2 * sizeof(unsigned long))));


4. Module Structure

struct module

{

enum module_state state;

/* Member of list of modules */

struct list_head list;

/* Unique handle for this module */

char name[MODULE_NAME_LEN];

/* Sysfs stuff. */

struct module_kobject mkobj;

struct module_attribute *modinfo_attrs;

const char *version;

const char *srcversion;

struct kobject *holders_dir;

/* Exported symbols */

const struct kernel_symbol *syms;

const unsigned long *crcs;

unsigned int num_syms;

/* Kernel parameters. */

struct kernel_param *kp;

unsigned int num_kp;

/* GPL-only exported symbols. */

unsigned int num_gpl_syms;

const struct kernel_symbol *gpl_syms;

const unsigned long *gpl_crcs;


#ifdef CONFIG_UNUSED_SYMBOLS

/* unused exported symbols. */

const struct kernel_symbol *unused_syms;

const unsigned long *unused_crcs;

unsigned int num_unused_syms;

/* GPL-only, unused exported symbols. */

unsigned int num_unused_gpl_syms;

const struct kernel_symbol *unused_gpl_syms;

const unsigned long *unused_gpl_crcs;

#endif


#ifdef CONFIG_MODULE_SIG

/* Signature was verified. */

bool sig_ok;

#endif


/* symbols that will be GPL-only in the near future. */

const struct kernel_symbol *gpl_future_syms;

const unsigned long *gpl_future_crcs;

unsigned int num_gpl_future_syms;


/* Exception table */

unsigned int num_exentries;

struct exception_table_entry *extable;


/* Startup function. */

int (*init)(void);


/* If this is non-NULL, vfree after init() returns */

void *module_init;


/* Here is the actual code + data, vfree'd on unload. */

void *module_core;


/* Here are the sizes of the init and core sections */

unsigned int init_size, core_size;


/* The size of the executable code in each section. */

unsigned int init_text_size, core_text_size;


/* Size of RO sections of the module (text+rodata) */

unsigned int init_ro_size, core_ro_size;


/* Arch-specific module values ​​*/

struct mod_arch_specific arch;


unsigned int taints; /* same bits as kernel:tainted */


#ifdef CONFIG_GENERIC_BUG

/* Support for BUG */

unsigned num_bugs;

struct list_head bug_list;

struct bug_entry *bug_table;

#endif


#ifdef CONFIG_KALLSYMS

Elf_Sym *symtab, *core_symtab;

unsigned int num_symtab, core_num_syms;

char *strtab, *core_strtab;


/* Section attributes */

struct module_sect_attrs *sect_attrs;


/* Note attributes */

struct module_notes_attrs *notes_attrs;

#endif


char *args;


#ifdef CONFIG_SMP

/* Per-cpu data. */

void __percpu *percpu;

unsigned int percpu_size;

#endif


#ifdef CONFIG_TRACEPOINTS

unsigned int num_tracepoints;

struct tracepoint * const *tracepoints_ptrs;

#endif


#ifdef HAVE_JUMP_LABEL

struct jump_entry *jump_entries;

unsigned int num_jump_entries;

#endif


#ifdef CONFIG_TRACING

unsigned int num_trace_bprintk_fmt;

const char **trace_bprintk_fmt_start;

#endif


#ifdef CONFIG_EVENT_TRACING

struct ftrace_event_call **trace_events;

unsigned int num_trace_events;

#endif


#ifdef CONFIG_FTRACE_MCOUNT_RECORD

unsigned int num_ftrace_callsites;

unsigned long *ftrace_callsites;

#endif


#ifdef CONFIG_MODULE_UNLOAD

/* What modules depend on me? */

struct list_head source_list;

/* What modules do I depend on? */

struct list_head target_list;


/* Who is waiting for us to be unloaded */

struct task_struct *waiter;


/* Destruction function. */

void (*exit)(void);

struct module_ref __percpu *refptr;

#endif


#ifdef CONFIG_CONSTRUCTORS

/* Constructor functions. */

ctor_fn_t *ctors;

unsigned int num_ctors;

#endif

};


5. ELF file information structure

struct load_info {

Elf_Ehdr *hdr; //point to the elf header

unsigned long len;

Elf_Shdr *sechdrs; //point to the section header

char *secstrings; //Points to the address of the section name in the string section

char *strtab; //points to the address of the string section

unsigned long symoffs;

unsigned long stroffs;

struct _ddebug *debug;

unsigned int num_debug;

bool sig_ok; //Module signature check

struct {

unsigned int sym; //module symbol table section index number

unsigned int str; //Module string section index number

unsigned int mod; //module's ".gnu.linkonce.this_module" section index number

unsigned int vers; //module's "__versions" section index

unsigned int info; //module's .modinfo section index number

unsigned int pcpu;

} index;

};


3. Source code analysis

//In the insmod.c file in busybox

int insmod_main(int argc UNUSED_PARAM, char **argv)

{

char *filename;

int rc;


IF_FEATURE_2_4_MODULES(

getopt32(argv, INSMOD_OPTS INSMOD_ARGS);

argv += optind - 1;

);


//Get the path name of the module to be loaded

filename = *++argv;

if (!filename)

bb_show_usage();


rc = bb_init_module(filename, parse_cmdline_module_options(argv,0));

if (rc)

bb_error_msg("can't insert '%s': %s", filename, moderror(rc));


return rc;

}


char* FAST_FUNC parse_cmdline_module_options(char **argv, int quote_spaces)

{

char *options;

int optlen;


options = xzalloc(1);

optlen = 0;


//Traverse the module parameters after the module name

while (*++argv) {

const char *fmt;

const char *var;

const char *val;


var = *argv;

// Allocate space for options

options = xrealloc(options, optlen + 2 + strlen(var) + 2);

fmt = "%.*s%s";

//If '=' exists in var, then return the pointer to the first position where '=' appears in var, otherwise return the null character at the end of the string var.

val = strchrnul(var, '=');

if (quote_spaces) {//is 0

if (*val) { /* has var=val format. skip '=' */

val++;

if (strchr(val, ' '))

fmt = "%.*s"%s" ";

}

}

// The module parameters are stored in options in the format of "%.*s%s". "*" corresponds to (int)(val - var), and the first s corresponds to var, which means that (int)(val - var) characters are removed from the var string, that is, the characters before = are removed. In fact, only the val string (that is, the string after =) is stored in the address pointed to by the options pointer.

optlen += sprintf(options + optlen, fmt, (int)(val - var), var, val);

}


return options;

}


int FAST_FUNC bb_init_module(const char *filename, const char *options)

{

size_t image_size;

char *image;

int rc;

bool mmaped;


if (!options)

options = "";


//If the version before 2.6 calls bb_init_module_24(), this process is the module loading process of modutils in the past. Here we will study the module loading process after 2.6

#if ENABLE_FEATURE_2_4_MODULES

if (get_linux_version_code() < KERNEL_VERSION(2,6,0))

return bb_init_module_24(filename, options);

#endif


image_size = INT_MAX - 4095; //Initialize to the maximum value of the file

mmaped = 0;


//Map the module file into memory and return the size of the mapped space image_size

image = try_to_mmap_module(filename, &image_size);

if (image) {

mmaped = 1;

} else {

errno = ENOMEM; /* may be changed by eg open errors below */

image = xmalloc_open_zipped_read_close(filename, &image_size);

if (!image)

return -errno;

}

errno = 0;


[1] [2] [3] [4] [5] [6] [7] [8]
Reference address:Analysis of Linux driver kernel loading module process

Previous article:Linux driver to create a hello module
Next article:S3C2440 Watchdog Timer Principle

Recommended ReadingLatest update time:2024-11-16 18:00

Linux Platform devices Platform device drivers
The platform device driver is based on the device bus driver model. It just further encapsulates device into platform_device and device_driver into platform_device_driver. The device bus driver model has been analyzed before. The registration process of device and device_driver and their hierarchical relationship in
[Microcontroller]
OK6410A Study Notes 4: Advanced LED Driver for Embedded Linux Driver
As a sequel to the LED driver introduced in the previous article, the main change is that the function of automatically creating device nodes during driver loading is realized by using the mdev mechanism supported by the Linux system. In addition, the write function has been greatly improved.   //s3c6410_led.c – driv
[Microcontroller]
OK6410A Study Notes 4: Advanced LED Driver for Embedded Linux Driver
ARM-Linux driver transplantation--DM9000 network card driver transplantation
Hardware platform: FL2440 Kernel version: 2.6.39 Host platform: Ubuntu 11.04 Kernel version: 2.6.35 Cross compiler: arm-linux-gcc 4.3.2 Original work, please indicate the source when reprinting http://blog.csdn.net/yming0221/article/details/6641579 1. For the analysis of DM9000 network card driver, please
[Microcontroller]
ARM driver development method based on FPGA under Linux platform
The full name of the Linux operating system is GNU/Linux. It is an operating system composed of two parts: the GNU project and the Linux kernel. The source code of all components in the system is free, which can effectively protect the learning results, and thus has been widely used in the embedded field.
[Industrial Control]
ARM driver development method based on FPGA under Linux platform
Latest Microcontroller Articles
  • Download from the Internet--ARM Getting Started Notes
    A brief introduction: From today on, the ARM notebook of the rookie is open, and it can be regarded as a place to store these notes. Why publish it? Maybe you are interested in it. In fact, the reason for these notes is ...
  • Learn ARM development(22)
    Turning off and on interrupts Interrupts are an efficient dialogue mechanism, but sometimes you don't want to interrupt the program while it is running. For example, when you are printing something, the program suddenly interrupts and another ...
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
  • Learn ARM development(15)
  • Learn ARM development(16)
  • Learn ARM development(17)
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号