1.開機流程
- 載入 BIOS 的硬體資訊與進行自我測試,并依據設定取得第一個可開機的裝置;
- 讀取并執行第一個開機設别内 MBR 的 boot Loader (亦即是 grub, spfdisk 等程式);
- 依據 boot loader 的設定載入 Kernel ,Kernel 會開始偵測硬體與載入驅動程式;
- 在硬體驅動成功後,Kernel 會主動呼叫init程式,而init會取得run-level資訊;
- init 執行 /etc/rc.d/rc.sysinit檔案來準備軟體執行的作業環境 (如網路、時區等);
- init 根據 run-level 來啟動服務 (script方式);
- init 執行 /etc/rc.d/rc.local 檔案;
- init 執行終端機模拟程式 mingetty 來啟動 login 程式,最後就等待使用者登入啦;
grub的過程:
MBR 使用 Linux 的 grub 這個開機管理程式,并且裡面假設已經有了三個選單, 第一個選單可以直接指向 Linux 的核心檔案并且直接載入核心來開機;第二個選單可以将開機管理程式控制權交給 Windows 來管理,此時 Windows 的 loader 會接管開機流程,這個時候他就能夠啟動 windows 了。第三個選單則是使用 Linux 在 boot sector 内的開機管理程式,此時就會跳出另一個 grub 的選單啦
2.載入核心
我們可以先看下/boot下面的重要檔案
- [root@www ~]# ls --format=single-column -F /boot
- config-2.6.18-92.el5 <==此版本核心被編譯時選擇的功能與模組設定檔
- grub/ <==就是開機管理程式 grub 相關資料目錄
- initrd-2.6.18-92.el5.img <==虛拟檔案系統檔!
- System.map-2.6.18-92.el5 <==核心功能放置到記憶體位址的對應表
- vmlinuz-2.6.18-92.el5 <==就是核心檔案啦!最重要者!
Linux 核心是可以透過動态載入核心子產品的 (就請想成驅動程式即可),這些核心子產品就放置在 /lib/modules/ 目錄内,但問題是USB, SATA, SCSI... 等硬碟裝置的驅動程式通常都是以子產品的方式存在的,如果沒有SATA的驅動,就無法識别硬碟挂載根目錄,也就無法去讀取驅動子產品。那怎麼辦呢?可以透過虛拟檔案系統來處理這個問題。
虛拟檔案系統 (Initial RAM Disk) 一般使用的檔名為 /boot/initrd ,這個檔案的特色是,他也能夠透過 boot loader 來載入到記憶體中, 然後這個檔案會被解壓縮并且在記憶體當中模拟成一個根目錄, 且此模拟在記憶體當中的檔案系統能夠提供一支可執行的程式,透過該程式來載入開機過程中所最需要的核心子產品, 通常這些子產品就是 USB, RAID, LVM, SCSI 等檔案系統與硬碟介面的驅動程式啦!等載入完成後, 會幫助核心重新呼叫 /sbin/init 來開始後續的正常開機流程
不過,如果用的是IDE硬碟,不需要initrd也可以開機。
當核心完整載入後,就要開始執行系統的第一支程式: /sbin/init
/sbin/init 最主要的功能就是準備軟體執行的環境,包括系統的主機名稱、網路設定、語系處理、檔案系統格式及其他服務的啟動等。 而所有的動作都會透過 init 的設定檔,亦即是 /etc/inittab 來規劃,而 inittab 内還有一個很重要的設定項目,那就是預設的 runlevel (開機執行等級)
run level 分為 7 個等級,分别是:
- 0 - halt (系統直接關機)
- 1 - single user mode (單人維護模式,用在系統出問題時的維護)
- 2 - Multi-user, without NFS (類似底下的 runlevel 3,但無 NFS 服務)
- 3 - Full multi-user mode (完整含有網路功能的純文字模式)
- 4 - unused (系統保留功能)
- 5 - X11 (與 runlevel 3 類似,但加載使用 X Window)
- 6 - reboot (重新開機)
/etc/inittab 會使用 /etc/rc.d/rc.sysinit 進行系統初始化,
使用/etc/rc.d/rc N 這個指令來啟動不同level下的服務,etc/rc.d/rc 這個檔案:
- 透過外部第一号參數 ($1) 來取得想要執行的腳本目錄。亦即由 /etc/rc.d/rc 5 可以取得 /etc/rc .d/ 這個目錄來準備處理相關的腳本程式;
- 找到 /etc/rc5.d/K??* 開頭的檔案,并進行‘ /etc/rc5.d/K??* stop ’的動作;
- 找到 /etc/rc5.d/S??* 開頭的檔案,并進行‘ /etc/rc5.d/S??* start ’的動作;
/etc/rc5.d/[SK]xx 都是連結檔案,其實就是 /etc/init.d/ 相對應的服務腳本
使用/etc/rc.d/rc.local來打開使用者自定義開機啟動程式
開機過程中會使用到的配置檔案
/etc/modprobe.conf, 關于子產品的,系統自動産生,一般不需要手動修改
/etc/sysconfig/* ,裡面有很多配置資訊
Run level 的切換
- 要每次開機都執行某個預設的 run level ,則需要修改 /etc/inittab 内的設定項目, 亦即是‘ id:5:initdefault: ’裡頭的數字啊;
- 如果僅隻是暫時變更系統的 run level 時,則使用 init [0-6] 來進行 run level 的變更。 但下次重新開機時,依舊會是以 /etc/inittab 的設定為準。
3.核心與核心子產品
在整個開機的過程當中,是否能夠成功的驅動我們主機的硬體配備,是核心 (kernel) 的工作!而核心一般都是壓縮檔,是以在使用核心之前,就得要将他解壓縮後, 才能載入主記憶體當中。
另外,為了應付日新月異的硬體,目前的核心都是具有‘可讀取子產品化驅動程式’的功能, 亦即是所謂的‘ modules (子產品化)’的功能啦!所謂的模組化可以将他想成是一個‘外挂程式’, 該外挂程式可能由硬體開發廠商提供,也有可能我們的核心本來就支援~不過,較新的硬體, 通常都需要硬體開發商提供驅動程式模組啦!
那麼核心與核心子產品放在哪?
- 核心: /boot/vmlinuz 或 /boot/vmlinuz-version;
- 核心解壓縮所需 RAM Disk: /boot/initrd (/boot/initrd-version);
- 核心子產品:/lib/modules/version/kernel 或 /lib/modules/$(uname -r)/kernel;
- 核心原始碼: /usr/src/linux 或 /usr/src/kernels/ (要安裝才會有,預設不安裝)
如果我有個新的硬體,偏偏我的作業系統不支援,該怎麼辦?很簡單啊!
- 重新編譯核心,并加入最新的硬體驅動程式源代碼;
- 将該硬體的驅動程式編譯成為模組,在開機時載入該模組
核心模組與相依性:
要處理核心模組,自然就得要了解我們核心提供的子產品之間的相關性,核心模組的放置處是在 /lib/modules/$(uname -r)/kernel 當中,裡面主要還分成幾個目錄:
- arch :與硬體平台有關的項目,例如 CPU 的等級等等;
- crypto :核心所支援的加密的技術,例如 md5 或者是 des 等等;
- drivers :一些硬體的驅動程式,例如顯示卡、網路卡、PCI 相關硬體等等;
- fs :核心所支援的 filesystems ,例如 vfat, reiserfs, nfs 等等;
- lib :一些函式庫;
- net :與網路有關的各項協定資料,還有防火牆模組 (net/ipv4/netfilter/*) 等等;
- sound :與音效有關的各項模組;
- [root@www ~]# modprobe [-lcfr] module_name
- 選項與參數:
- -c :列出目前系統所有的模組!(更詳細的代号對應表)
- -l :列出目前在 /lib/modules/`uname -r`/kernel 當中的所有模組完整檔名;
- -f :強制載入該模組;
- -r :類似 rmmod ,就是移除某個模組啰~
- 範例一:載入 cifs 模組
- [root@www ~]# modprobe cifs
- # 很友善吧!不需要知道完整的模組檔名,這是因為該完整檔名已經記錄到
- # /lib/modules/`uname -r`/modules.dep 當中的緣故啊!如果要移除的話:
- [root@www ~]# modprobe -r cifs
/lib/modules/$(uname -r)/modules.dep 這個檔案記錄了在核心支援的模組的各項相依性。利用 depmod 這個指令可以建立(更新)該檔案
- [root@www ~]# depmod [-Ane]
- 選項與參數:
- -A :不加任何參數時, depmod 會主動的去分析目前核心的模組,并且重新寫入
- /lib/modules/$(uname -r)/modules.dep 當中。若加入 -A 參數時,則 depmod
- 會去搜尋比 modules.dep 内還要新的模組,如果真找到新模組,才會更新。
- -n :不寫入 modules.dep ,而是将結果輸出到螢幕上(standard out);
- -e :顯示出目前已載入的不可執行的模組名稱
- 範例一:若我做好一個網路卡驅動程式,檔名為 a.ko,該如何更新核心相依性?
- [root@www ~]# cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net
- [root@www ~]# depmod
核心子產品的觀察:
檢視目前核心載入了多少的子產品 :lsmod
檢視子產品的詳細資訊
- [root@www ~]# modinfo [-adln] [module_name|filename]
- 選項與參數:
- -a :僅列出作者名稱;
- -d :僅列出該 modules 的說明 (description);
- -l :僅列出授權 (license);
- -n :僅列出該模組的詳細路徑。
核心子產品的載入與移除:
insmod和rmmod兩個指令可以載入和移除,但是insmod不會分析子產品的依賴關系,而且這兩個指令必須要自行找到模組的完整檔名才行,不是很友善。
- [root@www ~]# modprobe [-lcfr] module_name
- 選項與參數:
- -c :列出目前系統所有的模組!(更詳細的代号對應表)
- -l :列出目前在 /lib/modules/`uname -r`/kernel 當中的所有模組完整檔名;
- -f :強制載入該模組;
- -r :類似 rmmod ,就是移除某個模組啰~
- 範例一:載入 cifs 模組
- [root@www ~]# modprobe cifs
- # 很友善吧!不需要知道完整的模組檔名,這是因為該完整檔名已經記錄到
- # /lib/modules/`uname -r`/modules.dep 當中的緣故啊!如果要移除的話:
- [root@www ~]# modprobe -r cifs
因為他是直接去搜尋 modules.dep 的紀錄, 是以可以克服模組的相依性問題,而且還不需要知道該模組的詳細路徑
4.Boot Loader: Grub
boot loader 是載入核心的重要工具,沒有 boot loader 的話,那麼 kernel 根本就沒有辦法被系統載入。grub是目前最流行的boot loader。
在 BIOS 讀完資訊後,接下來就是會到第一個開機裝置的 MBR 去讀取 boot loader 了。這個 boot loader 可以具有選單功能、直接載入核心檔案以及控制權移交的功能等, 系統必須要有 loader 才有辦法載入該作業系統的核心就是了。但是我們都知道, MBR 是整個硬碟的第一個 sector 内的一個區塊,充其量整個大小也才 446 bytes 而已。 我們的 loader 功能這麼強,光是程式代碼與設定資料不可能隻占不到 446 bytes 的容量吧?那如何安裝?
為了解決這個問題,是以 Linux 将 boot loader 的程式執行與設定值載入分成兩個階段 (stage) 來執行:
-
Stage 1:執行 boot loader 主程式:
第一階段為執行 boot loader 的主程式,這個主程式必須要被安裝在開機區,亦即是 MBR 或者是 boot sector 。但如前所述,因為 MBR 實在太小了,是以,MBR 或 boot sector 通常僅安裝 boot loader 的最小主程式, 并沒有安裝 loader 的相關設定檔;
-
Stage 2:主程式載入設定檔:
第二階段為透過 boot loader 載入所有設定檔與相關的環境參數檔案 (包括檔案系統定義與主要設定檔 menu.lst), 一般來說,設定檔都在 /boot 底下。
initrd 的重要性與建立新 initrd 檔案:
initrd的目的在于提供開機過程中所需要的最重要核心模組,以讓系統開機過程可以順利完成。 會需要 initrd 的原因,是因為核心模組放置于 /lib/modules/$(uname -r)/kernel/ 當中, 這些模組必須要根目錄 (/) 被挂載時才能夠被讀取。但是如果核心本身不具備磁碟的驅動程式時, 當然無法挂載根目錄,也就沒有辦法取得驅動程式,是以造成兩難的地步。
initrd 可以将 /lib/modules/.... 内的‘開機過程當中一定需要的模組’包成一個檔案 (檔名就是 initrd), 然後在開機時透過主機的 INT 13 硬體功能将該檔案讀出來解壓縮,并且 initrd 在記憶體内會模拟成為根目錄。
如果妳有特殊需要是以想重制 initrd 檔案的話, 可以使用 mkinitrd 來處理的。
- [root@www ~]# mkinitrd [-v] [--with=模組名稱] initrd檔名 核心版本
- 選項與參數:
- -v :顯示 mkinitrd 的運作過程
- --with=模組名稱:模組名稱指的是模組的名字而已,不需要填寫檔名。舉例來說,
- 目前核心版本的 ext3 檔案系統模組為底下的檔名:
- /lib/modules/$(uname -r)/kernel/fs/ext3/ext3.ko
- 那妳應該要寫成: --with=ext3 就好了 (省略 .ko)
- initrd檔名:妳所要建立的 initrd 檔名,盡量取有意義又好記的名字。
- 核心版本 :某一個核心的版本,如果是目前的核心則是‘ $(uname -r) ’