欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
從2.4 到2.6:Linux 內核可裝載模塊機制的改變對設備驅動(dòng)的影響

從 2.4 到 2.6:Linux 內核可裝載模塊機制的改變對設備驅動(dòng)的影響

周婷 , 軟件工程師

2006 年 2 月 09 日

從 2.4 到 2.6,Linux 內核在可裝載模塊機制、設備模型、一些核心 API 等方面發(fā)生較大改變,設備驅動(dòng)開(kāi)發(fā)人員面臨著(zhù)將驅動(dòng)從 2.4 移植到 2.6 內核,或是使驅動(dòng)同時(shí)支持2.4 與 2.6 內核的任務(wù)。站在設備驅動(dòng)開(kāi)發(fā)人員的角度,驅動(dòng)由一個(gè)或幾個(gè)外部可加載內核模塊組成,本文針對 2.6 內核里模塊機制的改變對編寫(xiě)設備驅動(dòng)程序的影響,從內核模塊的編譯、裝載時(shí)的版本檢查、初始化與退出、模塊使用計數、輸出內核符號、命令行輸入參數、許可證聲明等方面比較了 2.4 與 2.6 內核的區別;并總結了使設備驅動(dòng)同時(shí)支持 2.4 與 2.6 內核的一系列模板。

1. 獲取內核版本

當設備驅動(dòng)需要同時(shí)支持不同版本內核時(shí),在編譯階段,內核模塊需要知道當前使用的內核源碼的版本,從而使用相應的內核 API。2.4 與 2.6 內核下,源碼頭文件 linux/version.h 定義有:

LINUX_VERSION_CODE ― 內核版本的二進(jìn)制表示,主、從、修訂版本號各對應一個(gè)字節;

KERNEL_VERSION(major, minor, release) - 由主、從、修訂版本號構造二進(jìn)制版本號。

在同時(shí)支持2.4與2.6 內核的設備驅動(dòng)程序中,經(jīng)??梢钥吹揭韵麓a段:


清單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.1模塊編譯

從2.4到2.6,外部可裝載內核模塊的編譯、連接過(guò)程以及Makefile的書(shū)寫(xiě)都發(fā)生了改變。

2.4內核中,模塊的編譯只需內核源碼頭文件;需要在包含linux/modules.h之前定義MODULE;編譯、連接后生成的內核模塊后綴為.o。

2.6內核中,模塊的編譯需要配置過(guò)的內核源碼;編譯、連接后生成的內核模塊后綴為.ko;編譯過(guò)程首先會(huì )到內核源碼目錄下,讀取頂層的Makefile文件,然后再返回模塊源碼所在目錄。


清單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與普通用戶(hù)程序的Makefile在結構和語(yǔ)法上都相同,但是必須在CFLAGS中定義-D__KERNEL__-DMODULE,指定內核頭文件目錄-I$(KDIR)/include。 有一點(diǎn)需注意,之所以在CFLAGS中定義變量,而不是在模塊源碼文件中定義,一方面這些預定義變量可以被模塊中所有源碼文件可見(jiàn),另一方面等價(jià)于將這些預定義變量定義在源碼文件的起始位置。在模塊編譯中,對于這些全局的預定義變量,一般在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中定義的一個(gè)變量,在第一次讀取執行此Makefile時(shí),KERNELRELEASE沒(méi)有被定義, 所以make將讀取執行else之后的內容。如果make的目標是clean,直接執行clean操作,然后結束。當make的目標為all時(shí),-C $(KDIR) 指明跳轉到內核源碼目錄下讀取那里的Makefile;M=$(PWD) 表明然后返回到當前目錄繼續讀入、執行當前的Makefile。當從內核源碼目錄返回時(shí),KERNELRELEASE已被被定義,kbuild也被啟動(dòng)去解析kbuild語(yǔ)法的語(yǔ)句,make將繼續讀取else之前的內容。else之前的內容為kbuild語(yǔ)法的語(yǔ)句, 指明模塊源碼中各文件的依賴(lài)關(guān)系,以及要生成的目標模塊名。mymodule-objs := file1.o file2.o表示mymoudule.o 由file1.o與file2.o 連接生成。obj-m := mymodule.o表示編譯連接后將生成mymodule.o模塊。

補充一點(diǎn),"$(MAKE) -C $(KDIR) M=$(PWD)"與"$(MAKE) -C $(KDIR) SUBDIRS =$(PWD)"的作用是等效的,后者是較老的使用方法。推薦使用M而不是SUBDIRS,前者更明確。

