出于教学目的,我想在Debian Wheezy中实现一个系统调用。我希望在linux-image-3.2.0——rt-amd64包中的内核上实现它。以下是我尝试过的一个概述:
获取内核源代码:
apt-get source linux-image-3.2.0-4-rt-amd64
从中,我得到以下文件/目录(我执行的目录):
linux_3.2.41.orig.tar.xz
linux_3.2.41-2+deb7u2.dsc
linux_3.2.41-2+deb7u2.debian.tar.xz
以及:
linux_3.2.41
包含内核的源代码。
然后,为了添加系统调用而进行必要的更改,我基本上遵循了这一页:如何在debian/ubuntu上编写系统调用
以下是给出的说明的浓缩版本,经过修改以反映我所做的更改。
+文件1:linux-x.x.x/vpart_syscalls/vpart_syscalls.c
#include <linux/linkage.h>
#include <linux/kernel.h>
asmlinkage long insert_partition(char*dest, const char* src)
{
printk("<--- the syscall has been called!");
return 0;
}
文件2:linux-x.x.x/vpart_syscalls/Makefile. x。在上面创建的测试目录中创建一个Makefile,并在其中放入以下一行:
obj-y := vpart_syscalls.o
文件3:linux-x.x.x/arch/x86/kernel/syscall_table_32.S。现在,您必须将系统调用添加到系统调用表中。向文件追加以下行:
.long insert_partition
文件4:linux-x.x.x/arch/x86/include/asm/unistd_32.h
在此文件中,所有系统调用的名称将与一个唯一的数字相关联。在最后一个系统呼叫号码对之后,添加一行
#define __NR_insert_partition 349
然后替换NR_syscalls的值,用(现有的数量增加1)来声明系统调用的总数,即在这种情况下,NR_syscalls应该是338,新值是339。
#define NR_syscalls 350
- 文件5:linux-x.x.x/include/linux/syscalls.h
将函数的原型附加到文件中。
asmlinkage long insert_partition(int lenTicks, int vpid);
在文件#endif行之前。
- 文件6:在源目录的根目录下生成文件。
打开Makefile并找到定义core-y的行,并将目录test添加到该行末尾。
core-y += kernel/ mm/ fs/ test/ vpart_syscalls/
然后我开始以一种不同于上面描述的方式构建内核:
make localmodconfig
make menuconfig (making no changes)
make-kpkg clean
fakeroot make-kpkg --initrd --append-to-version=+tm kernel_image kernel_headers
cd ..
dpkg -i linux-image-3.8.*
dpkg -i linux-headers-3.8.*
安装的内核启动正常。我编写了以下c程序来测试系统调用:
#include <stdio.h>
#include <linux/unistd.h>
#include <sys/syscall.h>
int main(){
printk("Calling the new syscall!n");
int ret = 100;
ret = syscall(349, 1, 2);
printf("call return value: %in", ret);
return 0;
}
当我编译并运行这个程序时,我得到一个返回值-1。我使用dmesg检查消息,没有证据表明我的printk被调用了。
如果有人知道我的问题在哪里,我会非常非常高兴!我应该说我在修改和构建内核方面没有太多经验,但是我学到了很多。我读了Robert Loves的书- linux内核开发和网上的一些指南。
我认为,步骤3和4可能是不正确的64位内核:
File 3: linux-x.x.x/arch/x86/kernel/syscall_table_32.S.
File 4: linux-x.x.x/arch/x86/include/asm/unistd_32.h
这里有两个文件:http://lxr.linux.no/linux+v3.2.41/arch/x86/kernel/
syscall_64.c 668 2008-12-24 14:26:58 -0800
syscall_table_32.S 8659 2012-01-04 14:55:50 -0800
第一个使用C文件定义64位模式的系统调用表内容,并使用unistd_64.h宏作弊
#define __SYSCALL(nr, sym) [nr] = sym,
const sys_call_ptr_t sys_call_table[__NR_syscall_max+1] = {
....
#include <asm/unistd_64.h>
};
其中asm/unistd_64.h
为
#define __NR_read 0
__SYSCALL(__NR_read, sys_read)
等等
第二个是您更改的,用于32位模式,并使用asm文件和标签(.long sys_call_name
)编写。
所以,你为32位模式定义了系统调用,你使用的是linux-image-3.2.0-4-rt-amd64,这基本上是为"64位pc"。
我认为你将测试程序编译为gcc test.c
,默认为64位模式。您可以尝试gcc: gcc -m32 test.c
的-m32
选项来获得32位应用程序(这只会在您有32位构建的正确交叉环境时才有效)或在某些32位linux上编译此测试。
或者另一种选择是使步骤"4a": edit arch/x86/include/asm/unistd_64.h
添加两行:
#define __NR_insert_partition YOUR_NUMBER
__SYSCALL(__NR_insert_partition, insert_partition)
我不确定nr_sycall在哪里以及如何定义64位。它可能在构建期间生成。