MIT6.S081操作系统实验——system-calls

前言

Before you start coding, read Chapter 2 of the xv6 book, and Sections 4.3 and 4.4 of Chapter 4, and related source files:

  • The user-space code for systems calls is in user/user.h and user/usys.pl.
  • The kernel-space code is kernel/syscall.h, kernel/syscall.c.
  • The process-related code is kernel/proc.h and kernel/proc.c.

本次实验的主要内容是学习系统调用的工作流程,实现两个简单的系统调用。

实验原文:Lab: System calls (mit.edu)

系统调用基本流程

用户空间

根据实验说明的提示,用户进程执行系统调用时相关的代码在user/user.h中声明,在 user/usys.pl中定义。

首先可以看到user/user.h中有很多预设的系统调用。在Clion中,部分系统调用的左边会显示转到定义的双向箭头,但实际上转向的内容是内核空间对应的代码而非用户空间对应的代码。

实际的定义写在 user/usys.pl中,在make时perl脚本会被编译为汇编文件usys.S

打开编译后的usys.S可以看到以下内容:

# generated by usys.pl - do not edit
#include "kernel/syscall.h"
.global fork
fork:
 li a7, SYS_fork
 ecall
 ret
......

首先执行#include "kernel/syscall.h"导入系统调用的编号,然后接下来是各个系统调用的定义,每一个系统调用只有三行指令。

以fork举例,.global fork表示fork是一个全局函数,li a7, SYS_fork表示将SYS_fork的值加载到trapframe的a7中(li = load immediate),trapframe是在进程陷入内核态时保存寄存器状态的结构。接下来执行ecall陷入内核态,在内核完成系统调用后执行ret结束系统调用。

内核空间

根据实验说明的提示,内核空间关于系统调用的代码写在kernel/syscall.hkernel/syscall.c中。

在用户空间执行完ecall后,CPU陷入内核态,本质上是将当前运行的进程从执行系统调用的用户进程切换到内核进程,这个转换过程将在实验四trap中详细学习。

切换完成后,执行syscall()处理系统调用。

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;
  }
}

从trapframe的a7中获取系统调用编号,然后执行相应的系统调用,并将返回值写入trapframe的a0中,至此完成系统调用,CPU从内核态转回用户态,转换回去的具体过程同样在实验四中学

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值