通過(guò)以上比較可以看到,從Makefile編寫(xiě)來(lái)看,在2.6內核下,內核模塊編譯不必定義復雜的CFLAGS,而且模塊中各文件依賴(lài)關(guān)系的表示簡(jiǎn)潔清晰。


清單4: 可同時(shí)在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模塊裝載時(shí)的版本檢查

Linux內核一直在更新、完善,在a版本內核源碼下編譯的模塊在b版本內核下通常不能運行,所以必須有一種機制,限制在a版本內核下編譯生成的模塊在b版本內核下被加載。

2.4與2.6內核在可裝載內核模塊的版本檢查機制方面發(fā)生了根本性的改變,不過(guò)這些改變對設備驅動(dòng)開(kāi)發(fā)人員而言基本是透明的。為了使模塊裝載時(shí)的版本檢查機制生效,2.4 內核下,只需在CFLAGS中定義


                        -DMODVERSIONS -include $(KDIR)/include/linux/modversions.h;                        

2.6內核下,開(kāi)發(fā)人員無(wú)須采用任何操作。

不過(guò),在此仍有必要闡明2.4與2.6內核對可加載模塊的版本檢查機制。

2.4內核下, 執行`cat /proc/ksyms`可看到內核符號在名字后還跟隨著(zhù)一串校驗字符串,此校驗字符串與內核版本有關(guān)。在內核源碼頭文件linux/modules 目錄下存在許多*.ver文件,這些文件起著(zhù)為內核符號添加校驗后綴的作用,如ksyms.ver 文件里有一行 #define printk _set_ver(printk)。linux/modversions.h 文件會(huì )包含全部的 ver文件 。所以當模塊包含linux/modversions.h文件后,編譯時(shí),模塊里使用的內核符號實(shí)質(zhì)是帶有校驗后綴的內核符號。在加載模塊時(shí),如果模塊中所使用內核符號的校驗字符串與當前運行內核所導出的相應的內核符號的校驗字符串不一致,即當前內核空間并不存在模塊所使用的內核符號,就會(huì )出現"Invalid module format "的錯誤。

為內核符號添加校驗字符串來(lái)驗證模塊的版本與內核的版本是否匹配是繁雜和浪費內核空間的;而且隨著(zhù)SMP(對稱(chēng)多處理器)、PREEMPT(可搶占內核)等機制在2.6內核的引入和完善,模塊運行時(shí)對內核的依賴(lài)不僅取決于內核版本,還取決于內核的配置,此時(shí)內核符號的校驗碼是否一致不能成為判斷模塊可否被加載的充分條件。2.6 內核下,在linux/vermagic.h中定義有VERMAGIC_STRING,VERMAGIC_STRING不僅包含內核版本號,還包含有內核使用的gcc版本,SMP與PREEMPT等配置信息。模塊在編譯時(shí),我們可以看到屏幕上會(huì )顯示"MODPOST"。在此階段, VERMAGIC_STRING會(huì )添加到模塊的modinfo段。 在內核源碼目錄下scripts\mod\modpost.c文件中可以看到模塊后續處理部分的代碼。模塊編譯生成后,通過(guò)`modinfo mymodule.ko`命令可以查看此模塊的vermagic等信息。2.6 內核下的模塊裝載器里保存有內核的版本信息,在裝載模塊時(shí),裝載器會(huì )比較所保存的內核vermagic與此模塊的modinfo段里保存的vermagic信息是否一致,兩者一致時(shí),模塊才能被裝載。譬如Fedora core 4 與core 2 使用的都是2.6 版本內核, 在Fedore Core 2下去加載Fedora Core4下編譯生成的hello.ko,會(huì )出現"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使用前定義,否則會(huì )出現編譯錯誤。

2.4 模塊使用計數

模塊在被使用時(shí),是不允許被卸載的。2.4內核中,模塊自身通過(guò)MOD_INC_USE_COUNT、MOD_DEC_USE_COUNT宏來(lái)管理自己被使用的計數。2.6內核提供了更健壯、靈活的模塊計數管理接口try_module_get(&module)及module_put(&module)取代2.4中的模塊使用計數管理宏;模塊的使用計數不必由自身管理,而且在管理模塊使用計數時(shí)考慮到SMP與PREEMPT機制的影響。

int try_module_get(struct module *module):用于增加模塊使用計數;若返回為0,表示調用失敗,希望使用的模塊沒(méi)有被加載或正在被卸載中。

void module_put(struct module *module):減少模塊使用計數。

