从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响(一)
生活随笔
收集整理的這篇文章主要介紹了
从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响(一)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
從 2.4 到 2.6:Linux 內核可裝載模
? 塊機制的改變對設備驅動的影響
?? <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
(此文章非常精彩,強烈推薦)?
從 2.4 到 2.6,Linux 內核在可裝載模塊機制、設備模型、一些核心 API 等方面發生較大改變,設備驅動開發人員面臨著將驅動從 2.4 移植到 2.6 內核,或是使驅動同時支持2.4 與 2.6 內核的任務。站在設備驅動開發人員的角度,驅動由一個或幾個外部可加載內核模塊組成,本文針對 2.6 內核里模塊機制的改變對編寫設備驅動程序的影響,從內核模塊的編譯、裝載時的版本檢查、初始化與退出、模塊使用計數、輸出內核符號、命令行輸入參數、許可證聲明等方面比較了 2.4 與 2.6 內核的區別;并總結了使設備驅動同時支持 2.4 與 2.6 內核的一系列模板。 1. 獲取內核版本 當設備驅動需要同時支持不同版本內核時,在編譯階段,內核模塊需要知道當前使用的內核源碼的版本,從而使用相應的內核 API。2.4 與 2.6 內核下,源碼頭文件 linux/version.h 定義有: LINUX_VERSION_CODE ― 內核版本的二進制表示,主、從、修訂版本號各對應一個字節; KERNEL_VERSION(major, minor, release) - 由主、從、修訂版本號構造二進制版本號。 在同時支持2.4與2.6 內核的設備驅動程序中,經常可以看到以下代碼段:清單1:判斷內核版本的代碼段。
| #include <linux/version.h> #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) #define LINUX26 #endif #ifdef LINUX26 /*code in 2.6 kernel*/ #else /*code in 2.4 kernel */ #endif |
?
|
清單2:2.4 內核模塊的Makefile模板
| ??????? #Makefile2.4 KVER=$(shell uname -r) KDIR=/lib/modules/$(KVER)/build OBJS=mymodule.o CFLAGS=-D__KERNEL__ -I$(KDIR)/include -DMODULE -D__KERNEL_SYSCALLS__ -DEXPORT_SYMTAB ? -O2 -fomit-frame-pointer? -Wall? -DMODVERSIONS -include $(KDIR)/include/linux/modversions.h all: $(OBJS) mymodule.o: file1.o file2.o ??????? ld -r -o $@ $^ clean: ??????? rm -f *.o ??????? |
?
在2.4 內核下,內核模塊的Makefile與普通用戶程序的Makefile在結構和語法上都相同,但是必須在CFLAGS中定義-D__KERNEL__-DMODULE,指定內核頭文件目錄-I$(KDIR)/include。 有一點需注意,之所以在CFLAGS中定義變量,而不是在模塊源碼文件中定義,一方面這些預定義變量可以被模塊中所有源碼文件可見,另一方面等價于將這些預定義變量定義在源碼文件的起始位置。在模塊編譯中,對于這些全局的預定義變量,一般在CFLAGS中定義。清單3:2.6 內核模塊的Makefile模板
| # Makefile2.6 ifneq ($(KERNELRELEASE),) #kbuild syntax. dependency relationshsip of files and target modules are listed here. mymodule-objs := file1.o file2.o obj-m := mymodule.o else PWD? := $(shell pwd) KVER ?= $(shell uname -r) KDIR := /lib/modules/$(KVER)/build all: ??????? $(MAKE) -C $(KDIR) M=$(PWD) clean: rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions endif |
?
KERNELRELEASE是在內核源碼的頂層Makefile中定義的一個變量,在第一次讀取執行此Makefile時,KERNELRELEASE沒有被定義, 所以make將讀取執行else之后的內容。如果make的目標是clean,直接執行clean操作,然后結束。當make的目標為all時,-C $(KDIR) 指明跳轉到內核源碼目錄下讀取那里的Makefile;M=$(PWD) 表明然后返回到當前目錄繼續讀入、執行當前的Makefile。當從內核源碼目錄返回時,KERNELRELEASE已被被定義,kbuild也被啟動去解析kbuild語法的語句,make將繼續讀取else之前的內容。else之前的內容為kbuild語法的語句, 指明模塊源碼中各文件的依賴關系,以及要生成的目標模塊名。mymodule-objs := file1.o file2.o表示mymoudule.o 由file1.o與file2.o 連接生成。obj-m := mymodule.o表示編譯連接后將生成mymodule.o模塊。 補充一點,"$(MAKE) -C $(KDIR) M=$(PWD)"與"$(MAKE) -C $(KDIR) SUBDIRS =$(PWD)"的作用是等效的,后者是較老的使用方法。推薦使用M而不是SUBDIRS,前者更明確。 通過以上比較可以看到,從Makefile編寫來看,在2.6內核下,內核模塊編譯不必定義復雜的CFLAGS,而且模塊中各文件依賴關系的表示簡潔清晰。清單4: 可同時在2.4 與 2.6 內核下工作的Makefile
| #Makefile for 2.4 & 2.6 VERS26=$(findstring 2.6,$(shell uname -r)) MAKEDIR?=$(shell pwd) ifeq ($(VERS26),2.6) include $(MAKEDIR)/Makefile2.6 else include $(MAKEDIR)/Makefile2.4 endif ? |
?
2.2模塊裝載時的版本檢查 Linux內核一直在更新、完善,在a版本內核源碼下編譯的模塊在b版本內核下通常不能運行,所以必須有一種機制,限制在a版本內核下編譯生成的模塊在b版本內核下被加載。 2.4與2.6內核在可裝載內核模塊的版本檢查機制方面發生了根本性的改變,不過這些改變對設備驅動開發人員而言基本是透明的。為了使模塊裝載時的版本檢查機制生效,2.4 內核下,只需在CFLAGS中定義?
| -DMODVERSIONS -include $(KDIR)/include/linux/modversions.h; |
?
2.6內核下,開發人員無須采用任何操作。 不過,在此仍有必要闡明2.4與2.6內核對可加載模塊的版本檢查機制。 2.4內核下, 執行`cat /proc/ksyms`可看到內核符號在名字后還跟隨著一串校驗字符串,此校驗字符串與內核版本有關。在內核源碼頭文件linux/modules 目錄下存在許多*.ver文件,這些文件起著為內核符號添加校驗后綴的作用,如ksyms.ver 文件里有一行 #define printk _set_ver(printk)。linux/modversions.h 文件會包含全部的 ver文件 。所以當模塊包含linux/modversions.h文件后,編譯時,模塊里使用的內核符號實質是帶有校驗后綴的內核符號。在加載模塊時,如果模塊中所使用內核符號的校驗字符串與當前運行內核所導出的相應的內核符號的校驗字符串不一致,即當前內核空間并不存在模塊所使用的內核符號,就會出現"Invalid module format "的錯誤。 為內核符號添加校驗字符串來驗證模塊的版本與內核的版本是否匹配是繁雜和浪費內核空間的;而且隨著SMP(對稱多處理器)、PREEMPT(可搶占內核)等機制在2.6內核的引入和完善,模塊運行時對內核的依賴不僅取決于內核版本,還取決于內核的配置,此時內核符號的校驗碼是否一致不能成為判斷模塊可否被加載的充分條件。2.6 內核下,在linux/vermagic.h中定義有VERMAGIC_STRING,VERMAGIC_STRING不僅包含內核版本號,還包含有內核使用的gcc版本,SMP與PREEMPT等配置信息。模塊在編譯時,我們可以看到屏幕上會顯示"MODPOST"。在此階段, VERMAGIC_STRING會添加到模塊的modinfo段。 在內核源碼目錄下scripts\mod\modpost.c文件中可以看到模塊后續處理部分的代碼。模塊編譯生成后,通過`modinfo mymodule.ko`命令可以查看此模塊的vermagic等信息。2.6 內核下的模塊裝載器里保存有內核的版本信息,在裝載模塊時,裝載器會比較所保存的內核vermagic與此模塊的modinfo段里保存的vermagic信息是否一致,兩者一致時,模塊才能被裝載。譬如Fedora core 4 與core 2 使用的都是2.6 版本內核, 在Fedore Core 2下去加載Fedora Core4下編譯生成的hello.ko,會出現"invalid module format" 錯誤。?
| #insmod hello.ko Invalid module format hello: version magic '2.6.11-1.1369_FC4 686 REGPARM 4KSTACKS gcc-4.0' should be '2.6.5-1.358 686 REGPARM 4KSTACKS gcc-3.3' |
?
2.3模塊的初始化與退出 在2.6內核中,內核模塊必須調用宏module_init 與module_exit() 去注冊初始化與退出函數。在2.4 內核中,如果初始化函數命名為init_module()、退出函數命名為cleanup_module(),可以不必使用module_init 與module_exit 宏。推薦使用module_init 與module_exit宏,使代碼在2.4與2.6內核中都能工作。清單5:適用于2.4與2.6內核的模塊的初始化與退出模板
| #include <linux/module.h>? /* Needed by all modules */ #include <linux/init.h>??? /* Needed for init&exit macros */ static int mod_init_func(void) { /*code here*/ return 0; } static void mod_exit_func(void) { /*code here*/ } module_init(mod_init_func); module_exit(mod_exit_func); |
?
需要注意的是初始化與退出函數必須在宏module_init和module_exit使用前定義,否則會出現編譯錯誤。?
?轉載于:https://blog.51cto.com/zyg0227/270373
總結
以上是生活随笔為你收集整理的从 2.4 到 2.6:Linux 内核可装载模块机制的改变对设备驱动的影响(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js 运算符 || 妙用
- 下一篇: 2010版CCNP教材一览【图文】