天天看點

linux檢視硬碟smart_linux啟動過程分析

在描述linux系統啟動過程之前,我們需要先來看看linux在啟動之後,實體記憶體的布局情況,我們可以通過檢視檔案/proc/iomen獲得詳細的實體記憶體布局圖,在我的系統中,/proc/iomen檔案内容如下:

linux檢視硬碟smart_linux啟動過程分析

linux實體記憶體布局

很多人在用cat或者vi檢視這個檔案的時候,發現前面的位址值都是清一色的0,不知道為什麼?是時候展現真正的技術了,隻需要在cat或者vi前面加上sudo就好了,沒有點特殊權限是不會讓你看的。另外,上面這張圖是在32位系統上的布局圖。如果你想深入研究linux的核心原理,建議在32位系統上,這樣在檢視記憶體布局方面比較友善。如果隻是“使用”linux,可以直接用64位的。

在0.12版本核心中,由于核心小于640kb,是以被加載到0-640k空間内。而我們在上圖中看到,核心是從1M開始的記憶體區域開始加載的。這是因為,在後來版本的linux核心大小超過了640kb,如果加載到從4kb開始的640kb空間裡,就會占用後面顯示緩沖區和各種ROM區域,該部分區域是由系統保留的,用于映射系統BIOS和顯示卡ROM。而核心必須被裝載到一個連續的記憶體區中,是以隻能從1M開始的位置進行加載。這裡注意BIOS ROM和顯示卡ROM是和記憶體RAM統一編址的。

首先,在我們啟動電源的那一刻,cpu首先跳轉到記憶體0xFFFFFF0處讀取指令并執行,該位址位置正是BIOS ROM的映射區,存放的是BIOS的代碼。系統執行BIOS用于各個硬體子系統的自檢和初始化。

執行完BIOS後,我們的硬碟等裝置都已經處于可用狀态了,系統就會去讀取第一個可啟動裝置(通常就是硬碟)的第一個扇區,也就是我們經常說的MBR,這裡存放的就是用于加載核心的bootloader,現在基本都是grub了。grub會将我們的linux核心加載到記憶體中,那麼grub是從哪裡加載linux核心的呢?當然是從硬碟加載到記憶體了。我們的linux核心映像檔案就放在硬碟/boot分區裡。在我的系統中,/boot目錄如下:

linux檢視硬碟smart_linux啟動過程分析

boot目錄

其中vmlinuz-4.15.0-20-generic這個檔案就是grub将會加載到記憶體中的linux核心映像檔案了,這裡采用的是壓縮的形式存放的,是以加載到記憶體中還需要解壓縮。而grub目錄中存放的是grub的配置檔案,grub被加載到記憶體中,首先會讀取該目錄中的配置檔案,是以如果你想對grub進行配置,就可以在這個目錄裡修改配置檔案。注意,該目錄中存放的是配置檔案,并不是grub的可執行代碼檔案,grub的可執行代碼我們剛才已經說了,是存放在硬碟的第一個扇區中,這個是在安裝系統的時候寫入該扇區的。

在該目錄中,值得關注的還有一個initrd.img-4.15.0-20-generic檔案,這個檔案是用來做什麼的呢?我們知道,核心在啟動的過程中,要先挂載根目錄,挂載根目錄肯定要能識别硬碟,而識别硬碟需要硬碟裝置驅動程式,而我們的linux為了減少自己的體積,并不會将裝置驅動程式編譯到自己的核心映像中,而是将大部分裝置驅動程式編譯成單獨的子產品,動态的加載裝置驅動程式。子產品檔案一般都放置在/lib/moduls/目錄下。這時候就出現了一個問題了,linux要挂載硬碟,首先需要能識别硬碟,需要硬碟裝置驅動程式,而裝置驅動程式又在硬碟的/lib/moduls/目錄下,而此時硬碟還沒有挂載,就無法取得該目錄,無法取得該目錄就沒法加載裝置驅動程式,沒有裝置驅動程式,就無法加載硬碟,好像陷入了無法解決的死循環。Linux核心的開發者們,當然不允許這種互相踢皮球的現象存在,于是想出了一個辦法,那就是虛拟檔案系統RAM disk,也就是我們看到的這個檔案initrd.img-4.15.0-20-generic,該檔案也會在系統啟動的過程中由boot loader(grub)加載,加載到記憶體中解壓縮後,會臨時充當linux的根檔案系統,該檔案系統中存放了linux所需裝置的驅動程式。我們可以檢視該檔案的内容,就是一個比較完整的跟檔案系統。具體的檢視方式,這裡就不詳細闡述了。

/boot目錄下還有幾個檔案,config是核心在編譯階段的一些配置選項,system.map為系統的符号在虛拟位址空間的位址。

到這裡我們的核心就加載到記憶體中了,并開始執行,核心會在執行一系列的初始化操作後,變成0号idle程序,0号程序會啟動一個叫kthreadd的核心守護線程,由該線程啟動一系列的核心線程,最後0号程序會啟動我們的第一個使用者層程序init,目前大部分發行版的init程序執行的是systemd了。我們用ps -ef可以檢視系統中啟動的程序,在我的系統中執行ps -ef指令如下:

linux檢視硬碟smart_linux啟動過程分析

ps -ef

其中COMMAND列中帶中括号的就是系統的核心線程,剩下的就是系統啟動的使用者層程序。其實他們本質上都是一樣的,都是linux程序,隻是一個是在核心空間執行,另一個是在使用者空間執行的。通過pid和ppid我們也能看出,所有核心守護線程都是由kthreadd啟動的,而kthreadd的父程序id号是0。而我們看到pid号為1的程序就是我們的init程序,他同樣也是由0号程序啟動的。通過COMMAND列我們看到init程序啟動的是/sbin/init這個可執行檔案,通過ls -al發現,該檔案正是systemd的連結,是以我們的init程序其實就是systemd了。

systemd正是使用者空間所有程序的父程序了,所有的使用者空進程序都是由他來啟動的,我們也可以通過pstree指令直覺的看到系統中程序的父子關系:

linux檢視硬碟smart_linux啟動過程分析

pstree

我們通過pstree發現系統中所有的程序都是由systemd啟動的,由于我是通過ssh遠端登入的linux,是以也可以看到bash是由sshd啟動的,這個也就是我在前幾篇文章重點讨論的shell了。

再往下就是systemd的啟動過程了,我不打算在這篇文章中詳細讨論了,我會在下一篇嘗試探讨systemd的啟動過程。為什麼說用嘗試探讨,因為我發現,很多東西,懂了跟寫出來是完全不一樣的,就像這篇文章,一開始我以為寫個啟動過程會很容易,但是寫着寫着就會發現,内容實在是太龐大了,很多東西即使弄懂了,但是把它寫出來好像也沒有那麼容易,是以隻能說嘗試了。

結合上一篇文章《linux shell環境配置檔案》,到這裡,基本上把linux啟動過程的方面方面都涉及到了,但是不可能在一篇文章中讨論所有的細節。比如linux核心的啟動過程,隻是幾句話帶過了。本文權當是給各位抛磚引玉了。