【MIT6.S081】Lab4: traps(详细解答版)

本文介绍了在RISC-V架构的实验中,如何处理trapframe和栈结构,包括函数调用时栈帧的创建、返回地址的存储,以及在用户空间中实现定时器触发的报警处理,涉及syscall扩展和trapframe备份等技术。

实验内容网址:https://xv6.dgs.zone/labs/requirements/lab4.html
本实验的代码分支:https://gitee.com/dragonlalala/xv6-labs-2020/tree/traps2/

Backtrace

关键点:trapframe、栈

思路:

这道题的关键是栈结构,先阅读xv6中关于栈的知识(https://mit-public-courses-cn-translatio.gitbook.io/mit6-s081/lec05-calling-conventions-and-stack-frames-risc-v/5.5-stack)。
[图片]

阅读链接的资料,我们可以知道,

  1. 每调用一个函数,函数都会为自己创建一个Stack Frame。
  2. 栈是从高地址开始向低地址使用。所以栈总是向下增长。
  3. Return address总是会出现在Stack Frame的第一位,指向前一个Stack Frame的指针也会出现在栈中的固定位置
  4. 第一个寄存器是SP(Stack Pointer),SP始终指向栈顶(当前可用内存的最低地址),随着压栈/弹栈实时更新。而FP仅标记当前栈帧的起始位置,可能位于栈的较高地址(如函数调用链的固定位置)。FP-8位是返回地址,FP-16位是上一个stack frame的fp地址。
  5. 保存前一个Stack Frame的指针的原因是为了让我们能跳转回去。
    XV6在内核中以页面对齐的地址为每个栈分配一个页面。你可以通过PGROUNDDOWN(fp)和PGROUNDUP(fp)(参见kernel/riscv.h)来计算栈页面的顶部和底部地址。

步骤&代码:

  1. 将下面的函数添加到kernel/riscv.h
static inline uint64
r_fp()
{
   
   
  uint64 x;
  asm volatile("mv %0, s0" : "=r" (x) );
  return x;
}
  1. 在kernel/defs.h中添加backtrace的原型,在printf.c中定义backtrace函数。
void       
backtrace(void){
   
   
  // 读取当前Frame Pointer
  uint64 fp = r_fp();
  while(PGROUNDUP(fp) - PGROUNDDOWN(fp) == PGSIZE){
   
   
    // 返回地址保存在-8偏移的位置
    uint64 ret_addr = *(uint64*)(fp-8);
    printf("%p\n",ret_addr);
    // 前一个帧指针保存在-16偏移的位置
    fp = *(uint64*)(fp-16);
  }
}
  1. 在sys_sleep中添加对backtrace函数的调用。
uint64
sys_sleep(void)
{
   
   
  int n;
  uint ticks0;

  if(argint(0, &n) < 0)
    return -1;
  acquire(&tickslock);
  ticks0 = ticks;
  while(ticks - ticks0 < n){
   
   
    if(myproc()->killed){
   
   
      release(&tickslock);
      return -1;
    }
    
MIT 6.S081 是麻省理工学院开设的一门关于操作系统的课程,课程全称为 **MIT 6.S081: Operating System Engineering**。该课程以实践为导向,通过让学生从零开始逐步构建一个简单的类 Unix 操作系统内核(基于 RISC-V 架构),深入理解操作系统的核心原理和实现机制。 课程内容涵盖线程、调度、虚拟内存、文件系统、系统调用、中断、设备驱动、同步机制等操作系统关键主题。课程材料公开,包括讲义、实验(labs)、视频讲座和源代码,非常适合自学。 ### 课程资源获取方式 1. **官方网站** MIT OpenCourseWare 提供了完整的课程材料,包括实验指导、源代码、讲义和部分视频讲座。 - 官网地址:[https://pdos.csail.mit.edu/6.828/2020/index.html](https://pdos.csail.mit.edu/6.828/2020/index.html) (注意:6.S0816.828 的新编号,内容基本一致) 2. **XV6 操作系统源码** 课程使用 xv6 作为教学操作系统,它是 Unix V6 的简化,使用 C 语言编写,适合教学和学习。 - 源码地址:[https://github.com/mit-pdos/xv6-riscv](https://github.com/mit-pdos/xv6-riscv) 3. **实验(Labs)** 课程实验包括: - **Lab 1: Xv6 and Unix utilities** - **Lab 2: System calls** - **Lab 3: Page tables** - **Lab 4: Traps** - **Lab 5: Threads** - **Lab 6: Locking** - **Lab 7: File system** - **Project: Networking (optional)** 每个实验都要求修改 xv6 源码以实现特定功能,例如添加系统调用、实现线程调度、实现文件系统操作等。 4. **社区与讨论区** - **GitHub 项目**:许多学生将他们的实验成果上传到 GitHub,可以参考他们的实现思路和代码。 - **Reddit 和 Stack Overflow**:在 r/mit、r/operatingsystems 和 Stack Overflow 上可以找到相关讨论和问题解答。 - **知乎、优快云 等中文社区**:一些中文用户也分享了他们对 MIT 6.S081 的学习笔记和实验解析。 5. **学习建议** - 熟悉 C 语言和汇编基础。 - 掌握基本的数据结构(如链表、队列、树等)。 - 理解计算机体系结构(特别是 RISC-V)。 - 有操作系统基础理论知识(如进程、内存管理、文件系统等)。 ### 示例代码:添加系统调用 以下是一个简单的系统调用示例,用于在 xv6 中添加一个新的系统调用 `sys_helloworld`: ```c // user/user.h int helloworld(void); // user/usys.pl entry("helloworld"); // kernel/syscall.h #define SYS_helloworld 22 // kernel/syscall.c extern uint64 sys_helloworld(void); // kernel/sysproc.c uint64 sys_helloworld(void) { printf("Hello, world from kernel!\n"); return 0; } ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值