當前位置:
首頁 > 最新 > 嵌入式未來一段時間還是Linux天下,一位嵌入式er初探Linux kernel經驗

嵌入式未來一段時間還是Linux天下,一位嵌入式er初探Linux kernel經驗

首先闡述一下我為什麼想學習一下Linux kernel。最早是因為對嵌入式的一時腦熱,我買了開發板,買了不少資料,前前後後投進去了1000多了。不過好歹還是有點回報的,雖然還沒有怎麼著調,但又似乎拓寬了不小的知識面。

慢慢的我發現,對於從學軟體入手的我來說,硬體知識的薄弱是個不容忽視的缺陷,畢竟軟硬體間的代溝還是不小的,就像現在的老爹和fashion閨女一樣,鴻溝還是忽視不得的。這有點讓我望而卻步,不過多大的困難都無法阻擋我的前進啊。我對策略稍作調整,因為我發現,嵌入式無論是現在,還是未來一段時間都還是Linux的天下;另外是真正的做Linux的大牛們似乎也都有涉足embedded system 的經歷。這就使得僅僅會管理Linux系統和服務,簡單的用幾個Shell commands ,編譯安裝幾個Linux應用,讀懂幾個Makefile……根本滿足不了需求;另外也為了不讓學習的OS知識只是空洞的理論。這都要求著自己必須有編寫自己Shell程序的能力;要求著可以在Linux做程序開發的能力;要求著可以自己往kernel中附加自定義的系統調用、重組內核、添加自寫驅動……的能力。這就要求著必須深入了解,正如任何一門技術一樣,接觸久了你就有種相地層實現挖掘的衝動。

調整後的策略就是先把Linux這個OS的機制弄明白,才可以遷移定製滿足需求的系統,才可以寫出高效率的Linux應用。整體路線就是農村包圍城市,不斷補充必要知識,循序漸進,最終呈現星星之火可以燎原之勢。額,扯得夠遠。廢話不多說,下面開始。

Kernel入門,要選本好的入門書籍,我從網上download一本《Linux內核設計與實現》。這本書簡單易讀,有OS基礎和Linux應用基礎的人一讀即懂,我現已閱過3章,感覺很不錯,另外配合《Linux操作系統內核實習》效果更佳。我想儘可能通過更加通俗的形式向你闡述kernel的機理,讓我們一起如喝涼水般拿下kernel。

首先介紹一下內核源碼的根目錄描述:

arch(architecture) 特定體系結構的源碼

crypto crypto API

Documention 內核源碼文檔

drivers 設備驅動程序

fs VFS和各種文件系統

include 內核頭文件

init 內核引導和初始化

ipc 進程間通訊代碼

kernel 像調度程序這樣的核心子系統

lib 通用內核函數

mm 內存管理子系統和VM

net 網路子系統

scripts 編譯內核所用到的腳本

security Linux安全模塊

sound 語音子系統

usr 早期用戶空間代碼(所謂的initramfs)

這裡只是簡單闡述個目錄及系統模塊分布。隨著慢慢地學習我相信一定可以把它們搞明白是怎麼一回事的。

另外,你需要明白一些Linux必備的一些常識性名詞解釋知識,這裡羅列一些名詞,不明白的不再一一闡述,自己百度,Google:管態、目態、內核空間、用戶空間、POSIX、system V、GNU、GPL、GNOME、KDE、QT、GTK+、openGL、shell、awk、Makefile、CC、GCC、G++、GDB、Perl……

下面來介紹一下內核開發和應用程序開發的差別:

內核編程時不能訪問C庫(因為Linux下很多C庫函數是對Linux系統調用的封裝,自身怎麼可以調用自身呢?)

內核編程時必須使用GNU C。

內核編程時缺乏像用戶空間那樣的內存保護機制。

內核編程時浮點數很難使用。

內核只有一個很小的定長堆棧。

由於內核支持非同步中斷、搶佔和SMP,因此必須時刻注意同步和並發。

要考慮可移植性的重要性。

對以上這幾點進行描述。

1、首先就是內核不能訪問C庫的問題,你想啊Linux下很多C庫函數是對Linux系統調用的封裝,自身怎麼可以調用自身呢?這裡的系統調用學過OS的應該都清楚,是系統應用給用戶提供的編程介面,注意這裡的對象是用戶。注意啦,程序員也是分等級的,在kernel級別的編程(這裡指純kernel編程),你已經看不到系統調用,此時你的職責可能就是為系統添加一個系統調用(後邊會講到),且C庫是應用層對底層系調(系統調用,為了便於我打字,後邊可能會多次出現)的封裝,從邏輯的角度你也該明白了吧。那麼問題就出來了,沒有c庫怎麼辦,還談什麼模塊化,難不成都自己寫?這就是接下來的問題。

