linux程序设计之设备驱动—hello kernel

------------------------------------------------------------------

实验:写一个简单的内核模块并加载,消除对内核的恐惧感。

此程序网上有,但有些不够详细,有的连一些基本命令都是错误的,特意记录下。

source code

hello.c

------------------------------------------------------------------

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

MODULE_LICENSE("Dual BSD/GPL");    
static int hello_init(void) //有的上面定义的是init_modules(void)是通不过编译的
{
    printk(KERN_ALERT "Hello, world/n");
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye, world/n");
}

module_init(hello_init);
module_exit(hello_exit);
------------------------------------------------------------------------

Makefile的书写

obj-m := hello.o 
KDIR:=/lib/modules/$(shell uname -r)/build 
PWD:=$(shell pwd)

all:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif

clean:
    rm -f *.o *.ko *.mod.c .hello*

------------------------------------------------------------------------

在2.6.*系统上,将hello.c与Makefile放在同一目录下,执行make将会生成hello.ko等其他的一些文件,hello.ko即是我们需要的内核。

加载内核命令:insmod hello.ko

查看内核加载列表:lsmod

注意used by选项。

 

另外想知道我们插入内核是否成功可以用,从内核缓冲区读出最后的消息。
dmesg | tail -n1
当我们不需要用到内核后,可卸载掉
rmmod hello.ko
 ----------------------------------------------------------------------------------------------------------------------------------------------------------
解析部分:

模块框架讲解:

模块的框架包含下面四个部分:

(1)     模块在加载的时候需要执行的module_init(function),以及在module_init()中指定的function,模块在卸载的时候执行的module_exit(function)以及在module_exit()中定义的function.如果声明使用module_exit(),那么此模块将不具备动态卸载功能。

(2)     需要定义module_init()调用的初始化函数,以及在module_exit()中使用的清理函数。只有当初始化函数返回非负值(因为在内核中,负值表示操作失败),内核模块才能被正确的加载,否则模块加载失败。而清理函数返回void类型。一般情况下,初始化函数是在模块加载的时候用来申请资源,而清理函数是在模块卸载的时候用来释放资源,有点类似于C++中的constructor与deconstructor.

(3)     头文件, 对于内核模块来讲,必须要使用<linux/module.h>和<linux/init.h>。需要特别注意的是,这里面使用了<>来包含头文件,但很明显这两个头文件都不会是标准函数的头文件,因为,正如前面所说,内核模块不能引用标准函数库的函数。这里的头文件实际上来自于Linux的内核源代码路径下的$(KERNELSRC)/include目录。

(4)     由MODULE_XXX表示的相关内容,这些都是对当前内核模块的描述,虽然不是必须的,但是一般情况下,还是请你们填上几项,特别是模块的许可问题。 当然也让你有扬名立万的机会,同时你也该负有责任。你对模块有更详尽的描述将对你以后调试错误是有帮助的。Modinfo可以让你更快的识别模块,如果有需要,请参考LDD(<<Linux 设备驱动程序>>,以后均简称为LDD)中有关更多的MODULE_XXX的宏描述。

--------------------------------------------------------------------------------------------------------------------------------------------------------------

Makefile讲解:

网上流传版本为下面的Makefile,但编译不过,后将ifneq内容删除则可。

Makefile的内容:
ifneq ($(KERNELRELEASE),)
    obj-m := hello.o
else
    KDIR:=/lib/modules/$(shell uname -r)/build
    PWD:=$(shell pwd)

all:
    $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules  #编译内核模块的指令
endif

clean:
    rm -f *.o *.ko *.mod.c .hello*

1.obj-m 是要编译的对象,第一个ifeq ($(KERNELRELEASE),)目前,并无用处,它的由来是指在Linux源码根目录下的Makefile编译内核时,KERNELRELEASE宏会被定义,那么如果是从源码根目录开始的make则会将hello.o模块编译进内核。

2.KDIR 是kernel的目录,其中$(shell uname -r)代表了kernel的版本。

  PWD定义为$(shell pwd)代表了c源文件hello.c的绝对目录

3. $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules

这句是Makefile的规则:这里的$(MAKE)就相当于make,-C 选项的作用是指将当前工作目录转移到你所指定的位置。“SUBDIRS=”选项的作用是,当用户需要以某个内核为基础编译一个外部模块的话,需要在make modules 命令中加入“SUBDIRS=dir”,程序会自动到你所指定的dir目录中查找模块源码,将其编译,生成KO文件。

4.clean:一个目标,清除生成的文件。

--------------------------------------------------------------------------------------------------------------------------------------------------------------

posted @ 2013-01-11 14:26  偶的神!!  阅读(354)  评论(0编辑  收藏  举报