<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > Linux啟動(dòng)過(guò)程中硬件模塊的加載

Linux啟動(dòng)過(guò)程中硬件模塊的加載

作者: 時(shí)間:2011-02-28 來(lái)源:網(wǎng)絡(luò ) 收藏

  前言:我覺(jué)得我的文章相對來(lái)說(shuō)都是比較淺顯的。一些初學(xué)者可以看看,對于高手來(lái)說(shuō),如果你們不吝嗇時(shí)間的話(huà),希望也能幫我看看,指點(diǎn)一下其中的錯誤。這也是我到這里來(lái)和大家交流的目的。
  閱讀Linux內核啟動(dòng)代碼的直接動(dòng)力是我想編寫(xiě)RTL8019AS的網(wǎng)卡驅動(dòng)程序(2.4.18內核只支持了CS8900A)。既然要寫(xiě)驅動(dòng),我就想知道它是怎么樣被加載的,好奇心驅使我先去搞定這個(gè)問(wèn)題。
  拿到2.4.18的軟件包,一萬(wàn)多個(gè)文件,我不知怎么下手。所幸手頭有這么三件工具助我入門(mén):
  1,一塊移植好linux的開(kāi)發(fā)板,通過(guò)它可以看到linux啟動(dòng)過(guò)程打印的消息。
  2, google,網(wǎng)上關(guān)于linux的資料真是太多了?。?!
  3, Windows文件搜索引擎,通過(guò)它可以知道在那些文件中打印出那些消息。
  很快,我就找到了linux啟動(dòng)的總的入口,/arch/arm/boot/compressed/head.s。
  head.s完成的工作主要是底層寄存器、MMU的一些設定以及kernel的解壓縮。匯編文件中調用的C代碼大多位于該目錄下misc.c文件,比如decompress_kernel。
  當然,這部分不是重點(diǎn),head執行完畢以后就跳到start_kernel(),這才是我們的重點(diǎn)所在,這個(gè)函數位于文件/init/main.c中。這個(gè)文件是啟動(dòng)的主線(xiàn)?。?!
  在start_kernel中,依次執行各個(gè)初始話(huà)函數,這里具體我沒(méi)有看,一直到最后rest_init(),在這個(gè)函數里啟動(dòng)了一個(gè)init線(xiàn)程,而主線(xiàn)程自己則進(jìn)入了IDLE狀態(tài)。所以我們關(guān)心一下init線(xiàn)程做了什么事情,看文件最后init函數。
  在這個(gè)函數里面,先lock_kernel,然后調用do_basic_setup,在這個(gè)函數里面又是一堆的初始化,有一個(gè)函數要引起我們的注意: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();}
  很難相信,我們關(guān)心的外圍模塊的驅動(dòng)就是被這一段程序加載的。怎么回事?我們慢慢來(lái)看:
  首先看__initcall_start和__initcall_end,找遍了所有C代碼,沒(méi)有它們的定義。后來(lái)在vmlinux-armv.lds.in文件中找到了它們:
  __initcall_start = .;*(.initcall.init)__initcall_end = .;這個(gè)文件是和link相關(guān)的文件,它決定代碼在load環(huán)境中的位置,就好比ADS中的scf文件。我們還是先看.initcall.init的含義吧,它在/include/linux/init.h中定義:
  #define __init_call __attribute__ ((unused,__section__ (".initcall.init ")))參考GCC說(shuō)明,這段話(huà)的意思就是說(shuō)所有以__init_call前綴定義的函數在鏈接過(guò)程中都放到名字為.initcall.init的段(section)里面。OK,有點(diǎn)味道了,也就是說(shuō),如果我們給一個(gè)函數冠以__init_call,那么它在編譯鏈接的時(shí)候就會(huì )放到.initcall.init這個(gè)段里面。而上面這段循環(huán)所做的事情就很清楚了,它從段的首地址開(kāi)始,依次執行每一個(gè)函數,直到段尾為止。
  這個(gè)時(shí)候,我們應該在想,那些要注冊的外圍模塊的初始化程序是不是都是定義成__init_call類(lèi)型的呢?正如我們所料,查看各個(gè)模塊我們會(huì )發(fā)現其初始化函數x會(huì )被定義成為module_init(x),在/include/linux/init.h中它定義如下:
  #define module_init(x) __initcall(x);#define __initcall(fn) static initcall_t __initcall_##fn __init_call = fn這段代碼說(shuō)module_init(x)等價(jià)于__initcall(x),而__initcall(x)表示函數x是靜態(tài)的具有__init_call性質(zhì)的函數(這里名字比較多,容易看亂),因此在鏈接時(shí),它會(huì )被放在.initcall.init段中。只要x函數運行起來(lái)了,那就可以注冊設備、中斷入口、中斷服務(wù)函數了。接下來(lái)的事情就好辦了。
  搞清出設備如何被加載以后,我們還需要知道另外一個(gè)問(wèn)題:怎樣把一個(gè)模塊的驅動(dòng)程序加載到內核里面呢?SO簡(jiǎn)單,make menuconfig,把對應設備打開(kāi)。但是能不能再具體一點(diǎn)呢,我們做這么一個(gè)改動(dòng),怎么映射到編譯&鏈接過(guò)程呢。我這個(gè)人就是喜歡找麻煩,因此又在網(wǎng)上搜啊搜,而且用了最笨的方法,看看make menuconfig前后那些文件的修改日期發(fā)生了變化。最終還是找到了一點(diǎn),/scripts下的文件是用來(lái)支持各種config模式的(當然包括menuconfig),核心代碼在Kconfig中。在每個(gè)驅動(dòng)設備的文件夾下(比如net,mtd)都有一個(gè)叫config.in的文件,這些文件定義了我們在menuconfig畫(huà)面中看到的目錄結構&選項。
  眼睛看到的畫(huà)面總歸都是虛的,這些改動(dòng)究竟反映到了哪里去了呢??jì)蓚€(gè)文件:./config和/include/linux/ autoconf.h。我們做完menuconfig以后,所有改動(dòng)就反映到了這兩個(gè)文件中,這兩個(gè)文件的內容是一致的。在我們做編譯的過(guò)程中,頂層的makefile文件從autoconf.h文件中讀取各項宏定義然后傳遞給子一層的makefile,這些makefile根據宏定義選擇那些.o文件被鏈接進(jìn)來(lái)加到內核中。
  好了,知道這些我就知道怎么給8019添加驅動(dòng)了,yy一下:
  1,首先要有驅動(dòng)程序代碼,8019.c2,修改net目錄下的config.in文件中添加一項,dep_tristate ' RTL8019 support' CONFIG_RTL8019 $CONFIG_ISA3,打開(kāi)menuconfig,將RTL8019 support選擇y,保存推出后autoconf文件中應該就有了一個(gè)宏定義:#define CONFIG_RTL80194,打開(kāi)net目錄下的makefile,添加:
  obj-$( CONFIG_RTL8019) = 8019.o5,make dep; make zImage;搞定!
  注:在menuconfig中選擇m和 y的區別:
  y: 模塊驅動(dòng)編譯到內核中,啟動(dòng)時(shí)自動(dòng)加載m:模塊會(huì )被編譯,但是不會(huì )被編譯到內核中,只是生成.o文件,我們可以收集這些.o文件做到linux的文件系統中,然后用insmod實(shí)現動(dòng)態(tài)加載。

linux操作系統文章專(zhuān)題:linux操作系統詳解(linux不再難懂)


評論


相關(guān)推薦

技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>