若是你有幸看到這一章,那麼恭喜你,你已經完成了整個操做系統的一多半了,並且若是你前面的東西都徹底掌握了,那後面無非就是順水推舟的事情了。本章不作繼續的講解,而是將以前的知識進行回顧,並把類似的知識點作對比。同時我也將到目前爲止最大的感悟 細節是魔鬼 分享給你們。html
爲了讓你們清楚目前的程序進度,畫了到目前爲止的程序流程圖,以下。其實就是截至到內存管理這一塊git
這裏列出整個系列到目前爲止的目錄,恰好也能夠做爲索引方便你們閱讀了程序員
第 01 和 02 部分沒有實質性的代碼,但倒是學習一個新東西的必要開始,也就是解除困惑,梳理流程。它告訴了咱們 計算機的啓動過程,也就是計算機按下開機鍵以後,初始的程序計數器 IP 的值指向了哪裏,初始執行的 BIOS 中寫死的程序作了什麼,又跳轉到了哪裏。這讓咱們至少擁有了可以寫出一個讓電腦按下開機鍵以後不報錯併成功跳轉到咱們所寫的代碼的程序。以後的代碼,就是在這兩部分所創造的基本框架中添油加醋完成的。微信
第 03 部分是 讀取硬盤中的數據。咱們所寫的程序確定是放在硬盤裏的,須要加載到內存中才能被 CPU 一條一條取指令並執行。雖然 BIOS 幫咱們完成了啓動區的加載任務,但這只是很小的一部分,咱們不能及指望於將操做系統全部代碼都寫到啓動區這 512 字節中,因此啓動區裏的代碼須要實現把更多在硬盤中的程序加載到內存中,這樣一個關鍵任務。數據結構
第 04 部分是 實模式到保護模式,這也是第一次 CPU 廠商和操做系統 打配合。咱們只須要按照 CPU 要求的,好比 寫好段描述符結構、加載 gdt、將 cr0 的 pe 位置 1 等,就能夠順利開啓 CPU 的保護模式,利用其保護模式的特徵了。框架
第 05 部分是 開啓內存分頁機制,這又是一次 CPU 廠商和操做系統打配合的案例,也是按照 CPU 要求的步驟,把該有的數據結構(頁目錄表和頁表)寫好,就能夠開啓分頁機制,利用其提供的分頁特徵了,因爲打配合的案例愈來愈多,一會我單獨總結。函數
第 06 部分是咱們 第一次使用 C 語言 來作事,也能夠看出,以前用匯編語言把那些 瑣事 都處理乾淨了,真正寫內核主代碼時,再把 C 語言請過來。咱們學高級語言的人,包括我本身,都是認爲越底層的語言越高端。不過從咱們這個系列的角度看,彙編作的都是瑣事,或者 C 語言不屑於作的事情,而 C 語言作的,纔是「高大上」的事。因此學習這個系列,包括我本身寫這個系列,也是讓我從兩個角度來審視這個問題了,也不再會去爭論到底高級語言高級,仍是低級語言高級的事情了。學習
第 07 部分是 深刻淺出特權級,這部分也是沒有代碼。這部分就提到了咱們常說的 內核態、用戶態,只不過是從細節入手,講述了特權級是怎麼進行 保護、以及怎麼進行 跳轉 的。至於保護,天然有一套公式規則來判斷,至於跳轉,也是有一套跳轉規則,也就是什麼特權級,在什麼狀況下,能跳到什麼特權級下。固然這只是簡單的描述,實際狀況要複雜得多。操作系統
第 08 和 09 部分是 中斷,從硬件講到了軟件,同時也指出了一個重要的思想,就是 操做系統是個死循環,是靠中斷驅動 的,咱們的操做系統就是隨時等待着各類中斷進來,而後執行相應的中斷處理程序,爲整個操做系統的運行方式作了個思想準備。設計
第 10 部分是 內存管理系統,咱們實現了簡單的四個 內存池 的管理,並最終實現了一個 申請內核內存空間 的函數,該函數自動在內核的虛擬內存池中和物理內存池中找到可用的內存頁,並將其映射到頁表中。這讓咱們對內存管理有了個初步的認識。這塊就再也不須要更多的 CPU 配合操做系統的部分了(固然基礎的都是須要的,我是說再也不須要額外的),有點 純軟件設計 的感受了,以前的部分或多或少都有跟硬件打交道的部分。咱們慢慢地,將與硬件打交道的部分完善好,最後便只剩下軟件的天下了,也是咱們軟件工程師愈來愈熟悉的部分。
這也慢慢地,與咱們的已有的知識接軌,何時全串起來了,你就是高手了。技術領域的高手,不是看的高望得遠,而是基礎紮實,但要紮實到隨便把本身已有的知識進行關聯,就能得出一個很深入的結論。
咱們不僅一次提到了 CPU 與操做系統打配合的地方,如今咱們就一塊兒來串一串,把以前這種配合寫在一塊兒對比一下。
配合項 | 操做步驟1 | 操做步驟2 | 操做步驟3 |
開啓保護模式 | 打開 A20 | 加載 gdt | 將 cr0 的 pe 位置 1 |
加載 gdt | 內存某位置初始化全局描述符表 gdt | lgdt 指令將 GDT 起始地址存入 gdtr 寄存器 | 將 cr0 的 pe 位置 1 |
開啓分頁 | 內存某位置初始化頁表 pde、pte | 將頁目錄起始地址存入 cr3 寄存器 | 將 cr0 的 pg 位置 1 |
開啓中斷 | 內存某位置初始化中斷描述符表 idt,並初始化 pic | lidt 指令將 idt 起始地址存入 idtr 寄存器 | |
特權級 |
請本身默默體會其中的類似之處。
步驟類似,必然也存在着結構類似,下面我把到目前爲止用到的結構列出
至於後面的內存管理池的結構,那是咱們軟件本身定義的,而上面列出的這些,是硬件定義的,也就是說做爲程序員的咱們,必須接受。
這裏我沒有說談談本身對操做系統的理解,由於我以爲這裏談的可能超出了操做系統範疇。另外,我所談的真的是 到目前爲止 的理解與感悟,並非我已經把後面的知識學完了再來補的,可能都學完了再回憶本身在這個時候的感悟,已經不許確了。
高級語言與低級語言沒有高下之分。咱們廣泛有個印象,就是外行人認爲高級語言更高級,低級語言更低級,而內行人則相反。但我如今到以爲,它們根本沒有高下之分,只是不一樣角度罷了。若是從功能上說,低級語言能完成高級語言作不了的事情,也能夠解釋高級語言沒法解釋的原理,從這點看,低級語言顯得更高級。但若是從實際作的事情來看呢?本操做系統中,低級語言(也就是彙編)只是作了一些進入內核以前的瑣事(固然一部分緣由也是由於 c 語言作不了),一旦進入內核,只要能用 c 語言完成的,就絕對不用匯編了。從這個角度看,高級語言作的事情又比低級語言更高端一些。因此個人感悟就是,不再去爭論誰高誰低了,而只是說什麼事情更適合什麼語言來作而已。我以爲就單單是這個感悟,對我目前的 Java 語言幫助就很大,我再也不以爲 Java 比 C 語言或是彙編語言更 low 了。
細節是魔鬼。這真的是我最大的感悟,沒有之一。我起初學習操做系統的時候,老是想盡快,想着有些東西只要理解就能夠了,不必去扣太多的細節。其實這是錯誤的,正確的作法是,先把細節扣得死死的,以後回過頭看的時候就不再看細節了,開始注重總結與理解。而不是先就不扣細節,想着總結與理解。第一點是由於,細節掌握得足夠了,你會發現其餘的好多知識點是通用的,根本不用看就能夠理解了,好比 加載 gdt、加載 idt、以及加載分頁,若是你不是在看加載 gdt 這個部分時把細節吃透,後面兩個知識點你每一個都要從新理解一遍,並且理解得還不必定透徹,所花的總時間,還不如你去花大量時間把第一個吃透,然後面兩個很是快速地就能夠理解到很深刻的地步。
越簡單越透徹,越透徹越簡單。這裏的每個知識點,我一開始都以爲比天都難,而在真正理解以後,卻變得很簡單,甚至有點無聊。你可能以爲這是廢話,但有的時候,有些知識點我理解的糊里糊塗,理解得也很複雜,跟別人也說不明白,當時我以爲是知識點就很複雜,給被人講確定是講不明白的,得人家本身去理解。但後來我發現,不管多複雜的事,只要你真正掌握而且抓到本質了,是真的很簡單,甚至你能夠給一個不搞技術的人講明白(這個明白固然不是真正的懂哈)。就好比說內存管理這一塊,我看的時候甚至一度要放棄,但後來通過對每一行代碼,每個結構都扣出來剖析以後,我居然以爲這塊簡單得不要不要的,無非就是取一個虛擬地址,取一個物理地址,再把它們加到頁表中對應起來。不過這塊也同時說明了 細節是魔鬼。假若你一開始就看到這句話,好比從某個一分鐘搞懂操做系統的軟文,你的理解就是「取一個虛擬地址,取一個物理地址,再把它們加到頁表中對應起來」,和我扣完細節以後的理解同樣,但你以爲這是真正的同樣麼?因此,不是由於它簡單因此你理解的透徹,而是由於你理解的透徹,它就變得簡單起來了。
因此,細節真的是魔鬼,千萬不要企圖一篇文章就搞懂操做系統這種事,我也能夠把這篇文章改編成一個相似的文章,但若是你不去花時間扣細節,你從此必定會把更多的時間耽誤在這裏的,這個帳總會有一天找到你的頭上。
若是你對自制一個操做系統感興趣,不妨跟隨這個系列課程看下去,甚至加入咱們,一塊兒來開發。
《操做系統真相還原》這本書真的贊!強烈推薦
當你看到該文章時,代碼可能已經比文章中的又多寫了一些部分了。你能夠經過提交記錄歷史來查看歷史的代碼,我會慢慢梳理提交歷史以及項目說明文檔,爭取給每一課都準備一個可執行的代碼。固然文章中的代碼也是全的,採用複製粘貼的方式也是徹底能夠的。
若是你有興趣加入這個自制操做系統的大軍,也能夠在留言區留下您的聯繫方式,或者在 gitee 私信我您的聯繫方式。
本課程打算出系列課程,我寫到哪以爲能夠寫成一篇文章了就寫出來分享給你們,最終會完成一個功能全面的操做系統,我以爲這是最好的學習操做系統的方式了。因此中間遇到的各類坎也會寫進去,若是你能持續跟進,跟着我一塊寫,必然會有很好的收貨。即便沒有,交個朋友也是好的哈哈。
目前的系列包括
微信公衆號
我要去阿里(woyaoquali)