高效學習Linux核心——核心模組編譯

ningmengzier發表於2020-12-14

文主要 講解什麼是Linux核心,以 及透過多張圖片展示Linux核心的作用、功能及基本程式設計方法,以便於讀者能快速理解什麼是Linux核心,能看懂Linux核心。

擁有超過1300萬行的程式碼,Linux核心是世界上最大的開源專案之一,但是核心是什麼,它用於什麼?

什麼是linux核心模組?

核心是與計算機硬體介面的易替換軟體的最低階別。它負責將所有以 “使用者模式”執行的應用程式連線到物理硬體,並允許稱為伺服器的程式使用程式間通訊 (IPC) 彼此獲取資訊。

 Linux核心與硬體的關係 
核心可以透過所謂的中斷來管理系統的硬體。 當硬體要與系統介面時,會發出一箇中斷,中斷處理器,從而對核心執行相同的操作。 為了提供同步,核心可以禁用中斷,無論是單箇中斷還是全部中斷。 
但是,在Linux中,中斷處理程式不是在程式上下文中執行,而是在不與任何程式相關聯的中斷上下文中執行,這種特殊的中斷上下文僅是為了讓中斷處理程式快速響應單箇中斷然後最終退出而存在 。
linux核心整體非常龐大,包含元件特別多,當我們把需要的部分包含到核心中,直接把需要的所有功能都編譯到核心中會導致核心很大,而且當需要新增或者刪除功能,又要重新編譯,非常麻煩,因此linux提供了模組(Modele)的機制。

可以把核心比喻成一個很長的火車,每個車廂就是一個核心模組,核心在執行這個火車就會一直在開動,但是我們想在火車開動的情況下增加新的車廂,這個時候就需要 insmod ,意思就是往這個長長的火車車廂增加一個核心模組。

模組的特點:不編譯入核心映象;一旦載入和核心其他部分完全一樣。

為了使讀者對模組有個感性認知,先看一下簡單的HelloWorld模組,程式碼如下:

Linux核心模組組成結構

一個Linux核心模組主要由以下幾個部分組成。

1)模組載入函式(必須)
當透過 insmod 或 modprobe命令載入核心模組時,模組的載入函式會自動被核心執行,完成本模組的相關初始化工作。模組載入函式一般以__init標識宣告
static int __init FuntionA(void)
{
}
module_init( FuntionA);

2)模組解除安裝函式(必須)

當透過 rmmod 命令解除安裝某模組時,模組的解除安裝函式會自動被核心執行,完成與模組載入函式相反的功能。模組解除安裝函式一般以__exit標識宣告:
static void __exit  FuntionB(void)
{
}
module_exit( FuntionB );
通常來說,模組解除安裝函式要完成與模組載入函式相反的功能,如下所示。
a)若模組載入函式註冊了XXX,則模組解除安裝函式應該登出XXX。
b)若模組載入函式動態申請了記憶體,則模組解除安裝函式應釋放該記憶體。
c)若模組載入函式申請了硬體資源(中斷,DMA通道,I/O埠和I/O記憶體等)的佔用,則模組解除安裝函式應釋   放這些硬體資源。
d)若模組載入函式開啟了硬體,則解除安裝函式中一般要關閉硬體。

3)模組許可證宣告(必須)

模組許可證(LICENSE)宣告描述核心模組的許可許可權,如果不宣告 LICENSE,模組被載入時,將收到核心被汙染的警告。大多數情況下,核心模組應遵循GPL 相容許可權。
Linux2.6 核心模組最常見的是以MODULE_LICENSE(“Dual BSD/GPL”)語句宣告模組採用BSD/GPL 雙LICENSE

4)模組引數(可選)
是模組被載入的時候可以被傳遞給它的值,它本身對應模組內部的全域性變數。
用“module_param(引數名,引數型別,引數讀/寫許可權)”為模組定義一個引數
例如:module_param(num,int,S_IRUGO);

5)模組匯出符號(可選)
可以匯出符號(symbol,對應於函式或變數),這樣其它模組可以使用本模組中的變數或函式。
可以使用如下宏匯出符號到核心符號表:
EXPORT_SYMBOL(符號名);

EXPORT_SYMBOL_GPL(符號名);

6)模組作者等資訊宣告(可選)
我們可以使用MODULE_AUTHOR,MODULE_DESCRIPTION,MODULE_VERSION,MODULE_DEVICE_TABLE,MODULE_ALLAS
分別宣告模組的作者,描述,版本,裝置表和別名
例如:
MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);

Linux核心模組的編譯

首先為HelloWorld模組編寫MakeFile檔案


該MakeFile檔案應該與原始碼位於同一目錄

在Makefile中,在obj-m := helloworld.o這句中,.o的檔名要與編譯的.c檔名一致。 
如果一個模組包含多個.c檔案(如file1.c、file2.c)則應該使用如下方式編寫MakeFile:
Obj -m :=modulename.o
Modulename -obj :-file1.o file2.o
KERNELDIR ?= /usr/src/linux-headers-$(shell uname -r)指示當前linux系統核心的原始碼位置。 
1.在Makefile及helloworld.c所在目錄下,直接make,成功後檢視當前目錄下有無helloworld.ko文 件產生,有則核心模組生成成功。
2.使用insmod命令,把此核心模組程式載入到核心中執行。結合lsmod及管道命令,檢視核心模組程式在核心中是否正確執行。

結論

本文主要講解了linux核心模組的概念和基本程式設計方法、核心模組組成結構,由於linux裝置驅動以核心模組的形式存在,因此瞭解本文內容是編寫任何裝置驅動的必需。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69989353/viewspace-2741926/,如需轉載,請註明出處,否則將追究法律責任。

相關文章