您当前的位置:首页 > 时尚 > 内容

linux驱动的入口函数module,init的加载和释放

很多朋友对linux驱动的入口函数module,init的加载和释放不是很了解,125小编刚好整理了这方面的知识,今天就来带大家一探究竟。

linux驱动的入口函数module,init的加载和释放

就像你写C程序需要包含C库的头文件一样,Linux内核编程也需要包含内核头文件。大多数Linux驱动需要包含以下三个头文件:#include#include#include,其中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){ } _ _ init list(init _ a,1);它是如何通过这个宏实现初始化函数列表的?让我们先来看看__initlist的定义:

[CPP]查看纯文本# define _ _ init _ _ attribute _ _((未使用,__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 _ startextern u32 _ _ initlist _ end

这两个变量起作用。__initlist_start是。initlist部分,而__initlist_end是结尾。通过这两个变量,我们可以访问所有的初始化函数。这两个变量是在哪里定义的?[CPP]查看纯文本。=连接器脚本文件中的ALIGN(4);initlist:{__initlist_start=。*(.initlist)__initlist_end=。}这两个变量的值只是在。initlist部分,所以我们可以通过这两个变量访问所有的初始化函数。

同样,内核中也使用了这种方法,所以我们在写驱动的时候是独立的。我们不需要在固定的地方添加代码来调用自己的初始化函数和退出函数。连接器已经为我们完成了。我们先分析一下module_init。定义如下:[CPP]view plain copy # define module _ init(x)_ _ init call(x);//include/Linux/init . h # define _ _ init call(fn)device _ init call(fn)# define device _ init call(fn)_ _ define _ init call(' 6 'fn,6)

#define__define_initcall(level,fn,id)/static init call _ t _ _ init call _ # # fn # # id _ _ used/_ _ attribute _ _(_ _ section _ _('初始化调用“级别”.init ')))))=fn

如果一个驱动想用func作为驱动的入口,可以这样声明:module _ init(func);经过上面的宏处理后,它变成__initcall_func6 __used并被添加到。内核映像的“initcall”区域。当内核被加载时,它会搜索所有的条目。并根据优先级加载它们。普通司机的优先级是6。其他模块的优先级如下:值越小,加载越早。[CPP]view plain copy # define pure _ init call(fn)_ _ define _ init call(' 0 'fn,0)

# define core _ init call(fn)_ define _ init call(' 1 'fn,1)# define core _ init call _ sync(fn)_ define post core _ init call(' 1s 'fn,1s)_ define post core _ init call _ sync(fn)_ define _ init call(' 2s 'fn,2s)# define earch _ init call(fn)_

# define fs _ init call(fn)_ define _ init call(' 5 'fn,5)# define fs _ init call _ sync(fn)_ define _ init call(' 5s 'fn,5s)_ define _ init call(' root fs 'fn,root fs)# define device _ init call(fn)_ define _ init call(' 6 'fn,6)# define device _ init call _ sync(fn)_ define _ define可以看到,被声明为纯初始化调用的最先加载。

Module_init不仅初始化加载,还在稍后释放内存。linux内核中很大一部分代码是设备驱动代码,有初始化和反初始化功能。通常,这些代码只执行一次。为了更有效地利用内存,可以释放这些代码占用的内存。

linux就是这么做的。它向只需要初始化和运行一次的函数添加__init属性。__init宏告诉编译器,如果模块被编译到内核中,就把这个函数放在(. init.text)部分。module_exit的参数卸载类似于__init。如果驱动编译进内核,__exit宏会忽略清理功能,因为编译进内核的模块不需要清理。显然_ _

在内核初始化后期,所有这些函数代码占用的内存空间都被释放。连接器将带有__init属性的函数放在同一个节中,用完之后释放整个节。当函数初始化时,该区域可被清空以节省系统内存。Kenrel启动时看到的消息“释放未使用的内核内存: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();} creates a kernel thread, and there is a function at the end of the initialization of the main function kernel: [CPP]view plain copy/* * Well, we have finished the initialization and startup, and * we have basically finished running . */init _ post (); The first sentence in this initialization _ release is free _ initmem (); Is used to release the initialization code and data to view plain text.

voidfree_initmem(void){if(!机器集成器().machine _ is _ CIN积分器()){ free _ area((unsigned long)(_ _ init _ begin),(unsignedlong)(__init_end),' init ');}}接下来就是核心内存管理的事了。

以上就是关于linux驱动的入口函数module,init的加载和释放的知识,希望能够帮助到大家!


声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,谢谢。

上一篇: 小宇宙手机官网推出新款机型,最新功能一览

下一篇: qq等级怎么升的更快,QQ等级如何升级更快



猜你感兴趣

推荐阅读

网站内容来自网络,如有侵权请联系我们,立即删除! | 软文发布 | 粤ICP备2021106084号