将结构传递给 xv6 系统调用

Pass struct to xv6 system call

我知道我们无法直接将参数传递给 xv6 系统调用,我们不得不使用它的内置方法。

但是这个站点中的所有示例和问题都是关于如何将整数发送到系统调用的。它的答案是使用 argint() 方法。

但我的问题是,是否可以将 "struct" 传递给 xv6 系统调用?是否也有用于此目的的内置方法?

如果有,能否请您举个简单的例子?

可以通过系统调用传递结构。

虽然不能将结构本身作为系统调用参数传递,但可以传递指向它的指针,并且允许将其用作输入或输出参数。

允许将数据本身用作参数而不是指向它的指针将破坏系统调用机制的要求 - 因为传递数据必须以通用方式实现以允许所有数据类型(以及未来结构)被使用。

让我们看一下系统调用 fstat 的现有实现。

int fstat(int fd, struct stat *st);

fstat 需要一个文件描述符编号作为输入,并使用 struct stat 输出匹配的统计信息。

struct stat {
  short type;  // Type of file
  int dev;     // File system's disk device
  uint ino;    // Inode number
  short nlink; // Number of links to file
  uint size;   // Size of file in bytes
};

虽然 fstat 使用结构指针作为输出参数,但将其用作输入将是类似的。

内核代码中的函数sys_fstat开始执行fstat系统调用(XV6的约定是通过sys_*函数处理从用户space获取的参数)。

int sys_fstat(void)
{
  struct file *f;
  struct stat *st;

  if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
    return -1;
  return filestat(f, st);
}

该函数首先获取一个对应于第一个fstat函数参数(使用argf​​d)接收到的文件描述符编号的struct file。然后,使用 argptr 获取第二个 fstat 函数参数接收的 struct stat 指针,并将给定指针保存在局部(函数范围)指针变量中。

至此,所有参数都已获取并可供内核实现使用。

注:虽然struct stat指针是user-space指针(位于virtualspace的下半部分),但它是内核在这里使用它是安全的,因为当内核为进程的系统调用提供服务时,它使用进程自己的分页 table.

虽然上面的答案是正确的,但我更愿意编写自己的解决方案,以使其对其他用户更有用。

我使用 argptr 将指向结构的指针传递给我的系统调用。

在sysproc.c中:

int sys_counts (void){

    struct countTable *ct;
    argptr (0 , (void*)&ct ,sizeof(*ct));
    return counts(ct);
    }

在proc.c中:

int counts (struct countTable *ct){


    for (int i=0 ; i<22 ; i++){
    (ct->system_calls)[i] = count_calls[i] ;
    } 


    return 22;
    }

最后在我的用户-space-程序中:

int main (){

    struct countTable *ct = malloc (sizeof (struct countTable));

    // call system call
    counts(ct);


    exit();
    }
尽管其中一个答案是可以接受的,但我写下了清晰完整的答案。

请注意,将参数直接传递给 system-call 是不可能的。我们将使用 argptr 来做到这一点。

在用户空间中,我们定义了一个我们想要使用的结构。在 user-level 文件中,例如 test.c

#include "types.h"
#include "stat.h"
#include "user.h"

struct Data
{
    ...
    int id; // some fields
    ...
};


int main(int argc, char *argv[])
{
    struct Data *data = malloc(sizeof(struct Data));
    
    // call the systemcall
    doSomeWork((void *)data);

    exit();
    
}

在sysproc.c中我们定义system-call并使用argptr获取参数:

int sys_doSomeWork(void){

   struct Data *data;
   argptr(0, (void *)&data, sizeof(*data));
   return doSomeWork((void *)data);

}

并且在proc.c中我们可以编写system-call的功能:


int doSomeWork(void *data){
   // cast to (struct Data *)
   struct Data *my_data = (struct Data *)data;

   ...
   // work with my_data
   ...
   
   return 0;
}

并使数据结构在 sysproc.c 和 proc.c 内部可访问,我们在 defs.h:

内部定义数据结构
struct Data
{
    ...
    int id; // some fields
    ...
};