【MIT6.S081笔记5】Lecture5 Traps

5.0 Traps(对应视频6.1,这里都按照视频总结)

三种情况CPU暂停对正常指令执行

    1. syscall,移交kernel
    1. exception,非法操作:page default、运算时除以0
    1. 设备中断

内核空间和用户空间的切换通常称为trap。
例如: xv6启动后shell使用write输出提示信息,需要从用户态的shell进程到内核的sys_write
在用户态转换到内核态(权限的改变),状态非常重要

  • 最关心的状态是32个用户寄存器:a0、a1等。

  • 特殊寄存器:
    程序计数器(Program Counter Register)
    mode标志位
    控制CPU工作方式的寄存器,SATP 指向 page table 物理地址
    STVEC 寄存器,指向内核中处理trap的指令的起始地址
    SPEC 寄存器,trap过程保存程序计数器的值
    SSRATCH 寄存器,在进入到user space之前,内核会将trapframe page的地址保存在这个寄存器中,后面由于和其他寄存器交换内容

  • Trap 执行流程:
    1. 当user space中发生trap时,会将stvec的值复制到pc,而此时stvec的值是trampoline.S中的uservec2. 因此跳转到uservec,先保存一些现场的寄存器,恢复kernel栈指针、kernel page tablesatp寄存器,3. 再跳转到usertrap(kernel/trap.c)trap handler,4. 然后返回usertrapret(kernel/trap.c),跳回到kernel/trampoline.S,5. 最后用userret(kernel/trampoline.S)通过sret跳回到user space

    1. SH调用write(),write()会调用ecall
    • ecall之前(用户空间):可以通过info reg打印寄存器,a0、a1、a2是shell传递给write的值;QEMU按ctrl a+c进入QEMU的console,info mem可以打印完整的page table
    • 6条PTE,其中两条PTE_U没设置,分别是trapframe page 和trampoline page(在虚拟高地址),这里的用户page table可以看出来除了上述两条PTE,其他几乎都是为用户代码执行而创建的,所以对于内核执行代码没特殊作用(也能看出来内核和用户的分开)
    1. ecall:是一个CPU指令所以GDB看不到,ecall做了三件事
      a. 将代码从user mode改到supervisor mode
      b. 将PC值保存在SPEC,这里的PC是从STVEC拷贝过来(STVEC是实现设置好的trampoline page 的地址)
      c. ecall 跳转到 STVEC 寄存器指向的指令
    • ecall之后(内核空间,后面5-最后就是这个过程):
      a. 保存32个用户寄存器,为了恢复用户代码
      b. user page table 切换到 kernel page table
      c. 创建/找一个kernel stack,并将Stack Pointer指向kernel stack,给C代码提供栈
      d. 跳转到内核C代码的合理位置
    1. uservec()
      a. STVEC保存uservec()的地址,如前面3.c所述,ecall会跳转到STVEC 寄存器指向,也就是uservec()
      b. swap a0 amd sscratch,交换a0和sscratch的值,sscratch保存trapframe page的地址,trapfram结构如下
      c. sd ra 40(a0)…,保存用户寄存器的内容在trapframe page
      d. 当前a0存储trapframe page地址,sscratch保存用户态a0的值。将用户态a0保存在trapframe中。从trapframe中恢复sp(内核态栈指针),kernel_hartid(CPU核编号)等。
      e. 加载usertrap()地址到t0寄存器,恢复内核页表并刷新TLB,跳转到t0即usertrap()
      在这里插入图片描述
    2. usertrap() kernel/trap.c
      a. 当前已经在内核态,再发生trap,要内核处理,将STVEC指向kernelvec变量
      b. 判断trap产生原因并处理然后返回,如果是syscall将会调用对应的syscall
      c. 调用完最后usertrapret(),准备回到user space
    3. usertrapret() kernel/trap.c
      a. 关闭中断确保再设置trap vector期间不会有中断
      b. 将stvec设置为uservec,这样出现trap会跳转到uservec(Trampoline.S)
      c. 保存内核信息在trapframe(kernel_satp, kernel_sp, kernel_trap, kernel_hartid)
      d. 清除SPP位,表示下一次sret切换回用户模式
      e. SPEC寄存器设置为之前的用户程序计数器的值,根据user page table地址生成对应SATP值,为了回到用户态完成页表转换。
      f. 跳转回trampoline.S的userret函数
    4. userret() kernel/trampoline.S
      a. 切换页表
      b. 之前用trapframe保存寄存器值,通过trapframe恢复寄存器的值(包括a0),最后把trapframe保存在sscratch,用sret返回到user space
  • 40
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值