學習編寫核心程式(一)kernel modules

2021-10-01 03:33:03 字數 3172 閱讀 3390

儘管單塊核心比微核心快,但它的缺點是缺乏模組化和可擴充套件性。在現代的單片核心上,這已經通過使用核心模組解決了。核心模組(或可載入核心模式)是乙個目標檔案,其中包含可以在執行時擴充套件核心功能的**(根據需要載入);當不再需要核心模組時,可以解除安裝它。大多數裝置驅動程式以核心模組的形式使用。

這是乙個簡單的kernel module例子,載入核心時發出「hello」,再解除安裝的時候發出「bye」。

#include

#include

#include

module_description

("my kernel module");

moudle_author

("me");

module_licende

("gpl");

static

intk_init

(void

)static

void

k_exit

(void

)module_init

(k_init)

;module_exit

(k_exit)

;

產生的訊息不會再控制台出現需要通過日誌守護程序(syslog)。

# cat /var/log/syslog | tail -2

feb 20 13:57:38 asgard kernel: hi

feb 20 13:57:43 asgard kernel: bye

# dmesg | tail -2

hibye

編譯kernel module和使用者程式編譯不一樣。module必須有和載入時一樣的核心選項(option),等等很多。所以就引入了makefile和kbuild這兩個檔案。這裡就不解釋怎樣寫makefile,過一段時間我會有另一篇文章寫。

首先,我們看makefile:

kdir =

/lib/modules/

'uname -r'

/build

kbuild:

make -c $(kdir) m =

'pwd'

clean:

make -c $(kdir) m =

'pwd' clean

kbuild:

extra_cflags =

-wall -g

obj-m = supermodule.o

supermodule-y = module-a.o module-b.o

在例子中對makefile檔案呼叫make將導致核心源目錄(/lib/modules/ 』 uname -r 』 /build)中的make呼叫,並引用當前目錄(m = 』 pwd ')。

乙個kbuild檔案會包含編譯乙個或多個檔案的指令。最簡單的例子是編譯乙個檔案的。上面的例子是需要編譯多個檔案的例子。首先需要編譯module-a.c和module-b.o得到module-a.o和module-b.o檔案。module-a.o和module-b.o會被鏈結進supermodule.o。最後用supermodule.o來建立supermodule.ko。

對於再kbuild中字尾名的使用規則是這樣的:

1.m是可載入的kernel module檔案

2.y表示要編譯的物件檔案的目標,然後鏈結到模組($(mode_name)-y)或核心(obj-y)中

任何其它的字尾名會直接被kbuild忽視不會編譯

這些字尾可以通過執行make menuconfig命令或直接編輯.config檔案來配置核心。該檔案設定了一系列變數,用於確定在構建時向核心新增哪些特性。例如,當使用make menuconfig新增btrfs時,將config_btrfs_fs = y新增到.config檔案中。kbuild包含一行obj-$(config_btrfs_fs):= btrfs.o,即obj-y:= btrfs.o。這將編譯btrfs.o,並將其鏈結到核心。在沒這樣變數設定之前還只是odj:=btrfs.o,這樣就會被忽略不會有btrfs。

要載入核心模組,請使用insmod實用程式。該實用程式將*的路徑作為引數接收。編譯和鏈結模組的ko檔案。使用rmmod命令從核心解除安裝模組,該命令接收模組名作為引數。

$ insmod module.ko

$ rmmod module.ko

載入核心模組時,將執行作為module_init巨集引數指定的例程。類似地,在解除安裝模組時,將執行作為module_exit引數指定的例程。

排除核心模組的故障要比除錯常規程式複雜得多。首先,核心模組中的乙個錯誤可能導致阻塞整個系統。因此,可以大大降低故障排除的速度。為了避免重新啟動,建議使用虛擬機器(qemu、virtualbox、vmware)。當乙個包含bug的模組被插入核心時,它將最終生成乙個核心oops。核心oops是核心檢測到的無效操作,只能由核心生成。對於乙個穩定的核心版本,這一定是在該模組包含乙個bug。在oops出現之後,核心將繼續工作。

儲存生成的oops訊息非常重要。核心生成的訊息儲存在日誌中,可以使用dmesg命令顯示。為了確保沒有丟失核心訊息,建議直接從控制台插入/測試核心,或者定期檢查核心訊息。值得注意的是,oops可能因為程式設計錯誤而發生,也可能因為硬體錯誤而發生。

以下有個例子:

/*

* oops generating kernel module

*/#include

#include

#include

module_description (

"oops");

module_license (

"gpl");

module_author (

"pso");

#define op_read 0

#define op_write 1

#define op_oops op_write

static

int my_oops_init (

void

)static

void my_oops_exit (

void

)module_init (my_oops_init)

;module_exit (my_oops_exit)

;

這樣就會產生oops

kernel中通過機器碼編寫匯程式設計序

在c源中除了通過asm來嵌入式彙編,例如asm fsinx 1,0 f result f angle 也可以通過下面的方式來寫,例如 stp x0,x1,sp,16 insn aarch64 insn gen load store pair aarch64 insn reg 0,aarch64 in...

編寫乙個程式 8

計算器程式 對於計算的優先順序問題,如何從輸入讀取包括數字和操作符在內的表示式的方法,並以一種合理的方式進行儲存?分詞 tokenize 讀取輸入字元並組合成單詞 token 單詞可以看做乙個單元的乙個字串行,例如數字或者運算子。利用 kind,value 的形式來表示單詞,其中kind表示單詞是乙...

Spring 學習筆記1 編寫安裝程式

在程式設計ssh專案時,可能要寫乙個installer類來初始化資料庫,一般的編寫方式如下 component public class installer transactional public void install 這種方式的優點是可以直接使用 resource 注入的類,但是使用這種方式...