內核模塊-基本概念

Linux內核模塊簡介

衆所周知,Linux系統已經成了應用最爲廣泛的操作系統。小到日常經常用到的電子設備,比如,智能手機、智能手錶等,大到互聯網公司的數據中心,都可以見到Linux的身影。Linux之所以如此成功,其中一個比較關鍵的因素就是她非常優秀的內核設計。這種設計可以使其適應各種場景的需求,加上天生開源的特質,想不火都難。

今天,本文所要介紹的就是Linux內核相關開發中一個比較基礎的概念:Linux Kernel Module(LKM)。大家,可能都知道,Linux是一個跨平臺的操作系統,市面上幾乎所有的硬件平臺,Linux應該都是支持的。即便,暫時不支持,也可以經過少許的適配,就可以使Linux系統完美的運行起來。那麼,LKM在硬件平臺的適配中就扮演着十分鐘的角色,有數據表面,Linux內核源代碼中有超過50%都是設備驅動相關的代碼,而設備驅動一般都是以內核模塊的形式存在。

Linux內核是宏內核,簡單來說就是內核就是一個整體,可以理解成爲一個可執行程序,內核包攬了所有的系統功能,比如,進程調度、內核管理、文件系統、設備管理等等。這樣勢必出現一個問題,那就是如果開啓所有的功能,會使得內核變得十分的臃腫。而LKM,可以從一定程度上,解決這個問題。通過將內核功能模塊實現爲LKM,可以對內核進行精簡,只保留最爲核心的功能,然後,其他功能模塊,可以隨着後續需求,進行動態的加載。Linux內核通過LKM可以動態的管理內核功能,使內核功能就要U盤一樣,支持熱插拔,這樣做不僅可以節約內核運行時的硬件要求,同時可以滿足內核功能的實時擴展性。

Linux內核實現了一整套管理LKM的框架,用來加載、卸載、管理模塊間的關係。LKM本質上就是一段可以被鏈接到內核空間的代碼片段,其格式和內核一樣,都是ELF格式,其爲內核提供訪問該模塊的入口和出口,而後內核模塊管理框架,就會自動的將其鏈接到內核空間,從而完成內核功能的擴展。

下面,就通過一個實例,簡單的介紹一下LKM。

基本實例

LKM既然是內核代碼片段,那麼其運行的環境就是內核環境,而內核環境有其獨特開發標準和開發庫。Linux用戶空間開發一般的都是基於libc庫,比如大名鼎鼎的glibc。而內核環境不依賴於glibc,所以LKM不會依賴於libc開發,而是基於內核開發框架。下面以一個實例來說明一下,LKM的開發方式。

與大多數入門程序示例一樣,這裏我們也是實現一個打印“hello,world"的LKM。

  #include <linux/init.h>                                                                                                                                                                                                                                                                 
  #include <linux/module.h>
   
  static int __init module_init_func(void)
  {
      printk("hello, world.\n");
      return 0;
  }
   
  static void __exit module_exit_func(void)
  {
      return;
  }
   
  MODULE_LICENSE("GPL v2");
  MODULE_VERSION("v0.1");
  MODULE_AUTHOR("lhl");
  MODULE_DESCRIPTION("LKM, helloworld.");
   
  module_init(module_init_func);
  module_exit(module_exit_func);

上面代碼的基本含義如下:

  • init.h和module.h是編寫內核模塊必須包含的兩個頭文件,裏面包含LKM基本的數據結構和主要的API。
  • module_init_func和module_exit_func分別對應LKM的入口和出口,而module_init和module_exit用於將這兩個函數註冊到內核中。
  • 宏MODULE_LICENSE用於聲明內核模塊所遵循的協議,一般有GPL、GPL v2、GPL and additional rights、Dual BSD/GPL等。
  • 宏MODULE_VERSION用於聲明內核模塊的版本信息。
  • 宏MODULE_AUTHOR用於聲明LKM的作者信息。
  • 宏MODULE_DESCRIPTION用於聲明LKM的基本功能描述。

內核模塊的編譯分爲兩種:單獨編譯和嵌入到內核代碼中編譯。一般情況下,LKM的編譯選擇單獨編譯,這種編譯方式有兩種優勢:

  • 編譯速度快;
  • 便於代碼的維護。

單獨編譯需要提前構建內核編譯環境,構建方式有兩種:

  • 下載內核源碼,編譯完成後,執行make modules_install安裝。
  • 如果是Ubuntu系統,可以使用sudo apt-get install linux-headers-$(uname -r)安裝適配於當前內核的構建環境。

內核模塊的構建需要編寫Makefile文件,我們把上面的helloworld保存爲hellword.c,相應的Makefile文件的內容如下:

obj-m:=helloworld.o

KERS :=/lib/modules/$(shell uname -r)/build                                                                                                                                                                                                                                             

all:
  make -C $(KERS) M=$(shell pwd) modules

clean:
  make -C $(KERS) M=$(shell pwd) clean

上述代碼的基本含義如下:

  • obj-m:用於定義內核模塊的二進制名稱,注意,該文件名稱與內核模塊的c程序文件名進行對應。
  • KERS:用於聲明內核編譯環境的位置。
  • all:用於定義目標文件的編譯規則,make -C (KERS)M=(KERS)表示進入內核編譯環境,M=(shell pwd)指定當前LKM的路徑,modules表示進行LKM的編譯。
  • clean:與all目標類似,這裏用於定義清理LKM編譯過程中產生的文件,包括.ko文件。

好了,準備好了編譯內核模塊的所有文件,執行make,可以看到下面的編譯過程。
$ make

make -C /lib/modules/5.3.0-45-generic/build M=/home/lhl/learn/LKM/example modules
make[1]: 進入目錄“/usr/src/linux-headers-5.3.0-45-generic”
  CC [M]  /home/lhl/learn/LKM/example/helloworld.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/lhl/learn/LKM/example/helloworld.mod.o
  LD [M]  /home/lhl/learn/LKM/example/helloworld.ko
make[1]: 離開目錄“/usr/src/linux-headers-5.3.0-45-generic”

helloworld.ko就是最終生成的內核模塊,使用sudo insmod helloworold.ko,安裝該內核模塊,然後,執行dmesg,可以看到內核日誌:

$ sudo insmode helloworld.ko

$ dmesg
......
[18813.852210] hello, world.
......

$ sudo rmmod helloworld.ko

通過sudo rmmod helloworld,可以卸載內核模塊。

還可以通過,modinfo可以查看LKM的基本信息:

$ modinfo helloworld.ko

filename:       /home/lhl/learn/LKM/example/helloworld.ko
description:    LKM, helloworld.
author:         lhl
version:        v0.1
license:        GPL v2
srcversion:     44ADBB2239DA10943034DBE
depends:        
retpoline:      Y
name:           helloworld
vermagic:       5.3.0-45-generic SMP mod_unload 

總結

上面就是對於LKM的簡單介紹,對於一個小白足可以完成一個內核模塊,後續文章還會深入分析LKM的具體的實現機制。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章