Linux內核模塊簡介

一. 摘要linux

這篇文章主要介紹了Linux內核模塊的相關概念,以及簡單的模塊開發過程。主要從模塊開發中的經常使用指令、內核模塊程序的結構、模塊使用計數以及模 塊的編譯等角度對內核模塊進行介紹。在Linux系統開發過程當中,以模塊的形式開發其重要性不言自明,而在嵌入式設備驅動開發中將驅動程序以模塊的形式發 布,更是極大地提升了設備使用的靈活性——用戶只須要拿到相關驅動模塊,再插入到用戶的內核中,便可靈活地使用你的設備。shell

二. 文章提綱編程

1. 摘要函數

2. 文章提綱工具

3. 概述編碼

4. 模塊開發經常使用的指令spa

5. 內核模塊程序結構指針

6. 模塊使用計數日誌

7. 模塊的編譯code

8. 使用模塊繞開GPL

9. 總結

三.概述

Linux內核總體結構已經很龐大,包含了不少的組件,而對於咱們工程師而言,有兩種方法將須要的功能包含進內核當中。

         一:將全部的功能都編譯進Linux內核。

         二:將須要的功能編譯成模塊,在須要的時候動態地添加。

上述兩種方式優缺點分析:

         第一種:

                   優勢:不會有版本不兼容的問題,不須要進行嚴格的版本檢查

                   缺點:生成的內核會很大;要在現有的內核中添加新的功能,則要編譯整個內核

         第二種:

優勢:模塊自己不編譯進內核,從而控制了內核的大小;模塊一旦被加載,將和其它的部分徹底同樣。

缺點:可能會有內核與模塊版本不兼容的問題,致使內核崩潰;會形成內存的利用率比較低。

 

四.模塊開發經常使用的指令

在內核模塊開發的過程當中經常使用的有如下指令。

1)  insmod: 將模塊插入內核中,使用方法:#insmod XXX.ko

2)  rmmod: 將模塊從內核中刪除,使用方法:#rmmod XXX.ko

3)  lsmod: 列表顯示全部的內核模塊,能夠和grep指令結合使用。使用方法:#lsmod | grep XXX

4)  modprobe: modprobe可載入指定的個別模塊,或是載入一組相依賴的模塊。modprobe會根據depmod所產生的依賴關係,決定要載入哪些模塊。若在載入 過程當中發生錯誤,在modprobe會卸載整組的模塊。依賴關係是經過讀取 /lib/modules/2.6.xx/modules.dep獲得的。而該文件是經過depmod 所創建。

5)  modinfo: 查看模塊信息。使用方法:#modinfo XXX.ko

6)  tree –a: 查看當前目錄的整個樹結構。使用方法:#tree -a

 

五.內核模塊程序結構

1)  模塊加載函數(通常須要)

在用insmod或modprobe命令加載模塊時,該函數被執行。完成模塊的初始化工做。

Linux內核的模塊加載函數通常用__init標識聲明,模塊加載函數必須以module_init(函數名)的形式被指定。該函數返回整型值, 若是執行成功,則返回0,初始化失敗時則返回錯誤編碼,Linux內核當中的錯誤編碼是負值,在<linux/errno.h>中定義。

在Linux中,標識__init的函數在鏈接時放在.init.text這個區段,並且在.initcall.init中保留一份函數指針,初始化的時候內核會根據這些指針調用初始化函數,初始化結束後釋放這些init區段(包括前二者)。

代碼清單:

複製代碼

 1 static int __init XXX_init(void) 2  3 { 4  5          return 0; 6 } 7  8   9 10 moudle_init(XXX_init);

複製代碼

 

2)  模塊卸載函數(通常須要)

在用rmmod或modprobe命令卸載模塊時,該函數被執行。完成與加載相反的工做。

模塊的卸載函數和模塊加載函數實現相反的功能,主要包括

  1. 若模塊加載函數註冊了XXX,則模塊卸載函數註銷XXX

  2. 若模塊加載函數動態分配了內存,則模塊卸載函數釋放這些內存

  3. 若模塊加載函數申請了硬件資源,則模塊卸載函數釋放這些硬件資源

  4. 若模塊加載函數開啓了硬件資源,則模塊卸載函數必定要關閉這些資源

