uclinux啟動(dòng)過(guò)程詳細分析
一 般, 在Linux中初始化腳本在/etc/inittab 文件(或稱(chēng)初始化表)中可以找到關(guān)于不同運行級別的描述。inittab是以行為單位的描述性(非執行性)文本,每一個(gè)指令行都是固定格式。 inittab中有respawn項,但如果一個(gè)命令運行時(shí)失敗了,為了避免重運行的頻率太高,init將追蹤一個(gè)命令重運行了多少次,并且如果重運行的 頻率太高,它將被延時(shí)五分鐘后再運行。
② kernel進(jìn)程
A》 請注意init是1號進(jìn)程,其他進(jìn)程id分別是kflushd/ bdflush, kupdate, kpiod and kswapd。這里有一個(gè)要指出的:你會(huì )注意到虛擬占用(SIZE)和實(shí)際占用(RSS)列都是0,進(jìn)程怎么會(huì )不使用內存呢?
這些進(jìn)程就是內核守護進(jìn)程。大部分內核并不顯示在進(jìn)程列表里。守護進(jìn)程在init之后啟動(dòng),所以他們和其他進(jìn)程一樣有進(jìn)程ID,但是他們的代碼和數據都存放在內核占有的內存中。在列表中使用中括號來(lái)區別與其他進(jìn)程。
B》 輸入和輸出是通過(guò)內存中的緩沖來(lái)完成的,這讓事情變得更快,程序的寫(xiě)入會(huì )存放在內存緩沖中,然后再一起寫(xiě)入硬盤(pán)。守護進(jìn)程kflushd和kupdate 管理這些工作。kupdate間斷的工作(每5秒)來(lái)檢查是否有寫(xiě)過(guò)的緩沖,如過(guò)有,就讓kflushd把它們寫(xiě)入磁盤(pán)。
C》 進(jìn)程有時(shí)候無(wú)事可做,當它運行時(shí)也不一定需要把其所有的代碼和數據都放在內存中。這就意味著(zhù)我們可以通過(guò)把運行中程序不用的內容切換到交換分區來(lái)更好的是利用內存。把這些進(jìn)程數據移入/移出內存通過(guò)進(jìn)程IO管理守護進(jìn)程kpiod和交換守護進(jìn)程kswapd,大約每隔1秒,kswapd醒來(lái)并檢查內存情 況。如果在硬盤(pán)的東西要讀入內存,或者內存可用空間不足,kpiod就會(huì )被調用來(lái)做移入/移出操作。
D》 bdflush - BUF_DIRTY, 將dirty緩存寫(xiě)回到磁盤(pán)的核心守護進(jìn)程。對于有許多臟的緩沖區(包含必須同時(shí)寫(xiě)到磁盤(pán)的數據的緩沖區)的系統提供了動(dòng)態(tài)的響應。它在系統啟動(dòng)的時(shí)候作為一個(gè)核心線(xiàn)程啟動(dòng),它叫自己為 “kflushd”,而這是你用ps顯示系統中的進(jìn)程的時(shí)候你會(huì )看得的名字。即定期(5秒)將臟(dirty)緩沖區的內容寫(xiě)入磁盤(pán),以騰出內存;
E》 ksoftirqd_CPUx 是一個(gè)死循環(huán), 負責處理軟中斷的。它是用來(lái)對軟中斷隊列進(jìn)行緩沖處理的進(jìn)程。當發(fā)生軟中斷時(shí),系統并不急于處理,只是將相應的cpu的中斷狀態(tài)結構中的active 的相應的位,置位,并將相應的處理函數掛到相應的隊列,然后等待調度時(shí)機來(lái)臨,再來(lái)處理。
ksoftirqd_CPUx是由 cpu_raise_softirq() 即cpu觸發(fā)中斷,喚醒的內核線(xiàn)程,這涉及到軟中斷,ksoftirqd的代碼參見(jiàn)[kernel/softirq.c]。
F》 keventd,它的任務(wù)就是執行 scheduler 調度器隊列中的任務(wù),keventd 為它運行的任務(wù)提供了可預期的進(jìn)程上下文。
G》 khubd, 是用來(lái)檢測USB hub設備的,當usb有動(dòng)態(tài)插拔時(shí),將交由此內核進(jìn)程來(lái)處理。在檢測到有hub事件時(shí)會(huì )有相應的動(dòng)作(usb_hub_events())
H》 mtdblockd是用來(lái)對flash塊設備進(jìn)行寫(xiě)操作的守護進(jìn)程。NAND類(lèi)型的Flash需要MTD(Memory Technology Devices 內存技術(shù)驅動(dòng)程序)驅動(dòng)的支持才能被linux所使用。NAND的特點(diǎn)是不能在芯片內執行(XIP,eXecute In Place),需要把代碼讀到系統RAM中再執行,傳輸效率不是最高,最大擦寫(xiě)次數量為一百萬(wàn)次,但寫(xiě)入和擦除的速度很快,擦除單元小,是高數據存儲密度 的最佳選擇。NAND需要I/O接口,因此使用時(shí)需要驅動(dòng)程序。
I》 loop0 是負責處理loop塊設備的(回環(huán)設備)。loopback device指的就是拿文件來(lái)模擬塊設備, 在我們這里,loop設備主要用來(lái)處理需要mount到板上的文件系統,類(lèi)似mount /tmp/rootfs /mnt -o loop。。我們的實(shí)例有:mount -o loop -t cramfs /xxx.bin /xxx 也就是將xxx.bin這個(gè)文件mount到板上來(lái)模擬cramfs壓縮ram文件系統。loop0進(jìn)程負責對loop設備進(jìn)行操作。
loopback設備和其他的塊設備的使用方法相同。特別的是,可以在該設備上建立一個(gè)文件系統,然后利用mount命令把該系統映射到某個(gè)目錄下以便訪(fǎng)問(wèn)。這種整個(gè)建立在一個(gè)普通磁盤(pán)文件上的文件系統,就是虛擬文件系統 (virtual file system)。
總結
上面的內容是本人為了在實(shí)際開(kāi)發(fā)中更加清楚地了解uclinux的啟動(dòng)過(guò)程而做的一個(gè)總結性的文章。在對uclinux的啟動(dòng)過(guò)程做了一個(gè)詳細注釋后,大家 會(huì )對涉及到嵌入系統的各個(gè)概念有了一個(gè)更加明確的認識,并能對嵌入系統的軟硬件環(huán)境的有關(guān)設置更加清楚。當你自己動(dòng)手結合linux源代碼來(lái)分析時(shí),將會(huì )有一個(gè)清楚的全局觀(guān)。
=============================================================
1. 運行bootloader初始化程序
SRAM 、SDRAM等存儲設備屬于揮發(fā)性的存儲器,掉電以后其中的內容就會(huì )全部丟失,所以必須把操作系統的內核鏡像存放在Flash等不揮發(fā)性存儲介質(zhì)上。但是操作系統在運行時(shí),需要動(dòng)態(tài)的創(chuàng )建一些如數據段、堆棧、頁(yè)表(針對使用虛擬地址的操作系統)等內容,所以需要在RAM中運行操作系統。
因此,就需要一個(gè)引導程序把操作系統的內核鏡像從Flash存儲器拷貝到RAM中,然后再從RAM中執行操作系統的內核。Bootloader就是可以完成這樣一種功能的程序。
從本質(zhì)上來(lái)講,bootloader不屬于操作系統內核。它采用匯編語(yǔ)言編寫(xiě),因此針對不同的CPU體系結構,這一部分代碼不具有可移植性。在移植操作系統時(shí),這部分代碼必須加以改寫(xiě)
具體來(lái)講,bootloader在系統啟動(dòng)時(shí)主要完成以下幾項工作:
(1) 將操作系統內核從Flash拷貝到SDRAM中,如果是壓縮格式的內核,還要將之解壓縮。
(2) 改寫(xiě)系統的memory map,原先f(wàn)lash起始地址映射為0地址,這時(shí)需要將RAM的起始地址映射為0。
(3) 設置堆棧指針并將bss段清零。
將來(lái)執行C語(yǔ)言程序和調用子函數時(shí)要用到
(4) 改變pc值,使得CPU開(kāi)始執行真正的操作系統內核。
2. 運行操作系統內核
bootloader程序執行完上述的各項工作后,通過(guò)一條跳轉指令,轉而執行init目錄下C語(yǔ)言源文件main.c中的函數start_kernel()。
因為在此之前bootloader已經(jīng)創(chuàng )建好一個(gè)初始化環(huán)境,C函數可以開(kāi)始執行了。
整個(gè)操作系統內核的初始化工作從這里才算是真正開(kāi)始。這個(gè)函數的長(cháng)度比較短,代碼如下:
評論