我是一名学习操作系统的大学生。
我正在尝试在Linux内核中添加自己的系统调用,这出了问题。
我的环境如下:
由于我在x86_64机器上工作,因此我从 arch / x86 / entry / syscalls / syscall_64.tbl 开始。
在Linux内核v.4.19.1中,最后一项是
334 common rseq __x64_sys_rseq
所以我在下面添加了这三行。
335 common my_syscall_0 sys_my_syscall_0
336 common my_syscall_1 sys_my_syscall_1
337 common my_syscall_2 sys_my_syscall_2
其次,我在 include / linux / syscalls.h 中添加了函数原型。
asmlinkage int sys_my_syscall_0(void);
asmlinkage int sys_my_syscall_1(int);
asmlinkage int sys_my_syscall_2(int, int);
第三,我创建了一个新文件 kernel / my_syscall.c 并添加了函数的实现。
asmlinkage int sys_my_syscall_0(void)
{
printk("my_syscall_0\n");
return 0;
}
asmlinkage int sys_my_syscall_1(int a)
{
printk("my_syscall_1 : %d\n", a);
return 0;
}
asmlinkage int sys_my_syscall_0(int a, int b)
{
printk("my_syscall_2 : %d, %d\n", a, b);
return b;
}
然后,我在 kernel / Makefile 中添加了my_syscall.o来编译 kernel / my_syscall.c 。
obj-y = fork.o exec_domain.o panic.o \
cpu.o exit.o softirq.o resource.o \
sysctl.o sysctl_binary.o capability.o ptrace.o user.o \
signal.o sys.o umh.o workqueue.o pid.o task_work.o \
extable.o params.o \
kthread.o sys_ni.o nsproxy.o \
notifier.o ksysfs.o cred.o reboot.o \
async.o range.o smpboot.o ucount.o \
my_syscall.o
用 make-kpkg 和 dpkg 命令编译后,我制作了一个测试程序。
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main()
{
printf("1 : %d\n", syscall(335));
printf("2 : %d\n", syscall(336, 1));
printf("3 : %d\n", syscall(337, 2, 3));
return 0;
}
但是,结果很奇怪。 dmesg 向我展示了一些根本没有意义的数字。
# dmesg
...
my_syscall_0
my_syscall_1 : 1111490392
my_syscall_2 : 1111490392, 1111490392
每次执行程序时,它似乎都在改变。
显然,传递参数存在一些问题。但是, strace 命令告诉我这些值传递得很好。
# strace ./syscall
...
syscall_0x14F(0x7ffd21866538, 0x7ffd21866548, ....) = 0
...
syscall_0x150(0x1, 0, 0, 0, 0x7f9e1562f3a0, ....) = 0
...
syscall_0x14F(0x2, 0x3, 0x7f9e1562f3a0, ....) = 0
....
简介
我进行了简单的系统调用。
向他们传递参数的方式与预期不符。
问题:为了添加新的系统调用,上述步骤中是否存在任何问题?
问题:将参数传递给系统调用时,我应该注意什么问题?
先谢谢您。
答案 0 :(得分:3)
您需要告诉构建系统您的系统调用需要2个参数,并且它们的类型为int
。这样,作为构建系统一部分的脚本将生成适当的包装器,以将参数转换为所需的类型。而不是像您那样定义实际的处理程序,应该使用-
SYSCALL_DEFINE2(my_syscall_2, int, a, int, b) // Yes, there is a comma between the types and the argument names
{
printk("my_syscall_2 : %d, %d\n", a, b);
return b;
}
SYSCALL_DEFINEx
在linux/include/linux/syscalls.h中定义。
答案 1 :(得分:2)
我找到了解决方案。正如@Ajay Brahmakshatriya回答的那样,我应该使用SYSCALL_DEFINEx宏。而且,我也应该修改 arch / x86 / entry / syscalls / syscall_64.tbl 。
这是最终摘要。
首先,修改 arch / x86 / entry / syscalls / syscall_64.tbl :在下面添加这些行。
335 common my_syscall_0 __x64_sys_my_syscall_0
336 common my_syscall_1 __x64_sys_my_syscall_1
337 common my_syscall_2 __x64_sys_my_syscall_2
第二,修改 include / linux / syscalls.h :在下面添加这些行。
asmlinkage long sys_my_syscall_0(void);
asmlinkage long sys_my_syscall_1(int);
asmlinkage long sys_my_syscall_2(int, int);
第三,创建一个新文件用于实施。就我而言,是 kernel / my_syscall.c 。
#include <linux/syscalls.h>
#include <linux/kernel.h>
SYSCALL_DEFINE0(my_syscall_0)
{
printk("my_syscall_0\n");
return 0;
}
SYSCALL_DEFINE1(my_syscall_1, int, a)
{
printk("my_syscall_1 : %d\n", a);
return 0;
}
SYSCALL_DEFINE2(my_syscall_2, int, a, int, b)
{
printk("my_syscall_2 : %d, %d\n", a, b);
return b;
}
第四,将创建的文件添加到其目录中的Makefile中。就我而言,是内核/ Makefile 。
...
obj-y = fork.o exec_domain.o panic.o \
cpu.o exit.o softirq.o resource.o \
sysctl.o sysctl_binary.o capability.o ptrace.o user.o \
signal.o sys.o umh.o workqueue.o pid.o task_work.o \
extable.o params.o \
kthread.o sys_ni.o nsproxy.o \
notifier.o ksysfs.o cred.o reboot.o \
async.o range.o smpboot.o ucount.o \
my_syscall.o
...
最后,编译并安装内核。现在,您将可以看到新的系统调用运行良好。
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main()
{
printf("1 : %d\n", syscall(335));
printf("2 : %d\n", syscall(336, 1));
printf("3 : %d\n", syscall(337, 2, 3));
return 0;
}
dmesg 命令显示系统调用运行良好。
# dmesg
my_syscall_0
my_syscall_1 : 1
my_syscall_2 : 2, 3