因為linux
核心的整體結構非常龐大,包含的元件非常多,如何使用需要的元件呢?有一種方法是把所有的元件都編譯進核心檔案(
zimage
或bzimage
),但是這樣會產生兩個問題:一是生成的核心檔案過大;二是如果要新增或刪除某乙個元件,需要重新刪除編譯整個核心。於是我們需找另外一種機制讓核心檔案本身不包含某元件,而是在該元件需要的時候,動態地新增到正在執行的核心中,這在linux
中就叫做「核心模組」的機制。由此可看到,核心模組有2個特點:①模組本身並不編譯進核心;②可以根據需求,在核心執行期間動態地安裝與解除安裝。
核心模組與應用程式又有什麼區別呢?一、大多數應用程式是從頭到尾執行單個任務,而模組卻只是預先註冊自己以便服務於將來的某個請求,然後它的初始化函式就立即結束。換句話說,模組初始化函式的任務就是為以後呼叫模組函式預先做準備;二、應用程式在退出時,可以不用管資源的釋放或者其他的清除工作,但模組的退出函式卻必須仔細撤銷初始化函式所做的一切,否則,在系統重新引導之前某些東西就會殘留在系統中;三、應用程式可以呼叫它並未定義的函式,這是因為連線過程能夠解析外部引用從而使用適當的函式庫,然而,模組僅僅被鏈結到核心,因此它能呼叫的函式僅僅是由核心匯出的那些函式,而不存在任何可鏈結的函式庫。四、應用程式一般執行在使用者空間,而核心模組執行在核心空間,在unix中使用了處理器的最高端別和最低級別,當處理器處於最高端別時稱其執行在核心空間,反之則稱其執行在使用者空間,並且每個模式都有自己的記憶體對映,也即自己的位址空間,一般使用者空間為0~3g,核心空間為3~4g。
下面就介紹下如何為自己的模組建立makefile,首先先來看下乙個例子
ifneq ($(kernelrelease),)
obj-m := hello_world.o
else
kdir := /friendlyarm/linux-2.6.38
mod := ./hello_world.ko
all:
make -c $(kdir) m=$(pwd) modules arch=arm cross_compile=arm-linux-
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers *.order
endif
在乙個典型的構造過程中,makefile將被讀取兩次。在第一次呼叫的時候,因為kernelrelease尚未設定,所以只是定位了核心樹的目錄,並且返回當前目錄;在第二次呼叫的時候,設定了要構建的模組(obj-m),並且利用核心樹的makefile來構建模組。
在上面的makefile中,obj-m為hello_world.o,其對應的c檔案為hello_world.c,現在就來看下該檔案的內容
#include #include #include static char *name = "abcd";
static int __init hello_module_init(void)
static void __exit hello_module_cleanup(void)
module_init(mini6410_hello_module_init);
module_exit(mini6410_hello_module_cleanup);
module_param(name,charp,s_irugo);
module_license("gpl");
我們先來看下該模組的初始化函式和解除安裝函式
初始化函式為hello_module_init,負責註冊模組所提供的任何設施,它被宣告為static,因為這種函式在特定檔案之外沒有其他意義,且乙個模組函式如果要對核心其他部分可見,則必須被顯式匯出。另外, 還被標記為__init,它對核心來講是一種暗示,表明該函式僅在初始化期間使用。在模組被裝載之後,模組裝載器就會將初始化函式扔掉,這樣可將該函式占用的記憶體釋放出來,類似的還有__initdata。再來看下module_init,它的使用是強制性的,其會在模組的目標**中增加乙個特殊的段,用於說明核心初始化函式所在的位置,如果沒有這個定義,則初始化函式永遠不會被呼叫。
解除安裝函式為hello_module_cleanup,其作用是在模組被移除錢登出介面並向系統中返回所有資源。__exit修飾詞標記該**僅用於模組解除安裝。如果模組被直接內嵌到核心中,或者核心的配置不允許解除安裝模組,則被標記為__exit的函式將被簡單地丟棄。module_exit的作用與module_init類似,也是模組必不可少的。
接下來再看module_param巨集,該巨集宣告了模組引數。核心允許對驅動程式指定引數,而這些引數可在裝載驅動程式模組時改變。引數的值可在執行insmod或modprobe命令裝載模組時賦值。引數的型別一般有一下幾種:bool、invbool、charp、int、long、short、uint、ulong、ushort。module_param巨集的第乙個成員是引數的名字,第二個成員是引數的型別,第三個成員是訪問許可值,如果引數使用了s_irugo,則任何人均可讀取該引數,但不能修改。在hello_world的例子中,如果要給引數賦值,具體方法如下:insmod hello_world.ko name=******
module_license("gpl")指定了模組的許可證為gpl,可在模組中包含的其他描述性定義包括module_author、modulr_description、module_version、module_alias以及module_device_table等等。
Linux核心驅動模組學習
ko檔案在是elf excutable and link format 格式,是一種可重定位的目標檔案。在編譯驅動模組時,我們在makefile中用obj m o來指定生成核心驅動模組檔案,即.ko檔案。首先insmod會通過檔案系統將ko讀到使用者空間的一塊記憶體中,然後執行系統呼叫sys ini...
Linux核心 驅動學習筆記 二
linux是如何管理記憶體的?今天系統的整理一下這個問題。在系統的初始化階段,核心根據檢測到的物理記憶體的大小,為每乙個頁面都建立乙個page結構,形成乙個page結構的陣列,並使乙個全域性量mem map指向這個陣列。同時又按需要將這些頁面拼合成許多記憶體頁面塊,再把塊組成管理區zone,分配和釋...
Linux核心模組(二)
ko kernel object so shared object root rhel6 ls lib modules uname r kernel arch x86 kvm kvm amd.ko kvm intel.ko kvm.ko 通過移除核心模組可達到禁用該模組的作用 root rhel6 ...