try_module_get 與module_put的引入與使用與2.6內核下的設備模型密切相關(guān)。模塊是用來(lái)管理硬件設備的,2.6 內核為不同類(lèi)型的設備定義了struct module *owner 域,用來(lái)指向管理此設備的模塊。如字符設備的定義:


                        struct cdev {                        struct kobject kobj;                        struct module *owner;                        struct file_operations *ops;                        struct list_head list;                        dev_t dev;                        unsigned int count;                        };                        

從設備使用的角度出發(fā),當需要打開(kāi)、開(kāi)始使用某個(gè)設備時(shí),使用try_module_get(dev->owner)去增加管理此設備的owner模塊的使用計數;當關(guān)閉、不再使用此設備時(shí),使用module_put(dev->owner)減少對管理此設備的owner模塊的使用計數。這樣,當設備在使用時(shí),管理此設備的模塊就不能被卸載;只有設備不再使用時(shí)模塊才能被卸載。

2.6內核下,對于為具體設備寫(xiě)驅動(dòng)的開(kāi)發(fā)人員而言,基本無(wú)需使用try_module_get與module_put,因為此時(shí)開(kāi)發(fā)人員所寫(xiě)的驅動(dòng)通常為支持某具體設備的owner模塊,對此設備owner模塊的計數管理由內核里更底層的代碼如總線(xiàn)驅動(dòng)或是此類(lèi)設備共用的核心模塊來(lái)實(shí)現,從而簡(jiǎn)化了設備驅動(dòng)開(kāi)發(fā)。





2.5 模塊輸出的內核符號

2.4 內核下,缺省情況時(shí)模塊中的非靜態(tài)全局變量及函數在模塊加載后會(huì )輸出到內核空間。

2.6 內核下,缺省情況時(shí)模塊中的非靜態(tài)全局變量及函數在模塊加載后不會(huì )輸出到內核空間,需要顯式調用宏EXPORT_SYMBOL才能輸出。所以在2.6 內核的模塊下,EXPORT_NO_SYMBOLS宏的調用沒(méi)有意義,是空操作。在同時(shí)支持2.4與2.6內核的設備驅動(dòng)中,可以通過(guò)以下代碼段來(lái)輸出模塊的內核符號


清單6: 同時(shí)支持2.4與2.6的輸出內核符號代碼段
                        #include <linux/module.h>                        #ifndef LINUX26                        EXPORT_NO_SYMBOLS;                        #endif                        EXPORT_SYMBOL(var);                        EXPORT_SYMBOL(func);                        

需要注意的是如需在2.4內核下使用 EXPORT_SYMBOL,必須在 CFLAGS中定義 EXPORT_SYMTAB,否則編譯將會(huì )失敗。

從良好的代碼風(fēng)格角度出發(fā),模塊中不需要輸出到內核空間且不需為模塊中其它文件所用的全局變量及函數最好顯式申明為static類(lèi)型,需要輸出的內核符號以模塊名為前綴。

模塊加載后,2.4內核下可通過(guò) /proc/ksyms、 2.6 內核下可通過(guò)/proc/kallsyms查看模塊輸出的內核符號





2.6 模塊的命令行輸入參數

在裝載內核模塊時(shí),用戶(hù)可以向模塊傳遞一些參數,如`modprobe modname var=value`,否則,var將使用模塊內定義的缺省值。

2.4內核下,linux/module.h中定義有宏MODULE_PARM(var,type) 用于向模塊傳遞命令行參數。var為接受參數值的變量名,type為采取如下格式的字符串[min[-max]]{b,h,i,l,s}。min及max用于表示當參數為數組類(lèi)型時(shí),允許輸入的數組元素的個(gè)數范圍;b:byte;h:short;i:int;l:long;s:string。

2.6內核下,宏MODULE_PARM(var,type)不再被支持。在頭文件linux/moduleparam.h里定義了如下宏:


                        module_param(name, type, perm)                        module_param_array(name, type, nump, perm)                        

type 類(lèi)型可以是byte、short,、ushort、 int、 uint、long、ulong、charp, bool or invbool, 不再采用2.4內核中的字符串形式,而且在模塊編譯時(shí)會(huì )將此處申明的type與變量定義的類(lèi)型進(jìn)行比較,判斷是否一致。

