module_init的加载和释放

kernel:module_init模块加载顺序 [第二次修改:linux中有各个模块init函数放在init断中。最先init的设备(驱动最先被注册),睡眠唤醒的时候最后被suspend最先被resume。] 需求:dsi这边的驱动需要比我一个挂载在i2c上的设备晚. 也就是说.平台端要先初始化i2c从设备以后,再输出mipi信号. 平台:qcom 8930 做法 1.修改dsi --- a/drivers/video/m... 阅读详情
像你写C程序需要包含C库的头文件那样, Linux 内核编程也需要包含Kernel头文件,大多的Linux驱动程序需要包含下面三个头文件:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
    其中,init.h 定义了驱动的初始化和退出相关的函数,kernel.h 定义了经常用到的函数原型及宏定义,module.h 定义了内核模块相关的函数、变量及宏。
    几乎每个linux驱动都有个module_init(与module_exit的定义在Init.h (\include\linux) 中)。没错,驱动的加载就靠它。为什么需要这样一个宏?原因是按照一般
的编程想法,各部分的初始化函数会在一个固定的函数里调用比如:

void init(void)

{

    init_a();
    init_b();    

}

    如果再加入一个初始化函数呢,那么在init_b()后面再加一行:init_c(); 这样确实能完成我们的功能,但这样有一定的问题,就是不能独立的添加初始化函数,每次添
加一个新的函数都要修改init函数。可以采用另一种方式来处理这个问题,只要用一个宏来修饰一下:

void init_a(void)
{

}

__initlist(init_a, 1);

 

它是怎么样通过这个宏来实现初始化函数列表的呢?先来看__initlist的定义:

#define __init __attribute__((unused, __section__(".initlist")))

#define __initlist(fn, lvl) \
static initlist_t __init_##fn __init = { \
  magic:    INIT_MAGIC, \
  callback: fn, \
  level:   lvl }

请注意:__section__(".initlist"),这个属性起什么作用呢?它告诉连接器这个变量存放在.initlist区段,如果所有的初始化函数都是用这个宏,那么每个函数会有
对应的一个initlist_t结构体变量存放在.initlist区段,也就是说我们可以在.initlist区段找到所有初始化函数的指针。怎么找到.initlist区段的地址呢?

extern u32 __initlist_start;
extern u32 __initlist_end;

这两个变量起作用了,__initlist_start是.initlist区段的开始,__initlist_end是结束,通过这两个变量我们就可以访问到所有的初始化函数了。这两个变量在哪定义的呢?在一个连接器脚本文件里

 . = ALIGN(4);
 .initlist : {
  __initlist_start = .;
  *(.initlist)
  __initlist_end = .;

}

 这两个变量的值正好定义在.initlist区段的开始和结束地址,所以我们能通过这两个变量访问到所有的初始化函数。为我们做好了。先来分析一下module_init。定义如下:

#define module_init(x)     __initcall(x);              //include\linux\init.h

#define __initcall(fn) device_initcall(fn)

#define device_initcall(fn)                 __define_initcall("6",fn,6)

#define __define_initcall(level,fn,id) \

         static initcall_t __initcall_##fn##id __used \

         __attribute__((__section__(".initcall" level ".init"))) = fn

 

如果某驱动想以func作为该驱动的入口,则可以如下声明:module_init(func);被上面的宏处理过后,变成 __initcall_func6 __used加入到内核映像的".initcall"区
。内核的加载的时候,会搜索".initcall"中的所有条目,并按优先级加载它们,普通驱动程序的优先级是6。其它模块优先级列出如下:值越小,越先加载。

#define pure_initcall(fn)           __define_initcall("0",fn,0)

#define core_initcall(fn)            __define_initcall("1",fn,1)

#define core_initcall_sync(fn)          __define_initcall("1s",fn,1s)

#define postcore_initcall(fn)             __define_initcall("2",fn,2)

#define postcore_initcall_sync(fn)  __define_initcall("2s",fn,2s)

#define arch_initcall(fn)            __define_initcall("3",fn,3)

#define arch_initcall_sync(fn)          __define_initcall("3s",fn,3s)

#define subsys_initcall(fn)                 __define_initcall("4",fn,4)

#define subsys_initcall_sync(fn)      __define_initcall("4s",fn,4s)

#define fs_initcall(fn)                          __define_initcall("5",fn,5)

#define fs_initcall_sync(fn)               __define_initcall("5s",fn,5s)

#define rootfs_initcall(fn)                  __define_initcall("rootfs",fn,rootfs)

