(四) linux內核模塊編程

 

  Linux 就是一般所說的單內核(monolithic kernel),即操做系統的大部分功能都被稱爲內核,並在特權模式下運行。經過 Linux 內核模塊(LKM)能夠在運行時動態地更改 Linux。Linux可加載內核模塊(從內核的 1.2 版本開始引入)是 Linux 內核的最重要創新之一。它們提供了可伸縮的、動態的內核。探索隱藏在可加載模塊後面的原理,並學習這些獨立的對象如何動態地轉換成 Linux 內核的一部分。linux

 (1) linux 內核模塊的建立shell

  LKM 包含 entry 和 exit 函數。當向內核插入模塊時,調用 entry 函數,從內核刪除模塊時則調用 exit 函數。由於 entry 和 exit 函數是用戶定義的,因此存在 module_initmodule_exit 宏,用於定義這些函數屬於哪一種函數。LKM 還包含一組必要的宏和一組可選的宏,用於定義模塊的許可證、模塊的做者、模塊的描述等等,見下例。數組

#include <linux/module.h>     
#include <linux/kernel.h>       
#include <linux/init.h>         


static int __init hello_3_init(void)
{
        printk(KERN_ALERT "Hello, world n");
        return 0;
}

static void __exit hello_3_exit(void)
{
        printk(KERN_ALERT "Goodbye, world \n" );
}

MODULE_LICENSE("GPL");
module_init(hello_3_init);
module_exit(hello_3_exit);

(2)構建linux 內核模塊函數

  編譯模塊的make file 必須是Makefile,不能是makefile,而且要生成模塊必須先編譯經過。 內核模塊的makefile以下學習

  ifneq ($(KERNELRELEASE),)

  obj-m := mytest.o

  mytest-objs := file1.o

  else
  
  KVER ?= $(shell uname -r)


  KDIR :
= /lib/modules/$(shell uname -r)/build   PWD := $(shell pwd)   default:   $(MAKE) -C $(KDIR) M=$(PWD) modules

  clean:

  
  rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions   endif

 

  1> KERNELRELEASE是在內核源碼的頂層Makefile中定義的一個變量,在第一次讀取執行此Makefile時,KERNELRELEASE沒有被定義。因此執行else以後內容。ui

  2> 當執行make 時候 執行默認目標defalult。spa

    $(KDIR) 指明跳轉到內核源碼目錄下讀取那裏的Makefile;M=$(PWD)   指示路徑;代表而後返回到當前目錄繼續讀入、執行當前的Makefile。操作系統

    $(KVER)  要生成的模塊內核版本 當前系統版本code

  3> 當從內核源碼目錄返回時,KERNELRELEASE已被被定義,kbuild也被啓動去解析kbuild語法的語句,make將繼續讀取else以前的內容。視頻

    mytest-objs := file1.o  表示mytest.o 由file1.o 鏈接生成

    obj-m := mytest.o 表示編譯鏈接後將生成mytest.o模塊 mytest.ko。

 

(3) 編譯  安裝 卸載

 1> 編譯 執行make 生成mytest.ko內核模塊

 2> 安裝內核模塊 sudo insmod mytest.ko  

 3> 查看內核模塊輸出 dmesg -

 4> 卸載內核模塊 sudo rmmod mytest.ko  

 注意:Linux命令dmesg用來顯示開機信息,kernel會將開機信息存儲在ring buffer中。您如果開機時來不及查看信息,可利用dmesg來查看。開機信息亦保存在/var/log目錄中,名稱爲dmesg的文件裏。

 

(4)內核模塊的啓動參數

  像咱們普通的應用程序同樣,有main函數啓動能夠有參數,內核模塊啓動時候也可使用參數。這點很重要,如在視頻壓縮中經過最優參數達到不一樣壓縮效率。先看一個例子 咱們在解釋其中的代碼。

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>

#define MAX_ARRAY 66
static int int_var = 0;

static char *str_var = "default";
static int int_array[6];
int narr;

module_param(int_var, int, 0644);
MODULE_PARM_DESC(int_var, "A integer variable");

module_param(str_var,charp,0644);
MODULE_PARM_DESC(str_var, "A string variable");

module_param_array(int_array, int, &narr, 0644);
MODULE_PARM_DESC(int_array, "A integer array");

static int __init hello_init(void)
{
     int i;
     printk(KERN_ALERT "Hello, my LKM.\n");
     printk(KERN_ALERT "int_var %d.\n", int_var);
     printk(KERN_ALERT "str_var %s.\n", str_var);
     for(i = 0; i < narr; i ++)
     {
        printk("int_array[%d] = %d\n", i, int_array[i]);
     }
     return     0;
}
static void __exit hello_exit(void)
{
    printk(KERN_ALERT "Bye, my LKM.\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("This module is a example.");

 方式一:在內核模塊裏,參數的用法如同全局變量。

    module_param(name, type, perm);

    name  用戶看到的參數名,又是模塊內接受參數的變量

    type  表示參數的數據類型,下列之一:byte, short, ushort, int, uint, long, ulong, charp, bool, invbool

    perm 指定了在sysfs中相應文件的訪問權限

  eg:

      static unsigned int int_var = 0;

    module_param(int_var, uint, S_IRUGO);

方式二:模塊源文件內部的變量名與外部的參數名有不一樣的名

    module_param_named(name, variable, type, perm);

    name 外部可見的參數名

    variable 源文件內部的全局變量名

方式三:字符串

    static char *name;

    module_param(name, charp, 0); 

  或者

    static char species[BUF_LEN];

     module_param_string(name, string, len, perm);

方式四:數組  

    static int finsh[MAX_FISH];

    static int nr_fish;

    module_param_array(fish, int, &nr_fish, 0444); //最終傳遞數組元素個數存在nr_fish中

編譯生成內核模塊

裝載內核模塊 sudo insmod parm.ko int_var=100 str_var=hello int_array=100,200

相關文章
相關標籤/搜索