版权信息:可以任意转载, 转载时请务必以超链接形式标明文章原文出处,谢谢
原文出处: http://libiao.appspot.com/2009/07/first_lkm_intro.html

LKM: Loadable Kernel Module,也叫KLD (Dynamic Kernel Linker)就是编写可动态加载和卸载的内核模块。使用kldload(8)加载内核模块,使用kldunload(8)卸载内核模块,使用kldstat(8)来显示查看已经加载的内核模块。调用kldload(8),必须要在内核上链接并且注册上,在FreeBSD的内核编程上,可以使用宏DECLARE_MODULE来进行链接和注册,

宏DECLARE_MODULE一共有4个参数

第一个参数是模块的名称,传入的是一个字符串,但是很奇怪的是,好像这个字符串不需要加引号

第二个参数是最重要的一个参数,其为数据结构struct moduledata(即moduledata_t类型结构),在该结构中保存该模块的官方名称,事件处理函数以及一些额外的数据

如:

static moduledata_t hello_mod = {

            "hello",

            load,

            NULL

};

其中load是一个事件处理函数,其处理了如下的事件

typedef enum modeventtype {

            MOD_LOAD,/* 当模块以及被加载后触发*/

            MOD_UNLOAD,/*当模块被卸载的时候触发*/

            MOD_SHUTDOWN,/*当在SHUTDOWN的时候触发*/

            MOD_QUIESCE/*当模块quiesce时候触发*/

}

第三个参数是该模块的类型,可选值可以参考enum sysinit_sub_id(在sys/kernel.h),一般情况下是使用SI_SUB_DRIVERS

第四个参数是KLD初始化的顺序,可以参考enum sysinit_elem_order(在sys/kernel.h)中的值,一般情况下是使用SI_ORDER_MIDDLE

实例:

DECLARE_MODULE(hello,hello_mod,SI_SUB_DRIVERS,SI_ORDER_MIDDLE);

下面是整个代码

 

#include
#include
#include
#include

static int load(struct module* module,int cmd,void* arg)
{
	int error = 0;

	switch(cmd)
	{
		case MOD_LOAD:
			uprintf("Hello world\n");
			break;

		case MOD_UNLOAD:
			uprintf("Good-Bye, cruel world!\n");
			break;

		default:
			error = EOPNOTSUPP;
			break;
	}

	return error;
}

static moduledata_t hello_mod = {
	"hello",
	load,
	NULL
};

DECLARE_MODULE(hello,hello_mod,SI_SUB_DRIVERS,SI_ORDER_MIDDLE);
 

 

对于整个内核模块的Makefile文件如下:

KMOD= hello
SRCS= hello.c

.include <bsd.kmod.mk>

最后是对该模块进行编译,执行的结果

 

sunrise# make
Warning: Object directory not changed from original /usr/home/kingoal/tmp/kernel
cc -O2 -fno-strict-aliasing -pipe  -D_KERNEL -DKLD_MODULE -std=c99 -nostdinc   -I. -I@ -I@/contrib/altq -finline-limit=8000 --param inline-unit-growth=100 --param large-function-growth=1000 -fno-common  -mno-align-long-strings -mpreferred-stack-boundary=2  -mno-mmx -mno-3dnow -mno-sse -mno-sse2 -mno-sse3 -ffreestanding -Wall -Wredundant-decls -Wnested-externs -Wstrict-prototypes  -Wmissing-prototypes -Wpointer-arith -Winline -Wcast-qual  -Wundef -Wno-pointer-sign -fformat-extensions -c hello.c
ld  -d -warn-common -r -d -o hello.kld hello.o
:> export_syms
awk -f /sys/conf/kmod_syms.awk hello.kld  export_syms | xargs -J% objcopy % hello.kld
ld -Bshareable  -d -warn-common -o hello.ko hello.kld
objcopy --strip-debug hello.ko
sunrise# kldstat
Id Refs Address    Size     Name
 1    3 0xc0400000 9fab28   kernel
 2    1 0xc0dfb000 6a45c    acpi.ko
sunrise# kldload ./hello.ko 
Hello world
sunrise# kldstat
Id Refs Address    Size     Name
 1    4 0xc0400000 9fab28   kernel
 2    1 0xc0dfb000 6a45c    acpi.ko
 3    1 0xc2afb000 2000     hello.ko
sunrise# kldunload hello.ko
Good-Bye, cruel world!
sunrise# kldstat
Id Refs Address    Size     Name
 1    3 0xc0400000 9fab28   kernel
 2    1 0xc0dfb000 6a45c    acpi.ko
sunrise# 

 

永久链接: http://libiao.appspot.com/2009/07/first_lkm_intro.html