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

fsa.gplok = gplok;

fsa.warn = warn;


//Find the symbol and fill in the output part of the symbol parameter structure

if (each_symbol_section(find_symbol_in_section, &fsa)) {

if (owner) //NULL, no value is required below

*owner = fsa.owner;


if (crc) //Get the crc value of the symbol

*crc = fsa.crc;


//Return the kernel symbol structure named by name

return fsa.sym;

}


//No kernel symbol found, return NULL

pr_debug("Failed to find symbol %sn", name);

return NULL;

}


bool each_symbol_section(bool (*fn)(const struct symsearch *arr,struct module *owner,void *data),void *data)

{

struct module *mod;

//The first part searches for the corresponding symbol in the symbol table exported by the kernel. If found, the corresponding symbol information is returned. Otherwise, the second part searches again.

/*struct symsearch {

const struct kernel_symbol *start, *stop;

const unsigned long *crcs;

enum {

NOT_GPL_ONLY,

GPL_ONLY,

WILL_BE_GPL_ONLY,

}licence;

bool unused;

};

*/

static const struct symsearch arr[] = {

{ __start___ksymtab, __stop___ksymtab,

__start___kcrctab,NOT_GPL_ONLY, false },

{ __start___ksymtab_gpl, __stop___ksymtab_gpl,

__start___kcrctab_gpl,GPL_ONLY, false },

{ __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,

__start___kcrctab_gpl_future,WILL_BE_GPL_ONLY, false },

#ifdef CONFIG_UNUSED_SYMBOLS

{ __start___ksymtab_unused, __stop___ksymtab_unused,

__start___kcrctab_unused,NOT_GPL_ONLY, true },

{ __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,

__start___kcrctab_unused_gpl,GPL_ONLY, true },

#endif

};


if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))

return true;


//If the corresponding symbol is not found in the symbol table exported by the kernel, search in the modules loaded by the system

list_for_each_entry_rcu(mod, &modules, list) {

struct symsearch arr[] = {

{ mod->syms, mod->syms + mod->num_syms,

mod->crcs,NOT_GPL_ONLY, false },

{ mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,

mod->gpl_crcs,GPL_ONLY, false },

{ mod->gpl_future_syms,mod->gpl_future_syms + mod->num_gpl_future_syms,

mod->gpl_future_crcs,WILL_BE_GPL_ONLY, false },

#ifdef CONFIG_UNUSED_SYMBOLS

{ mod->unused_syms,mod->unused_syms + mod->num_unused_syms,

mod->unused_crcs, NOT_GPL_ONLY, true },

{ mod->unused_gpl_syms,mod->unused_gpl_syms + mod->num_unused_gpl_syms,

mod->unused_gpl_crcs,GPL_ONLY, true },

#endif

};


//If the module state is MODULE_STATE_UNFORMED, the symbols of this module are not available

if (mod->state == MODULE_STATE_UNFORMED)

continue;


if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data))

return true;

}

return false;

}


static bool each_symbol_in_section(const struct symsearch *arr,unsigned int arrsize,struct module *owner,bool (*fn)(const struct symsearch *syms,struct module *owner,void *data),void *data)

{

unsigned int j;


//Call find_symbol_in_section() to search the symbol address range specified by each array

for (j = 0; j < arrsize; j++) {

if (fn(&arr[j], owner, data))//Call find_symbol_in_section()

return true;

}

return false;

}


static bool find_symbol_in_section(const struct symsearch *syms,struct module *owner,void *data)

{

struct find_symbol_arg *fsa = data;

struct kernel_symbol *sym;


//Search for kernel symbols with symbol name fsa->name in the range

sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,sizeof(struct kernel_symbol), cmp_name);


//If the kernel symbol is found, check whether it is valid

if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data))

return true;


return false;

}


void *bsearch(const void *key, const void *base, size_t num, size_t size,int (*cmp)(const void *key, const void *elt))

