ucore step by step
tutorial
tutorial
  • 欢迎来到ucore step-by-step的世界
  • lab0: 预备起
    • 溯源: ucore的历史
    • 概览: 指导书的结构
    • 开搞: 实验环境搭建
  • lab0.5: 比麻雀更小的麻雀(最小可执行内核)
    • 内存布局,OpenSBI,elf和bin
    • 链接脚本和入口点
    • "真正的"入口点
    • 从SBI到stdio
    • Just make it
    • 项目组成和执行流
  • lab1: 断, 都可以断
    • 掉进兔子洞(中断入口点)
    • 中断处理程序
    • 滴答滴答(时钟中断)
    • 项目组成和执行流
  • lab2: 物理内存和页表
    • 内核初始映射
    • 物理内存管理
    • 页面分配算法
    • 项目组成和执行流
  • lab3: 缺页异常和页面置换
    • 扫清外围
    • 使用多级页表
    • 页面置换机制
    • FIFO置换算法
    • 项目组成和执行流
  • lab4: 进程管理
    • 进程与线程
    • 相关数据结构
    • 进程模块初始化
    • 进程切换
    • 项目组成和执行流
  • lab5: 用户程序
    • 用户程序
    • system call!
    • 中断处理
    • 项目组成和执行流
  • lab6: 进程调度
    • 再次认识进程切换
    • 调度算法框架
    • 项目组成和执行流
  • lab7: 同步互斥
    • 同步互斥的基本概念
    • 信号量
    • 条件变量与管程
    • 项目组成和执行流
  • lab8: 文件系统
    • 文件系统抽象层VFS
    • 硬盘文件系统SFS
    • 设备即文件
    • 从zhong duan 到 zhong duan
    • 项目组成和执行流
  • 练习题
    • lab1
    • lab2
    • lab3
    • lab4
    • lab5
    • lab6
    • lab7
    • lab8
  • 附录
    • makefile
由 GitBook 提供支持
在本页

这有帮助吗?

  1. lab5: 用户程序

中断处理

由于用户进程比起内核进程多了一个"用户栈",也就是每个用户进程会有两个栈,一个内核栈一个用户栈,所以中断处理的代码trapentry.S要有一些小变化。关注用户态产生中断时,内核栈和用户栈两个栈顶指针的移动。

# kern/trap/trapentry.S

#include <riscv.h>

# 若在中断之前处于 U mode(用户态)
# 则 sscratch 保存的是内核栈地址
# 否则中断之前处于 S mode(内核态),sscratch 保存的是 0

    .altmacro
    .align 2
    .macro SAVE_ALL
    LOCAL _restore_kernel_sp
    LOCAL _save_context

    # If coming from userspace, preserve the user stack pointer and load
    # the kernel stack pointer. If we came from the kernel, sscratch
    # will contain 0, and we should continue on the current stack.
    csrrw sp, sscratch, sp #这里交换了sp和sccratch寄存器
    #sp为0,说明之前是内核态,我们刚才把内核栈指针换到了sscratch, 需要再拿回来
    #sp不为0 时,说明之前是用户态,sp里现在存的就是内核栈指针,sscratch里现在是用户栈指针
    #sp不为0,就跳到_save_context, 跳过_restore_kernel_sp的代码
    bnez sp, _save_context     

_restore_kernel_sp:
    csrr sp, sscratch #刚才把内核栈指针换到了sscratch, 需要再拿回来