#define device_initcall(fn)                 __define_initcall("6",fn,6)

#define device_initcall_sync(fn)       __define_initcall("6s",fn,6s)

#define late_initcall(fn)             __define_initcall("7",fn,7)

#define late_initcall_sync(fn)           __define_initcall("7s",fn,7s)

可以看到,被声明为pure_initcall的最先加载。

    module_init除了初始化加载之外,还有后期释放内存的作用。linux kernel中有很大一部分代码是设备驱动代码,这些驱动代码都有初始化和反初始化函数,这些代码     linux就是这样做的,对只需要初始化运行一次的函数都加上__init属性,__init 宏告诉编译器如果这个模块被编译到内核则把这个函数放到(.init.text)段,module_exit的参数卸载时同__init类似,如果驱动被编译进内核,则__exit宏会忽略清理函数,因为编译进内核的模块不需要做清理工作,显然__init和__exit对动态加载的模块是无效的,只支持完全编译进内核。


    在kernel初始化后期,释放所有这些函数代码所占的内存空间。连接器把带__init属性的函数放在同一个section里,在用完以后,把整个section释放掉。当函数初始化
完成后这个区域可以被清除掉以节约系统内存。Kenrel启动时看到的消息“Freeing unused kernel memory: xxxk freed”同它有关。
    我们看源码,init/main.c中start_kernel是进入kernel()的第一个c函数,在这个函数的最后一行是rest_init();

static void rest_init(void)

{

     .....

     kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);
     unlock_kernel();
     cpu_idle();

     .....    

}

创建了一个内核线程,主函数kernel_init末尾有个函数: init_post();

这个init_post中的第一句就是free_initmem();就是用来释放初始化代码和数据的。

void free_initmem(void)

{

    if (!machine_is_integrator() && !machine_is_cintegrator()) {
    free_area((unsigned long)(&__init_begin),
     (unsigned long)(&__init_end),
     "init"); }

}

 接下来就是kernel内存管理的事了。

 

原文: http://wenku.baidu.com/view/c9a1b2e9172ded630b1cb66d.html

【linux内核】module_init和module_exit __exit: 这是一个宏,指示编译器,清理函数(如`hello_end`)在模块卸载时会被调用。这个标记对于内置到内核的模块是没有意义的(因为内置模块不会被卸载),所以它通常在与`module_exit`宏一起使用时被内核用来避免编译不必要的代码。在最近的Linux内核版本中,如果内核经过了模块签名,只有签名的模块才能被加载进内核,这是出于安全考虑的策略。在Linux内核模块编程中,`module_init`和`module_exit`是两个宏,分别用来声明模块初始化函数和模块卸载函数。 阅读详情

相关推荐

TEM图像处理实战指南:从基础操作到金属材料分析

本文提供了一份全面的透射电镜(TEM)图像处理实战指南,涵盖从基础操作到金属材料深度分析的全流程。重点讲解了TEM图像预处理、选区电子衍射(SAED)标定、高分辨像(HRTEM)分析及STEM图像应用等核心技能,并结合金属材料(如铝合金、钢)的析出相鉴定、位错分析和界面结构研究等实际案例,帮助研究者从原始数据中准确提取晶体结构、缺陷及成分信息。

weixin_29284201的博客 208

linux驱动说开去(五)--驱动模块的加载-insmod

概述:    linux采用整体时的内核结构,一般不支持动态增加新功能,为此linux提供了一套叫做模块的全新机制,可以根据需要在不重新编译连接内核的情况下将新的安装模块动态的插入/移除运行态的内核,使得内核映像保持最小化,从而达到灵活性及扩展性.    模块化并不仅局限于驱动模块同时也支持文件系统,但常见与驱动或与驱动紧密联系的模块,内核提供了4个系统调用以支持动态安装卸载:create_mod...

一只拖鞋 694

TI IWR 6843 ISK 毫米波雷达开箱测试

TI IWR6843 ISK毫米波雷达上手体验,教程十分详细,对于新手很友好。

qq_57061492的博客 4032

module_init 的优先级

在include/linux/module.h 中有如下定义 #ifndef MODULE /**  * module_init() - driver initialization entry point  * @x: function to be run at kernel boot time or module insertion  *  * module_init() will

jason的笔记 2999

用户存续期价值评估CLV(二) BG/NBD Model python模拟

BG/NBD Model …继续 想象每一个客户有两个硬币,一个“Buy Coin"控制客户购买的概率;一个"Die Coin"控制客户流失、不再购买的概率。 前面假设了客户的交易次数服从泊松过程: 在一年中的每个月,客户都以抛硬币的方式来决定是否购买。我们所观察到的购买次数取决与泊松分布的参数 ????。 %matplotlib inline import numpy as np impor...

