http://blog.csdn.net/haomcu/article/details/10364329 2013 上一篇介紹了Linux驅(qū)動的概念,,以及l(fā)inux下設(shè)備驅(qū)動的基本分類情況及其各個分類的依據(jù)和差異,,這一篇我們來描述如何寫一個類似hello world的簡單測試驅(qū)動程序。而這個驅(qū)動的唯一功能就是輸出hello world,。 在編寫具體的實例之前,,我們先來了解下linux內(nèi)核下調(diào)試程序的一個重要函數(shù)printk以及幾個重要概念。 printk類似C語言的printf,,是內(nèi)核中輸出打印信息的函數(shù),。以后驅(qū)動調(diào)試中的重要性不言而喻,下面先做一個簡單介紹,。 printk的級別 日志級別一共有8個級別,,printk的日志級別定義如下(在include/linux/kernel.h中): 沒有指定日志級別的printk語句默認采用的級別是:DEFAULT_ MESSAGE_LOGLEVEL(這個默認級別一般為<4>,即與KERN_WARNING在一個級別上),其定義在kernel/printk.c中可以找到,。在驅(qū)動調(diào)試過程中打開所有日志信息可使用echo 7 > /proc/sys/kernel/printk,,相對應(yīng)關(guān)閉日志使用echo
0 > /proc/sys/kernel/printk。 下面再來介紹幾個重要的概念,,這些概念可以先做一個了解,,后續(xù)的文章中還會提到。 內(nèi)核空間和用戶空間 linux系統(tǒng)分為兩個級別,。內(nèi)核運行在最高級別,,可以進行所有的操作。而應(yīng)用程序運行在最低級別,,處理器控制著對硬件的直接訪問以及對內(nèi)存的非授權(quán)訪問,。內(nèi)核空間和用戶空間不僅有不同的優(yōu)先級等級,,而且有不同的內(nèi)存映射,有各自的地址空間,。詳見內(nèi)存管理,。 應(yīng)用程序只能通過系統(tǒng)調(diào)用或中斷從用戶空間切換到內(nèi)核空間,其中系統(tǒng)調(diào)用是軟中斷(0x80號中斷),。執(zhí)行系統(tǒng)調(diào)用的系統(tǒng)代碼運行在進程上下文中,,它代表調(diào)用進程執(zhí)行操作,因此能夠訪問進程地址空間的所有數(shù)據(jù),。而處理硬件中斷的內(nèi)核代碼和進程是異步的,,與任何一個特定進程無關(guān)。 內(nèi)核中的并發(fā) 內(nèi)核編程區(qū)別于常見應(yīng)用程序編程的地方在于對并發(fā)的處理,。大部分應(yīng)用程序除多線程外,,通常是順序執(zhí)行的,不需要關(guān)心由于其他事情的發(fā)生而改變它的運行環(huán)境,。內(nèi)核代碼不是這樣,,同一時刻,可能有多個進程使用訪問同一個模塊,。 內(nèi)核編程要考慮并發(fā)問題的原因:1.linux是通常正在運行多個并發(fā)進程,,并且可能有多個進程同時使用我們的驅(qū)動程序。2.大多數(shù)設(shè)備能夠中斷處理器,,而中斷處理程序異步進行,而且可能在驅(qū)動程序正試圖處理其它任務(wù)時被調(diào)用,。3.一些類似內(nèi)核定時器的代碼在異步運行,。4.運行在對稱多處理器上(SMP),不止一個cpu在運行驅(qū)動程序,。5.內(nèi)核代碼是可搶占的,。 當前進程 內(nèi)核代碼可通過訪問全局項current來獲得當前進程。current指針指向當前正在運行的進程,。在open,、read、等系統(tǒng)調(diào)用的執(zhí)行過程中,,當前進程指的是調(diào)用這些系統(tǒng)調(diào)用的進程,。內(nèi)核代碼可以通過current指針獲得與當前進程相關(guān)的信息。 內(nèi)核中帶“__”的函數(shù):內(nèi)核API函數(shù)具有這種名稱的,,通常都是一些接口的底層函數(shù),,應(yīng)該謹慎使用。實質(zhì)上,,這里的雙下劃線就是要告訴程序員:謹慎調(diào)用,,否則后果自負,。以__init為例,__init表明該函數(shù)僅在初始化期間使用,。在模塊被裝載之后,,模塊裝載器就會將初始化函數(shù)扔掉,這樣可以將函數(shù)占用的內(nèi)存釋放出來,,已做它用,。注意,不要在結(jié)束初始化之后仍要使用的函數(shù)(或者數(shù)據(jù)結(jié)構(gòu))上使用__init,、__initdata標記,。這里摘抄網(wǎng)上的一段總結(jié),如下,。 __init,, __initdata等屬性標志,是要把這種屬性的代碼放入目標文件的.init.text節(jié),,數(shù)據(jù)放入.init.data節(jié)──這一過程是通過編譯內(nèi)核時為相關(guān)目標平臺提供了xxx.lds鏈接腳本來指導ld完成的,。 下面我們來看一個驅(qū)動程序的hello world程序是如何實現(xiàn)的:
內(nèi)核模塊的編譯與應(yīng)用程序的編譯有些區(qū)別,,此hello world模塊的編譯命令為: make -C /xxx/xxx/kernel_src/ M=$(PWD) modules 其中/xxx/xxx/kernel_src/ 為已經(jīng)配置編譯過的內(nèi)核源碼路徑,ubuntu下一般在/lib/modules/$(shell uname -r)/build目錄下。 此函數(shù)只有兩個函數(shù),,一個是hello_init,,在insmod的時候執(zhí)行,這個是模塊的初始化函數(shù),,另一個是hello_exit,,在rmmod的時候執(zhí)行,是模塊卸載時要執(zhí)行的函數(shù),。此模塊的唯一功能就是在insmod的時候輸出Hello,,world,在rmmod的時候輸出Goodbye,,cruel world,。 在編寫應(yīng)用程序時,我們一般都是由多個源文件組成的,,這個時候編譯肯定就不能繼續(xù)使用命令行編譯了,,就要使用到Makefile。同樣,,驅(qū)動模塊的編譯也需要使用的makefile,,下面就是一個在編譯含有多個源碼文件的驅(qū)動模塊時可以參考的Makefile文件。Makefile模板
以上就是這一篇的內(nèi)容,,下一篇會從簡單的字符驅(qū)動開始,,介紹驅(qū)動編寫的主要內(nèi)容。
|
|
來自: 心不留意外塵 > 《linux dev》