首頁 > 軟體

CentOS6開機啟動過程詳解

2020-06-16 16:49:22

CentOS 6 開機流程——Linux由kernel和rootfs組成。kernel負責進程管理、記憶體管理、網路管理、驅動程式、檔案系統、安全等;rootfs由程式和glibc組成,完善作業系統的功能。同時Linux核心的特點是模組化,通過對模組裝載解除安裝可以對核心功能自定義。Linux核心映象檔案:/boot/vmlinuz-2.6.32-696.el6.x86_64

整體的流程

  • BIOS/開機自檢

  • MBR引導(Boot Loader)

  • 啟動核心

  • 啟動第一個進程init

 

一、BIOS/開機自檢

1.1 微控制器

    系統想要啟動必須先載入BIOS,按下電源鍵時,給微控制器下達一條復位指令,各暫存器復位,最後下達一條跳轉指令,跳轉到BIOS的ROM,使得硬體去讀取主機板上的BIOS程式,在這之前都是由硬體來完成,之後硬體就會把控制權交給BIOS;

1.2 BIOS->POST

    隨後BIOS程式載入CMOS(可讀寫的RAM晶片,儲存BIOS設定硬體引數的資料)的資訊,藉CMOS取得主機的各項硬體設定

    取得硬體設定的資訊之後,BIOS進行加電自檢(Power-on self Test,POST)過程,檢測計算機各種硬體資訊,如果發現硬體錯誤則會報錯(發出聲音警告)

    之後BIOS對硬體進行初始化

    BIOS將自己複製到實體記憶體中繼續執行,開始按順序搜尋可引導儲存裝置,決定儲存裝置的順序(即定義第一個可引導的磁碟,當然是在有兩個磁碟的前提),接下來就會讀取磁碟的內容,但是要讀取磁碟檔案必須要有檔案系統,這對BIOS掛載檔案系統來說是不可能,因此需要一個不依賴檔案系統的方法使得BIOS讀取磁碟內容,這種方法就是引入MBR。最後BIOS通過INT 13硬體中斷功能讀取第一個可引導的儲存裝置的MBR(0磁軌0磁區)中的boot loader。將MBR載入到實體記憶體中執行。小tip:判斷可引導磁碟就是判斷每個磁碟前512位元組結尾是否存在55AA,有就是可引導,沒有就繼續檢查下一個磁碟。

    MBR載入記憶體後,BIOS將控制權轉交給MBR(準確的說應該是MBR中的boot loader),然後MBR接管任務開始執行。

二、MBR引導(Boot Loader)

    載入了第一個可引導的儲存裝置的MBR後,MBR中的boot loader就要讀取所在磁碟的作業系統核心檔案(即後面所說的核心)了。

2.1 boot loader

    但是呢還存在一些問題,不同作業系統的檔案系統格式不同?還有我們知道一個磁碟可以安裝多個作業系統,boot loader怎麼能夠做到引導的就是我們想要的作業系統呢?這麼多不同的功能單靠一個446位元組的boot loader是遠遠不夠的。因此必須弄一個相對應的程式來處理各自對應的作業系統核心檔案,這個程式就是作業系統的loader(注意不是MBR中的boot loader),這樣一來boot loader只需要將控制權交給對應作業系統的loader,讓它負責去啟動作業系統就行了。

    這裡有張圖能更好地解釋boot loader的作用:

   

    解讀上圖內容,我們知道一個硬碟的每個分割區的第一個磁區叫做boot sector,這個磁區存放的就是作業系統的loader,所以我們常說一個分割區只能安裝一個作業系統,如上圖,第一個分割區的boot sector存放著windows的loader,第二個分割區放著Linux的loader,第三個第四個由於沒有安裝作業系統所以空著。至於MBR的boot loader是幹嘛呢, boot loader有三個功能:提供選單,讀取核心檔案,轉交給其他loader

    提供選單就是給使用者提供一張選項單,讓使用者選擇進入哪個作業系統;

    讀取核心檔案,我們知道系統會有一個預設啟動的作業系統,這個作業系統的loader在所在分割區的boot sector有一份,除此之外,也會將這個預設啟動的作業系統的loader複製一份到MBR的boot loader中,這樣一來MBR就會直接讀取boot loader中的loader了,然後就是啟動預設的作業系統;

    轉交個其他的loader,當使用者選擇其他作業系統啟動的時候,boot loader會將控制權轉交給對應的loader,讓它負責作業系統的啟動。

    另外我看書上寫,安裝windows作業系統的時候,windows會主動複製一份自己的loader到MBR中的boot loader中,這種操作在linux下不會。所以我們安裝多重作業系統的時候要求先安裝windows,然後再安裝Linux;我們假設先安裝Linux,再安裝windows的時候就會自動把windows的loader複製到MBR中的boot loader,這樣一來就會預設優先啟動windows。然而先安裝windows,自動複製windows的loader到boot loader,再安裝Linux的時候,我們可以設定把Linux的loader複製到boot loader中,把原先windows的覆蓋掉,這樣才能設定Linux預設啟動。

