天天看點

開機流程

1.開機流程

  1. 載入 BIOS 的硬體資訊與進行自我測試,并依據設定取得第一個可開機的裝置;
  2. 讀取并執行第一個開機設别内 MBR 的 boot Loader (亦即是 grub, spfdisk 等程式);
  3. 依據 boot loader 的設定載入 Kernel ,Kernel 會開始偵測硬體與載入驅動程式;
  4. 在硬體驅動成功後,Kernel 會主動呼叫init程式,而init會取得run-level資訊;
  5. init 執行 /etc/rc.d/rc.sysinit檔案來準備軟體執行的作業環境 (如網路、時區等);
  6. init 根據 run-level 來啟動服務 (script方式);
  7. init 執行 /etc/rc.d/rc.local 檔案;
  8. init 執行終端機模拟程式 mingetty 來啟動 login 程式,最後就等待使用者登入啦;

grub的過程:

開機流程

MBR 使用 Linux 的 grub 這個開機管理程式,并且裡面假設已經有了三個選單, 第一個選單可以直接指向 Linux 的核心檔案并且直接載入核心來開機;第二個選單可以将開機管理程式控制權交給 Windows 來管理,此時 Windows 的 loader 會接管開機流程,這個時候他就能夠啟動 windows 了。第三個選單則是使用 Linux 在 boot sector 内的開機管理程式,此時就會跳出另一個 grub 的選單啦

2.載入核心

我們可以先看下/boot下面的重要檔案

  1. [root@www ~]# ls --format=single-column -F /boot 
  2. config-2.6.18-92.el5      <==此版本核心被編譯時選擇的功能與模組設定檔 
  3. grub/                     <==就是開機管理程式 grub 相關資料目錄 
  4. initrd-2.6.18-92.el5.img  <==虛拟檔案系統檔! 
  5. System.map-2.6.18-92.el5  <==核心功能放置到記憶體位址的對應表 
  6. 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 的切換

  1. 要每次開機都執行某個預設的 run level ,則需要修改 /etc/inittab 内的設定項目, 亦即是‘ id:5:initdefault: ’裡頭的數字啊;
  2. 如果僅隻是暫時變更系統的 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 當中,裡面主要還分成幾個目錄:

  1. arch    :與硬體平台有關的項目,例如 CPU 的等級等等; 
  2. crypto  :核心所支援的加密的技術,例如 md5 或者是 des 等等; 
  3. drivers :一些硬體的驅動程式,例如顯示卡、網路卡、PCI 相關硬體等等; 
  4. fs  :核心所支援的 filesystems ,例如 vfat, reiserfs, nfs 等等; 
  5. lib :一些函式庫; 
  6. net :與網路有關的各項協定資料,還有防火牆模組 (net/ipv4/netfilter/*) 等等; 
  7. sound   :與音效有關的各項模組; 
  1. [root@www ~]# modprobe [-lcfr] module_name 
  2. 選項與參數: 
  3. -c  :列出目前系統所有的模組!(更詳細的代号對應表) 
  4. -l  :列出目前在 /lib/modules/`uname -r`/kernel 當中的所有模組完整檔名; 
  5. -f  :強制載入該模組; 
  6. -r  :類似 rmmod ,就是移除某個模組啰~ 
  7. 範例一:載入 cifs 模組 
  8. [root@www ~]# modprobe cifs 
  9. # 很友善吧!不需要知道完整的模組檔名,這是因為該完整檔名已經記錄到 
  10. # /lib/modules/`uname -r`/modules.dep 當中的緣故啊!如果要移除的話: 
  11. [root@www ~]# modprobe -r cifs 

/lib/modules/$(uname -r)/modules.dep 這個檔案記錄了在核心支援的模組的各項相依性。利用 depmod 這個指令可以建立(更新)該檔案

  1. [root@www ~]# depmod [-Ane] 
  2. 選項與參數: 
  3. -A  :不加任何參數時, depmod 會主動的去分析目前核心的模組,并且重新寫入 
  4.       /lib/modules/$(uname -r)/modules.dep 當中。若加入 -A 參數時,則 depmod 
  5.       會去搜尋比 modules.dep 内還要新的模組,如果真找到新模組,才會更新。 
  6. -n  :不寫入 modules.dep ,而是将結果輸出到螢幕上(standard out); 
  7. -e  :顯示出目前已載入的不可執行的模組名稱 
  8. 範例一:若我做好一個網路卡驅動程式,檔名為 a.ko,該如何更新核心相依性? 
  9. [root@www ~]# cp a.ko /lib/modules/$(uname -r)/kernel/drivers/net 
  10. [root@www ~]# depmod 

核心子產品的觀察:

檢視目前核心載入了多少的子產品 :lsmod

檢視子產品的詳細資訊

  1. [root@www ~]# modinfo [-adln] [module_name|filename] 
  2. 選項與參數: 
  3. -a  :僅列出作者名稱; 
  4. -d  :僅列出該 modules 的說明 (description); 
  5. -l  :僅列出授權 (license); 
  6. -n  :僅列出該模組的詳細路徑。 

核心子產品的載入與移除:

insmod和rmmod兩個指令可以載入和移除,但是insmod不會分析子產品的依賴關系,而且這兩個指令必須要自行找到模組的完整檔名才行,不是很友善。

  1. [root@www ~]# modprobe [-lcfr] module_name 
  2. 選項與參數: 
  3. -c  :列出目前系統所有的模組!(更詳細的代号對應表) 
  4. -l  :列出目前在 /lib/modules/`uname -r`/kernel 當中的所有模組完整檔名; 
  5. -f  :強制載入該模組; 
  6. -r  :類似 rmmod ,就是移除某個模組啰~ 
  7. 範例一:載入 cifs 模組 
  8. [root@www ~]# modprobe cifs 
  9. # 很友善吧!不需要知道完整的模組檔名,這是因為該完整檔名已經記錄到 
  10. # /lib/modules/`uname -r`/modules.dep 當中的緣故啊!如果要移除的話: 
  11. [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 來處理的。

  1. [root@www ~]# mkinitrd [-v] [--with=模組名稱] initrd檔名 核心版本 
  2. 選項與參數: 
  3. -v  :顯示 mkinitrd 的運作過程 
  4. --with=模組名稱:模組名稱指的是模組的名字而已,不需要填寫檔名。舉例來說, 
  5.        目前核心版本的 ext3 檔案系統模組為底下的檔名: 
  6.        /lib/modules/$(uname -r)/kernel/fs/ext3/ext3.ko 
  7.        那妳應該要寫成: --with=ext3 就好了 (省略 .ko) 
  8. initrd檔名:妳所要建立的 initrd 檔名,盡量取有意義又好記的名字。 
  9. 核心版本  :某一個核心的版本,如果是目前的核心則是‘ $(uname -r) ’ 

繼續閱讀