過程概述
BIOS開機加電自檢
BIOS(基本輸入輸出系統
),該系統存儲於主板的ROM
芯片上,計算機在開機時,會最先讀取該系統,然後會有一個加電自檢過程。這個過程其實就是檢查CPU和內存,計算機最基本的組成單元(控制器、運算器和存儲器),還會檢查其他硬件,若沒有異常就開始加載BIOS程序到內存當中。BIOS的功能大概可以分爲3個部分:
-
用於電腦剛接通電源時對硬件部分的檢測,也叫做加電自檢(
Power On Self Test
,簡稱POST
)。功能是檢查電腦是否良好,通常完整的POST自檢將包括對CPU,640K基本內存,1M以上的擴展內存,ROM,主板,CMOS存儲器,串並口,顯示卡,軟硬盤子系統及鍵盤進行測試,一旦在自檢中發現問題,系統將給出提示信息或鳴笛警告。自檢中如發現有錯誤,將按兩種情況處理:- 對於嚴重故障(致命性故障)則停機,此時由於各種初始化操作還沒完成,不能給出任何提示或信號;
- 對於非嚴重故障則給出提示或聲音報警信號,等待用戶處理。
-
初始化硬件(這個玩過開發板的應該都很清楚)。包括創建中斷向量、設置寄存器、對一些外部設備進行初始化和檢測等,其中很重要的一部分是BIOS設置,主要是對硬件設置的一些參數,當電腦啓動時會讀取這些參數,並和實際硬件設置進行比較,如果不符合,會影響系統的啓動。
-
引導操作系統程序。
BIOS
會按照硬盤的引導記錄去查找第一個磁盤頭的MBR信息,並加載和執行MBR
中的Bootloader
程序,若第一個磁盤不存在MBR,則會繼續查找第二個磁盤(啓動順序可以在BIOS
的界面中進行設置),一旦BootLoader
程序被檢測並加載內存中,BIOS
就將控制權交接給了BootLoader
程序(控制權交接其實就是指CPU跳轉到Bootloader
程序的內存位置執行)
加載MBR中的BootLoader
MBR(Master Boot Record
)主引導記錄,MBR存儲於磁盤的頭部,大小爲512 bytes
,組成爲:[446 bytes
(存儲BootLoader
程序)+64 bytes
(存儲分區表信息)+2 bytes
(用於MBR
的有效性檢查)]。
這個部分就需要分爲3個階段來執行了:
Stage_1
BIOS加載它找到的第一個引導記錄(MBR)中到內存中,並開始執行此代碼。Bootloader
必須非常小,因爲它必須連同分區表放到硬盤的第一個 512 字節的扇區中。 在傳統的常規 MBR 中,引導代碼實際所佔用的空間大小爲 446
字節。這個MBR中這個 446
字節的文件通常被叫做引導鏡像(boot.img)
,其中不包含設備的分區信息,分區是一般單獨添加到引導記錄中。
Stage_1.5
由於boot.img
必須做的非常小,所以基本不可能有太多複雜的功能,他唯一能做的就是加載Stage_1.5中的存儲的代碼,也就是core.img
(字節)。該文件通常位於MBR與第一個分區之間,也就是扇區之間(未包括),總大小爲字節。這個文件,存放了一些通用的文件系統驅動程序,如標準的 EXT
和其它的 Linux
文件系統,如 FAT
和 NTFS
等。所以這階段就是負責執行Stage_1.5
中存放的驅動程序,並加載相關的驅動程序。
Grub2
的core.img
遠比老一版的Grub1
更復雜且更強大。這意味着Grub2
的core.img
能夠放在標準的EXT
文件系統內,但是不能放在邏輯卷內。故在Grub2
中,Stage_1.5
中的文件可以存放於/boot
文件系統中,一般在/boot/grub2
目錄下。
Stage_2
進入Stage_2
時,所有的文件(內核、initrd
等)都已存放於/boot
目錄及其幾個子目錄之下。同時,該階段還可以從 /boot/grub2/i386-pc
目錄下加載一些內核運行時模塊。所以Stage_2
的主要功能是定位和加載 Linux 內核和initrd
到內存中,並轉移控制權。
關於Grub2
在linux
啓動時按下C
即可進入Grub2
的命令行模式,這裏你可以自己手動引導內核和initrd的加載。關於手動引導的相關操作,可以自行百度。這裏我們重點來看下配置文件/boot/grub2/grub.cfg
,這裏有篇文章已經說得很詳細,這裏就直接與大家分享了:
加載內核並初始化initrd
由於Linux內核是很精簡的,只保留必要的驅動程序,而現實中的設備種類繁多,例如:根文件系統可以存儲在包括IDE、SCSI、USB在內的多種介質上,如果將這些設備的驅動都編譯進內核那該多麼臃腫,所以就乾脆將設備特有的驅動與內核分離,單獨形成initrd
(一般自己編譯的系統不需要,發行版需要兼容所以會需要)。需要哪種驅動就提取到initrd
中,待啓動時提前加載即可。所以內核啓動一般分兩步:
初始化initrd
在 linux
內核啓動前, bootloader
會將存儲介質中的 initrd
文件加載到內存,內核啓動時會在訪問真正的根文件系統前先訪問該內存中的 initrd
文件系統,這個過程將會完成相關驅動模塊的加載,最主要就是加載根文件系統存儲介質的驅動模塊等,這樣內核就可以正常識別設備和真正的根文件系統了。
initrd( boot loader initialized RAM disk),就是由
bootloader
初始化的內存盤,算是一個很mini版的文件系統。
啓動內核
之後,內核會以只讀方式掛載根文件系統,當根文件系統被掛載後,開始裝載第一個進程(用戶空間的進程),執行/sbin/init
,之後就將控制權交接給了init程序。如果是使用systemd的話,則是加載systemd
進程到內存中。
初始化系統
這一節呢,我們分爲兩個init
系統來敘述:
Sysvinit系統
sysvinit
就是 System V
風格的 init
系統,顧名思義,它源於 System V
系列的 UNIX
。最初的 linux
發行版幾乎都是採用 sysvinit
作爲 init 系統。sysvinit
用術語 runlevel 來定義 “預訂的運行模式”。比如
- runlevel 3 是命令行模式,
- runlevel 5 是圖形界面模式,
- runlevel 0 是關機,
- runlevel 6 是重啓。
這個初始化系統的涉及到的配置文件如下(按init進程讀先後順序):
/etc/inittab
####省去多餘註釋#######
###表示當前缺省運行級別爲5(initdefault),即默認以圖形界面啓動
id:5:initdefault:
###啓動時自動執行/etc/rc.d/rc.sysinit腳本(sysinit)
# 這一項表示在系統啓動時執行/etc/rc.d/rc.sysinit程序
si::sysinit:/etc/rc.d/rc.sysinit
l0:0:wait:/etc/rc.d/rc 0
l1:1:wait:/etc/rc.d/rc 1
l2:2:wait:/etc/rc.d/rc 2
# 當切換到runlevel3(命令行模式時),執行一下/etc/rc.d/rc這個程序,並傳遞參數3
l3:3:wait:/etc/rc.d/rc 3
l4:4:wait:/etc/rc.d/rc 4
###當運行級別爲5時,以5爲參數運行/etc/rc.d/rc腳本,init將等待其返回(wait)
l5:5:wait:/etc/rc.d/rc 5
#這個就是同時匹配多個runlevel
l6:23456:wait:/etc/rc.d/rc 6
每個配置項格式如下:
各項含義如下:
-
id
id是指入口標識符,它是一個字符串,對於getty或mingetty等其他login程序項,要求id與tty的編號相同,否則getty程序將不能正常工作。
-
runlevel
runlevel是init所處於的運行級別的標識.runlevel可以是並列的多個值,以匹配多個運行級別,對大多數action來說,僅當runlevel與當前運行級別匹配成功纔會執行
- 0:表示關機
- 1:表示單用戶模式,在這個模式中,用戶登錄不需要密碼,默認網卡驅動是不被加載,一些服務不能用。
- 2:表示多用戶模式,NFS服務不開啓
- 3:表示命令行模式
- 4:這個模式保留未用
- 5:表示圖形用戶模式
- 6:表示重啓系統
-
action
respawn
:當process終止後馬上啓動一個新的wait
:當進入指定的runlevels後process纔會啓動一次,並且到離開這個runlevels終止initdefault
:設定默認的運行級別,即我們開機之後默認進入的運行級別,不能是0,6,你懂的sysinit
:系統初始化,只有系統開機或重新啓動的時候,這個process纔會被執行一次powerwait
:當init接收到電源失敗信號的時候執行相應的process,並且如果init有進程在運行,會等待這個進程完成之後,再執行相應的processpowerfail
:當init接收到電源失敗信號的時候執行相應的process,並且如果init有進程在運行,不會等待這個進程完成,它會直接執行相應的processpowerokwait
:電源已經故障,但是在等待執行對應操作的時候突然來電了就執行對應的processpowerfailnow
:當電源故障並且init被通知UPS電源已經快耗盡執行相對應的processctrlaltdel
:當用戶按下ctrl+alt+del這個組合鍵的時候執行對應的processboot
:只有在引導過程中,才執行該進程,但不等待該進程的結束;當該進程死亡時,也不重新啓動該進程bootwait
:只有在引導過程中,才執行該進程,並等待進程的結束;當該進程死亡時,也不重新啓動該進程off
:如果process正在運行,那麼就發出一個警告信號,等待20秒後,再通過殺死信號強行終止該process。如果process並不存在那麼就忽略該登記項once
:啓動相應的進程,但不等待該進程結束便繼續處理/etc/inittab文件中的下一個登記項;當該進程死亡時,init也不重新啓動該進程
-
process
表示啓動哪個程序或腳本或執行哪個命令
/etc/rc.d/rc.sysinit
所有的運行級別下,init依賴/etc/rc.d/rc.sysinit
這個腳本對系統進行初始化。按照下面的順序按部就班的初始化系統:
- 激活 udev 和 selinux
- 設置定義在
/etc/sysctl.conf
中的內核參數 - 設置系統時鐘
- 加載 keymaps
- 啓用交換分區
- 設置主機名(hostname)
- 根分區檢查和 remount
- 激活 RAID 和 LVM 設備
- 開啓磁盤配額
- 檢查並掛載所有文件系統
- 清除過期的 locks 和 PID 文件
- 最後找到指定 runlevel 下的腳本並執行,其實就是啓動服務。
/etc/rc.d/rc
這個程序就是根據傳入的參數,調用/etc/rc.d/rc0.d~rc6.d
中的相應的腳本程序,來完成相應的初始化工作和啓動相應的服務,最後調用/etc/rc.d/rc.local
,這個文件裏面可以放一些用戶自定義的啓動腳本等等
Systemd系統
systemd 是 linux 系統中最新的初始化系統(init),它主要的設計目標是克服 sysvinit
固有的缺點,提高系統的啓動速度。
在開始看Systemd
進程做的事情之前,請先了解一下開機啓動腳本的編寫和選項含義,這裏直接推薦一篇不錯的文章:編寫systemd下服務腳本。新舊系統運行等級映射關係如下:
SystemV 運行級別 | systemd 目標態 | systemd 目標態別名 | 描述 |
---|---|---|---|
halt.target |
停止系統運行但不切斷電源。 | ||
0 | poweroff.target |
runlevel0.target |
停止系統運行並切斷電源. |
S | emergency.target |
單用戶模式,沒有服務進程運行,文件系統也沒掛載。這是一個最基本的運行級別,僅在主控制檯上提供一個 shell 用於用戶與系統進行交互。 |
|
1 | rescue.target |
runlevel1.target |
掛載了文件系統,僅運行了最基本的服務進程的基本系統,並在主控制檯啓動了一個 shell 訪問入口用於診斷。 |
2 | runlevel2.target |
多用戶,沒有掛載 NFS 文件系統,但是所有的非圖形界面的服務進程已經運行。 | |
3 | multi-user.target |
runlevel3.target |
所有服務都已運行,但只支持命令行接口訪問。 |
4 | runlevel4.target |
未使用。 | |
5 | graphical.target |
runlevel5.target |
多用戶,且支持圖形界面接口。 |
6 | reboot.target |
runlevel6.target |
重啓。 |
default.target |
這個目標態target是總是 multi-user.target 或 graphical.target 的一個符號鏈接的別名。systemd 總是通過 default.target 啓動系統。default.target 絕不應該指向halt.target 、poweroff.target 或 reboot .target。 |
Systemd
進程在被加載到內後,將依次執行五個目標:
/usr/lib/systemd/system/default.target
,這個文件鏈接到當前目錄的graphical.target
[Unit]
Description=Graphical Interface
Documentation=man:systemd.special(7)
Requires=multi-user.target
Wants=display-manager.service
Conflicts=rescue.service rescue.target
After=multi-user.target rescue.service rescue.target display-manager.service
AllowIsolate=yes
- 根據上一步中可以看到
default.target
強依賴於multi-user.target
,所以接下來這步就要執行如下兩個目錄中的目標了:
/etc/systemd/system/multi-user.target.wants/
/usr/lib/systemd/system/multi-user.target.wants/
大部分的用戶程序的目標都在這兩個目錄下有配置,在這步就一併啓動了
#/usr/lib/systemd/system/multi-user.target.wants/multi-user.target
[Unit]
Description=Multi-User System
Documentation=man:systemd.special(7)
Requires=basic.target
Conflicts=rescue.service rescue.target
After=basic.target rescue.service rescue.target
AllowIsolate=yes
- 接下來到了
basic.target
目標了,內容如下:
/etc/systemd/system/basic.target.wants/
/usr/lib/systemd/system/basic.target.wants/
#/usr/lib/systemd/system/multi-user.target.wants/basic.target
[Unit]
Description=Basic System
Documentation=man:systemd.special(7)
Requires=sysinit.target
After=sysinit.target
Wants=sockets.target timers.target paths.target slices.target
After=sockets.target paths.target slices.target
sysinit.target
會啓動重要的系統服務例如系統掛載,內存交換空間和設備,內核補充選項.
/etc/systemd/system/sysinit.target.wants/
/usr/lib/systemd/system/sysinit.target.wants/
[Unit]
Description=System Initialization
Documentation=man:systemd.special(7)
Conflicts=emergency.service emergency.target
Wants=local-fs.target swap.target
After=local-fs.target swap.target emergency.service emergency.target
- 然後是最後一個目標
local-fs.target
,它不會啓動用戶相關服務,它只處理底層核心服務,這個target會根據/etc/fstab
來執行相關磁盤掛載操作
Systemd系統服務配置修改
/usr/lib/systemd/system/xx服務.service
:官方默認配置文件,不建議修改這個位置的文件,而應該像下面這項這樣操作;/etc/systemd/system/xx服務.service.d/custom.conf
:在/etc/systemd/system
下面創建與配置文件相同文件名的目錄,但是要加上.d
的擴展名。然後在該目錄下創建配置文件即可。另外,配置文件最好附文件名取名爲.conf
。 在這個目錄下的文件配置會合併到/usr/lib/systemd/system/xx服務.service
。/etc/systemd/system/xx服務.service.wants/*
:此目錄內的文件爲鏈接文件,設置相依服務的鏈接。意思是啓動了 xx服務.service 之後,最好再加上這目錄下面建議的服務。/etc/systemd/system/xx服務.service.requires/*
:此目錄內的文件爲鏈接文件,設置相依服務的鏈接。意思是在啓動 xx服務.service 之前,需要事先啓動哪些服務的意思。
打開終端
sysvinit系統
在sysvinit系統中,由於/etc/inittab
中的配置如下:
1:2345:respawn:/sbin/mingetty tty1
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
# 只有我們進入5運行級別,會打開圖形用戶終端,並且一旦終端終止,就會再創建一個新的
x:5:respawn:/etc/X11/prefdm -nodaemon
在2345運行級別下,會調用/sbin/mingetty
啓用6個命令行界面的終端,並且一旦終端終止,就會再創建一個新的。
Systemd系統
在上面初始化的第1步中等待了display-manager.service
這個服務就是用於啓動終端界面的,內容如下:
[Service]
ExecStart=/usr/sbin/gdm
ExecStartPost=-/bin/bash -c "TERM=linux /usr/bin/clear > /dev/tty1"
KillMode=mixed
Restart=always
IgnoreSIGPIPE=no
BusName=org.gnome.DisplayManager
StandardOutput=syslog
StandardError=inherit
EnvironmentFile=-/etc/locale.conf
ExecReload=/bin/kill -SIGHUP $MAINPID
[Install]
Alias=display-manager.service