linux動態內核模塊編程-3

將一組與模塊相關的命令加載進內核

完成功能相似2,打印proc下的相關信息。可是不用從新編譯內核,節省時間,更爲靈活linux

內核模塊介紹

模塊是在內核空間運行的程序,其實是一種目標文件,不能單獨運行但其代碼可在運行時連接到系統中做爲內核的一部分運行或卸載。Linux內核模塊是一個編譯好的、具備特定格式的獨立目標文件,用戶可經過系統提供的一組與模塊相關的命令將模塊加載進內核,當內核模塊被加載後,它有以下特色:
1) 與內核一塊兒運行在相同的內核態和內核地址空間;
2) 運行時與內核具備一樣的特權級;
3) 可方便地訪問內核中的各類數據結構。
此外,內核模塊還能夠很容易地被移出內核,當用戶再也不須要某模塊功能時,能夠將它從內核卸載以節省系統主存開銷。shell

一個典型的內核模塊應包含以下幾個部分:
1)頭文件聲明。其中module.h和init.h是必不可少的。module.h包含加載模塊時須要的函數和符號定義;init.h中包含模塊初始化和清理函數的定義。若是在加載時容許用戶傳遞參數,模塊中還應包含moduleparam.h頭文件。
2)模塊許可聲明。從內核2.4.10版本開始,模塊必須經過MODULE_LICENSE宏聲明此模塊的許可證,不然在加載此模塊時會顯示「kernel tainted」(內核被污染)的警告信息。從linux/module.h文件中可看到,被內核接受的許可證有GPL、GPL v二、GPL and additionalrights、Dual BSD/GPL、Dual MPL/GPL、Dual MIT/GPL和Proprietary。
3)初始化和清理函數聲明。內核模塊必須調用宏module_init和module_exit去註冊初始化和清理函數。初始化和清理函數必須在宏module_init和module_exit使用前定義,不然會出現編譯錯誤。這兩個函數配對使用,例如當初始化函數申請了一個資源,那麼清理函數就應釋放這個資源,使得模塊不留下任何反作用。除了模塊初始化函數和清理函數,還能夠根據須要設計編寫其它函數。數據結構

設計內核模塊程序

注意增長了模塊相關的庫函數和函數聲明,命名爲 mymodules.c(與下面的Makefile對應)函數

#include<linux/module.h>
#include<linux/init.h>
#include <linux/fs.h> 
#include <asm/uaccess.h> 
#include<linux/sched.h>
static int mymodule_init(void)//模塊初始化
{
    struct file *fp;
    mm_segment_t fs;
    loff_t pos;
    int i,j,k,temp,flag;
    char cpuinfo[600],cpuinfo_end[]={'f','l','a','g','s'};
    char meminfo[200],meminfo_end[]={'B','u','f','f','e','r','s'};
    char uptime[20];int runtime;
    char version[150];

    printk("system info print.(by system_call)\n");

    /*cpuinfo*/
    fp=filp_open("/proc/cpuinfo",O_RDONLY,0);
    fs=get_fs();
    set_fs(KERNEL_DS);
    pos=0;
    vfs_read(fp,cpuinfo,sizeof(cpuinfo),&pos);

    for(i=0;i<5000;i++)
    {
        flag=1;
        for(j=0;j<5;j++)
            if(cpuinfo[i+j]!=cpuinfo_end[j])
            {
                flag=0;
                break;
            }
        if(flag)
            break;
    }
    cpuinfo[i]='\0';
    printk("cpuinfo:\n%s\n\n",cpuinfo);

    filp_close(fp,NULL);
    set_fs(fs);


    /*meminfo*/
    fp=filp_open("/proc/meminfo",O_RDONLY,0);
    fs=get_fs();
    set_fs(KERNEL_DS);
    pos=0;
    vfs_read(fp,meminfo,sizeof(meminfo),&pos);

    for(i=0;i<1500;i++)
    {
        flag=1;
        for(j=0;j<7;j++)
            if(meminfo[i+j]!=meminfo_end[j])
            {
                flag=0;
                break;
            }
        if(flag)
            break;
    }
    meminfo[i]='\0';
    printk("meminfo:\n%s\n\n",meminfo);

    filp_close(fp,NULL);
    set_fs(fs);


    /*uptime*/
    fp=filp_open("/proc/uptime",O_RDONLY,0);
    fs=get_fs();
    set_fs(KERNEL_DS);
    pos=0;
    vfs_read(fp,uptime,sizeof(uptime),&pos);

    for(i=0;i<20;i++)
    {
        if(uptime[i]=='.')
            break;
    }
    uptime[i]='\0';
    runtime=0;
    for(j=0;j<i;j++)
    {
        temp=uptime[j]-'0';
        for(k=0;k<i-j-1;k++)
           temp*=10;
        runtime+=temp;
    }
    printk("uptime:\nsystem has already started for %d minutes.\n\n",runtime/60);
    
    filp_close(fp,NULL);
    set_fs(fs);


    /*version*/
    fp=filp_open("/proc/version",O_RDONLY,0);
    fs=get_fs();
    set_fs(KERNEL_DS);
    pos=0;
    vfs_read(fp,version,sizeof(version),&pos);

    version[132]='\0';
    printk("version:\n%s\n",version);

    filp_close(fp,NULL);
    set_fs(fs);
    
    printk("info printed over.\n");
    return 0;
}
static void mymodule_exit(void)//模塊清理函數
{
    printk("module unloading.\n");
}
module_init(mymodule_init); //註冊初始化函數
module_exit(mymodule_exit); //註冊清理函數
MODULE_LICENSE("GPL"); //模塊許可聲明

Makefile

注意modules下以tab開頭ui

ifneq ($(KERNELRELEASE),)
    obj-m := mymodules.o#obj-m 指編譯成外部模塊
else
    KERNELDIR := /lib/modules/$(shell uname -r)/build #定義一個變量,指向內核目錄
    PWD := $(shell pwd)
modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif

安裝模塊

切換root用戶,執行如下
make
insmod ./mymodules.ko
lsmod
能夠看到模塊已安裝
設計

查看結果

dmesg –c

完成後可刪除模塊
rmmod mymodules3d

相關文章
相關標籤/搜索