weixin_43171270的博客 3420

【超详细】磁力计数据读取--以IST8310为例

第一章讲了IST8310的特性,I2C通信,最高支持400kHz通信速率,14位或者16位自适应数据输出等特性第二章讲了内部结构第三章讲了电气特性第四章讲了如何联系他们然后数据手册就没了。。。在大疆的开发手册中找到了寄存器的手册,如下:点开I2C配置选项, 下图是配好的:观察IST8310的数据手册,发现其支持最大400kHz的I2C通信速率,也就是快速I2C模式,所以第一行I2C Speed Mode我们选Fast Mode同时不要忘记了在C板中I2C3的两个IO口分别是PA8和PC9(一般来说都是这两个

lmh_12138的博客 1万+

linux驱动之module_init的加载和释放

转自:http://blog.youkuaiyun.com/dysh1985/article/details/7597105 &nbsp; 像你写C程序需要包含C库的头文件那样,Linux内核编程也需要包含Kernel头文件,大多的Linux驱动程序需要包含下面三个头文件:#include &lt;linux/init.h&gt;#include &lt;linux/module.h&gt;#include ...

boundlessAbjure的专栏 524

分布式存储系统关于GDPR条例中的数据清除原则

文章目录前言HDFS存储系统数据的完全删除基于加解密的输入输出流的数据保护方案 前言 关于GDPR是什么,可能许多同学之前并不太了解,至少笔者在之前也是不清楚的。GDPR全称为通用数据保护条例,General Data Protection Regulation。它是一项来自欧盟的关于计算机数据保护相关的条约,旨在规范系统如何收集,管控用户私人数据的种种行为。但是当前的一些存储系统并没有完全符合...

走在前往架构师的路上 3623

linux驱动的入口函数module_init的加载和释放

linux驱动的入口函数module_init的加载和释放 分类: Linux驱动 2009-12-02 23:20 10922人阅读 评论(3) 收藏 举报 modulelinuxlinux内核restcallback编程       就像你写C程序需要包含C库的头文件那样,Linux内核编程也需要包含Kernel头文件,大多的Linux驱动程序需要包含下面三个头文件

u012792791的专栏 482

STM32F407+LAN8720A+LwIP实战:FreeModbus TCP从机功能开发指南

本文详细介绍了基于STM32F407和LAN8720A硬件平台,结合LwIP协议栈实现FreeModbus TCP从机功能的开发指南。内容涵盖硬件连接、LwIP移植、FreeModbus TCP从机实现、任务调度及调试技巧,为工业控制领域的以太网通信开发提供实用参考。

weixin_29190651的博客 546

24GHz雷达DIY呼吸监测仪:用树莓派+TI IWR6843搭建生命体征检测系统(附Python代码)

本文详细介绍了如何利用树莓派和TI IWR6843毫米波雷达模块DIY非接触式呼吸监测仪。通过硬件选型、信号处理流水线设计和实时可视化系统搭建,实现高精度的生命体征检测,特别适合医疗健康和运动监测场景。附带的Python代码帮助开发者快速复现该系统。

rl6adventurer的博客 984

linux驱动的入口函数module_init的加载和释放【转】

本文转载自:http://blog.youkuaiyun.com/zhandoushi1982/article/details/4927579 就像你写C程序需要包含C库的头文件那样,Linux内核编程也需要包含Kernel头文件,大多的Linux驱动程序需要包含下面三个头文件: #include <linux/init.h>#include <linux/module.h>#i...

zzb2760715357的博客 97

Unity与IOS交互,调用IOS系统相机和相册

与IOS的交互,在步骤上要比android简单许多,不会产生因为系统版本,或者包名导致的许多问题。过程中最头疼的一个问题是IOS回调Unity,很简单的一个问题,搞了半天。

Hello Mingo 1万+

module_init宏解析 linux驱动的入口函数module_init的加载和释放

linux驱动的入口函数module_init的加载和释放 http://blog.youkuaiyun.com/zhandoushi1982/article/details/4927579 void free_initmem(void) { if (!machine_is_integrator() &amp;&amp; !machine_is_cintegrator()) { ...

weixin_33869377的博客 234

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

上一篇: 半球电磁炉EO/E2/E3/E4/E5故障问题
下一篇: Linux工作队列实现机制
常用技术
博客等级 码龄17年 91粉丝 100原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值