xv6-k210/doc/用户使用-系统调用.md

3.1 KiB
Raw Permalink Blame History

如何在xv6-k210中添加syscall

了解了Syscall在xv6-k210中的执行过程为系统添加一个新的syscall功能就不是什么难事了。添加新系统调用的步骤如下

  1. 在xv6-user目录下

    • 在user.h文件中添加新系统调用封装后的函数声明假设其函数名为mysyscall

    • 在usys.pl文件末尾添加如下行

      ......
      entry("mysyscall");
      
  2. 在kernel目录下

    • 在include/syscall.h文件中添加新系统调用号的宏定义

      ......
      #define SYS_mysyscall ?
      

      其中,“?”为新的合法系统调用号,本质上是一个数组下标,可根据需要设置,建议按顺序递增添加。

    • 在syscall.c文件中添加功能函数的声明并更新系统调用表

      ......
      extern uint64 sys_mysyscall(void);
      
      static uint64 (*syscalls[])(void) = {
          ......
          [SYS_mysyscall]    sys_mysyscall,
      };
      
      
  3. 根据该系统调用的功能,选择一个适合的内核模块的源文件,在其中实现sys_mysyscall函数的功能。 例如与文件相关的系统调用可以在kernel/sysfile.c中添加。 可以利用syscall.c文件中提供的相关函数sys_mysyscall中获取用户进程传递的参数。

下面给出一个更具体的例子。在我们的移植工作中,我们需要测试用户进程的运行,使其向屏幕进行输出。 但当时用户态尚未支持printf函数我们便通过系统调用在S态进行一些输出。 为此,我们需要添加一个test_proc函数,其需要一个整型参数。

首先我们在xv6-user/user.h文件中添加函数声明为用户程序添加调用接口

int test_proc(int);

在xv6-user/usys.pl中添加行:

entry("test_proc");

随后修改内核在kernel/include/syscall.h中添加调用号调用号可以自行选择这里我们选择22表示第22个系统调用。

#define SYS_test_proc 22

最后在kernel/include/syscall.c中修改系统调用表以及添加函数sys_test_proc。注意,这里需要声明为无参数类型。

extern uint64 sys_test_proc(void);

static uint64 (*syscalls[])(void) = {
    ......
    [SYS_test_proc]    sys_test_proc,
};

函数的实现如下。其中argint函数可以从进程的保护现场中取得参数第一个参数表示系统调用的第几个参数从0开始编号。

uint64 sys_test_proc(void) {
    int n;
    argint(0, &n);
    printf("hello world from proc %d, hart %d, arg %d\n", myproc()->pid, r_tp(), n);
    return 0;
}

至此,我们就已经成功添加了一个系统调用。在用户程序中可以使用这个系统调用,例如以下的用户程序实例:

#include "kernel/include/types.h"
#include "kernel/include/sntat.h"
#include "xv6-user/user.h"

int main()
{
    int n = 5;
    while (n--) {
        test_proc(n);
    }
    exit(0);
}

编译运行后的结果如下图所示(编译用户程序的方法详见此处