2.2 Linux的GRUB

    Linux的loader使用的是GRUB,我們常說的Linux中的loader就是grub,我認為這種說法是不準確的,我們知道MBR的boot loader是446位元組,而grub呢,不僅僅446位元組。

    那MBR的boot loader和grub到底是什麼關係呢,在這裡說明,GRUB是一個啟動管理器,和Linux沒有強制的關係,當然也可以用GRUB啟動Windows。首先我們可以通過rpm -qi grub命令檢視grub的版本。

    進入/boot/grub目錄下,我們可以看到很多檔案,其實Linux的loader為stage1那個檔案(如下圖,剛好512位元組),我們在安裝Linux的時候,系統會把stage1檔案安裝到所在分割區的boot sector中,同時預設Linux啟動的話,也需要把stage1中的引導程式碼安裝到MBR中的boot loader中。該檔案太小,能完成的功能有限,因此Linux的loader只是簡單的引導作用。

   MBR完成了主程式的引導後,會把控制權交給GRUB,主載入程式開始載入組態檔了,但是載入這些組態檔之前需要有檔案系統的支援,可是現在還沒有檔案系統呢,在網上查閱資料說的“GRUB內建檔案系統存取支援,雖然是極度精簡的,但已經具備根據路徑讀取相應檔案的二進位制流。換句話說,GRUB在不依賴Linux核心的情況下具有讀取組態檔與核心映像的能力”。GRUB的內建檔案系統其實是依靠stage1_5那些檔案定義的,而且有不同檔案系統的stage1_5。我們在安裝Linux的時候會把stage1_5相關檔案放到0磁軌1-62磁區中(一個磁軌63個磁區,劃分分割區是從1磁軌開始的,除了MBR外,所以會有62個磁區作為保留磁區),用於定義grub的檔案系統。

    而後開始讀取stage2開始真正地讀取組態檔grub.conf。解析/boot/grub/grub.conf檔案

default=0# 預設啟動第一個系統核心,即後面的title部分,1代表第二個,依次類推,
timeout=5# 設定系統留給使用者選擇系統核心的時間為5s。
splashimage=(hd0,0)/grub/splash.xpm.gz
# 使用者選擇核心時候的背景圖片檔案,這裡的hd0,0是第一個硬碟的第一個分割區,沒有/dev/sdaX的概念
hiddenmenu    # 是否顯示選單畫面
title CentOS 6 (2.6.32-696.el6.x86_64)    # 第一個選單的名字,可以自定義
    root (hd0,0)    # 核心檔案放置的分割區
    kernel ... ro root= ... rhgb quiet
    # 核心檔案;讀取核心檔案之後要掛載/目錄,唯讀,root後跟真正的/目錄掛載的分割區
    # rhgb 表示預設圖形顯示,把啟動過程覆蓋掉
    # quit表示系統啟動時將模組啟動的詳細資訊遮蔽,只顯示模組啟動時候成功(ok or failed)
    initrd ...# 核心映象檔案

   

    總之,MBR就是載入核心檔案的

三、啟動核心

3.1 載入核心檔案

    MBR將核心檔案(程式碼)載入實體記憶體中執行,核心就是/boot/vmlinuz-2.6.32-696.el6.x86_64,觀察該檔案,發現這是一個壓縮映象檔案。

    控制權轉交給核心後,核心重新檢測各種硬體資訊,(第一次為POST自檢)我們前邊說了,一個完整的Linux包括核心和核心之上的程式,因此核心還要載入提供這些程式功能的模組,然而這些模組都在根目錄的/lib/modules/2.6.32-696.el6.x86_64下(/和/lib/modules/不能掛載不同的分割區),這時候核心還沒有檔案系統的概念,沒有檔案系統就沒辦法掛載根目錄,想要掛載根目錄就需要相應的模組支援,而我們原本的問題就是如何載入模組(先有雞後有蛋的問題)。

3.2 載入initrd

    /boot/initramfs-2.6.32-696.el6.x86_64.img檔案就是解決上面問題的,我們來看一下這個檔案:

