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