2、既然kernel不能調用C庫,那麼它就得擁有自己獨立的c語言庫,這樣才能高內聚低耦合,並且提升其安全性,所以就用了GNU C 。短小精悍效率高,畢竟是專才專用。這裡需要注意一點,內核中沒有實現printf();但是有功能更為強大的printk();其實也談不上功能強大(因為printf()本身就很強大,尤其是在調試時,這裡也顯出了printk的優勢),它和printf()的顯著區別就是printk()允許通過指定一個標誌來設置優先順序。Syslog會根據這個優先順序標誌來決定什麼地方顯示這條系統消息。如:

printk( KERN_ERR 「This is an error!」);//不理解吧,我也不理解,後邊內核調試時肯定還會將這東西,不怕。

3、內核編程時缺乏像用戶空間那樣的內存保護機制。

你在做什麼?內核好不好,這是一個OS的核心部分,控制著整個系統的運轉,自然要有處理協調整個系統的權利,在內核coding的東西就是OS核心的一部分,是給別人或者自己在OS的上一層用的。既然你是把握這一切的,且又是在硬體基礎上的第一層抽象,另外還把握著全局,內存的控制自然也不能束縛你,就像在公司工作一樣,領導要在可能的範圍內儘可能的下放權力,下屬才能發揮他的極致,估計kernel也是這樣,內存訪問,包括其他的內核結構都不對出於內核的你進行束縛,當然也沒有進行相應的保護機制。因為這是的內核是你的,你沒必要傻逼到寫程序讓自己的系統崩潰吧,哈哈。這也留了一個問題,就是在coding過程中要斟酌好啊。

4、內核編程時浮點數很難使用。這裡你需要知道的是在用戶空間的進程進行浮點操作時,kernel會完成從整數到浮點數的模式轉換,一般是通過捕獲陷阱並作相應的處理的實現的。//陷阱可以算是一種特殊的異常,是從用戶態進入內核態的途徑,以後會進一步介紹。

與用戶空間不同的是,kernel並不能完美的支持浮點操作,因為自身不能陷入自身。在kernel中使用浮點數時,除了要人工保存和恢復浮點寄存器,還有很多瑣碎的事要做。直截了的說就是:不要在kernel中使用浮點數!!!

5、內核只有一個很小的定長堆棧。在x86上,kernel的棧是在編譯時配置的,可為4k或者8k,且每個處理器都有自己的棧。為什麼這麼小呢?大了不可以么?我的理解是,現在都在追求微內核,這是一方面原因,還有就是內核也是一個軟體,只不過是包含了硬體抽象且富含大量系統管理功能的進程,而其他功能的進程(系統調用,其他內核進程),在調度是,存在內核搶佔和代替內核執行的情況,這是要將要執行的進程的上下文切換過來,當然這些數據都會出現在棧裡邊,你想如果棧很大,那麼操作時內存訪問地址會很長,訪問時占內存且費時間,會降低效率,所以要儘可能的小且靈活……

6、由於內核支持非同步中斷、搶佔和SMP,因此必須時刻注意同步和並發。這不僅僅是linux kernel ,是所有現有的多進程/多線程並發OS都要注意的,包括多線程編程也一樣,你就把kernel想成是一個多線程的執行程序就OK了,不難理解。

7、要考慮可移植性的重要性。這個更不用多說了,因為這是linux的一個灰常顯著的特徵,大到企業的伺服器,小到嵌入式的android,IP camera……等很多東西不同平台構架的cpu……應該是目前跑的平台最多的OS了,所以他的內核要有足夠的可移植性,似乎有點java的感覺......

由於篇幅原因,今天就介紹到這裡了,感興趣的同學明天繼續收看哦!~

推薦閱讀:

1.你的Coding style規範否?大神談談為Linux內核寫驅動的編碼規範

2.嵌入式Linux下最常用的C語言編譯器GCC命令詳解

3.嵌入式Linux設備驅動之匯流排、設備、驅動之間有何關係?

4.嵌入式Linux上的應用程序開發只有高手才能完成?一起來打破這種「迷信」


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嵌入式ARM 的精彩文章:

一位嵌入式Linux菜鳥設備驅動學習之路

TAG:嵌入式ARM |