Yra's blog Yra's blog
Homepage
  • LeetCode周赛
  • Acwing周赛
  • 刷题整理
  • 题解
  • CPP
  • Golang
  • System

    • MIT6.S081 Labs
  • Computer Networking

    • CS144: Computer Networking
  • DataBase

    • MySQL
    • Redis
  • Others

    • ......
  • Paper Reading

    • Petri Net
  • Static Analysis

    • NJU Course Notes
  • Deep Learning

    • Dive into Deep Learning
Casual Records
Archives

Yra

Only a vegetable dog.
Homepage
  • LeetCode周赛
  • Acwing周赛
  • 刷题整理
  • 题解
  • CPP
  • Golang
  • System

    • MIT6.S081 Labs
  • Computer Networking

    • CS144: Computer Networking
  • DataBase

    • MySQL
    • Redis
  • Others

    • ......
  • Paper Reading

    • Petri Net
  • Static Analysis

    • NJU Course Notes
  • Deep Learning

    • Dive into Deep Learning
Casual Records
Archives
  • System

    • MIT6.S081 | 21Fall

      • Lab1: Unix utilities
      • Lab2: System Calls
      • Lab3: Page Tables
      • Lab4: Traps
        • Lab5: Copy-on-Write Fork for xv6
        • Lab6: Multithreading
        • Lab7: Networking
        • Lab8: Locks
        • Lab9: File System
        • Lab10: Mmap
    • Computer Networking

    • DataBase

    • Software Engineering

    • Others

    • Learning Notes
    • System
    • MIT6.S081 | 21Fall
    Yra
    2023-02-11
    目录

    [MIT6.S081]Lab4: Traps

    # [MIT6.S081]Lab4: Traps

    Lab: Traps (mit.edu) (opens new window)

    # 1、RISC-V assembly

    这个 assignment 主要是用来熟悉一些简单的 RISCV 的汇编。

    1. Which registers contain arguments to functions? For example, which register holds 13 in main's call to printf?

    一般用 a0 - a7 来存放参数,显然参数 13 放在 a2 寄存器中。

    1. Where is the call to function f in the assembly code for main? Where is the call to g? (Hint: the compiler may inline functions.)
    • 根据下面两行汇编,显然两个函数都被内联优化了
      24:	4635                	li	a2,13
      26:	45b1                	li	a1,12
    
    1. At what address is the function printf located?
    • 由下面两行汇编可以看出,我们在修改完 pc 的值之后跳转到了 0x30 + 1536 的地方,1536 的十六进制是 0x600,所以我们最后会跳转到 printf 所在的地方 0x630
      30:	00000097          	auipc	ra,0x0
      34:	600080e7          	jalr	1536(ra) # 630 <printf>
    
    1. What value is in the register ra just after the jalr to printf in main?
    • 由下图可以看出,我们会把 原 pc + 4 的值写入寄存器 ra,因此此时他的值是 0x38
    image-20230215231009187
    1. Run the following code.

      unsigned int i = 0x00646c72;
      printf("H%x Wo%s", 57616, &i);
      

      What is the output?

      The output depends on that fact that the RISC-V is little-endian. If the RISC-V were instead big-endian what would you set i to in order to yield the same output? Would you need to change 57616 to a different value?

    • 输出是 He110 World
    • 整体按字节逆转一下顺序就行,0x726c6400
    • 不用,大小端是存储的形式,与数值无关,无论 57616 如何被存储,其十六进制都是 0xe110
    1. In the following code, what is going to be printed after 'y='? (note: the answer is not a specific value.) Why does this happen?

      printf("x=%d y=%d", 3);
      
    • 从汇编我们可以很容易知道参数传递是通过寄存器实现的,在这里的两个参数分别由 a1 和 a2 传递。由于我们没有给第二个参数,因此这里会由当前 a2 中的值代替,这取决于这行代码之前的部分了。

    # 2、Backtrace

    在这个 assignment 中,我们调用系统调用 sys_sleep 后,要递归打印被调用的函数的 return address。

    image-20230217133440288

    这张图展现了栈的地址空间,可以看出我们要打印的 return address 在 fp -8 的位置,而前一个栈的 fp,存在了 fp - 16 的位置,了解了这些后,这个 assigment 就非常好实现了,我们直接看代码:

    void backtrace(void) {
      uint64 fp = r_fp(); // 系统提供的,获取了当前执行函数的 fp 
      uint64 top = PGROUNDUP(fp); // 系统提供的
      uint64 bottom = PGROUNDDOWN(fp);
      printf("backtrace:\n");
      while (fp > bottom && fp < top) {
        uint64 ra = *(uint64 *)(fp - 8); // 转化成指针再解引用
        fp = *(uint64 *)(fp - 16);
        printf("%p\n", ra);
      }
    }
    

    # 3.Alarm

    这个 assignment 比较复杂,简单来说就是要我们自己实现两个系统调用,能够通过倒计时来陷入 timer interrupt,来执行相关函数。

    我们先要添加两个系统调用 sys_sigalarm、sys_sigreturn,添加流程和之前一致,就不赘述了。

    为了实现要求,我们先要在 struct proc 中添加一些新的变量

    struct proc {
    //..................
      int interval; // 计时器间隔
      uint64 handler; // 倒计时结束后执行的函数地址
      int passed_ticks; // 当前过了多久时间
      struct trapframe *saved_trapframe; // 执行 handler 之前要保存 trapframe
      int in_trap; // 当前是否在 trap 中,如果在要避免再次遇到 trap
    };
    

    对应的要在 proc.c 中进行初始化,以及 free

    static struct proc* allocproc(void) {
    // ...................
      // Allocate a saved_trapframe page.
      if((p->saved_trapframe = (struct trapframe *)kalloc()) == 0){
        freeproc(p);
        release(&p->lock);
        return 0;
      }
      p->interval = 0;
      p->passed_ticks = 0;
      p->in_trap = 0;
    
      return p;
    }
    
    static void freeproc(struct proc *p) {
    // ......
      if(p->saved_trapframe)
        kfree((void*)p->saved_trapframe);
      p->handler = 0;
      p->in_trap = 0;
      p->interval = 0;
      p->passed_ticks = 0;
    // ......
    }
    

    接着我们在 trap.c 中实现倒计时和切换函数。

      // give up the CPU if this is a timer interrupt.
      if(which_dev == 2) {
        if (p->in_trap == 0) { // 保证当前不在 trap 里
          p->passed_ticks++; // 经过时间 + 1
          if (p->passed_ticks == p->interval) { // 倒计时结束
            p->passed_ticks = 0; // 重置时间
            p->in_trap = 1; // 进入trap
            *p->saved_trapframe = *p->trapframe; // 保存当前的 trapframe
            p->trapframe->epc = p->handler; // 切换执行函数
          }
          
        }
        yield();
      }
    

    具体的看注释就可以了,需要注意的是我们通过修改 p->trapframe->epc = p->handler 来切换到相关函数并执行

    另外我们还需要实现一下两个系统调用

    uint64 sys_sigalarm(void) { // 获取相关参数并赋值
      int ticks;
      uint64 handler;
      if(argint(0, &ticks) < 0)
        return -1;
      if(argaddr(1, &handler) < 0)
        return -1;
    
      myproc()->interval = ticks;
      myproc()->handler = handler;
      return 0;
    }
    
    uint64 sys_sigreturn(void) { 
        myproc()->in_trap = 0; // 又恢复了不在 trap 的转台
        *myproc()->trapframe = *myproc()->saved_trapframe; // 恢复现场,将之前保存下来的 trapframe 恢复
      return 0;
    }
    

    # 实验结果


    image-20230217180544163

    # 存在问题

    不知道是我的问题还是有 bug,我特地跑了 origin/traps 的原代码最后还是没有通过 usertests 🥲,后面的 labs 就

    #Learning Notes#System#6.S081
    Last Updated: 3/4/2023, 5:38:14 PM
    Lab3: Page Tables
    Lab5: Copy-on-Write Fork for xv6

    ← Lab3: Page Tables Lab5: Copy-on-Write Fork for xv6→

    最近更新
    01
    408 计组笔记
    07-19
    02
    Dive into Deep Learning
    01-27
    03
    25 考研随记
    11-27
    更多文章>
    Theme by Vdoing | Copyright © 2022-2025
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式