代碼清單:

複製代碼

1 static void __exit XXX_exit(void)2 3 {4 5 }6 7  8 9 moudle_exit(XXX_exit);

複製代碼

 

3)  模塊許可證聲明(必須)

若是不聲明,則在模塊加載時會收到內核被污染的警告,通常應遵循GPL協議。

代碼清單:

1 MODULE_LICENSE("GPL");

 

4)  模塊參數(可選)

模塊在被加載時傳遞給模塊的值,自己應該是模塊內部的全局變量。

示例程序book.c

複製代碼

 1 #include <linux/init.h> 2  3 #include <linux/module.h> 4  5   6  7 static char *bookName = "Good Book."; 8  9 static int bookNumber = 100;10 11  12 13 static int __init book_init(void)14 15 {16 17          printk(KERN_INFO "Book name is %s\n", bookName);18 19          printk(KERN_INFO "Book number is %d\n", bookNumber);20 21          return 0;22 23 }24 25  26 27 static void __exit book_exit(void)28 29 {30 31          printk(KERN_INFO "Book module exit.\n");32 33 }34 35  36 37 module_init(book_init);38 39 module_exit(book_exit);40 41 module_param(bookName, charp, S_IRUGO);42 43 module_param(bookNumber, int, S_IRUGO);44 45  46 47 MODULE_LICENSE("GPL");

複製代碼

 

在向內核插入模塊的時候能夠用如下方式,而且能夠在內核日誌中看到模塊加載之後變量已經有了值。

 

 

5)  模塊導出符號(可選)

使用模塊導出符號,方便其它模塊依賴於該模塊,並使用模塊中的變量和函數等。

在Linux2.6的內核中,/proc/kallsyms文件對應着符號表,它記錄了符號和符號對應的內存地址。對於模塊而言,使用下面的宏能夠導出符號。

1 EXPORT_SYMBOL(符號名);

1 EXPORT_GPL_SYMBOL(符號名);

 

6)  模塊信息(可選)

模塊信息則是指模塊的做者信息等。

 

六.模塊使用計數

Linux內核提供了MOD_INC_USE_COUNT和MOD_DEC_USE_COUNT宏來管理模塊使用計數。可是對於內核模塊而言,通常不會本身管理使用計數。

 

七.模塊的編譯

將下面的Makefile文件放在book.c同級的目錄下,而後使用#make命令或者#make all命令編譯便可生成book.ko模塊文件。

對應的Makefile:

複製代碼

 1 ifneq ($(KERNELRELEASE),) 2  3 mymodule_objs := book.o 4  5 obj-m := book.o 6  7 else 8  9 PWD := $(shell pwd)10 11 KVER ?= $(shell uname -r)12 13 KDIR := /usr/src/linux-headers-2.6.38-8-generic14 15  16 17 all:18 19          $(MAKE) -C $(KDIR) M=$(PWD)20 21 clean:22 23          rm -rf *.mod.c *.mod.o *.ko *.o *.tmp_versions *.order *symvers24 25 endif

複製代碼

 

八.使用模塊繞開

若是功能不編譯成模塊,則沒法繞開GPL,編譯成模塊後公司發佈產品則只須要發佈模塊,而不須要發佈源碼。爲了Linux系統可以支持模塊,須要作如下的工做:

  1. 內核編譯時選擇「能夠加載模塊」,嵌入式產品通常都不須要卸載模塊,則能夠不選擇「可卸載模塊」

  2. 將咱們的ko文件放在文件系統中

  3. Linux系統實現了insmod、rmmod等工具

  4. 使用時能夠用insmod手動加載模塊,也能夠修改/etc/init.d/rcS文件,從而在系統啓動的時候就加載模塊。

 

九.總結

本文主要介紹內核模塊的概念和基本編程方法,內核模塊主要由加載、卸載函數功能函數等一系列聲明組成。它能夠被傳入參數,也能夠導出符號,供其它的模塊使用。

相關文章
相關標籤/搜索