Warning: session_start(): open(/tmp/sess_rqgm219rmlv4bfb6su3ak4brj6, O_RDWR) failed: Disk quota exceeded (122) in /home/tensungn/public_html/www.tzlink.com/info/show.php on line 8

Warning: session_start(): Cannot send session cookie - headers already sent by (output started at /home/tensungn/public_html/www.tzlink.com/info/show.php:8) in /home/tensungn/public_html/www.tzlink.com/info/show.php on line 8

Warning: session_start(): Cannot send session cache limiter - headers already sent (output started at /home/tensungn/public_html/www.tzlink.com/info/show.php:8) in /home/tensungn/public_html/www.tzlink.com/info/show.php on line 8
Linux启动过程中硬件模块的加载 - Linux内核/嵌入技术 - 站长之家

热烈祝贺台州维博网络的站长论坛隆重上线!(2012-05-28)    热烈庆祝伟大的祖国60周年生日 点击进来我们一起为她祝福吧(2009-09-26)    站长论坛禁止发布广告,一经发现立即删除。谢谢各位合作!.(2009-08-08)    热烈祝贺台州网址导航全面升级,全新版本上线!希望各位一如既往地支持台州网址导航的发展.(2009-03-28)    台州站长论坛恭祝各位新年快乐,牛年行大运!(2009-01-24)    台州Link正式更名为台州网址导航,专业做以台州网址为主的网址导航!(2008-05-23)    热烈祝贺台州Link资讯改名为中国站长资讯!希望在以后日子里得到大家的大力支持和帮助!(2008-04-10)    热烈祝贺台州Link论坛改名为台州站长论坛!希望大家继续支持和鼓励!(2008-04-10)    台州站长论坛原[社会琐碎]版块更名为[生活百科]版块!(2007-09-05)    特此通知:新台州站长论坛的数据信息全部升级成功!">特此通知:新台州站长论坛的数据信息全部升级成功!(2007-09-01)    台州站长论坛对未通过验证的会员进行合理的清除,请您谅解(2007-08-30)    台州网址导航|上网导航诚邀世界各地的网站友情链接和友谊联盟,共同引领网站导航、前进!(2007-08-30)    禁止发广告之类的帖,已发现立即删除!(2007-08-30)    希望各位上传与下载有用资源和最新信息(2007-08-30)    热烈祝贺台州站长论坛全面升级成功,全新上线!(2007-08-30)    
便民网址导航,轻松网上冲浪。
台州维博网络专业开发网站门户平台系统
您当前的位置: 首页 » Linux内核/嵌入技术 » Linux启动过程中硬件模块的加载

Linux启动过程中硬件模块的加载

论坛链接
  • Linux启动过程中硬件模块的加载
  • 发布时间:2010-11-09 16:53:00    浏览数:7248    发布者:abcdef133    设置字体【   
前言:我觉得我的文章相对来说都是比较浅显的。一些初学者可以看看,对于高手来说,如果你们不吝啬时间的话,希望也能帮我看看,指点一下其中的错误。这也是我到这里来和大家交流的目的。

  阅读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。看看它干了什么:(这之后的东西在下文文件系统中讲解)

  static void __init do_initcalls(void)

  {

  initcall_t *call;

  call = &__initcall_start;

  do {

  (*call)( );

  call++;

  } while (call < &__initcall_end);

  /* Make sure there is no pending stuff from the initcall sequence */

  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中它定义如下:

  #define module_init(x) __initcall(x);

  #define __initcall(fn) static initcall_t __initcall_##fn __init_call = fn

  这段代码说module_init(x)等价于__initcall(x),而__initcall(x)表示函数x是静态的具有__init_call性质的函数(这里名字比较多,容易看乱),因此在链接时,它会被放在.initcall.init段中。只要x函数运行起来了,那就可以注册设备、中断入口、中断服务函数了。接下来的事情就好办了。

  搞清出设备如何被加载以后,我们还需要知道另外一个问题:怎样把一个模块的驱动程序加载到内核里面呢?SO简单,make menuconfig,把对应设备打开。但是能不能再具体一点呢,我们做这么一个改动,怎么映射到编译&链接过程呢。我这个人就是喜欢找麻烦,因此又在网上搜啊搜,而且用了最笨的方法,看看make menuconfig前后那些文件的修改日期发生了变化。最终还是找到了一点,/scripts下的文件是用来支持各种config模式的(当然包括menuconfig),核心代码在Kconfig中。在每个驱动设备的文件夹下(比如net,mtd)都有一个叫config.in的文件,这些文件定义了我们在menuconfig画面中看到的目录结构&选项。

  眼睛看到的画面总归都是虚的,这些改动究竟反映到了哪里去了呢?两个文件:./config和/include/linux/ autoconf.h。我们做完menuconfig以后,所有改动就反映到了这两个文件中,这两个文件的内容是一致的。在我们做编译的过程中,顶层的makefile文件从autoconf.h文件中读取各项宏定义然后传递给子一层的makefile,这些makefile根据宏定义选择那些.o文件被链接进来加到内核中。

  好了,知道这些我就知道怎么给8019添加驱动了,yy一下:

  1,首先要有驱动程序代码,8019.c

  2,修改net目录下的config.in文件中添加一项,

  dep_tristate ' RTL8019 support' CONFIG_RTL8019 $CONFIG_ISA

  3,打开menuconfig,将RTL8019 support选择y,保存推出后autoconf文件中应该

  就有了一个宏定义:#define CONFIG_RTL8019

  4,打开net目录下的makefile,添加:

  obj-$( CONFIG_RTL8019) += 8019.o

  5,make dep; make zImage;搞定!

  注:在menuconfig中选择m和y的区别:

  y: 模块驱动编译到内核中,启动时自动加载

  m:模块会被编译,但是不会被编译到内核中,只是生成.o文件,我们可以收集这些.o文件做到linux的文件系统中,然后用insmod实现动态加载。
娱乐休闲专区A 影视预告B 音乐咖啡C 英语阶梯D 生活百科
网页编程专区E AMPZF HTMLG CSSH JSI ASPJ PHPK JSPL MySQLM AJAX
Linux技术区 N 系统管理O 服务器架设P 网络/硬件Q 编程序开发R 内核/嵌入
管理中心专区S 发布网址T 版主议事U 事务处理

Warning: Unknown: open(/tmp/sess_rqgm219rmlv4bfb6su3ak4brj6, O_RDWR) failed: Disk quota exceeded (122) in Unknown on line 0

Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/tmp) in Unknown on line 0