|
OpenBSD可加载内核模块编程完全指南(2) 了一个指向结构sysent的模块框架 我们将用MOD_SYSCALL宏来安装它:
MOD_SYSCALL("ourcall", -1, &newcallent)
我们来分析一下上面的宏,很明显,模块名为"ourcall",用来标示模块,还有一个作用就是我们利用modstat命令时会显示出来.-1代表我们
的syscall该插入的位置,在这个 宏当中的-1的意思是我们不用关心位置具体在什么地方,它会被分配到一个空的位置.最后一个字段newcallent是一个指向sysent的结构,
它包含了我们系统调用的相应的数 据. 除此之外我们还需要一个句柄用来加载和卸载内核模块,好,在这个例子中我用'hi'来加载,用'bye'来卸载.这对我们调试程序很有帮助.句柄可
以是相同的函数或者单个函数, 如果没有定义句柄,那么lkm_nofunc()会简单的返回0,这个模块是没有加载卸载的,也就失去了作用.
我们模块的外部入口点是ourcall():
int ourcall(lkmtp, cmd, ver) struct lkm_table *lkmtp; int cmd; int ver; { DISPATCH(lkmtp, cmd, ver, ourcall_handler, ourcall_handler, lkm_nofunc) }
这个句柄可以用来加载,卸载模块.第四个参数我们用作加载操作,第五个参数用作卸载操作,第六个参数是状态函数(在此例中没有用到). ok!完整的系统调用模块代码如下(syscall.c):
#include <sys/param.h> #include <sys/systm.h> #include <sys/ioctl.h> #include <sys/cdefs.h> #include <sys/conf.h> #include <sys/mount.h> #include <sys/exec.h> #include <sys/lkm.h> #include <sys/proc.h> #include <sys/syscallargs.h>
/* 定义我们自己的系统调用原型 */ int newcall __P((struct proc *p, void *uap, int *retval));
/* * 所有的系统调用都有三个参数: 一个指向proc结构的结构指针,一个空指针指向参 * 数本身和一个返回指针.下面,我们定义这些参数的结构.如果你只有一个参数,则 * 只需要一个入口就可以了. */
struct newcall_args{ syscallarg(int) value; syscallarg(char *) msg; };
/* * 下面这个结构定义了我们的系统调用.第一个参数是系统调用的参数数目,第二个参数 * 是参数的大小,第三个参数是我们的系统调用的代码了,呵呵:) */
static struct sysent newcallent = { 2, sizeof(struct newcall_args), newcall
|