xv6 系统调用

本文详细介绍了在Lab1环境中,如何通过user文件夹下的sleep.c程序利用RISC-V的系统调用机制,如sys_sleep,以及内核中对系统调用的处理过程,包括ecall指令和syscall函数的实现细节。
摘要由CSDN通过智能技术生成

以lab1的sleep为例。在user文件夹下,创建sleep.c。

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

int main(int argc, char* argv[]) {
    if (argc < 2) {
        fprintf(2, "usage: sleep <ticks>\n");
        exit(1);
    }
    if (sleep(atoi(argv[1])) < 0) {
        fprintf(2, "sleep error\n");
        exit(1);
    }
    exit(0);
}

该程序是一个用户程序,使用方法为命令行输入sleep <ticks>,这里的sleep是来自于文件名,如果文件不叫sleep.c而是shuijiao.c,那么则输出shuijiao <ticks>
在代码中通过系统调用sleep实现睡眠。该函数在user/user.h中声明。

// system calls
int sleep(int);

这个sleep函数只有声明没有实现(?)。在编译时,会生成如下代码(user/usys.S)

sleep:
 li a7, SYS_sleep
 ecall
 ret

ecall是ricsv提供的特殊指令,用于系统调用进入内核。li a7, SYS_sleep将sleep的系统调用号传入a7寄存器。
Sys_sleep被定义在kernel/syscall.h

#define SYS_sleep  13

kernel/syscall.c中有这样一段代码:

extern uint64 sys_chdir(void);
extern uint64 sys_close(void);
extern uint64 sys_dup(void);
extern uint64 sys_exec(void);
extern uint64 sys_exit(void);
extern uint64 sys_fork(void);
extern uint64 sys_fstat(void);
extern uint64 sys_getpid(void);
extern uint64 sys_kill(void);
extern uint64 sys_link(void);
extern uint64 sys_mkdir(void);
extern uint64 sys_mknod(void);
extern uint64 sys_open(void);
extern uint64 sys_pipe(void);
extern uint64 sys_read(void);
extern uint64 sys_sbrk(void);
extern uint64 sys_sleep(void);
extern uint64 sys_unlink(void);
extern uint64 sys_wait(void);
extern uint64 sys_write(void);
extern uint64 sys_uptime(void);

static uint64 (*syscalls[])(void) = {
[SYS_fork]    sys_fork,
[SYS_exit]    sys_exit,
[SYS_wait]    sys_wait,
[SYS_pipe]    sys_pipe,
[SYS_read]    sys_read,
[SYS_kill]    sys_kill,
[SYS_exec]    sys_exec,
[SYS_fstat]   sys_fstat,
[SYS_chdir]   sys_chdir,
[SYS_dup]     sys_dup,
[SYS_getpid]  sys_getpid,
[SYS_sbrk]    sys_sbrk,
[SYS_sleep]   sys_sleep,
[SYS_uptime]  sys_uptime,
[SYS_open]    sys_open,
[SYS_write]   sys_write,
[SYS_mknod]   sys_mknod,
[SYS_unlink]  sys_unlink,
[SYS_link]    sys_link,
[SYS_mkdir]   sys_mkdir,
[SYS_close]   sys_close,
};

void
syscall(void)
{
  int num;
  struct proc *p = myproc();

  num = p->trapframe->a7;
  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
    p->trapframe->a0 = syscalls[num]();
  } else {
    printf("%d %s: unknown sys call %d\n",
            p->pid, p->name, num);
    p->trapframe->a0 = -1;
  }
}

static uint64 (*syscalls[])(void)定义了一个数组,其元素是函数指针,这些函数部分定义在kernel/sysproc.c
在函数syscall中

num = p->trapframe->a7;
  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
    p->trapframe->a0 = syscalls[num]();
  }

这段代码从a7处取得系统调用号,然后通过syscall[num]()在数组中得到对应函数并调用,将返回值存到a0寄存器。
可见所有系统调用都会经由这个函数来调用。

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值