{

size_t start = 0, end = num;

int result;


while (start < end) {//binary search

size_t mid = start + (end - start) / 2;


//Call cmp_name() function to compare whether the symbol name is consistent

result = cmp(key, base + mid * size);

if (result < 0)

end = mid;

else if (result > 0)

start = mid + 1;

else

return (void *)base + mid * size;

}

return NULL;

}


static int cmp_name(const void *va, const void *vb)

{

const char *a;

const struct kernel_symbol *b;

a = va; b = vb;

return strcmp(a, b->name);

}


static bool check_symbol(const struct symsearch *syms,struct module *owner,unsigned int symnum, void *data)

{

struct find_symbol_arg *fsa = data;


if (!fsa->gplok) { //If gplok is not set, it must be GPL licensed

if (syms->licence == GPL_ONLY)

return false;

if (syms->licence == WILL_BE_GPL_ONLY && fsa->warn) {

printk(KERN_WARNING "Symbol %s is being used "

"by a non-GPL module, which will not "

"be allowed in the future", fsa->name);

}

}


#ifdef CONFIG_UNUSED_SYMBOLS

if (syms->unused && fsa->warn) {

printk(KERN_WARNING "Symbol %s is marked as UNUSED, "

"however this module is using it.n", fsa->name);

printk(KERN_WARNING"This symbol will go away in the future.n");

printk(KERN_WARNING

"Please evalute if this is the right api to use and if "

"it really is, submit a report the linux kernel "

"mailinglist together with submitting your code for "

"inclusion.n");

}

#endif


fsa->owner = owner; //Symbol belongs to the module

//#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)

fsa->crc = symversion(syms->crcs, symnum); // CRC value of the symbol

fsa->sym = &syms->start[symnum]; //Returned symbol structure

return true;

}


static int check_version(Elf_Shdr *sechdrs,unsigned int versindex,const char *symname,struct module *mod, const unsigned long *crc,const struct module *crc_owner)

{

unsigned int i, num_versions;

struct modversion_info *versions;


//If the crc value of the symbol in the system is 0, return 1 directly.

if (!crc)

return 1;


//If there is no __versions section in the elf format file of the module, try to force load the module

//However, the implementation of the try_to_force_load() function depends on whether the CONFIG_MODULE_FORCE_LOAD macro is defined. This macro is not defined by default, so failure will be returned here. It seems that the kernel does not recommend forced module loading.

if (versindex == 0)

return try_to_force_load(mod, symname) == 0;


//Find the starting address of the module "__versions" section in the memory image. Equivalent to the contents of the section

versions = (void *) sechdrs[versindex].sh_addr;

num_versions = sechdrs[versindex].sh_size/ sizeof(struct modversion_info);

for (i = 0; i < num_versions; i++) {

if (strcmp(versions[i].name, symname) != 0) // Find the symbol to be compared in this section

continue;


//Compare the CRC value of the symbol in the module with the CRC value of the kernel symbol on the current system to see if they are consistent

if (versions[i].crc == maybe_relocated(*crc, crc_owner))

return 1;

pr_debug("Found checksum %lX vs module %lXn",maybe_relocated(*crc, crc_owner), versions[i].crc);

goto bad_version;

}


//If the symbol to be compared is not found in the "__versions" section, a common error when loading a module will be given: "no symbol version for"

printk(KERN_WARNING "%s: no symbol version for %sn",mod->name, symname);

return 0;

bad_version:

//If the CRC values ​​of the comparison symbols are inconsistent, a common error when loading modules will be given: "disagrees about version of symbol"

printk("%s: disagrees about version of symbol %sn",mod->name, symname);

return 0;

}


static int try_to_force_load(struct module *mod, const char *reason)

{

#ifdef CONFIG_MODULE_FORCE_LOAD

//If option CONFIG_MODULE_FORCE_LOAD is on, check if tainted_mask has the TAINT_FORCED_MODULE flag set, if not give a warning message

if (!test_taint(TAINT_FORCED_MODULE))

printk(KERN_WARNING "%s: %s: kernel tainted.n",mod->name, reason);


//Set the TAINT_FORCED_MODULE flag of mod->taints and tainted_mask to force the module to load and return the correct value 0

add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_NOW_UNRELIABLE);

