Chinaunix首页 | 论坛 | 博客
  • 博客访问: 179677
  • 博文数量: 60
  • 博客积分: 677
  • 博客等级: 上士
  • 技术积分: 667
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-30 15:49
文章分类

全部博文(60)

文章存档

2015年(1)

2013年(6)

2012年(16)

2011年(9)

2010年(28)

我的朋友

分类: BSD

2011-08-30 10:07:45

大家都知道内核编译完成后,启动时加载到系统中,系统运行的时候不能再改变内核的功能,如果想修改,必须要重新编译,然后替代旧的内核。内核模块kernel module则提供了在系统在运行时,动态的修改内核功能的一个机制,而不必重新编译内核。

我在工作中倒是没有用非用到kernel module的时候,但是有时候为查看内核数据,动态修改某些行为,通过kernel module还是很方便的。

在/usr/src/share/examples/kld/里有一些kernel module的例子,我们可以举一个例子来说明kernel module的使用。参考syscall这个目录,查看一下syscall.c文件。
  1. /*
  2.  * The function for implementing the syscall.
  3.  */

  4. static int
  5. hello (struct thread *td, void *arg)
  6. {
  7.     printf ("hello kernel\n");
  8.     return 0;
  9. }

  10. /*
  11.  * The `sysent' for the new syscall
  12.  */

  13. static struct sysent hello_sysent = {
  14.     0,            /* sy_narg */
  15.     hello            /* sy_call */
  16. };

  17. /*
  18.  * The offset in sysent where the syscall is allocated.
  19.  */

  20. static int offset = NO_SYSCALL;

  21. /*
  22.  * The function called at load/unload.
  23.  */

  24. static int
  25. load (struct module *module, int cmd, void *arg)
  26. {
  27.     int error = 0;

  28.     switch (cmd) {
  29.     case MOD_LOAD :
  30.         printf ("syscall loaded at %d\n", offset);
  31.         break;
  32.     case MOD_UNLOAD :
  33.         printf ("syscall unloaded from %d\n", offset);
  34.         break;
  35.     default :
  36.         error = EOPNOTSUPP;
  37.         break;
  38.     }
  39.     return error;
  40. }

  41. SYSCALL_MODULE(syscall, &offset, &hello_sysent, load, NULL);
