2021 LDD3 第2章 === contribute by `Liao712148` ###### tags: `Linux Device Drivers`, `Linux ` ### 遇到的問題 **ERROR: could not insert module hello.ko: Operation not permitted** 解決辦法: 根據 [insmod: ERROR: could not insert module HelloWorld.ko: Operation not permitted](https://stackoverflow.com/questions/58546126/insmod-error-could-not-insert-module-helloworld-ko-operation-not-permitted) 會使用到 [Why do I get “Required key not available” when install 3rd party kernel modules or after a kernel upgrade?](https://askubuntu.com/questions/762254/why-do-i-get-required-key-not-available-when-install-3rd-party-kernel-modules) 根據 >sudo apt install mokutil sudo mokutil --disable-validation 之後reboot --- Makefile 是一種腳本,用來生成模組, ## Makefile ```cpp= # To build modules outside of the kernel tree, we run "make" # in the kernel source tree; the Makefile these then includes this # Makefile once again. # This conditional selects whether we are being included from the # kernel Makefile or not. ifneq ($(KERNELRELEASE),) # call from kernel build system obj-m := hello.o else KERNELDIR ?= /lib/modules/$(shell uname -r)/build PWD := $(shell pwd) modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif clean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.mod modules.order *.symvers *.dwo *.mod.dwo ``` * 第8行:我們寫的Makefile第一次被執行,此時KERNELRELEASE還沒被定義,因此條件不成立。執行else的內容。 * 第15行:因為`?=`表示如果左邊的變數上未定義,就將右邊賦值給左邊。否則維持原來的值。而`/lib/modules/$(shell uname -r)/build`是核心原碼樹的頂層目錄。![](https://i.imgur.com/8j6CmNn.png),會有一個Makefile幫助我們完成模組。 * 第16行:PWD變數紀錄當的Makefile所在的位子。 * 第18,19行:一開始會切換目錄到`-C`選項所指的目錄(核心原碼樹的頂層目錄),在該處找出核心原碼樹頂層目錄的Makefile。而`M=`選項會使得該Makefile回到模組的原始程式目錄,然後才開始建構第18行所定義的`modules`目標,此目標代表`obj-m`變數所列的模組,也就是`hello.o`。執行第19行時,會造成我們所寫的Makefile又再被執行了一次,此次條件成立,因此會執行第11行。 * 第11行:它宣稱有一個模組要從目的碼`hello.o`建構出來,所產生的模組檔是`hello.ko`。與傳統的Makefile不同,使用了GNU make的擴充語法,樣讓這個Makefile有作用,必須從核心建構系統來調用它 ==> ==利用核心的Makefile來產生模組==。 * 第25行:清除檔案。 ```cpp= #include <linux/init.h>//定義了模組所需的許多函式與變數 #include <linux/module.h>//模組的初始函式與清理函式 MODULE_LICENSE("Dual BSD/GPL"); static int hello_init(void) { printk(KERN_ALERT "Hello, world\n"); return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, cruel world\n"); } module_init(hello_init); module_exit(hello_exit); ``` * 第1,2行:定義於`/usr/src/linux-headers-5.11.0-27-generic/include/linux`。 * 第3行:用來讓kernel知道此模組遵守自由授權條款。 * 第11行:在模組載入kernel時會執行module_init巨集中的函式。也就是helo_init。初始函式是向核心註冊模組所提供新功能(可能是整個驅動程式,或是可供應用程式存取的軟體抽象層)。可以將此函式改成`static int __int hello_init()`當中的`__init`讓核心可以知道該函式==只用於初始期間==。 * 第12行:在模組卸載時會執行module_exit巨集中的函式。也就是helo_exit。清理函式負責在模組被卸載之前,註銷曾這冊的軟體介面,並將資源還給系統。以將此函式改成`static void __exit hello_exit()`當中的`__exit`讓核心可以知道該函式==只用於卸載期間==。 * 第5行:使用的是`printk`而不是`printf`,因為`printf`屬於libc,==模組不能與一般函式庫連結,只能與核心連結==,因此要使用定義於linux核心內的`printk`,可供模組使用。而當中的`KERN_ALERT`代表訊息的優先度,我們刻意指定一個高的優先度,因為預設的優先度不一定會使得訊息出現在你看得到的地方。 --- ```cpp= #include <linux/init.h> #include <linux/module.h> #include <linux/sched.h>//只要引入sched.h就可以將current當成當時執行的process。 #include <linux/moduleparam.h> MODULE_LICENSE("Dual BDE/GPL"); static char *whom = "world"; static int howmany = 1; module_param(howmany, int, S_IRUGO); module_param(whom, charp, S_IRUGO); static int hello_init(void) { printk(KERN_ALERT "Hello world\n"); printk(KERN_ALERT "The init process is \"%s\" (pid %i)\n", current->comm, current->pid); int i; for(i = 0; i < howmany; i++) { printk(KERN_ALERT "%s %d times\n", whom, howmany); } return 0; } static void hello_exit(void) { printk(KERN_ALERT "Goodbye, curel world\n"); printk(KERN_ALERT "The exit process is \"%s\" (pid %i)\n", current->comm, current->pid); } module_init(hello_init); module_exit(hello_exit); ``` * 第3, 11, 21行:核心的大部份動作,都是在代替當時正在執行的process執行遠本無法在user-space完成的工作。透過定義於`<asm/current.h>`的全局變數`current`,current永遠指向當時正在執行的process。透過current,核心程式可以取得當時正在執行的狀態資訊。 * 第6,7,8,9行:在`insmod`時改變系統的參數,模組本身要先以`module_param`巨集來宣告參數。 >`#` insmod hello.ko howmany=10 whom="Mom" ==所有的模組參數都必須有預設值==,`module_param()`的最後一欄是權限值,決定模組參數在sysfs裡的對應項目的存取權限。 ### 參考資料 [Makefile 語法和示範](https://hackmd.io/@sysprog/SySTMXPvl) [編譯內核模塊的的Makefile的講解](https://www.twblogs.net/a/5b81bc442b71772165ae0321) [驅動模組Makefile解析](https://www.itread01.com/p/1377069.html)