我們從按下電腦電源鍵開始說起。
(1) 首先是主板BIOS通電自檢。按照《微機原理》課本上的說法,CS寄存器被置為0xFFFF,其它寄存器清零,因此CPU從FFFF:0000H處開始執行,這裡儲存的是跳轉指令,跳轉到固化在ROM中的自檢程式處。於是對系統硬體包括記憶體進行自檢。
當BIOS檢查到硬體正常並且與CMOS的設定相符後,按照CMOS 中對啟動裝置的設定順序檢測可用的啟動裝置。
(2) 假設從硬碟啟動,BIOS首先將硬碟的MBR區讀入記憶體,檢查MBR結束標記,如果為0x55AA表示找到有效MBR資訊(如果不為0x55AA就檢查下一個啟動裝置),在硬碟MBR區找到系統引導程式執行。
MBR指Master Boot Record,它在硬碟的三維地址(柱面,磁頭,扇區) == (0, 0, 1)。一般硬碟1個扇區為512位元組。MBR區開頭440個位元組是代碼區,儲存的是第1階段引導代碼,主要作用是檢查硬碟分區表是否正確並在完成硬體自檢後將控制權交給硬碟上的系統引導程式如GRUB(Windows是nt-loader)。
然後是標準MBR硬碟分區表,佔64個位元組,每個主要磁碟分割表資訊佔用16Byte,包括可引導標誌、檔案系統格式、分區開始和結束的磁頭號扇區號柱面號、總的扇區數等。因此最多隻能劃分4個主要磁碟分割,為了支援更多的分區,於是有了擴充分區和邏輯分區的概念,一個擴充分區可以再分為多個邏輯分區。擴充分區的入口佔用MBR區16Byte也就是頂替了1個主要磁碟分割,擴充分區的入口放著邏輯分區表,其中儲存每個邏輯分區的入口。綜上,擴充分區最多1個而且要再劃分邏輯分區才可以使用,主要磁碟分割
+ 擴充分區最多4個,一個擴充分區中可以劃分N多個邏輯分區(上限貌似是64,一般用不了這麼多)。
最後是結束標記字,如果是0x55AA表示MBR資訊有效。
(3) MBR中的引導程式將控制權交給GRUB後,GRUB引導Linux核心,然後啟動init進程。
GRUB完成引導任務後,CPU控制權交給Linux,開始執行LInux的核心映象代碼,開始了Linux啟動過程。這會用到Linux源碼樹中arch/i386/boot/下的幾個檔案。
因為Linux核心提供了眾多的驅動顯得比較大,所以在核心編譯中常使用"makebzImage"選項產生壓縮的核心vmlinuz。在Linux引導過程中由arch/i386/boot/compressed/下的head.S將核心鏡像vmlinuz解壓到0x100000。
arch/i386/boot/下的setup.S將BIOS中的記憶體、磁碟等系統參數拷貝到記憶體中,以便這些參數後面被保護模式的代碼讀取,然後setup.S將系統切換到保護模式並跳轉到0x100000即vmlinuz的入口。然後CPU跳轉init/main.c中的start_kernel(),該函數調用一系列的初始化函數完成kernel本身的設定,建立Linux核心環境。start_kernel()最後調用init(),系統建立第一個核心線程。
核心線程init()調用do_basic_setup(),該函數完成外設及其驅動程式的載入和初始化,並完成檔案系統初始化和root檔案系統的安裝。之後init()開啟/dev/console裝置,重新導向stdin, stdout, stderr到控制台。最後,核心線程init()搜尋檔案系統中的init程式,並使用execve()系統調用載入執行init程式。至此init()函數結束,核心引導部分也結束了。
(4) init調用rc.sysinit和rc。rc.sysinit和rc完成系統初始化和啟動各種服務的任務後返回init。
init進程號為1,是系統所有進程的起點。init進程讀取設定檔/etc/inittab,該檔案指定了系統啟動時預設的運行層級以及init進程要調用的初始化指令碼。
init進程首先執行/etc/rc.d/rc.sysinit。該指令碼是每個運行層級都要首先啟動並執行重要指令碼,完成一些系統初始化工作:啟用swap交換分區,檢查磁碟,載入硬體模組等。
然後init進程以運行層級為參數執行/etc/rc.d/rc指令碼。假設當前運行層級為5 : X11,rc指令碼會執行/etc/rc.d/rc5.d/下所有的rc啟動指令碼,這些指令碼實際上都是符號連結,指向/etc/rc.d/init.d/中的啟動指令碼。/etc/rc.d/rc5.d/中的rc啟動指令碼通常是K或S開頭的連結檔案。對於以以S開頭的啟動指令碼,將以start參數來運行;而如果發現K打頭的連結,而且已經處於運行態了(以/var/lock/subsys/下的檔案作為標誌),則將首先以stop為參數停止這些已經啟動了的守護進程,然後再重新運行。這樣做是為了保證是當init改變運行層級時,所有相關的守護進程都將重啟。
此時基本的系統內容已經設定好,各種守護進程也已經啟動。
(5) 建立終端,登陸系統。
按照/etc/inittab檔案,下一步init能在2、3、4、5四個運行層級下以respawn方式運行mingetty程式開啟6個終端,同時mingetty程式還會顯示一個文本登陸介面。
runlevel 5 : X11下顯示的是圖形登陸介面,登陸成功後進入GNOME視窗管理器。下面還是以文本登陸方式講解。
Linux的帳號驗證程式是login,login接收從mingetty傳來的使用者名稱作為使用者名稱參數,在分析完使用者名稱後,login將搜尋/etc/passwd以及/etc/shadow來驗證密碼以及設定賬戶的其它資訊,比如:主目錄是什麼、使用何種shell。如果沒有指定主目錄,將預設為根目錄;如果沒有指定shell,將預設為/bin/bash。
login程式成功後,會向對應的終端輸出最近一次登入的資訊(在/var/log/lastlog中有記錄),並檢查使用者是否有新郵件(在/usr/spool/mail/使用者名稱目錄下)。然後開始設定各種環境變數:對bash而言,系統首先尋找/etc/profile指令碼並執行之,然後在使用者的主目錄下尋找.bash_profile檔案,如果有就執行它。在這兩個指令碼可能還調用了其他設定檔,所有的設定檔執行完之後,各種環境變數也設好了,這時會出現大家熟悉的commandline
prompt。
到此整個啟動過程就結束了。