收看要看的是SYSCALL_MODULE宏,它是对DECLARE_MODULE的封装,本module是syscall module。
  1. #define SYSCALL_MODULE(name, offset, new_sysent, evh, arg) \
  2. static struct syscall_module_data name##_syscall_mod = { \
  3.        evh, arg, offset, new_sysent, { 0, NULL, AUE_NULL } \
  4. }; \
  5.                                                                \
  6. static moduledata_t name##_mod = { \
  7.        #name, \
  8.        syscall_module_handler, \
  9.        &name##_syscall_mod \
  10. }; \
  11. DECLARE_MODULE(name, name##_mod, SI_SUB_SYSCALLS, SI_ORDER_MIDDLE)
可以理解为声明一个module,DECLARE_MODULE定义如下
  1. #define    DECLARE_MODULE(name, data, sub, order)                \
  2.     MODULE_METADATA(_md_##name, MDT_MODULE, &data, #name);        \
  3.     SYSINIT(name##module, sub, order, module_register_init, &data)    \
  4.     struct __hack
具体是什么意思,不太清楚,可以理解像内核注册了个module。
接下来看SYSCALL_MODULE的参数:

  1. offset:是一个输入输出参数,是syscall的number,如果设置为NO_SYSCALL,kernel会为我们分配一个nubmer,我们可以自己指定一个数字,210-219之间,其他的会注册失败
  2. new_sysent:syscall回调函数的相关信息,比如参数
  3. evh:注册本module时候回调函数,需要处理MOD_LOAD,MOD_UNLOAD等信息
  4. arg:调用注册module回调函数需要传入的参数,我觉得在一个内核模块注册多个syscall的时候有用(用于区分哪个syscall)
hello_sysent定义了syscall的执行函数的相关信息,比如参数是0个,函数名字是hello。
那我们如果想定义有参数的syscall怎么办呢?
需要做三步:
1.修改hello_sysent:
  1. static struct sysent hello_sysent = {
  2.         1, /* sy_narg */
  3.         hello /* sy_call */
  4. }
2.定义一个参数结构体:
  1. struct hello_args
  2. {
  3.         int arg1;
  4. };
3.修改syscall 函数hello
  1. static int
  2. hello (struct thread *td, struct hello_args *arg)
  3. {
  4.         printf ("hello, arg is:%d\n", arg->arg1);
  5.         return 0;
  6. }
这样调用回调函数时候,就可以打印传入的参数了。怎么调用syscall呢?
  1. int
  2. main(int argc, char **argv)
  3. {
  4.         char *endptr;
  5.         int syscall_num;
  6.         struct module_stat stat;

  7.         stat.version = sizeof(stat);
  8.         modstat(modfind("syscall"), &stat);
  9.         syscall_num = stat.data.intval;
  10.         return syscall (syscall_num, 4);
  11. }
上面就是根据module名字找syscall id,然手调用syscall,如果知道id,也可以直接调用,那个4是hello的参数。
还有一个问题,可不可以在一个ko文件里定义多个syscall呢?答案可以,多次调用SYSCALL_MODULE就可以了,但每次的module名字不可以相同,这里贴一下完整的代码

  1. #include <sys/types.h>
  2. #include <sys/param.h>
  3. #include <sys/proc.h>
  4. #include <sys/module.h>
  5. #include <sys/sysproto.h>
  6. #include <sys/sysent.h>
  7. #include <sys/kernel.h>
  8. #include <sys/systm.h>

  9. void* p = 0

  10. struct myalloc_args
  11. {
  12.     int count;
  13. };

  14. /*
  15.  * The function for implementing the syscall.
  16.  */

  17. static int
  18. my_alloc (struct thread *td, struct myalloc_args *arg)
  19. {
  20.     printf ("alloc, arg is:%d\n", arg->count);
  21.     return 0;
  22. }

  23. static int
  24. my_release (struct thread *td, struct myalloc_args *arg)
  25. {
  26.     printf ("release, arg is:%d\n", arg->count);
  27.     return 0;
  28. }

  29. /*
  30.  * The `sysent' for the new syscall
  31.  */

  32. static struct sysent my_sysent[2] = {
  33.     {
  34.         1,            /* sy_narg */
  35.          (void*)my_alloc        /* sy_call */
  36.     },
  37.     {
  38.         1,            /* sy_narg */
  39.          (void*)my_release        /* sy_call */
  40.     }
  41. };

  42. /*
  43.  * The offset in sysent where the syscall is allocated.
  44.  */
  45. #if 0
  46. static int offset[] = {NO_SYSCALL,NO_SYSCALL};
  47. #endif
  48. static int offset[] = {212,213};

  49. char alloc_mod[] = "alloc";
  50. char release_mod[] = "release";

  51. /*
  52.  * The function called at load/unload.
  53.  */

  54. static int
  55. load (struct module *module, int cmd, void *arg)
  56. {
  57.     int error = 0;
  58.     int modn = 0;

  59.     if(arg == alloc_mod){
  60.         modn = 0;
  61.     }
  62.     if(arg == release_mod){
  63.         modn = 1;
  64.     }

  65.     switch (cmd) {
  66.     case MOD_LOAD :
  67.         printf ("syscall %s loaded at %d\n",(char*)arg, offset[modn]);
  68.         break;
  69.     case MOD_UNLOAD :
  70.         printf ("syscall unloaded from %d\n", offset[modn]);
  71.         break;
  72.     default :
  73.         error = EOPNOTSUPP;
  74.         break;
  75.     }
  76.     return error;
  77. }

  78. SYSCALL_MODULE(mymodule, &offset[0], &my_sysent[0], load, (void*)alloc_mod);
  79. SYSCALL_MODULE(mymodule1, &offset[1], &my_sysent[1], load, (void*)release_mod);

阅读(1442) | 评论(0) | 转发(0) |
0

上一篇:fb安装东西

下一篇:freebsd sshd启动慢

给主人留下些什么吧!~~