一、核心子產品的概念
1、什麼是子產品?
核心子產品是一些可以讓作業系統核心在需要時載入和執行的代碼,同時在不需要的時候可以解除安裝。這是一個好的功能,擴充了作業系統的核心功能,卻不需要重新啟動系統,是一種動态加載的技術。
特點:動态加載,随時載入,随時解除安裝,擴充功能
2、核心子產品的加載作用
核心子產品隻是向linux核心預先注冊自己,以便于将來的請求使用;由目标代碼組成,沒有形成完整的可執行程式。隻是告訴核心,它有了新增的功能,而并不馬上使用(執行),隻是等待應用程式的調用;而應用程式在加載後就開始執行。
3、核心子產品所用函數
核心子產品代碼編寫沒有外部的函數庫可以用,隻能使用核心導出的函數。而應用程式習慣于使用外部的庫函數,在編譯時将程式與庫函數連結在一起。例如對比printf( ) and printk( )。
是以驅動所用頭檔案均來自核心源代碼,應用程式所用頭檔案來自庫函數。
4、核心子產品代碼運作空間
核心代碼運作在核心空間,而應用程式在使用者空間。應用程式的運作會形成新的程序,而核心子產品一般不會。每當應用程式執行系統調用時,linux執行模式從使用者空間切換到核心空間。
二、linux核心子產品的架構
最少兩個入口點
*子產品加載函數 module_init()
*子產品解除安裝函數 module_exit()
module_init() and module_exit()兩個宏定義聲明子產品的加載函數和解除安裝函數,這個定義在linux3.14/include/linux/init.h中。内容為:
#define module_init(x) __initcall(x)
//在核心啟動或子產品加載時執行
#define module_exit(x) __exitcall(x)
//在子產品解除安裝時執行
每一個子產品隻能有一個module_init 和一個module_exit。
下面我們對比一下應用程式,看看應用程式與核心子產品的差別:
#include <stdio.h> int main() { printf("Hello World!\n"); return 0; } | #include <linux/module.h> //所有核心子產品都必須包含這個頭檔案 #include<linux/kernel.h> //使用核心資訊優先級時要包含這個 #include<linux/init.h> //一些初始化的函數如module_init() static int hello_init(void) { printk("hello_init"); } static void hello_exit(void) { printk("hello_exit \n"); } MODULE_LICENSE("GPL"); //子產品許可聲明 module_init(hello_init); 加載時候調用該函數insmod module_exit(hello_exit);解除安裝時候 rmmod |
應用程式和核心子產品對比總結如下
應用程式 | 子產品 | |
入口函數 | main | 加載時候調用hello_init |
函數的調用 | /lib | 所有函數可以直接調用 |
運作空間 | 使用者空間 | 核心空間 |
資源的釋放 | 系統自動釋放 kill -9 pid 手動釋放 | 手動釋放 |
三、Linux 核心子產品的編譯和加載 其實核心的編譯在前面就已經講過了,現在回顧一下: linux3.14核心的Makefile分為5個組成部分: Makefile 最頂層的Makefile .config 核心的目前配置檔案,編譯時成為定層Makefile的一部分 arch/$(ARCH)/Makefile 與體系結構相關的Makefile
s/ Makefile.* 一些Makefile的通用規則
kbuild Makefile 各級目錄下的大概約500個檔案,編譯時根據上層Makefile傳下來的宏定義和其他編譯規則,将源代碼編譯成子產品或者編入核心
頂層的Makefile檔案讀取 .config檔案的内容,并總體上負責build核心和子產品。Arch Makefile則提供補充體系結構相關的資訊。 s目錄下的Makefile檔案包含了所有用來根據kbuild Makefile 建構核心所需的定義和規則。(其中.config的内容是在make menuconfig的時候,通過Kconfig檔案配置的結果,上面已經說過) 對于大部分核心子產品或裝置驅動的開發者和使用者來說,最常接觸到的就是各層目錄下 基于kbuild架構的kbuild Makefile檔案。主要部分有:
1、目标定義 目标定義就是用來定義哪些内容要做為子產品編譯,哪些要編譯連結進核心。 最簡單的隻有一行,如 obj-y += foo.o
表示要由foo.c或者foo.s檔案編譯得到foo.o并連結進核心,而obj-m則表示該檔案要作為子產品編譯。除了y,m以外的obj-x形式的目标都不會被編譯。
由于既可以編譯成子產品,也可以編譯進核心,更常見的做法是根據.config檔案的CONFIG_ 變量來決定檔案的編譯方式,如:
obj-$(CONFIG_HELLO_MODULE) += hello.o
除了obj-形式的目标以外,還有lib-y library庫,hostprogs-y 主機程式等目标,但是基本都應用在特定的目錄和場合下
2、多目标
一個核心子產品由多個源檔案編譯而成,這是Makefile有所不同。
采用子產品名加 –objs字尾或者 –y字尾的形式來定義子產品的組成檔案。
如以下例子: obj-$(CONFIG_EXT2_FS) += ext2.o
ext2-y := balloc.o bitmap.o
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o 模 塊的名字為ext2,由balloc.o和bitmap.o兩個目标檔案最終連結生成ext2.o 直至ext2.ko檔案,是否包括xattr.o取決于核心配置檔案的配置情況。如果CONFIG_EXT2_FS的值是y也沒有關系,在此過程中生成的 ext2.o将被連結進built-in.o最終連結進核心。這裡需要注意的一點是,該kbuild Makefile所在的目錄中不應該再包含和子產品名相同的源檔案如ext2.c/ext2.s 或者寫成如-objs的形式: obj-$(CONFIG_ISDN) += isdn.o isdn-objs := isdn_net_lib.o isdn_v110.o isdn_common.o
3、目錄的疊代
obj-$(CONFIG_EXT2_FS) += ext2/ 如果CONFIG_EXT2_FS 的值為y或m,kbuild将會将ext2目錄列入向下疊代的目标中,但是其作用也僅限于此,具體ext2目錄下的檔案是要作為子產品編譯還是鍊入核心,還是有ext2目錄下的Makefile檔案的内容來決定的
4、不同的子產品編譯方式
編譯子產品的時候,你可以将子產品放在代碼樹中,用Make modules的方式來編譯你的子產品,你也可以将子產品相關檔案目錄放在代碼樹以外的位置,用如下指令來編譯子產品:
make -C path/to/kernel/src M=$PWD modules -C指定核心源碼的根目錄,$PWD 或 `PWD` 是目前目錄的環境變量,告訴kbuild回到目前目錄來執行build操作。
5、子產品安裝
當你需要将子產品安裝到非預設位置的時候,你可以用INSTALL_MOD_PATH 指定一個字首,如: make INSTALL_MOD_PATH=/foo modules_install
子產品将被安裝到 /foo/lib/modules目錄下
注:核心子產品是.ko字尾,使核心子產品和普通的目标檔案差別開。