在实时Debian Wheezy上实现一个系统调用

时间:2013-05-23 22:41:04

标签: linux-kernel system-calls

出于教育目的,我想在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

包含内核的源代码。

然后,为了进行必要的更改以添加系统调用,我基本上遵循了这个页面: How to write system calls on 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。在上面创建的同一个测试目录中创建一个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位于源目录的根目录。

打开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: %i\n", ret);
    return 0;

}

当我编译并运行此程序时,我得到的返回值为-1。我使用dmesg检查消息,并且没有证据表明我的printk被调用..

如果有人知道我的问题在哪里,我真的很开心!我应该说我在改变和构建内核方面没有太多经验,但我已经学到了很多东西。我阅读了Robert Loves的书 - linux内核开发和网上的几个指南。

1 个答案:

答案 0 :(得分:2)

我认为,对于64位内核,步骤3和4可能不正确:

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位模式定义了syscall,并且您正在使用linux-image-3.2.0-4-rt-amd64,这基本上是针对“64位PC”。

我认为您将测试程序编译为gcc test.c,默认为64位模式。您可以尝试使用gcc:-m32的{​​{1}}选项来获取32位应用程序(这只有在32位版本具有正确的交叉环境时才有效)或者在某些32位Linux上编译此测试

或另一种选择是制作步骤“4a”:编辑gcc -m32 test.c以添加两行:

arch/x86/include/asm/unistd_64.h

我不确定定义64位的NR_syscalls的位置和方式。它可能在构建期间生成。