嵌入式Linux的啟動流程:
Bootloader:硬體上電後跳到一個固定位置執行相應代碼,初始化相應裝置,載入核心代碼到記憶體,跳到核心代碼起始位置執行;
kernel:核心自解壓,初始化靜態編譯進核心的驅動模組,掛載根檔案系統,直接執行第一個使用者空間程式;
第一個使用者空間程式:配置使用者環境和執行服務進程。
1. 系統的啟動和初始化
在基於Intel的系統上,當 loadlin.exe 或 LILO把核心裝入到記憶體並把控制權傳遞給核心時,核心開始啟動。arch/i386/kernel/head.S 進行特定結構的設定,然後跳轉到init/main.c的main()常式。
2. 記憶體管理
記憶體管理的代碼主要在/mm,但特定結構的代碼在arch/*/mm。缺頁中斷處理的代碼在mm/memory.c ,而記憶體映射和頁快取器的代碼在mm/filemap.c。緩衝器快取是在mm/buffer.c 中實現,而交換快取是在mm/swap_state.c 和 mm/swapfile.c中實現。
3. 核心
核心中,特定結構的代碼在arch/*/kernel,發送器在kernel/sched.c,fork的代碼在kernel/fork.c,task_struct 資料結構在 include/linux/sched.h中。
4. PCI
PCI 偽驅動程式在 drivers/pci/pci.c ,其定義在include/linux/pci.h。每一種結構都有一些特定的 PCI BIOS 代碼,Intel的在arch/alpha/kernel/bios32.c。
5. 處理序間通訊
所有System V IPC 對象許可權都包含在 ipc_perm 資料結構中,這可以在 include/linux/ipc.h中找到。System V 訊息是在ipc/msg.c中實現,共用記憶體在 ipc/shm.c中,訊號量在 ipc/sem.c中,管道在 ipc/pipe.c中實現。
6. 中斷處理
核心的中斷處理代碼是幾乎所有的微處理器所特有的。中斷處理代碼在arch/i386/kernel/irq.c中,其定義在include/asm-i386/irq.h中。
7. 裝置驅動程式
Linux裝置驅動程式的所有原始碼都儲存在/driver,根據類型可進一步劃分為:
/block
塊裝置驅動程式如ide(在ide.c)。如果你想看包含檔案系統的所有裝置是如何被初始化的,你應當看drivers/block/genhd.c中的device_setup(),device_setup()不僅初始化了硬碟,當一個網路安裝nfs檔案系統時,它也初始化網路。塊裝置包含了基於IDE和SCSI的裝置。
/char
這是看字元裝置(如tty,串口及滑鼠等)驅動程式的地方。
/cdrom
Linux的所有CDROM代碼都在這兒,如在這兒可以找到Soundblaster CDROM的驅動程式。注意ide CD的驅動程式是 ide-cd.c,放在drivers/block,SCSI CD的驅動程式是scsi.c,放在drivers/scsi。
/pci
這是PCI偽驅動程式的原始碼,在這裡可以看到PCI子系統是如何被映射和初始化的。
/scsi
在這裡可以找到所有的SCSI代碼及Linux所支援的scsi裝置的所有裝置驅動程式。
/net
在這裡可以找到網路裝置驅動程式,如DECChip 21040 PCI 乙太網路驅動程式在tulip.c中。
/sound
這是所有音效卡驅動程式的所在地。
8. 檔案系統
EXT2 檔案系統的原始碼全部在fs/ext2/目錄下,而其資料結構的定義在include/linux/ext2_fs.h, ext2_fs_i.h 及ext2_fs_sb.h中。虛擬檔案系統的資料結構在include/linux/fs.h中描述,而代碼在fs/*中。緩衝區快取與更新核心的守護進程的實現是在 fs/buffer.c中 。
8. 網路
網路代碼儲存在/net中,大部分的include檔案在include/net下,BSD套節口代碼在net/socket.c中,IP 第4版本的套節口代碼在net/ipv4/af_inet.c。一般的協議支援代碼(包括sk_buff 處理常式)在net/core下,TCP/IP連網代碼在net/ipv4下,網路裝置驅動程式在/drivers/net下。
9. 模組
核心模組的代碼部分在核心中,部分在模組包中,前者全部在kernel/modules.c中,而資料結構和核心守護進程kerneld的資訊分別在include/linux/module.h和include/linux/kerneld.h 中。如果你想看ELF目標檔案的結構,它位於include/linux/elf.h中。
電腦在啟動時都是先加電,然後進行硬體檢測並引導作業系統的初始化程式,然後作業系統的初始化程式程負責讀入系統核心並建產系統的運行環境.一這過程相對來說比較複而且與CPU體繫結構相關,這裡我們通過linux並以i386的體繫結構對這一過程進行較為詳細的說明.
一、硬體檢測
當
機器加電後它首先執行BIOS(基本輸出入系統 (BIOS))中的代碼,BIOS首先執行加電自檢程式(POST),當自檢通過程便完成了硬體的啟動。POST程式
通過對記憶體及其他硬體的裝置的診斷檢測確定硬體的存在並可正確操作。BIOS是固化在晶片裡的程式,執行這一過程一般只需要幾秒鐘。當自檢完成後
BIOS按照系統COMS中設定的啟動順序搜尋有效開機磁碟機(這裡我們以硬碟為例),並讀入系統開機磁區,並將系統控制權交給引導程式。
二、載入和執行引導程式
系統引導程式主要是把系統核心裝載到記憶體,啟動盤必須在第一個邏輯磁軌上包含引導記錄。這512個位元組的扇區又被稱作是開機磁區,在系統完成加電自檢後,
BIOS從啟動盤中將開機磁區讀入到記憶體中。引導記錄中包含了一些磁碟的物理特性的參數。在開機磁區被讀入記憶體後,BIOS就能從這裡讀取到啟動盤的物理
參數。一旦引導記錄載入完畢,BIOS就交出系統的執行控制權,跳轉到引導程式
的頭部執行。引導記錄開頭是一條無條件轉移指令,它將立即跳轉到地址0x03e執行引導程式,在開機磁區中這個引導程式將從磁碟中讀出其他幾個更為複雜的程式並由它們載入系統核心。
Linux的
引導程式由彙編代碼檔案arch/i386/boot/bootsect.S產生,它利用對BIOS功能的調用將
arch/i386/boot/下的setup.S檔案和核心映象載入到記憶體。i386的體繫結構的CPU分保護模式和實模式兩種,在實模式下只能使用低
端的640K記憶體。系統在載入引導程式時CPU是處在實模式下,而現在的核心映象檔案一般都超過了640K的限制,即使是經過壓縮過的核心映象,這個核心
映象檔案通常是bzImage,我們在編譯核心時通常要用到這個檔案。由於bzImage超出了640K這一限制,所以linux設
計了一個
bootsect_helper子程式(定義在arch/i386/boot/setup.S中),引導程式通過迴圈調用bootsect_helper
將核心映象一塊一塊的裝入記憶體,當核心載入完畢,系統跳轉到setup.S的開始位置開始執行,setup.S仍在實模式下運行,主要功能是設定系統參數
(如:記憶體、磁碟等),並為進入保護模式做準備,最後進入到保護模式並跳轉到核心映象檔案的頭部開始執行核心。這裡提一下有關linux的
引導程式
lilo和grub,lilo和grub可以引導多個系統,如果機器上要裝多系統的話一般都會用到它們,這一引導程式也儲存在開機磁區中或者存放在主引導
記錄中(MBR),lilo和grub都許允使用者自己配置,它們在系統安裝時建立了關於系統核心佔用磁碟資料區塊的位置對照表。當使用者選擇啟動linux系統後,同樣也跳轉到setup.S上運行。
三、核心初始化
當setup.S執行完後,CPU進行保護模式,並開始執行核心,如果核心是經過壓縮的,那麼首先執行 arch/i386/boot/compressed目錄下的head.S建立堆棧並解壓核心映象檔案,然後再轉入arch/i386/kernel下的 head.S。如果沒有壓縮則直接轉到arch/i386/kernel下的head.S開始執行。arch/i386/kernel/head.S程式負責資料區(BBS)、中斷描述表(IDT)、段描述表(GDT)、頁表和寄存器的初始化。最後進入start_kernel()模組。
此時系統運行在核心模式(0層級)下,轉入到init/main.c中的start_kernel()。start_kernel()繼續其他方面的初始化工作,主要是初始化系統的核心資料結構,主要包括:
setup_arch():執行與體繫結構相關的設定。
trap_init():設定各種入口地址。
init_IRQ():初始化IRQ中斷處理機制。
sched_init():設定並啟動第一個進程init_task()。
softirq_init():對非強制中斷子系統進行初始化。
console_init():初始化控制台、顯示器.
init_modules():初始化kernel_module。
fork_init():定義系統最大進程數.
最後進入rest_init()函數並調用kernel_thread()建立init核心線程,進行系統配置。
init核心線程佔用進程描述表的第一項,由它來建立其他完成系統初始他的進程。
init核心線程首先要銷定核心,然後調用do_basic_setup()來初始化外部裝置及載入驅動程式。主
要的初始化工作包括:
PCI匯流排初始化。
網路初始化。
檔案系統初始化。
負載檔案系統。
在do_basic_setup()調用完成後,init()會釋放初始化函資料佔用的記憶體,並且開啟/dev/console
裝置重新定向控制台,用系統調用execve來執行使用者態程式/sbin/init。至此,linux的核心初始化工作完成。
下面的工作就由使用者態的/sbin/init程式來完成。init程式程讀取/etc/inittab檔案來決定它具體的工作。在inittab中比較重要的幾條是:
id:5:initdefault 決定作業系統啟動時預設的執行層級(這裡說講的是系統的運行層級,而不同於CPU的層級)
si:sysinit:/etc/rc.d/rc.sysinit 執行/etc/rc.d/rc.sysinit的指令碼。rc.sysinit主要的工作是 啟用交換分區、檢查磁碟、載入硬體模組。
1:2345:respawn:/sbin/mingetty tty1 顯示登入介面