file initramfs-2.6.32-696.el6.x86_64.img # 檢視該檔案型別
cp initramfs-2.6.32-696.el6.x86_64.img /app
cd /app
mv initramfs-2.6.32-696.el6.x86_64.img initramfs-2.6.32-696.el6.x86_64.img.gz
# gzip解壓檔案必須以.gz字尾
gzip -d initramfs-2.6.32-696.el6.x86_64.img.gz
file initramfs-2.6.32-696.el6.x86_64.img
# 檢視需要借助cpio命令
mkdir init
cd init
cpio -id < /app/initramfs-2.6.32-696.el6.x86_64.img
# 解壓至/app/init目錄下

   

    我們發現解壓之後的內容類似於真正/目錄下內容,這是因為這是一個最小化的Linux根檔案系統。核心就是先把這個檔案展開,形成一個虛擬檔案系統,核心藉虛擬檔案系統裝載必要的模組,完成後釋放該虛擬檔案系統並掛載真正的根目錄。

    initrd的製作:

mkinitrd /boot/initramfs-$(uname -r).img $(uname -r)

dracut /boot/initramfs-$(uname -r).img $(uname -r)

四、啟動第一個進程init

4.1 init進程:主要功能是準備軟體執行的環境   

    核心完成硬體檢測和載入模組後,核心會呼叫第一個進程,就是/sbin/init,至此核心把控制權交給init進程   

    讀取初始化組態檔/etc/inittab,決定作業系統的runlevel,/etc/inittab內有這樣一句: 

        id:runlevel:action:process 

id 代表設定的專案,沒有具體的實際意義
runlevel

執行級別,0-關機、1-單使用者、2-沒有NFS的多使用者、

3-真正的多使用者、4-預留、5-Xwindows、6-reboot

action init的動作行為,initdefault表示要預設啟動的runlevel
process 執行動作的指令,一般為指令碼檔案

4.2 /etc/rc.d/rc.sysinit

    讀取/etc/rc.d/rc.sysinit系統初始化指令碼,設定主機名,掛載/etc/fstab中的檔案系統,修改/etc/sysctl.conf 的核心引數等各項系統環境。

    檢視該指令碼內容,大致功能如下

        定義主機名,如果不存在則將主機名定義為localhost;

        讀取/etc/sysconfig/network檔案,設定網路環境;

        掛載記憶體裝置/proc和USB裝置/sys,如果USB裝置存在,則會載入usb模組並掛載usb檔案系統;

        接下來是SELINUX的一些相關設定;

        設定text banner,顯示歡迎介面;

        ...

        將開機啟動資訊存放到/var/log/dmesg中。

4.3 /etc/rc.d/rc

    執行/etc/rc.d/rc指令碼,下面是/etc/rc.d/rc指令碼中我們關心的程式碼部分:

# First, run the KILL scripts.
for i in /etc/rc$runlevel.d/K* ; do
# Check if the subsystem is already up.
subsys=${i#/etc/rc$runlevel.d/K??}
[ -f /var/lock/subsys/$subsys -o -f /var/lock/subsys/$subsys.init ] || continue
check_runlevel "$i" || continue
# Bring the subsystem down.
[ -n "$UPSTART" ] && initctl emit --quiet stopping JOB=$subsys
$i stop
[ -n "$UPSTART" ] && initctl emit --quiet stopped JOB=$subsys
done
# Now run the START scripts.
for i in /etc/rc$runlevel.d/S* ; do
# Check if the subsystem is already up.
subsys=${i#/etc/rc$runlevel.d/S??}
[ -f /var/lock/subsys/$subsys ] && continue
[ -f /var/lock/subsys/$subsys.init ] && continue
check_runlevel "$i" || continue

    根據執行級別(0123456)進入相應的/etc/rc.d/rcN.d目錄,啟動和關閉相關的系統服務。裡邊存放著一堆以K和S開頭的軟連結檔案,分別代表對應的服務。K開頭表示該執行級別下需要把該服務殺死,S開頭表示該執行級別下需要把該服務開啟。,上訴操作都是由/etc/rc.d/rc指令碼來完成的。另外我們還注意都S和K後邊的數位,他們的數位代表了讀取的順序,因為有些服務是具有一定的關聯性。

    而且每個rcN.d目錄內最後都會有一個S99local檔案 ,該檔案指向 ../rc.local指令碼。

4.4 /etc/rc.d/rc.local

    系統根據runlevel執行完/etc/rc.d/rcN.d中的指令碼後,呼叫/etc/rc.d/rc.local指令碼

    這時候系統已經完成了各種必要系統服務的啟動,假如我們想自定義一些指令要在開機的時候啟動,我們就可以把他們放到/etc/rc.d/rc.local內,該檔案預設為空。

4.5 啟動終端   

    接下來會由/sbin/mingetty指令啟動終端,由於系統設定啟動tty1-tty6 ,所以會啟動6個命令列終端。最終呈現給我們的就是這樣一個畫面:

Linux公社的RSS地址:https://www.linuxidc.com/rssFeed.aspx

本文永久更新連結地址https://www.linuxidc.com/Linux/2018-08/153455.htm


IT145.com E-mail:sddin#qq.com