详解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 = .;

如果心在远方,只需勇敢前行,梦想自会引路,

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

相关文章:

你感兴趣的文章:

标签云: