`
qiaoweishu
  • 浏览: 65335 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

【zz】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。看看它干了什么:(这之后的东西在下文文件系统中讲解)
    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实现动态加载。

http://hi.baidu.com/jackyu/blog/item/a89ba634e31418bcd1a2d3e5.html

2010-12-07-21-55
分享到:
评论

相关推荐

    应用广泛的嵌入式操作系统——ZZ-Linux.pdf

    应用广泛的嵌入式操作系统——ZZ-Linux.pdf

    base zz zz zz zz

    base zz zz zz zz zz base zz zz zz zz zz base zz zz zz zz zz base zz zz zz zz zz

    linux db2 安装过程中可能缺少的 libaio 安装文件

    linux db2 安装过程中可能缺少的 libaio 安装文件

    超出NLO QCD的高横向动量的ZZ产生

    还包括对ZZ过程的精确胶子融合环平方的贡献。 最重要的是,我们将来自胶子-胶子通道的胶子-融合ZZ + jet贡献添加到我们的合并样本中,胶子-胶子通道正式是N3LO,并在NLO上为胶子-融合机理提供了近似结果。 这些预测...

    zz CAD快速计算长度插件

    在CAD中想要快速测量长度,在CAD工具栏找到加载应用程序,再点击加载 加载成功后在输入栏输入“zz”(不分大小写)在选择你需要测量的线段即可。

    ZZ561401.CAB

    ZZ561401.CAB ZZ561401.CAB ZZ561401.CAB

    Linux应用技术:Linux的安装.pptx

    第一讲 初识Linux --概况及安装;第一讲 主要内容;安装前的准备;添加虚拟机(演示);安装版本选择;安装途径选择;安装方式选择;安装演示;安装演示;Linux的分区格式;Linux如何表示硬盘和分区;...Linux的启动与登录

    wincc AX NF ZZ

    wincc SIMATIC WinCC是第一个使用最新的32位技术的过程监视系统,具有良好的开放性和灵活性。 从面市伊始,用户就对SIMATIC WinCC印象深刻。

    linux教程——很使用的那种

    Linux中数据块是储存数据的基本数据单元,在linux中可以设置3中数据块大小分别是1024(1kB),2048(2KB),4096(4KB)。数据块大小决定了文件磁盘占有量,如果设置了数据块大小是1024,不管文件有多大,至少要占1KB的空间,所以...

    Linux 中util-linux 工具包的源码

    Linux 中util-linux 工具包的源码,可用于交叉编译,里面包含hwclock等Linux命令的完整版,busybox里面系统自带的命令是阉割版,这里的是完整版本

    zz1165935664-BLab-master_zzk3686_pcb_esp8266电路_esp8266电路板_模块pcb_

    zz1165935664-BLab-master_zzk3686_pcb_esp8266电路_esp8266电路板_模块pcb_源码.zip

    Linux经典学习书籍

    第一章 linux 系统简介及安装  Linux 内核项目是由芬兰赫尔辛基大学的 Linus Torvalds 创建  内核版本是由 Linux 内核社区统一进行发布的 1.内核版本的格式 内核版本号的格式为 xx.yy.zz 版本号中 yy为奇数...

    Advanced Linux Programming.pdf

    Advanced Linux Programming zz from: 20本最好的Linux免费书籍 http://cocre.com/?p=355

    funcoeszz:ZZ功能-适用于Linux,Mac和Cygwin的180多个命令行应用程序

    功能ZZ是一个集合,具有超过180个不同用途的小程序,可以在UNIX类型的系统(Linux,BSD,Cygwin,Mac OS X等)的命令行中使用。 网站: : GitHub: : Wiki: : 推特: : 许可证: 贡献者名单 如何贡献 分叉...

    ZZ8500/20/40型液压支架中缸筒设计及工艺的改进

    针对ZZ8500/20/40型液压支架中缸筒设计不合理部分进行改进。分别列举了中缸筒按原设计和改进后设计进行加工的工艺过程,并对二者进行了比较。改进前设计加工工艺繁琐,费料费时,效率低;改进后省工省料,可降低成本,提高...

    在pp碰撞中测量ZZ生产截面和Z→分支分数

    质子-质子碰撞中的四轻子产生,pp→(Z /γ⁎)(Z /γ⁎)→ℓ+ℓ-ℓ′+ ℓ′-,其中ℓ,ℓ′= e或μ,在 大型强子对撞机的CMS检测器的质心能量为13 TeV。 数据样本对应于2.6 fb $ ^ {-1} $的综合亮度。 对于具有两...

    7zip_linux_21.7.deb

    根据 7zip 官方版本制作的 deb 安装包,可以直接在Linux 系统上使用 `dpkg...本资源仅仅是为方便安装进行的deb包封装,并对可执行文件 `7zz` 进行了重命名复制为 `7zip`,因此安装后使用时可以直接使用`7zip`作为命令。

    3_Level_ZZ_Semafor.zip_3 level_zz_3_Level_ZZ_semafor_ZZ Semafor_

    ,主图指标,顶底信号,突破,转折信号,都很明显

    程序员的编辑器——VIM(zz) - 饮水思源

    程序员的编辑器——VIM(zz) - 饮水思源

    geebinf modified by zz.ens

    写中文文章,或者外文,参考文献格式。例如:[1] Niu M, Hu Y, Sun S, et al. A novel hybrid decomposition-ensemble model based on VMD and HGWO for container throughput forecasting[J]. Applied Mathematical...

Global site tag (gtag.js) - Google Analytics