乐观 发表于 2015-1-16 10:55:27

来谈谈:Linux启动时加载硬件模块的历程

经常看到有人问用什么版本的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,就意味着更快的开发效率,等更多关于软件本身或者说操作系统本身的理解。

乐观 发表于 2015-1-16 12:12:05

来谈谈:Linux启动时加载硬件模块的历程

对于开发环境的选择尽量要轻量级和高度可定制,航空母舰级别的工具往往会让你迷惑不解;
下:</P>  1,起首要有驱动程序代码,8019.c
  2,修正net目次下的config.in文件中增加一项,
  dep_tristateRTL8019supportCONFIG_RTL8019$CONFIG_ISA
  3,翻开menuconfig,将RTL8019support选择y,保留推出后autoconf文件中应当
  就有了一个宏界说:#defineCONFIG_RTL8019
  4,翻开net目次下的makefile,增加:
  obj-$(CONFIG_RTL8019)+=8019.o
  5,makedep;makezImage;弄定!
  注:在menuconfig当选择m和y的区分:
  y:模块驱动编译到内核中,启动时主动加载
  m:模块会被编译,可是不会被编译到内核中,只是天生.o文件,我们能够搜集这些.o文件做到linux的文件体系中,然后用insmod完成静态加载

</p>上一页12


如果你只是想应付一下操作系统的课程,劝你最好别学,或者说不要指望能用的怎么样。

飘飘悠悠 发表于 2015-1-18 14:38:54

一些显而易见的小错误还是用vi改正比较方便。以后的大一点的程序就得在Linux下调试了,因为有的头文件在VC里面说找不到。?

冷月葬花魂 发表于 2015-1-27 09:10:32

现在的linux操作系统如redhat,难点,红旗等,都是用这么一个内核,加上其它的用程序(包括X)构成的。

精灵巫婆 发表于 2015-2-5 11:46:53

linux鸟哥的私房菜,第三版,基础篇,网上有pdf下的,看它的目录和每章的介绍就行了,这个绝对原创!

若相依 发表于 2015-3-2 19:41:27

熟悉并掌握安装Linux,安装是学习的前提。目前较常见的安装方法有二种:

飘灵儿 发表于 2015-3-11 07:06:18

随着实验课程的结束,理论课也该结束了,说实话教OS的这两位老师是我们遇到过的不错的老师(这话放这可能不太恰当).

admin 发表于 2015-3-18 03:26:27

安装一个新的软件时先看README,再看INSTALL然后看FAQ,最后才动手安装,这样遇到问题就知道为什么。如果Linux说明文档不看,结果出了问题再去论坛来找答案反而浪费时间。

只想知道 发表于 2015-3-25 13:29:19

学习Linux应具备的。[书籍+网络资源]
页: [1]
查看完整版本: 来谈谈:Linux启动时加载硬件模块的历程