Linux启动过程中硬件模块是如何加载的?

出处:互联网    发布于:2011-09-04 12:31:40

  阅读Linux内核启动代码的直接动力是我想编写RTL8019AS网卡驱动程序(2.4.18内核只支持了CS8900A)。既然要写驱动,我就想知道它是怎样被加载的,好奇心驱使我先去弄清楚这个问题。

  拿到2.4.18的软件包,一万多个文件,不知如何下手。所幸的是手头有三件工具助我入门:

  1、一块移植好linux的开发板,通过它可以看到linux启动过程打印的消息。

  2、google,网上关于linux的资料真是太多了!

  3、Windows文件搜索引擎,通过它可以知道在那些文件中打印出那些消息。

  很快,就找到了linux启动的总的入口,/arch/arm/boot/compressed/head.s。

  start:

  .type  start,#functiON

  .rept    8

  mov    r0,r0

  .endr

  ……

  head.s完成的工作主要是底层寄存器、MMU的一些设定以及kernel的解压缩。汇编文件中调用的C代码大多位于该目录下misc.c文件,例如:decompress_kernel。

  head执行完毕后跳到start_kernel(),这个函数位于文件/init/main.c中。

  在start_kernel中,依次执行各个初始话函数,直到rest_init(),在这个函数里启动了一个init线程,而主线程自己则进入了IDLE状态。

  在这个函数里面,先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)里面。如果我们给一个函数冠以__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函数运行起来,就可以注册设备、中断入口、中断服务函数了。

  明白了设备是如何被加载以后,要明白怎么样把一个模块的驱动程序加载到内核里面呢?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实现动态加载。



  

版权与免责声明

凡本网注明“出处:维库电子市场网”的所有作品,版权均属于维库电子市场网,转载请必须注明维库电子市场网,https://www.dzsc.com,违反者本网将追究相关法律责任。

本网转载并注明自其它出处的作品,目的在于传递更多信息,并不代表本网赞同其观点或证实其内容的真实性,不承担此类作品侵权行为的直接责任及连带责任。其他媒体、网站或个人从本网转载时,必须保留本网注明的作品出处,并自负版权等法律责任。

如涉及作品内容、版权等问题,请在作品发表之日起一周内与本网联系,否则视为放弃相关权利。

OEM清单文件: OEM清单文件
*公司名:
*联系人:
*手机号码:
QQ:
有效期:

扫码下载APP,
一键连接广大的电子世界。

在线人工客服

买家服务:
卖家服务:
技术客服:

0571-85317607

网站技术支持

13606545031

客服在线时间周一至周五
9:00-17:30

关注官方微信号,
第一时间获取资讯。

建议反馈

联系人:

联系方式:

按住滑块,拖拽到最右边
>>
感谢您向阿库提出的宝贵意见,您的参与是维库提升服务的动力!意见一经采纳,将有感恩红包奉上哦!