2018-2019-1 20189206 《Linux核心原理與分析》第四周作業
linux核心分析學習筆記 ——第三章 MenuOS的構造
計算機的“三大法寶”和作業系統的“兩把寶劍”
三大法寶
- 程式儲存計算機 即馮諾依曼體系結構,基本上是所有計算機的基礎性的邏輯框架
- 函式呼叫堆疊 高階語言可以執行的起點就是函式呼叫堆疊
- 中斷機制
- 中斷上下文 儲存現場和恢復現場
- 程序上下文 程序的排程
構建一個linux核心--MenuOS系統
linux核心原始碼幾個重要的目錄
arch
目錄- 是與體系結構相關的子目錄列表,存放了許多CPU體系結構相關的程式碼
- 該目錄主要作用是使linux核心支援不同的CPU體系結構
init
目錄- 存放linux核心啟動時的初始化程式碼
- 在
init
目錄下有main.c原始檔,是整個linux核心啟動的開始
kernel
目錄- 存放核心本身所需要的一些核心程式碼檔案
- 存放程序排程相關的程式碼
lib
目錄- 公用庫檔案
- 在核心程式設計中不能使用C語言的標準庫函式,lib目錄就是用來替代那些標準庫函式的
構造MenuOS系統
MenuOS系統由Linux核心映象和根檔案系統整合起來的
上圖所示,在實驗樓linux環境下,利用圖示命令啟動MenuOS系統。
qemu
模擬kernelbzImage
是壓縮的核心映像- 根檔案系統一般包括記憶體根檔案系統和磁碟根檔案系統
- 本系統中利用rootf.img只有一個init功能,用menu程式代替init。
相關概念
- 檔案系統和根檔案系統
- 檔案系統:是對一個儲存裝置上的資料和元資料進行組織的機制,有利於使用者和作業系統之間的互動。檔案系統的使用者只要知道所需檔案的檔名,就可存取檔案中的資訊,而無需知道這些檔案究竟存放在什麼地方。
- 根檔案系統:也是一種檔案系統,並且它是核心啟動時,所掛載的第一個檔案系統,核心程式碼的映像檔案儲存在根檔案系統中,系統引導啟動程式會在根檔案系統掛載之後從中把一些初始化指令碼和服務載入到記憶體中去執行。
檔案系統和核心是完全獨立的兩個部分,linux啟動第一個必須掛載根檔案系統
- 核心編譯之後會生成兩個檔案,一個是Image,另一個是zImage,其中Image為核心映像檔案,zImage為核心的一種映像壓縮檔案。其中bzImage適用於大核心,zImage適用於小核心。
跟蹤除錯linux核心的啟動過程
使用gdb跟蹤除錯核心,使用兩個引數,-s 和-S
- -s 是在1234埠上建立了一個gdb-server
- -S 是在CPU初始化之前凍結起來
利用target remote:1234
建立連線,在start_kernel
處建立斷點,輸入c
繼續執行,將會看到,系統開始啟動執行,到start_kernel
處停止。
再設定一個斷點rest_init
繼續執行,停在斷點處
linux核心啟動過程分析
start_kernal()函式
在位於init目錄下的main.c檔案中,有核心啟動的起點函式start_kernal()
在此函式呼叫之前,程式碼主要工作是完成硬體的初始化等。
- 圖中可以看到init_task是一個
struct task_struct
型別的變數。是程序描述符,使用巨集INIT_TASK直接對其進行初始化。 task_struct
就是核心執行緒,init_task就是0號程序,是系統建立的第一個程序,也是唯一一個沒有通過fork或者kernel_thread產生的程序,最後演變成idel程序
- 圖中可以看到init_task是一個
rest_init()函式
kernel_thread()
函式作用是建立新的核心執行緒,除了0號程序,其餘所有的核心執行緒都是由kernel_thread()這個介面產生的。下圖所示是kernel_thread()的原始碼。
kthreadd()
函式的任務是管理和排程其他核心執行緒,可以看到在kthreadd()
程式碼中,有一個while(1)迴圈執行,將進的核心執行緒加入到kthread_creat_list全域性連結串列中。也就是當呼叫kernel_thread()
建立的核心執行緒會被加入到連結串列中
針對於rest_init()函式來說,會啟動三個程序,分別是idle(0號程序)、kernel_init(1號程序)、kthreadd(2號程序)
idle(0號程序) 由init_task程序建立後,呼叫cpu_idle()演變而成,
kernel_init(1號程序)由idle程序呼叫kernel_thread()建立,在核心空間完成初始化後, 演變成init程式,init程序是核心啟動的第一個使用者態程序。<font color="Tomato">kernel_init執行在核心空間,隨後會完成從核心態向用戶態的轉變,變成init程序,執行在使用者空間</font>在系統啟動完成完成後,init將變為**守護程序**監視系統其他程序。
kthreadd(2號程序)由idle通過kernel_thread建立,並始終執行在核心空間, 負責所有核心執行緒的排程和管理,也是大部分建立的核心程序的父程序。
下圖所示,是linux核心啟動的流程示意圖:
參考資料:
核心啟動階段程序分析
Linux下1號程序的前世(kernel_init)今生(init程序)----Linux程序的管理與排程(六)
問題
執行緒與程序
在分析linux核心啟動過程中,設計到了好幾個程序的啟動與轉變,書上的描述方式是 核心執行緒 但是建立的又是程序,我就分不清楚核心執行緒和程序的關係,我就去找了些概念:
- 程序:指在系統中能夠獨立執行並作為資源分配的基本單位,程序只能由父程序建立。
- 執行緒:是程序中的一個實體,作為系統排程的基本單位
- 程序的個體是完全獨立的,而執行緒間是彼此依存的。
- 多程序環境中,任何一個程序的終止,不會影響到其他程序。而多執行緒環境中,父執行緒終止,全部子執行緒被迫終止(沒有了資源)。而任何一個子執行緒終止一般不會影響其他執行緒,除非子執行緒執行了exit()系統呼叫。任何一個子執行緒執行exit(),全部執行緒同時滅亡。
可以看出,程序和執行緒是包含的關係,對於書上核心執行緒的描述就更加迷惑了,又查找了關於linux系統下的程序與執行緒相關資料:
- 核心執行緒,只是一個稱呼,實際上就是一個程序,有自己獨立的TCB,參與核心排程,也參與核心搶佔。這個程序的特別之處有兩點,第一、該程序沒有前臺。第二、永遠在核心態中執行。
- 核心執行緒類似於使用者程序,通常用於並併發處理性質的任務,並且可以搶佔排程。不同於使用者程序,核心執行緒位於核心空間,並且可以訪問核心函式和核心資料。