如何从Linux内核模块中使用Linux系统调用

8
我遇到了一些困难,无法从Linux内核模块中调用系统调用。这些系统调用已经通过标准的c用户空间程序进行了测试,并且运行正常,但我似乎无法让内核模块对其进行编译和运行。
在我的用户程序中,我包含以下代码,系统调用可以正常工作:
#include <linux/unistd.h>   
#define __NR_sys_mycall 343

extern long int _syscall(long int_sysno,...)__THROW;

//and then a simple call is done as such
long value = syscall(__NR_sys_mycall);

printf("The value is %ld\n",value);

但是当我在我的Linux内核模块中尝试同样的操作时,我会遇到一堆错误,其中有些会说error: implicit declaration of function 'syscall'(如果我没有包含_syscall定义),或者是如果我这样做的话语法上有很多错误,那么我的假设是我需要内核空间版本来调用系统调用。我的想法对吗?

//My LKM code
#include <linux/module.h>
#include <linux/unistd.h>
#define __NR_sys_mycall 343

static int start_init(void)
{
   long value = syscall(__NR_sys_mycall);
   printk("The value is %ld\n",value);

   return 0;
}

static void finish_exit(void)
{
      printk("Done!\n");
}

module_init(start_init);
module_exit(finish_exit);

6
你为什么要在内核模块中尝试使用系统调用?99.95%的情况下,在内核模块中使用系统调用都是错误的做法,不管你试图做什么。 - tangrs
我需要重复使用kmalloc,然后测量我重新设计其中一个Linux内存分配器所造成的平均碎片化。系统调用提供了结果信息,而LKM允许我使用kmalloc...这不仅是一个要求...因此我希望能够在分配后立即调用系统调用。 - dimlee
3
这听起来像是用于你需要的事情的sysfs工作,它可以将内核信息导出到用户空间。您还可以编写字符设备驱动程序。还有procfsnetlink可供选择。编写一个全新的系统调用可能是您尝试做的最不正确的方式。 - tangrs
在内核源代码中寻找导出的函数(EXPORTED_*),在大多数情况下,这比直接调用sys_something()更好。 - askb
2个回答

11

你可以直接调用 sys_mycall

#include <linux/module.h>
#include <linux/unistd.h>


static int start_init(void)
{
   long value = sys_mycall (pass_arguments)
   printk("The value is %ld\n",value);

   return 0;
}

static void finish_exit(void)
{
      printk("Done!\n");
}

module_init(start_init);
module_exit(finish_exit);

5

大多数系统调用使用asmlinkage,这意味着在堆栈上查找参数而不是寄存器。确保在调用系统调用时,在堆栈上传递参数。

此外,很多系统调用只使用copy_from_user。如果你将内核地址传递给这样的系统调用,它们会失败。


为 copy_from_user 获取内核地址的 bug 提及加 1。 - RootPhoenix
系统调用参数并不总是通过堆栈传递;这取决于您的架构以及内核。例如,请参见:UNIX和Linux x86-64系统调用的调用约定是什么 - user2975337

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接