|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
经常看到有人问用什么版本的linux好,其实只要你认真学习无论什么版本都挺好的。
媒介:我以为我的文章绝对来讲都是对照浅易的。一些初学者能够看看,关于妙手来讲,假如你们不惜啬工夫的话,但愿也能帮我看看,指导一下个中的毛病。这也是我到这里来和人人交换的目标。
浏览Linux内核启动代码的间接动力是我想编写RTL8019AS的网卡驱动程序(2.4.18内核只撑持了CS8900A)。既然要写驱动,我就想晓得它是怎样被加载的,猎奇心使令我先往弄定这个成绩。
拿到2.4.18的软件包,一万多个文件,我不知怎样动手。所幸手头有这么三件工具助我进门:
1,一块移植好linux的开辟板,经由过程它能够看到linux启动历程打印的动静。
2,google,网上关于linux的材料真是太多了!!!
3,Windows文件搜刮引擎,经由过程它能够晓得在那些文件中打印出那些动静。
很快,我就找到了linux启动的总的出口,/arch/arm/boot/compressed/head.s。
head.s完成的事情次要是底层存放器、MMU的一些设定和kernel的解紧缩。汇编文件中挪用的C代码年夜多位于该目次下misc.c文件,好比decompress_kernel。
固然,这部分不是重点,head实行终了今后就跳到start_kernel(),这才是我们的重点地点,这个函数位于文件/init/main.c中。这个文件是启动的主线!!!
在start_kernel中,顺次实行各个初始话函数,这里详细我没有看,一向到最初rest_init(),在这个函数里启动了一个init线程,而主线程本人则进进了IDLE形态。以是我们体贴一下init线程做了甚么事变,看文件最初init函数。
在这个函数内里,先lock_kernel,然后挪用do_basic_setup,在这个函数内里又是一堆的初始化,有一个函数要引发我们的注重:do_initcalls。看看它干了甚么:(这以后的器材鄙人文文件体系中解说)
staticvoid__initdo_initcalls(void)
{
initcall_t*call;
call=&__initcall_start;
do{
(*call)();
call++;
}while(call<&__initcall_end);
/*Makesurethereisnopendingstufffromtheinitcallsequence*/
flush_scheduled_tasks();
}
很难信任,我们体贴的核心模块的驱动就是被这一段程序加载的。怎样回事?我们渐渐来看:
起首看__initcall_start和__initcall_end,找遍了一切C代码,没有它们的界说。厥后在vmlinux-armv.lds.in文件中找到了它们:
__initcall_start=.;
*(.initcall.init)
__initcall_end=.;
这个文件是和link相干的文件,它决意代码在load情况中的地位,就比如ADS中的scf文件。我们仍是先看.initcall.init的寄义吧,它在/include/linux/init.h中界说:
#define__init_call__attribute__((unused,__section__(".initcall.init")))
参考GCC申明,这段话的意义就是说一切以__init_call前缀界说的函数在链接过程当中都放到名字为.initcall.init的段(section)内里。OK,有点滋味了,也就是说,假如我们给一个函数冠以__init_call,那末它在编译链接的时分就会放到.initcall.init这个段内里。而下面这段轮回所做的事变就很分明了,它从段的首地点入手下手,顺次实行每个函数,直到段尾为止。
这个时分,我们应当在想,那些要注册的核心模块的初始化程序是否是都是界说成__init_call范例的呢?正如我们所料,检察各个模块我们会发明其初始化函数x会被界说成为module_init(x),在/include/linux/init.h中它界说以下:
#definemodule_init(x)__initcall(x);
#define__initcall(fn)staticinitcall_t__initcall_##fn__init_call=fn
这段代码说module_init(x)等价于__initcall(x),而__initcall(x)暗示函数x是静态的具有__init_call性子的函数(这里名字对照多,简单看乱),因而在链接时,它会被放在.initcall.init段中。只需x函数运转起来了,那就能够注册设备、中止出口、中止服务函数了。接上去的事变就好办了。
弄清出设备怎样被加载今后,我们还必要晓得别的一个成绩:如何把一个模块的驱动程序加载到内核内里呢?SO复杂,makemenuconfig,把对应设备翻开。可是能不克不及再详细一点呢,我们做这么一个修改,怎样映照到编译&链接历程呢。我这团体就是喜好找贫苦,因而又在网上搜啊搜,并且用了最笨的办法,看看makemenuconfig前后那些文件的修正日期产生了变更。终极仍是找到了一点,/scripts下的文件是用来撑持各类config形式的(固然包含menuconfig),中心代码在Kconfig中。在每一个驱动设备的文件夹下(好比net,mtd)都有一个叫config.in的文件,这些文件界说了我们在menuconfig画面中看到的目次布局&选项。
眼睛看到的画面总回都是虚的,这些修改事实反应到了那里往了呢?两个文件:./config和/include/linux/autoconf.h。我们做完menuconfig今后,一切修改就反应到了这两个文件中,这两个文件的内容是分歧的。在我们做编译的过程当中,顶层的makefile文件从autoconf.h文件中读取各项宏界说然后传送给子一层的makefile,这些makefile依据宏界说选择那些.o文件被链接出去加到内核中。
好了,晓得这些我就晓得怎样给8019增加驱动了,yy一
12下一页
学习linux,就意味着更快的开发效率,等更多关于软件本身或者说操作系统本身的理解。 |
|