久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

linux設(shè)備驅(qū)動第二篇:構(gòu)造和運行模塊

 心不留意外塵 2017-05-17

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中):  
#define KERN_EMERG 0/*緊急事件消息,系統(tǒng)崩潰之前提示,,表示系統(tǒng)不可用*/  
#define KERN_ALERT 1/*報告消息,,表示必須立即采取措施*/  
#define KERN_CRIT 2/*臨界條件,通常涉及嚴重的硬件或軟件操作失敗*/  
#define KERN_ERR 3/*錯誤條件,,驅(qū)動程序常用KERN_ERR來報告硬件的錯誤*/  
#define KERN_WARNING 4/*警告條件,,對可能出現(xiàn)問題的情況進行警告*/  
#define KERN_NOTICE 5/*正常但又重要的條件,用于提醒*/  
#define KERN_INFO 6/*提示信息,,如驅(qū)動程序啟動時,,打印硬件信息*/  
#define KERN_DEBUG 7/*調(diào)試級別的消息*/

沒有指定日志級別的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完成的,。
   對編譯成module的代碼和數(shù)據(jù)來說,當模塊加載時,,__init屬性的函數(shù)就被執(zhí)行;
   對靜態(tài)編入內(nèi)核的代碼和數(shù)據(jù)來說,,當內(nèi)核引導時,do_basic_setup()函數(shù)調(diào)用do_initcalls()函數(shù),,后者負責所有.init節(jié)函數(shù)的執(zhí)行,。
   在初始化完成后,用這些關(guān)鍵字標識的函數(shù)或數(shù)據(jù)所占的內(nèi)存會被釋放掉,。
1) 所有標識為__init的函數(shù)在鏈接的時候都放在.init.text這個區(qū)段內(nèi),,在這個區(qū)段中,函數(shù)的擺放順序是和鏈接的順序有關(guān)的,,是不確定的,。 
2) 所有的__init函數(shù)在區(qū)段.initcall.init中還保存了一份函數(shù)指針,在初始化時內(nèi)核會通過這些函數(shù)指針調(diào)用這些__init函數(shù)指針,,并在整個初始化完成后,,釋放整個init區(qū)段(包括.init.text,.initcall.init等),,注意,,這些函數(shù)在內(nèi)核初始化過程中的調(diào)用順序只和這里的函數(shù)指針的順序有關(guān),和1)中所述的這些函數(shù)本身在.init.text區(qū)段中的順序無關(guān),。 

下面我們來看一個驅(qū)動程序的hello world程序是如何實現(xiàn)的:

  1. #include <linux/init.h>  
  2. #include <linux/module.h>  
  3. MODULE_LICENSE("Dual BSD/GPL");  
  4.   
  5. static int hello_init(void)  
  6. {  
  7.         printk(KERN_ALERT "Hello, world\n");  
  8.         return 0;  
  9. }  
  10. static void hello_exit(void)  
  11. {  
  12.   
  13.         printk(KERN_ALERT "Goodbye, cruel world\n");  
  14. }  
  15.   
  16. module_init(hello_init);  
  17. module_exit(hello_exit);  

內(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模板

[plain] view plain copy
  1. ifndef CROSS_COMPILE  
  2. export CROSS_COMPILE ?=arm-none-linux-gnueabi-  
  3. endif  
  4.   
  5. ARCH ?= arm  
  6.   
  7. SRC_DIR := /home/XXX/XXX  
  8. OBJ_DIR  := $(SRC_DIR)/obj  
  9. PWD := $(shell pwd)  
  10.   
  11. LINUX_SRC ?= /home/XXX/kernel  
  12.   
  13. CFG_INC = -I$(SRC_DIR) \  
  14.     -I$(DIR_A) \  
  15.     -I$(DIR_B)  
  16.   
  17. CFG_FLAGS += -O2  
  18. EXTRA_CFLAGS  += $(C_FLAGS) $(CFG_INC) $(CFG_INC)  
  19.   
  20. obj-m := mymodule.o  
  21.   
  22. mymodule-objs := a.o  
  23. mymodule-objs += b.o  
  24. mymodule-objs += c.o  
  25.   
  26. modules:  
  27.     @make ARCH=$(ARCH) -C $(LINUX_SRC) M=$(PWD) modules  
  28.   
  29. clean:  
  30.     @echo "cleaning..."  
  31.     rm -f mymodule.ko mymodule.o mymodule.mod.* modules.order Module.symvers  
  32.     rm -f $(mymodule-objs)  

以上就是這一篇的內(nèi)容,,下一篇會從簡單的字符驅(qū)動開始,,介紹驅(qū)動編寫的主要內(nèi)容。



    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導購買等信息,,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多