xv6 系统调用

1. 系统调用的实现

  开发程序需所有的接口在user.h中,包含两部分system call和ulib

  user.h中的系统接口函数在usys.S中通过汇编实现

#define SYSCALL(name) \
  .globl name; \
  name: \
    movl $SYS_ ## name, %eax; \
    int $T_SYSCALL; \
    ret

SYSCALL(fork)
.......

  把系统调用ID放入eax中,使用int T_SYSCALL中断

2. int 指令

  int n 指令是调用n号中断的中断过程。最终效果和函数调用类似,中断过程执行结束过后返回。

3. xv6 中断处理

  在tvinit中生成了中断描述表(IDT),然后在idtinit中加载该中断描述表,注册0-255中断的处理过程。在tvinit函数中我们可以看到T_SYSCALL中断要求的调用权限是 DPL_USER,所有我们可以在用户空间调用T_SYSCALL中断。

  每个中断的处理过程在vectors.S(vector.pl生成)中实现,压入不同参数过后执行alltraps。在alltraps中准备参数trapframe,然后调用c实现的函数trap。

  trap函数实现如下:

  

void trap(struct trapframe *tf)
{
  if(tf->trapno == T_SYSCALL){
    if(myproc()->killed)
      exit();
    myproc()->tf = tf;
    syscall();
    if(myproc()->killed)
      exit();
    return;
  }
    .....
}

  当中断是T_SYSCALL时执行函数syscall, syscall根据eax中的系统调用id,确定具体函数,执行相应函数,把执行结果放入eax中。

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

  num = curproc->tf->eax;
  if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
    curproc->tf->eax = syscalls[num]();
  } else {
    cprintf("%d %s: unknown sys call %d\n",
            curproc->pid, curproc->name, num);
    curproc->tf->eax = -1;
  }
}

//TODO trapframe 是如何构建的

参考:https://th0ar.gitbooks.io/xv6-chinese/content/content/chapter0.html

猜你喜欢

转载自www.cnblogs.com/hygblog/p/9337643.html