我不認為我是 linux 之上的高手,因為我的shell 沒有達到c語言的 拿來即用的水平,而且我的核心開發主要集中於裝置驅動的開發。但我確信我現在已經是一個入門者,可以再遇到問題的時候,迅速定位,然後給出正確的指導和答案。
linux核心難嗎。
接觸之初,和現在完全是兩種答案。在學習linux之前,我做過幾年的單片機開發,基本的51系列,msp430系列等等。這為我理解linux的對硬體的操作打下深刻基礎。因為對於cpu而言,最基本的部分是相同的,比如時鐘設定,看門狗,中斷,GPIO,串口等等。這些在單片機開發的時候,是完全要自己編寫驅動,使其適應不同要求的。所以,在轉移到linux之上時,我的學習的線索,就是以linux系統對硬體操作為主線的。比如,我要知道linux是怎麼操作cpu的時鐘的,我就要知道linux的api是通過什麼過程串連到最終的寄存器之上。
不斷的探索,記錄,理解,最終才對linux核心有了最初的瞭解。
在學習中,感覺與單片機開發,最大不同在於,linux有了介面的概念。在以前的開發過程中,從來沒有把cpu的驅動控制器跟外圍裝置的驅動分開來操作,而在linux中有了bus的概念。bus的一端連著控制器,一端連著外圍驅動。bus的介面屏蔽了不同cpu之上裝置磁碟機的不同,為外圍驅動開發提供了統一的介面。
在學習之初,我夢想著,自己可以寫一個bus驅動,但當我仔細查看核心源碼時,發現linux核心幾乎涵蓋了所有的匯流排介面。而對應的cpu匯流排控制器的驅動,多數都由CPU開發人員來提供。對於一個初級的驅動開發人員來說,可以熟練的使用匯流排介面,開發外圍裝置驅動就可以滿足要求了,不必理會bus另一端的具體實現。
但,我是學過硬體的,晶片採購,電路設計,pcb繪製都做過,所以我覺得自己應該瞭解的更深入一些。在裝置驅動開發之中,最重要的就是理解device,bus,driver的概念。如果理解了三者之間的關係,那麼裝置驅動就明白一半了。裝置驅動的其他部分就是核心中的基本概念,比如阻塞,同步,task,中斷,還有使用者層介面。
我想學習核心,除了從硬體上入手之外,還可以從使用者層介面入手。畢竟不是很多人都有硬體的基礎,所以如果對linux應用軟體熟悉的話,那麼最好的方法就是從使用者層介面入手了。比如裝置節點,proc 檔案,sys檔案,netlink,uevent,系統調用等等。當能夠熟練的運用不同的介面,來操作硬體裝置的時候,就是linux核心入門的時候。
既然已經入門了,這個時候,對當前所有的匯流排驅動都可以達到拿來即用的地步。下一步的目標是什麼呢。記憶體管理,dma管理,中斷管理,檔案系統管理,啟動過程。這一部分是走向linux精髓的必由之路。記憶體管理協助我們瞭解不同記憶體配置api的優點和缺點,不同記憶體配置演算法的特點,還有linux中的實存和虛存的空間分布等等。dma管理,可以使我們瞭解dma的啟動過程,使用方法,這個部分也依賴於硬體。中斷管理,協助我們瞭解中斷的組織和調用路由,以及中斷的使用方法和注意要素。檔案系統管理,可以讓我們深入理解linux的vfs層,所有的操作能看到的就是vfs的介面。啟動過程,我們可以知道 bootloader啟動linux核心的參數和引導,硬體的初始化順序,驅動的載入順序,rootfs的掛載等等。
到了這一步,我想對於linux核心的學習,可以達到60%左右了吧。最後一部分就是linux的核心調度和網路通訊協定棧。這兩個部分是最重要的部分。任務調度是任何一個作業系統的核心,通過任務調度可以得出一個系統的優勢和特點。關於核心調度,我想首先需要明白一個進程是如何建立並啟動並執行。這個時候,就涉及到了linux系統的可執行程式的格式,比如elf。為什麼一個程式,在shell中調用就可以執行了呢。先看看busybox中shell的代碼,看看系統調用的代碼,看看核心建立進程的過程等等。多個建立的進程在核心中是如何調度的呢。我只在大學的時候被告知了linux的幾種調度演算法,但親自看看代碼和實現過程將是另外的一種進步。如果你還看過其他系統的代碼,比如VxWorks,可以比較一下兩個系統的調度上的差異,以及這種差異導致的應用領域的不同(當然不全是調度差異導致的)。
網路通訊協定棧是複雜的工程。也是我的欠缺之處。沒有過多的涉及,我想知道socket是如何建立的,如何阻塞的,如果通訊的,棧中的演算法等等。或許網路通訊協定棧不是工作中必須的,但是linux高手必須的。
跟很多前輩一樣,同樣覺得核心中的 Makefile和Kconfig比較重要,它們是挖掘核心的線索。另外,我覺得學習核心,應該從自己的興趣點開始,比如你最想知道什麼問題,然後去追查。那麼,當你明白這一過程之後,你的知識庫中就形成了一條線,可能這個過程之中,涉及了很多其他的不懂得知識,那麼就讓他停留在你的想象中,你覺得他是什麼樣子的,那麼他就是什麼樣子的。關鍵的是,要抓住主線,抓住從上之下的傳遞過程。 這樣在你的知識庫中的線多到一定的數量時,你就擁有了一張網。幾個線上的連接點或許就是你最初不瞭解的東西。如果在你將兩條線編織在一起的時候,從更高的角度重新審視和總結一下過去的工作,將會有更多的理解。當你的網越織越大,最後填滿核心各個方面的時候,就到達了新的裡程碑。此後,你可以線上上掛自己的鈴鐺,或者你可以最佳化某些演算法,使線跟線之間的連結更有序高效。
我不推薦把線上的每個鈴鐺都了如指掌,那需要太多時間。我們要掌握的是那一張網。如果要在網上添一個鈴鐺,你可以迅速定位到想要的位置就可以。甚至,我不知道該放在哪個位置,但我可以通過網上某個線索迅速的定位到那個位置,然後再學習串連方法都行。
linux核心就是一張網,其中的階層和介面,是引人入勝的地方。
如果網路上沒有你要的答案,那麼源碼就是最佳解決方案。
一起加油吧。