return 0;

#else

//If the option CONFIG_MODULE_FORCE_LOAD is not enabled, an error is returned directly

return -ENOEXEC;

#endif

}


static int check_modinfo(struct module *mod, struct load_info *info, int flags)

{

//Get the version magic from the module .modinfo section

const char *modmagic = get_modinfo(info, "vermagic");

int err;

if (flags & MODULE_INIT_IGNORE_VERMAGIC)

modmagic = NULL;


//If version magic is 0, try to force load

if (!modmagic) {

err = try_to_force_load(mod, "bad vermagic");

if (err)

return err;

}

// Is it consistent with the kernel's vermagic? If not, give the famous error: "version magic ... should be ..." and return the error code

else if (!same_magic(modmagic, vermagic, info->index.vers)) {

printk(KERN_ERR "%s: version magic '%s' should be '%s'n",mod->name, modmagic, vermagic);

return -ENOEXEC;

}


//Return the content of intree="..." in the .modinfo section. If it does not exist, set the flag TAINT_OOT_MODULE

if (!get_modinfo(info, "intree"))

add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);


//Return the content of staging="..." in the .modinfo section, if there is a flag set TAINT_CRAP

if (get_modinfo(info, "staging")) {

add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK);

printk(KERN_WARNING "%s: module is from the staging directory,"" the quality is unknown, you have been warned.n",mod->name);

[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 20:40

Linux driver: s3c2410_ts/s3c2440_ts module loading process
Preface By analyzing the s3c2410_ts/s3c2440_ts module loading process, the bus-device-driver model and input subsystem framework in the Linux driver are analyzed . Main process analysis diagram s3c2440_ts main process analysis system initialization MACHINE_START(SMDK2410,"SMDK2410") MACHINE_START(SMDK2410, "SMDK241
[Microcontroller]
[Linux bottom layer] U-boot ksz8081 network driver debugging
Micrel is an excellent PHY chip. For more information about the chip, please refer to: ksz8081 datasheet interpretation System version: Ubuntu18.04-64 Compiler version: gcc version 7.4.0 (Ubuntu/Linaro 7.4.0-1ubuntu1~18.04.1) uboot version: 2018.07-linux4sam_6.0 Board model: at91sama5d3x-xplained MCU mode
[Microcontroller]
LCD device driver in Linux (1) - framebuffer
1. framebuffer Framebuffer is an interface provided by Linux system for display devices. It abstracts the display buffer, shields the underlying differences of image hardware, and allows upper-level applications to directly read and write the display buffer in graphics mode. Users do not need to care about the speci
[Microcontroller]
LCD device driver in Linux (1) - framebuffer
09-S3C2440 driver learning (Part 3) Embedded Linux platform bus driver and separation and layering driver framework
Introduction Platform: The kernel has IIC bus, PCI bus, serial bus, SPI bus, CAN bus, single bus, etc. Some devices can be mounted on these buses, and then the devices and drivers are matched through bus matching. However, some devices do not belong to these buses, so a virtual bus, that is, Platform bus, is introdu
[Microcontroller]
09-S3C2440 driver learning (Part 3) Embedded Linux platform bus driver and separation and layering driver framework
S3C6410 RTC driver in Linux (3)
The previous article talked about the s3c_rtc_probe function, but because it was too long, I didn’t finish it. This article continues the previous article. After talking about this function, we can go back to the s3c_rtc_probe function and continue talking about it in the next article. Do you still remember this sen
[Microcontroller]
S3C6410 RTC driver in Linux (3)
S3C2416 Linux2.6.21 driver porting - added UART3 and baud rate setting bug eliminated
1. Transplantation Environment (The red bold text indicates the modified content, and the blue bold text indicates the content with special attention) 1.Host environment: Ubuntu-10.10 under Virtualbox 2. Compilation Compilation environment: arm-linux-gcc v4.4.3 3.uboot: U-Boot 1.3.4 (provided by Youjian) 4. Li
[Microcontroller]
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号