Linux系統的啓動流程大致可以分爲以下幾個步驟:
POST(加電自檢)--> 系統引導(grub,efi)--> 啓動內核 --> 初始化系統 --> 打印登錄提示符
下面詳細介紹下每個步驟的情況:
1、BIOS啓動
BIOS(Basic Input / Output System),又叫基本輸入輸出系統,這是一段程序,永久性的記錄在主板上的ROM中,ROM中的內容一但寫入則無法更改,所以上面的內容是隻讀的。現在高級了一點,用閃存代替了ROM,可以對BIOS程序進行升級。BIOS包括這幾個內容:
● 自診斷程序 #通過讀取CMOS RAM中的內容識別硬件配置,並對其進行自檢和初始化
● CMOS設置程序 #引導過程中,通過特殊熱鍵啓動,進行設置後,存入CMOS RAM中
● 系統自動裝載程序 #在系統自檢成功後,將磁盤相對0道0扇區上的引導程序裝入內存使其運行
● 主要I/O驅動程序 #BIOS和硬件直接打交道,需要加載I/O驅動程序
● 中斷服務 #主要用來在程序軟件與微機硬件之間實現銜接
這些程序的具體執行過程如下:
1) 按下電源開關,電源就開始向主板和其它設備供電;當芯片組檢測到電源已經開始穩定供電了,它便撤去RESET信號,CPU馬上就從地址FFFF:0000H 處開始執行指令,放在這裏的只是一條跳轉指令,跳到系統BIOS中真正的啓動代碼處。
2)系統BIOS的啓動代碼首先進行POST(Power-On Self Test,加電後自檢)。POST的主要檢測系統中一些關鍵設備是否存在和能否正常工作,例如內存和顯卡等設備;由於POST是最早進行的檢測過程,此時顯卡還沒有初始化,如果系統BIOS在進行POST的過程中發現了一些致命錯誤,例如沒有找到內存或者內存有問題(此時只會檢查640K常規內存),那麼系統BIOS就會直接控制喇叭發聲來報告錯誤,聲音的長短和次數代表了錯誤的類型;在正常情況下,POST過程進行得非常快,幾乎無法感覺到它的存在。POST結束之後就會調用其它代碼來進行更完整的硬件檢測。
3)接下來系統BIOS將查找顯卡的BIOS。前面說過,存放顯卡BIOS的ROM芯片的起始地址通常設在C0000H處,系統BIOS在這個地方找到顯卡BIOS之後就調用它的初始化代碼,由顯卡BIOS來初始化顯卡。此時多數顯卡都會在屏幕上顯示出一些初始化信息,介紹生產廠商、圖形芯片類型等內容,不過這個畫面幾乎是一閃而過。系統BIOS接着會查找其它設備的BIOS程序,找到之後同樣要調用這些BIOS內部的初始化代碼來初始化相關的設備。
4)查找完所有其它設備的BIOS之後,系統BIOS將顯示出它自己的啓動畫面,其中包括有系統BIOS的類型、序列號和版本號等內容。
5)接着系統BIOS將檢測和顯示CPU的類型和工作頻率,測試所有的RAM,並同時在屏幕上顯示內存測試的進度。可以在CMOS設置中自行決定使用簡單耗時少或者詳細耗時多的測試方式。
6)內存測試通過之後,系統BIOS將開始檢測系統中安裝的一些標準硬件設備,包括硬盤、CD-ROM、串口、並口和軟驅等設備,另外絕大多數較新版本的系統BIOS在這一過程中還要自動檢測和設置內存的定時參數、硬盤參數和訪問模式等。
7) 標準設備檢測完畢後,系統BIOS內部支持即插即用的代碼將開始檢測和配置系統中安裝的即插即用設備。每找到一個設備之後,系統BIOS都會在屏幕上顯示出設備的名稱和型號等信息,同時爲該設備分配中斷、DMA通道和I/O端口等資源。
8)到這一步爲止,所有硬件都已經檢測配置完畢了,多數系統BIOS會重新清屏並在屏幕上方顯示出一個表格,其中概略地列出了系統中安裝的各種標準硬件設備,以及它們使用的資源和一些相關工作參數。
9)接下來系統BIOS將更新ESCD(Extended System Configuration Data,擴展系統配置數據)。ESCD是系統BIOS用來與操作系統交換硬件配置信息的一種手段,這些數據被存放在CMOS(一小塊特殊的RAM,由主板上的電池來供電)之中。
10) ESCD更新完畢後,系統BIOS的啓動代碼將進行它的最後一項工作:即根據用戶指定的啓動順序從軟盤、硬盤或光驅啓動MBR。在這個過程中會按照啓動順序比較其放置MBR的位置的結尾兩位是否爲0xAA55,通過這種方式判斷從哪個引導設備進行引導。在確定之後,將該引導設備的MBR內容讀入到0x7C00的位置,並再次判斷其最後兩位,當檢測正確之後,進行階段1(stage1)的引導。
加載了MBR後,就開始了系統的引導過程,系統的引導過程分2個階段:stage1,stage2。主要的引導工作有stage2完成。其實在stage1和stage2之間還有一個stage1_5,stage1_5,是進入stage2的一個橋樑。先介紹一下MBR,MBR是Master Boot Record的縮寫,位於硬盤的0柱面0磁道1扇區上,總大小512字節,一共由3部分組成:
● 1~446(字節): bootloader # 引導加載器,是一段程序
● 之後的64(字節):partation table #分區表
● 最後2(字節):5A #表示bootloader和分區表是否有效的標記位(MBR 以兩個特殊數字的字節(0xAA55)結束。這個數字會用來進行 MBR 的有效性檢查。)
2、grub的stage1階段
stage1部分佔用了446字節,其代碼文件是源碼目錄下stage1/stage1.S文件,彙編後生成一個512字節的boot.img,被寫在硬盤的0柱面0磁道1扇區中,作爲硬盤的MBR。stage1的工作很簡單,就是加載0柱面0磁道2扇區上的512字節到0×8000(通過調用 BIOS INIT13中斷完成),然後跳轉到0×8000執行。 在0柱面0磁道2扇區上的512字節內容爲stage1/start.S文件彙編後生成。該扇區上的內容的作用是加載stage1.5,並將控制權轉交。
3、加載stage1.5 階段
Stage1.5作用很單一,但是非常關鍵。它的主要功用就是構造一個boot分區系統對應的文件系統,這樣可以通過文件系統的路徑(/boot/grub/)尋找stage2過程需要的core.img,進而加載到內存中開始執行。
Stage1.5存在於0柱面磁道3扇區開始的地方,並一直延續十幾k字節的區域,具體的大小與相應的文件系統的大小有關(文中涉及到了0柱面0磁道1-3+x扇區,這部分扇區爲保留扇區,BIOS不會放置任何數據。Stage1.5過程被構建成多種不同類型,但是功能類似。e2fs_stage1_5(針對ext2fs,可引導ext2和ext3文件系統)、fat_stage1_5(針對fat文件系統,可引導fat32和fat16)、ffs_stage1_5、jfs_stage1_5、minix_stage1_5、reiserfs_stage1_5、vstafs_stage1_5和xfs_stage1_5,這些文件被稱爲stage1.5過程,這些文件每個至少都在11k以上(stage1.5支持的文件系統位於/boot/grub目錄下,以stage1_5結尾的文件)。
[root@baby-CentOS grub]# pwd /boot/grub [root@baby-CentOS grub]# ll total 280 -rw-r--r--. 1 root root 63 May 29 16:23 device.map -rw-r--r--. 1 root root 13380 May 29 16:23 e2fs_stage1_5 -rw-r--r--. 1 root root 12620 May 29 16:23 fat_stage1_5 -rw-r--r--. 1 root root 11748 May 29 16:23 ffs_stage1_5 -rw-------. 1 root root 769 May 29 16:43 grub.conf -rw-r--r--. 1 root root 11756 May 29 16:23 iso9660_stage1_5 -rw-r--r--. 1 root root 13268 May 29 16:23 jfs_stage1_5 lrwxrwxrwx. 1 root root 11 May 29 16:23 menu.lst -> ./grub.conf -rw-r--r--. 1 root root 11956 May 29 16:23 minix_stage1_5 -rw-r--r--. 1 root root 14412 May 29 16:23 reiserfs_stage1_5 -rw-r--r--. 1 root root 1341 Nov 15 2010 splash.xpm.gz -rw-r--r--. 1 root root 512 May 29 16:23 stage1 -rw-r--r--. 1 root root 126100 May 29 16:23 stage2 -rw-r--r--. 1 root root 12024 May 29 16:23 ufs2_stage1_5 -rw-r--r--. 1 root root 11364 May 29 16:23 vstafs_stage1_5 -rw-r--r--. 1 root root 13964 May 29 16:23 xfs_stage1_5
除此之外還有兩個比較特殊的文件,分別爲nbgrub和pxegrub,這兩個文件主要是在網絡引導時使用,只是格式不同而已,他們很類似與stage2,只是需要建立網絡來獲取配置文件。 Stage1.5(0柱面0磁道3扇區開始,一直延續十幾k字節)這中的內容是在安裝grub時,安裝程序通過判斷/boot的文件系統類型,然後將這個文件系統安裝至Stage1.5中。加載了stage1.5之後,引導程序就有了識別文件系統的能力,此後grub纔有能力去訪問/boot分區/boot/grub目錄下的 stage2文件,將stage2載入內存並執行,將控制權移交給stage2。
4、加載stage2階段
stage2被載入內存之後,就會去解析grub的配置文件/boot/grub/grub.conf,然後根據配置文件中的指定,裝載內核和initramfs。來看下grub.conf文件內容:
default=0 timeout=5 splashimage=(hd0,0)/grub/splash.xpm.gz hiddenmenu title CentOS (2.6.32-431.el6.x86_64) root (hd0,0) kernel /vmlinuz-2.6.32-431.el6.x86_64 ro root=UUID=9d0bc805-83e7-4721-a22e-d78719566d51 rd_NO_LUKS rd_NO_LVM LANG=en_US.UTF-8 rd_NO_MD SYSFONT=latarcyrheb-sun16 crashkernel=128M KEYBOARDTYPE=pc KEYTABLE=us rd_NO_DM rhgb quiet initrd /initramfs-2.6.32-431.el6.x86_64.img
default #默認選擇哪一個title
timeout #菜單顯示的超時時長
splashimage=/path/to/some_image_file #grub背景圖片;此圖片只能爲14bits色,xpm格式,gzip壓縮;
hiddenmenu #是否隱藏菜單
title TILTE STRING #菜單中的標題(每一個title爲一個內核與其相應的配置數據)
root #指定根目錄,(hd0,0)以第一塊硬盤,第一個分區(/boot)爲根目錄
kernel #指定內核位置,後面爲啓動內核的參數
initrd #指定initrd位置
再來介紹一下initramfs,由於內核加載之後需要驅動所有的硬件,而這些驅動程序的模塊就存放在initramfs中,它就是一個虛擬的根文件系統。由於linux內核需要支持不同類型的硬件架構,但是不可能把每一種硬件的驅動都集成到內核中,所以在安裝操作系統時,安裝程序會去判斷當前機器的硬件類型,然後將對應的驅動模塊放到initramfs中(安裝程序集成了當前市場上絕大部分硬件的驅動模塊),然後在加載內核時,隨內核一起被加載至內存中。下面是initramfs中的內容(通過cpio解壓得到),和根目錄下的文件內容差不多:
[root@baby-CentOS abc]# ls bin emergency initqueue-finished lib pre-trigger sys var cmdline etc initqueue-settled lib64 pre-udev sysroot dev init initqueue-timeout mount proc tmp dracut-004-335.el6 initqueue initramfs-2.6.32-431.el6.x86_64.img pre-pivot sbin usr
在initramfs中也有init程序,所以內核的啓動被分成兩個階段:先執行initramfs中的init腳本,這時內核的控制權交給了init文件,這個腳本完成的主要是加載各種存儲介質相關的設備驅動程序。當所需的驅動程序加載完後,會創建一個根設備,然後將根文件系統rootfs以只讀的方式掛載。這一步結束後,釋放未使用的內存,轉換到真正的根文件系統上面去,同時運行/sbin/init程序,執行系統的1號進程。此後系統的控制權就全權交給/sbin/init進程了。
5、運行/sbin/init完成系統初始化
/sbin/init啓動之後,會先調用/etc/init/rcS.conf,這個文件內容不多,來看一下:
start on startup stop on runlevel task # Note: there can be no previous runlevel here, if we have one it's bad # information (we enter rc1 not rcS for maintenance). Run /etc/rc.d/rc # without information so that it defaults to previous=N runlevel=S. console output pre-start script for t in $(cat /proc/cmdline); do case $t in emergency) start rcS-emergency break ;; esac done end script exec /etc/rc.d/rc.sysinit #執行/etc/rc.d/rc.sysinit post-stop script if [ "$UPSTART_EVENTS" = "startup" ]; then #判斷系統的啓動級別 [ -f /etc/inittab ] && runlevel=$(/bin/awk -F ':' '$3 == "initdefault" && $1 !~ "^#" { print $2 }' /etc/inittab) [ -z "$runlevel" ] && runlevel="3" for t in $(cat /proc/cmdline); do case $t in -s|single|S|s) runlevel="S" ;; [1-9]) runlevel="$t" ;; esac done exec telinit $runlevel fi end script
這個腳本會先調用/etc/rc.d/rc.sysinit來完成系統的進一步初始化,/etc/rc.d/rc.sysinit對系統進行基本的配置,以讀寫方式掛載根文件系統及其它文件系統,到此係統算是基本運行起來了,後面需要進行運行級別的確定及相應服務的啓動。rc.sysinit所做的事情(不同的Linux發行版,該文件可能有些差異)如下:
(1)獲取網絡環境與主機類型。首先會讀取網絡環境設置文件”/etc/sysconfig/network”,獲取主機名稱與默認網關等網絡環境。
(2)測試與載入內存設備/proc及usb設備/sys。除了/proc外,系統會主動檢測是否有usb設備,並主動加載usb驅動,嘗試載入usb文件系統。
(3)決定是否啓動SELinux。
(4)接口設備的檢測與即插即用(pnp)參數的測試。
(5)用戶自定義模塊的加載。用戶可以再”/etc/sysconfig/modules/*.modules”加入自定義的模塊,此時會加載到系統中。
(6)加載核心的相關設置。按”/etc/sysctl.conf”這個文件的設置值配置功能。
(7)設置系統時間(clock)。
(8)設置終端的控制檯的字形。
(9)設置raid及LVM等硬盤功能。
(10)檢驗磁盤文件系統(fsck)。
(11)進行磁盤配額quota的轉換。
(12)重新以讀寫模式載入系統磁盤。
(13)啓動quota功能。
(14)啓動系統隨機數設備(產生隨機數功能)。
(15)清楚啓動過程中的臨時文件。
(16)將啓動信息加載到”/var/log/dmesg”文件中。
當/etc/rc.d/rc.sysinit執行完後,系統就可以順利工作了,只是還需要啓動系統所需要的各種服務,這樣主機纔可以提供相關的網絡和主機功能,因此便會執行下面的腳本。
/sbin/init執行完/etc/rc.d/rc.sysinit,會接着通過/etc/inittab文件判斷系統的運行級別,然後調用/etc/rc.d/rc腳本,啓動或者關閉/etc/rc.d/rc*.d(*=0~6)目錄下的服務,如果運行級別是3,則對應的目錄是/etc/rc.d/rc3.d。這些目錄下的文件都是以S或K開頭的軟鏈接文件,均指向/etc/init.d目錄下的服務啓動腳本,S表示需要被開啓的服務,K表示需要關閉的服務,S或K後面的數字表示優先級別,數字越小越優先啓動或關閉。
完成了系統所有的啓動任務後,linux會啓動終端或X-Window來等待用戶登錄。tty1,tty2,tty3…這表示在運行等級1,2,3,4的時候,都會執行”/sbin/mingetty”,而且執行了6個,所以linux會有6個純文本終端,mingetty就是啓動終端的命令。除了這6個之外還會執行”/etc/X11/prefdm-nodaemon”這個主要啓動X-Window。
至此,系統就啓動完畢了。
參閱:
1)http://www.yunweipai.com/archives/782.html
2)http://wenku.baidu.com/link?url=0Qi2fJ8xsPeSgV_nQ0s0HqqAfz2FAhNcyDE6imM7g89aKzZxHi9EQckJJ05-nbhF2jh9MBCFxazzDwKTpgZ9aUTADq9ekqkSQllSZqQsV3a