Linux内核模块_helloworld

我们平时使用的用户程序和驱动程序不一样,驱动程序作为一个模块连接到内核模块并运行在内核空间里。引用LDD上的一句话“因为2.6内核的模块要和内核源代码树中的目标文件连接,通过这种方式,可得到一个更加健壮的模块加载器,但是需要这些目标文件存在于内核目录树中”。这里提到的内核目录树就是我们在运行我们自己构造的模块前,需要在我们的系统中已经配置好内核源代码树,然后在把构造好的目标模块和内核树连接起来再运行。
查看自己的系统里有没有配置好内核树的方法:在/lib/modules/2.6.35-30-generic目录下面,看看有没有build文件夹,如果有的话,说明我们的系统里已经有内核树了,如果没有的话,就需要自己构建一个内核树了。

1.安装编译内核所需软件

sudo apt-get install build-essential kernel-package libncurses5-dev fakeroot

2.下载内核源码编译

apt-cache search linux-source

apt-get install Linux-source-2.6.35

tar jxvf linux-source-2.6.32.tar.bz2

sudo cp /boot/config-2.6.35-30-generic /usr/src/linux-source-2.6.35/.config

cd /usr/src/linux-source-2.6.35

make menuconfig

make 

make bzImage

make modules 

make modules_install

最终在/lib/modules目录下面产生一个目录


Makefile 文件,其中default和clean下面一行是以Tab键开头

#如果已经定义KERNELRELEASE,则说明是从内核构造系统调用的
#因此可利用其内建语句
ifneq ($(KERNELRELEASE),)
    obj-m := helloworld.o
    helloworld-objs += hello.o
    
#否则,是直接从命令行调用的
#这时要调用内核构造系统
else
    KERNELDIR ?= /lib/modules/$(shell uname -r)/build
    PWD := $(shell pwd)
    
default:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    
endif

clean:
	rm -rf *.o *.ko .*.cmd .tmp_versions Module.* modules.* *.mod.c


KERNELRELEASE是内核顶层Makefile定义的变量,首次执行本例的Makefile时KERNELRELEASE变量没有被定义,所以执行else分支;

-C $(KERNELDIR) 表示跳转到内核源代码目录执行那里的Makefile

M=$(PWD)表示然后返回到当前目录继续读入、执行当前的Makefile

当从内核源码目录返回后,KERNELRELEASE变量已经定义,执行if分支

linux内核makefile体系参考:

http://blog.csdn.net/artechtor/article/details/1424619


hellowork.ko

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

static int namecount = 3;
static char* whom = "world";
static int howmany = 1;
static char* namelist[] = {"init1", "init2", "init3", "init4", "init5"};

static int __init hello_init(void)
{
    int i = 0;
    for(i = 0; i < howmany; i++)
    {
        printk(KERN_ALERT "Hello %s,index:%d\n", whom, i+1);
    }
    
    printk(KERN_ALERT "countof(namelist):%d\n", sizeof(namelist)/sizeof(char*));
    
    for(i = 0; i < namecount; i++)
    {
        printk(KERN_ALERT "Hello %s,index:%d\n", namelist[i], i+1);
    }
    return 0;
}

static void __exit hello_exit(void)
{
    printk(KERN_ALERT "Goodbye....\n");
    return;
}

module_init(hello_init);
module_exit(hello_exit);
module_param(howmany, int, 0);
module_param(whom, charp, S_IRUGO);
module_param_array(namelist, charp, &namecount, S_IRUGO);

MODULE_LICENSE("Dual BSD/GPL");

insmod helloworld.ko howmany=10 whom=kitty namelist=john,jack,cathy


内核支持的模块参数类型如下:

bool

invbool

    布尔值(取true或false),关联的变量应该是int型。invbool类型反转其值,也就是说,true值变成false,而false变成true。

charp

    字符指针指。内核会为用户提供字符串分配内存,并相应设置指针。

int

long

short

uint

ulong

ushort

    具有不同长度的基本整数值。以u开头的类型用于无符号数。


模块装载器也支持数组参数,在提供数组值时用逗号划分各数组成员。要声明数组参数,需要使用下面的宏:

module_param_array(name, type,num,perm);

其中,name是数组的名称(也就是模块参数的名称),type是数组元素类型,num是一个整数变量用于记录输入的数组元素个数,而perm是常见的访问许可值。

如果在装载时设置数组参数,则num会被设置为用户提供的值的个数。模块装载器会拒绝接受超过数组大小的值(本例中加载时设置namelist参数超过5个时加载失败)。


perm参数:这个值用来控制谁能访问sysfs中对模块参数的表述(在/sys/module/helloword/parameters目录下面有三个文件:whom/howmany/namelist分别对应三个模块参数,文件内容为模块加载时的参数值。)。如果perm值被设置为0,则不会有对应的sysfs入口项(如果whom参数的给标志被置为0,则在/sys/module/helloword/parameters目录下面没有whom文件);否则,模块参数会在/sys/module中出现,并设置为给定的访问许可。

S_IRUGO 在<linux/stat.h>中定义,如果一个参数通过sysfs被修改,则如果模块修改了这个参数的值一样,但是内核不会以任何方式通知模块。通常情况下,不应该设置模块参数为可写的,除非打算检测这种修改并作出相应的动作。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值