一個完整的操做系統主要由4部分組成:硬件、操做系統內核、操做系統服務和用戶應用程序,如圖0.1所示。操做系統內核程序主要用於對硬件資源的抽象和訪問調度。linux
內核的主要做用是爲了與計算機硬件進行交互,實現對硬件部件的編程控制和接口操做,調度對硬件資源的訪問,併爲計算機上的用戶程序提供一個高級的執行環境和對硬件的虛擬接口。shell
操做系統內核的結構模式主要可分爲總體式的單內核模式和層次是的微內核模式。Linux 0.11採用了單內核模式。編程
如圖1.2所示,單內核操做系統所提供的服務流程爲:應用主程序使用指定的參數值執行系統調用指令(int x80),使CPU從用戶態切換到核心態,而後操做系統根據具體的參數值調用特定的系統調用服務程序,這些服務程序根據須要再調用底層的一些支持函數以完成特定的功能。完成服務後,系統使CPU從核心態回到用戶態,執行後續的指令。數組
Linux內核主要由5個模塊構成,分別爲:進程調度模塊、內存管理模塊、文件系統模塊、進程間通訊模塊和網絡接口模塊。模塊之間的依賴關係如圖2.1所示,虛線部分表示0.11版本內核中未實現部分(全部的模塊都與進程調度模塊存在依賴關係)。網絡
從單內核模式結構模型出發,Linux 0.11內核源代碼的結構將內核主要模塊分配如圖2.2所示。(除了硬件控制方框,其餘粗線分別對應內核源代碼的目錄組織結構)數據結構
對於機器中的物理內存,Linux 0.11內核中,系統初始化階段將其劃分的功能區域如圖3.1所示。函數
虛擬地址:(virtual address)由程序產生的由段選擇符合段內偏移地址兩個部分組成的地址。(虛擬地址空間由GDT和LDT映射的地址空間組成,最大空間16384*4G=64T)操作系統
邏輯地址:(logical address)由程序產生的與段相關的偏移地址部分。(Intel保護模式下就是程序執行代碼段限長內的便宜地址)指針
線性地址:(linear address)虛擬地址到物理地址變換之間的中間層,是處理器可尋址的內存空間中的地址。對象
物理地址:(physical address)出如今CPU外部地址總線上的尋址物理內存的地址信號,是地址變換的最終結果地址。
虛擬存儲/虛擬內存:(virtual memory)指計算機呈現出要比實際擁有的內存大得多的內存量。
保護模式下,虛擬地址到物理地址的變換過程如圖3.2所示。
內存分段機制:Intel CPU使用了段的概念對程序進行尋址。在保護模式下,段寄存器中存放的是一個段描述符表中某一描述符項在表中的索引值。(索引的段描述符項中有該段描述符選項中指定的段基地址、段長度和段的訪問特權級等信息——GDT/IDT/LDT)
在Linux 0.11中,中斷描述符表IDT保存在內核代碼段中。程序邏輯地址到線性地址的變換過程使用了CPU的全局段描述符表GDT和局部段描述符表LDT。由GDT映射的地址空間稱爲全局地址空間,LDT映射的地址空間稱爲局部地址空間,二者共同構成了虛擬地址空間,如圖3.3所示。圖中顯示了兩個任務時的狀況,每一個LDT自己也是由GDT中描述定義的一個內存段,任務狀態段TSS也是由GDT中描述符定義的一個內存段。(TSS用於在任務切換時CPU自動保存或恢復相關任務的當前CPU狀態)
內存分頁管理:基本原理是將CPU整個線性內存區域劃分紅爲4096字節爲1頁的內存頁面。對於頁目錄和頁表,格式基本相同,都佔用4個字節,每一個頁目錄表或頁表必須只能包含1024個頁表,一個頁目錄表或一個頁表均佔1頁內存。圖3.4爲線性地址到物理地址的變換過程示意圖。
Linux 0.11內核設置GDT段描述符項數最大爲256,2項空閒,2項系統使用,每一個進程使用2項,最多再容納126個任務,內核規定最大任務數64個,每一個任務邏輯地址範圍爲64M。
對於Linux 0.11 內核代碼和數據,初始化操做中,對其段長度都設置爲16MB,都是從線性地址的0開始到地址0xffffff共16MB的段。該範圍中含有內核全部的代碼、內核段表(GDT、IDT、TSS),頁目錄表和內核的二級頁表、內核局部數據以及內核臨時堆棧。(將被用做任務0的用戶堆棧)內核的虛擬地址空間、線性地址空間和物理地址空間的關係如圖3.6所示。
Intel 80x86 cpu共分爲4個保護級,Linux 0.11操做系統使用了cpu的0級和3級,內核代碼自己由系統中全部任務共享。當一個任務(進程)被中斷程序中斷時,此時用戶程序也能夠象徵性的稱爲處於進程的內核態,由於中斷程序使用當前進程的內核棧。多任務結構示意圖如圖3.7所示。
任務0是系統中一我的工啓動的第一個任務,代碼段和數據段長度被設置爲640KB(TSS0也是手工預設置好的,任務包含在內核代碼中,不須要再爲其分配內存頁)。任務1也是一個特殊任務,系統建立任務1時,爲存聽任務1的二級頁表在主內存區申請了一頁內存來存放,並複製了父進程(任務0)的頁目錄和二級頁表項,它佔用的線性空間範圍64MB-128MB(實際64MB-64MB+640KB)。對於建立的從任務2開始的其餘任務,其父進程都是init(任務1)進程,從任務2開始,任務在線性地址空間中的起始位置爲任務號*64MB,圖3.8爲任務2原先複製任務1的代碼和數據被shell程序的代碼段和數據段替換後的狀況。
內核以頁面爲單位分配和映射物理內存,malloc()函數具體記錄用戶程序使用了一頁內存的多少字節,剩餘的容量保留給程序再申請內存時使用。當用戶使用內存釋放函數free()動態釋放申請的內存塊時,C庫中的內存管理函數會把釋放的內存塊標記爲空閒,在這個過程當中內核爲該進程分配的這個物理頁面不會被釋放,只有進程結束時才全面回收已分配和映射到該進程地址空間範圍的全部物理內存頁面。
在PC/AT兼容機種,使用了兩塊8259A芯片,如圖4.1所示。在總線控制器控制下,8259A芯片能夠處於編程狀態和操做狀態。操做時,經過中斷判優選擇,芯片將選中當前最高優先級的中斷請求做爲中斷服務對象,並經過CPU引腳INT通知CPU外中斷請求的到來,CPU響應後,芯片從數據總線D7-D0將設定的當前服務對象的終端號送出。
當Intel CPU運行在32位保護模式下時,須要使用中斷描述符表IDT管理中斷或異常。每一箇中斷描述符中包含中斷服務程序地址、有關特權級和描述符類別信息。中斷信號一般分爲兩類:硬件中斷和軟件中斷(異常),每一箇中斷由0-255之間的一個數字來標識。對於中斷0x00-0x1f,由Intel公司固定設定或保留,屬軟件中斷。中斷分類如圖4.2所示。
Linux系統將0x20-0x2f對應於8259A中的中斷請求,把程序編程發初的系統調用中斷設置爲0x80。對於可能引發競爭條件的代碼區,內核使用cli指令和sti指令進行中斷的屏蔽和容許。
系統調用(syscalls)是Linux內核與上層應用程序進行通訊的惟一接口。應用程序、庫函數和內核系統調用之間的關係如圖5.1所示。Linux內核中,每一個系統調用都具備惟一的一個系統調用功能號。系統調用的結果會在返回值中表現出來,負值爲錯誤,0表示正確,出錯時,錯誤信息會在errno中(perror()函數可進行打印)。
程序發初中斷調用int 0x80時(系統調用開始),寄存器eax存放系統調用號,參數依次存放在ebx、ecx和edx中(該版本內核最多直接傳遞3個參數)。此外,Intel CPU還提供了系統調用門的參數傳遞方式,它在進程用戶態堆棧和內核態堆棧自動複製傳遞的參數。
ex.對於read()系統調用,其定義爲int read(int fd, char *buf, int n),系統調用的宏的形式爲_syscall3(int,read,int,fd,char*,buf,int,n),系統調用宏有2+2*n個參數,第一個參數爲返回值類型,第二個參數爲系統調用名稱。
PC/AT微機系統中提供了用電池供電的實時時鐘RT電路支持,使用了MC146818芯片,初始化時,內核讀取芯片當前時間和日期信息,轉換成從1970年1月1日午夜0時開始計到當前的以秒爲單位的時間(UNIX日曆時間)。再經過從系統啓動開始計數的系統滴答值jiffies,程序就能夠惟一肯定運行時刻的當前時間值。
在Linux 0.11內核的初始化過程當中,PC機將可編程定時芯片Intel 8254計數器通道0設置成方式3(方波發生器)初始技術支持設置成10ms在輸出一個上升沿,觸發一次時鐘中斷請求(IRQ0),這個時間也稱爲系統滴答或系統時鐘週期。每當發生一次時鐘中斷,jiffies值就增1。時間片的定義就是滴答數。
進程在內核態運行時不會被調度程序切換(進程在內核態程序中運行時是不可搶佔的(nonpreemptive),但當處於用戶態程序中運行時是能夠被搶佔的(preemptive))。Linux系統中能夠建立動態定時器,用於軟盤馬達開啓和關閉等定時操做,僅供內核使用,0.11內核中最多能夠有64個定時器。
上電啓動後,引導程序把內核從磁盤上加載到內存中,並讓系統進入保護模式,就開始執行初始化程序。系統首先肯定如何分配使用系統物理內存,而後調用內核各部分的初始化函數分別對內存管理、中斷處理、塊設備和字符設備、進程管理以及硬盤和軟盤硬件進行初始化處理。Linux 0.11內核中,第一個進程爲「手工」創建,其他的進程都由系統調用fork建立新進程,內核程序使用進程標識號(pid)標識每個進程。對於只有一個cpu的系統,某一時刻只能有一個進程運行,內核經過調度程序分時調度各個進程。Linux內核中,進程一般被稱做任務(task),運行在用戶空間的程序稱做進程。
內核程序經過進程表對進程進行管理,一個進程在進程表中佔有一項。Linux系統中,進程表項是一個task_struct指針,包含用於控制和管理進程的全部信息(進程當前運行的狀態信息、信號、進程號、父進程號、運行時間累計值、正在使用的文件和本任務的局部描述符以及任務狀態端信息)。
進程狀態及轉換關係如圖7.1所示。當一個進程的運行時間片用完,系統就會使用調度程序切換到其餘程序去執行。同時,只有當進程總「內核態」轉移到「睡眠態」時,內核纔會進行進程切換操做。爲了不進程切換時形成內核數據錯誤,內核在執行臨街區代碼時會禁止一切中斷。
對於進程的初始化,系統處於可運行狀態時,程序把本身「手工」移動到任務0(進程0)中運行,並使用fork()調用建立進程1(在進程1中程序繼續對應用環境進行初始化,執行shell登陸程序)。「移動到任務0中執行」這個過程由宏move_to_user_mode完成,移動以前,系統在對調度程序初始化的過程當中,首先對任務0的運行環境進行了設置(任務0數據結構各字段的值)。宏move_to_user_mode的功能就是把運行特權級從內核態的0級變換到用戶態的3級,移動過程當中,宏move_to_user_mode使用了中斷返回指令形成特權級改變的方法。在使用fork()建立新進程時,全部進程都是經過複製進程0獲得的,都是進程0的子進程。
對於新進程的建立,系統首先在任務數組中找出一個尚未被任何進程使用的空項(若是已有64個進程,則fork()系統調用會返回錯誤),而後系統爲新建進程在主內存區中申請一頁存聽任務的數據結構信息,複製當前進程任務數據結構做爲模板(防止未處理完成的新建進程被調度函數執行,設置其狀態爲不可中斷的等待狀態),接着修改任務數據結構(父進程、時間片、GDT、代碼和數據段基址、限長、內存分頁管理頁表等),隨後若父進程打開則對應文件打開次數增1,GDT中設置TSS,LDT,最後將其設置成可運行狀態。
對於進程的調度,首先掃描任務數組,選中就緒狀態中(TASK_RUNNING)運行時間最少的進程,使用任務切換宏函數切換到該進程運行。若全部處於就緒狀態進程時間片都用完,系統就根據每一個進程的優先級權值priority,重新計算counter=counter/2+priority。每當選出一個新的可運行進程,便進行進程切換。switch_to()宏會把CPU當前狀態替換成新進程的狀態(current置爲新任務指針->長跳轉新任務TSS地址出->CPU保存當前任務狀態後更新到新任務的狀態),整個過程如圖7.2所示。
對於進程的終止,在子進程執行期間,父進程一般使用wait()或waitpid()函數等待某子進程的終止,當被等待子進程進入僵死狀態時,父進程把子進程運行使用的時間累加到本身進程中後釋放已終止子進程任務數據結構所佔用的內存頁面,置空子進程在任務數組中的指針項,釋放進程所佔用的系統資源。
Linux 0.11系統中使用了四種堆棧。一種是系統引導初始化時臨時使用的堆棧;一種是進入保護模式後提供內核程序初始化使用的堆棧;另外一種是每一個任務經過系統調用,執行內核程序使用的堆棧;最後一種是任務在用戶態執行的堆棧。
使用多個棧或在不一樣狀況下使用不一樣棧的緣由主要有兩個:首先是從實模式進入保護模式,CPU對尋址訪問方式發生了變化,須要從新設置棧區域;爲了解決不一樣CPU特權級共享使用堆棧帶來的保護問題,0級和3級的代碼須要不一樣的棧。
Linux系統引導啓動時,默認使用的文件系統是根文件系統。其中包括規定的目錄、配置文件、設備驅動程序、開發程序以及全部其餘用戶數據或文本文件等。通常包括一些子目錄如圖9.1所示。
Linux 0.11內核所支持的文件系統是MINIX 1.0文件系統,目前Linux系統上使用最普遍的則是ext3或ext4文件系統。當Linux啓動盤加載根文件系統時,會根據啓動盤上引導扇區第50九、510字節處一個字(ROOT_DEV)中的跟文件系統設備號從指定設備中加載根文件系統(若設備號是0,則從引導盤所在的當前驅動器中加載根文件系統)。
圖10.1所示是Linux內核源代碼目錄結構圖,Linux是一種單內核模式的系統,內核中程序練習緊密,依賴和調用關係很是密切。該內核版本含有14個子目錄,總共包括102個代碼文件,linux努力是源代碼主目錄,除了圖示之外,還有惟一一個Makefile文件。
Linux系統中,內核爲用戶程序提供兩方面的支持:系統調用接口和經過開發環境庫函數或內核函數與內核進行信息交流。在UNIX類操做系統中,最爲廣泛使用的是基於POSIX標準的API接口。API與系統調用區別在於:爲了實現某一應用程序接口標準,API能夠與一個或幾個系統調用對應,也能夠不使用系統調用。統一的標準保證了程序再不一樣系統之間的可移植性。
系統調用是內核與外界接口的最高層,在內核中,每一個系統調用都有一個序列號,而且常以宏的形式實現。目前Linux標準庫LSB和許多其餘標準都不容許應用程序直接訪問系統調用宏。