perm表示此參數在sysfs文件系統中所對應的文件節點(diǎn)的屬性。2.6內核使用sysfs文件系統,這是一個(gè)建立在內存中比proc更強大的文件系統。sysfs文件系統可以動(dòng)態(tài)、實(shí)時(shí),有組織層次地反應當前系統中的硬件、驅動(dòng)等狀態(tài)。當perm為0時(shí),表示此參數不存在sysfs文件系統下對應的文件節點(diǎn)。 模塊被加載后,在/sys/module/ 目錄下將出現以此模塊名命名的目錄。如果此模塊存在perm不為0的命令行參數,在此模塊的目錄下將出現parameters目錄,包含一系列以參數名命名的文件節點(diǎn),這些文件的權限值等于perm,文件的內容為參數的值。

nump 為保存輸入的數組元素個(gè)數的變量的指針。當不需保存實(shí)際輸入的數組元素個(gè)數時(shí),可以設為NULL。從2.6.0至2.6.10 版本,須將變量名賦給nump;從2.6.10 版本開(kāi)始,須將變量的引用賦給nump,這更易為開(kāi)發(fā)人員理解。加載模塊時(shí),使用逗號分隔輸入的數組元素。


清單7: 適用于2.4與2.6內核的模塊輸入參數模板
                        #include <linux/module.h>                        #ifdef LINUX26                        #include <linux/moduleparam.h>                        #endif                        int debug = 0;                        char *mode = "800x600";                        int tuner[4] = {1, 1, 1, 1};                        #ifdef LINUX26                        int tuner_c = 1;                        #endif                        #ifdef LINUX26                        MODULE_PARM(debug, "i");                        MODULE_PARM(mode, "s");                        MODULE_PARM(tuner,"1-4i");                        #else                        module_param(debug, int, 0644);                        module_param(mode, charp, 0644);                        #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)                        module_param_array(tuner, int, &tuner_c, 0644);                        #else                        module_param_array(tuner, int, tuner_c, 0644);                        #endif                        #endif                        

模塊編譯生成后,加載模塊時(shí)可以輸入:`modprobe my_module mode=1024x768 debug=1 tuner=22,33`。

在linux/moduleparam.h還定義有:


                        module_param_array_named(name, array, type, nump, perm)                        module_param_call(name, set, get, arg, perm)                        module_param_named(name, value, type, perm)                        

讀者可以參閱linux/moduleparam.h查看這些宏的詳細描述,有一點(diǎn)需注意,在2.6內核里,module_param這一系列宏使用的都是小寫(xiě)名字。

2.7 模塊的許可證聲明

從2.4.10版本內核開(kāi)始,模塊必須通過(guò)MODULE_LICENSE宏聲明此模塊的許可證,否則在加載此模塊時(shí),會(huì )收到內核被污染"kernel tainted" 的警告。從linux/module.h文件中可以看到,被內核接受的有意義的許可證有 "GPL","GPL v2","GPL and additional rights","Dual BSD/GPL","Dual MPL/GPL","Proprietary"。

在同時(shí)支持2.4與2.6內核的設備驅動(dòng)中,模塊可按如下方式聲明自己的許可證。


清單8: 適用于2.4與2.6內核的模塊許可證聲明模板
                        #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10)                        MODULE_LICENSE("GPL");                        #endif                        

2.8 小結

此外,2.6內核里還有一些模塊機制的改變,不常為驅動(dòng)開(kāi)發(fā)人員用到。如加載內核模塊的接口request_module在2.4 下為request_module(const char * module_name);在2.6內核下為request_module(const char *fmt, ...)。在2.6 內核下,驅動(dòng)開(kāi)發(fā)人員可以通過(guò)調用


                        request_module("msp3400");                        request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev));                        

這種更靈活的方式加載其它內核模塊。

2.6內核在linux/module.h中還提供了MODULE_ALIAS(alias)宏,模塊可以通過(guò)調用此宏為自己定義一或若干個(gè)別稱(chēng)。而在2.4內核下,用戶(hù)只能在/etc/modules.conf中為模塊定義別稱(chēng)。

通過(guò)以上比較可以看到,從2.4到2.6內核,可裝載模塊管理機制的改變使設備驅動(dòng)的開(kāi)發(fā)變得更加簡(jiǎn)潔、靈活、健壯。





參考資料





關(guān)于作者

作者:周婷,軟件工程師,S3 Graphics 上海研發(fā)中心,工作方向: 視頻解碼。email: moting9@hotmail.com。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
linux內核驅動(dòng)模塊的編譯及加載
Linux內核模塊的編譯基礎知識
開(kāi)發(fā)一個(gè)簡(jiǎn)單的內核程序
linux驅動(dòng)入門(mén)(轉)
linux
教你寫(xiě)第一個(gè)Linux設備驅動(dòng)程序
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久