儘管單塊核心比微核心快,但它的缺點是缺乏模組化和可擴充套件性。在現代的單片核心上,這已經通過使用核心模組解決了。核心模組(或可載入核心模式)是乙個目標檔案,其中包含可以在執行時擴充套件核心功能的**(根據需要載入);當不再需要核心模組時,可以解除安裝它。大多數裝置驅動程式以核心模組的形式使用。
這是乙個簡單的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中字尾名的使用規則是這樣的:這些字尾可以通過執行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。1.m是可載入的kernel module檔案
2.y表示要編譯的物件檔案的目標,然後鏈結到模組($(mode_name)-y)或核心(obj-y)中
任何其它的字尾名會直接被kbuild忽視不會編譯
要載入核心模組,請使用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 注入的類,但是使用這種方式...