_save_context:
    #分配栈帧
    addi sp, sp, -36 * REGBYTES 
    # save x registers
    STORE x0, 0*REGBYTES(sp)
    STORE x1, 1*REGBYTES(sp)
    STORE x3, 3*REGBYTES(sp)
    STORE x4, 4*REGBYTES(sp)
    STORE x5, 5*REGBYTES(sp)
    STORE x6, 6*REGBYTES(sp)
    STORE x7, 7*REGBYTES(sp)
    STORE x8, 8*REGBYTES(sp)
    STORE x9, 9*REGBYTES(sp)
    STORE x10, 10*REGBYTES(sp)
    STORE x11, 11*REGBYTES(sp)
    STORE x12, 12*REGBYTES(sp)
    STORE x13, 13*REGBYTES(sp)
    STORE x14, 14*REGBYTES(sp)
    STORE x15, 15*REGBYTES(sp)
    STORE x16, 16*REGBYTES(sp)
    STORE x17, 17*REGBYTES(sp)
    STORE x18, 18*REGBYTES(sp)
    STORE x19, 19*REGBYTES(sp)
    STORE x20, 20*REGBYTES(sp)
    STORE x21, 21*REGBYTES(sp)
    STORE x22, 22*REGBYTES(sp)
    STORE x23, 23*REGBYTES(sp)
    STORE x24, 24*REGBYTES(sp)
    STORE x25, 25*REGBYTES(sp)
    STORE x26, 26*REGBYTES(sp)
    STORE x27, 27*REGBYTES(sp)
    STORE x28, 28*REGBYTES(sp)
    STORE x29, 29*REGBYTES(sp)
    STORE x30, 30*REGBYTES(sp)
    STORE x31, 31*REGBYTES(sp)

    # get sr, epc, tval, cause
    # Set sscratch register to 0, so that if a recursive exception
    # occurs, the exception vector knows it came from the kernel
    #如果之前是用户态产生的中断,用户栈指针从sscratch里挪到了s0寄存器, sscratch清零
    csrrw s0, sscratch, x0
    csrr s1, sstatus
    csrr s2, sepc
    csrr s3, 0x143 #stval
    csrr s4, scause

    STORE s0, 2*REGBYTES(sp) #如果之前是用户态发生中断,此时用户栈指针存到了内存里
    STORE s1, 32*REGBYTES(sp)
    STORE s2, 33*REGBYTES(sp)
    STORE s3, 34*REGBYTES(sp)
    STORE s4, 35*REGBYTES(sp)
    .endm

    .macro RESTORE_ALL
    LOCAL _save_kernel_sp
    LOCAL _restore_context

    LOAD s1, 32*REGBYTES(sp)
    LOAD s2, 33*REGBYTES(sp)

    andi s0, s1, SSTATUS_SPP #可以通过SSTATUS_SPP的值判断之前是用户态还是内核态
    bnez s0, _restore_context

_save_kernel_sp:
    # Save unwound kernel stack pointer in sscratch
    addi s0, sp, 36 * REGBYTES
    csrw sscratch, s0
_restore_context:
    csrw sstatus, s1
    csrw sepc, s2

    # restore x registers
    LOAD x1, 1*REGBYTES(sp)
    LOAD x3, 3*REGBYTES(sp)
    LOAD x4, 4*REGBYTES(sp)
    LOAD x5, 5*REGBYTES(sp)
    LOAD x6, 6*REGBYTES(sp)
    LOAD x7, 7*REGBYTES(sp)
    LOAD x8, 8*REGBYTES(sp)
    LOAD x9, 9*REGBYTES(sp)
    LOAD x10, 10*REGBYTES(sp)
    LOAD x11, 11*REGBYTES(sp)
    LOAD x12, 12*REGBYTES(sp)
    LOAD x13, 13*REGBYTES(sp)
    LOAD x14, 14*REGBYTES(sp)
    LOAD x15, 15*REGBYTES(sp)
    LOAD x16, 16*REGBYTES(sp)
    LOAD x17, 17*REGBYTES(sp)
    LOAD x18, 18*REGBYTES(sp)
    LOAD x19, 19*REGBYTES(sp)
    LOAD x20, 20*REGBYTES(sp)
    LOAD x21, 21*REGBYTES(sp)
    LOAD x22, 22*REGBYTES(sp)
    LOAD x23, 23*REGBYTES(sp)
    LOAD x24, 24*REGBYTES(sp)
    LOAD x25, 25*REGBYTES(sp)
    LOAD x26, 26*REGBYTES(sp)
    LOAD x27, 27*REGBYTES(sp)
    LOAD x28, 28*REGBYTES(sp)
    LOAD x29, 29*REGBYTES(sp)
    LOAD x30, 30*REGBYTES(sp)
    LOAD x31, 31*REGBYTES(sp)
    # restore sp last
    LOAD x2, 2*REGBYTES(sp) #如果是用户态产生的中断,此时sp恢复为用户栈指针
    .endm

    .globl __alltraps
__alltraps:
    SAVE_ALL

    move  a0, sp
    jal trap
    # sp should be the same as before "jal trap"

    .globl __trapret
__trapret:
    RESTORE_ALL
    # return from supervisor call
    sret

    .globl forkrets
forkrets:
    # set stack to this new process's trapframe
    move sp, a0
    j __trapret
上一页system call!下一页项目组成和执行流

最后更新于5年前

这有帮助吗?

目前为止的代码可以在找到。

这里