文章目录

  • 实验链接
  • 实验
    • RISC-V assembly
    • Backtrace
    • Alarm
    • 提交结果
    • 查看结果
  • 课程涉及知识汇总
    • 寄存器
    • page table
    • 指令
    • GDB
    • Trapline
    • Trapframe
  • 常用命令
  • 参考链接
  • Github

友情链接:全部实验哟


实验链接

https://pdos.csail.mit.edu/6.S081/2020/labs/pgtbl.html


实验

RISC-V assembly

  1. a0-a7,13保存在a2里

  2. 函数f和g直接被内联优化了,即printf的第2个参数直接是12(f(8)+1的结果).

  3. 0x640

  4. ra保存的是函数调用后返回的地址,由下图可以看出为0x38

  5. He110 World(本人的机器是小端的,所以是这个输入,如果是大端的,输出则不一样)

    unsigned int i = 0x00646c72;
    printf("H%x Wo%s", 57616, &i);
    
  6. y的输出结果为0,保存的是a2寄存器中的值。

    printf("x=%d y=%d", 3);
    

Backtrace

该题的主要目的是打印当前进程的调用链,为实现该函数,我们首先需要了解栈的分布情况,如下图所示:

  1. stack地址从高到低进行增长;
  2. sp: 指向栈的最底端;
  3. fp: 当前栈帧的顶端;
  4. return address是地址是fp-8
  5. prev frame fp保存地址是fp-16

按照实验提示进行代码更改:

  1. kernel/defs.h,添加头文件。

    // printf.c
    void            printf(char*, ...);
    void            panic(char*) __attribute__((noreturn));
    void            printfinit(void);
    // begin++++
    void            backtrace(void);
    // end------
    
  2. kernel/syspro.c,在函数sys_sleep中添加调用

    uint64
    sys_sleep(void)
    {int n;uint ticks0;// begin+++++backtrace();// end-------if(argint(0, &n) < 0)return -1;acquire(&tickslock);ticks0 = ticks;while(ticks - ticks0 < n){if(myproc()->killed){release(&tickslock);return -1;}sleep(&ticks, &tickslock);}release(&tickslock);return 0;
    }
    
  3. kernel/riscv.h文件中,添加如下函数,该函数的主要作用是从s0寄存器读取数值。(gcc编译器将当前正在执行函数的栈帧指针保存在s0寄存器中)

    static inline uint64
    r_fp()
    {uint64 x;asm volatile("mv %0, s0" : "=r" (x) );return x;
    }
    
  4. kernel/printf.c文件中,添加如下函数:

    
    void
    backtrace(void)
    {// 获取栈帧首地址uint64 fpaddr = r_fp();// 获取当前进程在kernel中stack的最大地址uint64 max = PGROUNDUP(fpaddr);// 因为栈是从高地址至低地址增长的,所以这里用小于号判断while (fpaddr < max) { // return address是当前fp-8printf("%p\n", *((uint64*)(fpaddr - 8)));// 调用该函数的栈帧便宜是fp - 16fpaddr = *((uint64*)(fpaddr - 16));}
    }
    
  5. kernel/printf.c文件中,在函数panic中添加对backtrace的调用:

    void
    panic(char *s)
    {// begin+++++  backtrace();// end+++++++  pr.locking = 0;printf("panic: ");printf(s);printf("\n");panicked = 1; // freeze uart output from other CPUsfor(;;);
    }
    
  6. 运行结果:


Alarm

该题的主要目的是让我们增加一个系统调用,该系统调用会在指定时间间隔后调用用户态的函数,因此需要我们对内核态的相关状态进行保存。按照实验提示一步一步来即可。涉及修改的文件如何所示:

  1. Makefile文件,增加如下代码:

    +       $U/_alarmtest\
    
  2. 文件kernel/proc.h文件

    struct proc {.... struct file *ofile[NOFILE];  // Open filesstruct inode *cwd;           // Current directorychar name[16];               // Process name // begin+++++++ int alarmticks; // ticks intervaluint64 alarmhandler; // function to handler alarmint tickspass;struct trapframe * alarmtrapframe;int accessable;// end+++++++
    }
  3. 文件Kernel/proc.c,在函数allproc中增加如下内容:

    static struct proc*
    allocproc(void)
    {......   // Allocate a trapframe page.// begin++++++if((p->alarmtrapframe = (struct trapframe *)kalloc()) == 0){release(&p->lock);return 0;}p->tickspass = 0;p->alarmticks = 0;p->alarmhandler = 0;p->accessable = 1;return p;// end++++++
    }
    
  4. 文件Kernel/proc.c,在函数freeproc中增加如下内容:

     // begin++++ if(p->alarmtrapframe)kfree((void*)p->alarmtrapframe);p->alarmtrapframe=0;// end+++++
    
  5. 在文件kernel/syscall.h中,增加如下内容

    // begin++++
    #define SYS_sigalarm 22
    #define SYS_sigreturn 23
    // end++++
    
  6. 在文件kernel/syscall.c中,增加如下内容

     ....extern uint64 sys_wait(void);extern uint64 sys_write(void);extern uint64 sys_uptime(void);// begin++++extern uint64 sys_sigalarm(void);extern uint64 sys_sigreturn(void);// end++++...
    static uint64 (*syscalls[])(void) = {....    //begin++++[SYS_sigalarm] sys_sigalarm,[SYS_sigreturn] sys_sigreturn,
    }// end+++++
  7. 在文件kernel/syproc.c中,增加两个系统调用函数

    uint64
    sys_sigalarm(void)
    {int ticks = 0;uint64 alarmhandler = 0;if(argint(0, &ticks) < 0 || argaddr(1, &alarmhandler) < 0)return -1;struct proc *p = myproc();p->alarmticks = ticks;p->alarmhandler = alarmhandler;p->tickspass = 0;p->accessable = 1;return 0;
    }uint64
    sys_sigreturn(void)
    {struct proc *p = myproc();// 恢复系统调用时用户的栈帧if (0 == p->accessable) {memmove(p->trapframe, p->alarmtrapframe, sizeof(struct  trapframe));p->accessable = 1;}return 0;
    }
    
  8. 在kernel/trap.c文件的usertrap函数中,改为如下内容:

      // give up the CPU if this is a timer interrupt.if(which_dev == 2) {p->tickspass++;if (p->alarmticks != 0 && p->tickspass == p->alarmticks) {// return to user space to call the alarm functionp->tickspass = 0;if (p->accessable == 1) {memmove(p->alarmtrapframe, p->trapframe, sizeof(struct trapframe));p->trapframe->epc = p->alarmhandler;p->accessable = 0;}} else {yield();}}
    
  9. 在文件user/user.h中,添加如下内容:

    int sigalarm(int ticks, void (*handler)());
    int sigreturn(void);
    
  10. 在文件user/usys.pl中,添加如下内容:

    entry("sigalarm");
    entry("sigreturn");
    
  11. 查看结果


提交结果

$ git commit -m "lab page tabls"
$ make handin

查看结果

登录网站https://6828.scripts.mit.edu/2020/handin.py/student,可以看到提交的结果。


课程涉及知识汇总

寄存器

  1. RISC-V有32个用户寄存器,用户可以使用全部的寄存器。
  2. 通过系统调用从用户态转到内核态时,相关系统调用的参数,可以通过a0至a7寄存器进行传递。通过调试我们发现:
    1. a7一般用来保存系统调用函数的编号;
    2. a0-a6可用来保存用户传递给系统调用的参数;
    3. a0也用来保存系统调用之后的返回结果;
  3. STVEC:在内核态的时候,指向的是内核的trap代码位置,在用户态的时候,应该指向用户的trap代码位置;
  4. SEPC: 内核的程序计算器
  5. 任何需要进行编译的语言(例如C语言),都不能修改用户寄存器。因此,用户寄存器必须在汇编代码中保存。
  6. SSTATUS:控制寄存器,本次课程中用到了其中的两个bit
    1. SPP:代表sret指令的行为,为0表示我们要进入用户态,为1表示我们要进入特权态();
    2. SPIE:代表是否打开中断,为0表示关闭,为1表示打开

page table

  1. trapframe page和trampoline page这两个页的PTE_U都为0,表示用户不能访问,只有进入supervisor mode才能访问;

指令

  1. ecall:该命令会将控制权由用户转到内核。执行该指令时,并不会切换page table

GDB

  1. tui enable可以打开对应的C语言代码;

Trapline

  1. 由内核映射在各个进程和内核空间的的代码;
  2. 该代码涉及到的功能有
    1. 将用户寄存器的值保存至trapframe对应字段;

Trapframe

  1. 保存用户态和内核态切换时的上下文信息,主要包含相关寄存器的值以及内核page table,内核stack的顶部指针,usertrap代码位置,程序计数器等相关信息,具体可参考文件的kernel/proc.h中的trapframe结构体。

常用命令

  1. ctrl + a c,进入qemu的console页面;

    1. 在console页面,输入info mem,可以打印当前的page table。

参考链接


Github

https://github.com/aerfalwl/mit-xv6-labs-2020.git

2020 mit6.s081 os Lab: xv6 traps相关推荐

  1. 2020 MIT6.s081 os Lab: page tables

    文章目录 实验链接 Print a page table A kernel page table per process Simplify 实验结果 提交实验 查看结果 参考链接 github地址 友 ...

  2. OS Lab 【Traps】

    一.实验内容: Part A RISC-V assembly 见问题回答 Part B Backtrace Add the prototype for your backtrace() to kern ...

  3. 2020 MIT6.s081 XV6操作系统调试

    文章目录 环境准备 启动调试 调试步骤 gdb layout GDB调试常用命令 参考链接 友情链接:全部实验哟 环境准备 操作系统:本人采用的操作系统版本为Ubuntu 20.04.2 LTS # ...

  4. MIT6.S081学习总结-lab4:traps

    lab4 是traps相关 Backtrace 添加一个backtrace函数,sys_sleep调用这个函数后可以打印出函数调用栈 实现: kernel/riscv.h里添加函数来获取frame p ...

  5. 操作系统MIT6.S081:[xv6参考手册第4章]->Trap与系统调用

    本系列文章为MIT6.S081的学习笔记,包含了参考手册.课程.实验三部分的内容,前面的系列文章链接如下 操作系统MIT6.S081:[xv6参考手册第1章]->操作系统接口 操作系统MIT6. ...

  6. MIT6.S081 2021 Copy-on-Write Fork for xv6

    MIT6.S081 2021 Copy-on-Write Fork for xv6 简要介绍 debug 代码参考 简要介绍 There is a saying in computer systems ...

  7. Mit6.S081学习记录

    Mit6.S081学习记录 前言 一.课程简述 二.课程资源 1,课程主页 2,参考书 3,实验环境 三.学习过程 Mit6.S081-实验环境搭建 Mit6.S081-GDB使用 Mit6.S081 ...

  8. MIT6.S081 2021

    MIT6.S081 2021 环境配置 Xv6 and Unix utilities vscode格式化头文件排序问题 以地址空间的视角看待变量 其他 代码参考 system calls trace ...

  9. 操作系统MIT6.S081:P7->Interrupts

    本系列文章为MIT6.S081的学习笔记,包含了参考手册.课程.实验三部分的内容,前面的系列文章链接如下 操作系统MIT6.S081:[xv6参考手册第1章]->操作系统接口 操作系统MIT6. ...

  10. 操作系统MIT6.S081:Lab4->Trap

    本系列文章为MIT6.S081的学习笔记,包含了参考手册.课程.实验三部分的内容,前面的系列文章链接如下 操作系统MIT6.S081:[xv6参考手册第1章]->操作系统接口 操作系统MIT6. ...

最新文章

  1. 这些HTML、CSS知识点,面试和平时开发都需要 No10-No11
  2. Windows CE 程序设计 (3rd 版)
  3. 四则运算APP最后阶段
  4. 数字图像处理:第九章 线性系统、卷积、傅立叶变换
  5. Find First and Last Position of Element in Sorted Array
  6. OpenShift 4 - 通过Maven镜像加速Java应用构建速度
  7. 安装python扩展库时只能使用pip_使用pip安装Python扩展库的方法
  8. 德鲁伊 oltp oltp_内存中OLTP –更快变得更简单!
  9. 用tbody解决div在table标签里无法隐藏某些行
  10. 述职答辩提问环节一般可以问些什么_陕西省高级职称评审,90%的人都“死”在答辩上?...
  11. linux安装python3环境_linux安装python3环境并配置虚拟环境
  12. P3110 [USACO14DEC]驮运Piggy Back
  13. PPT超链接字体颜色修改方法
  14. 软件工程文档——步骤流程图
  15. 一文道尽JavaScript 20年的发展史
  16. SEO网站优化基础解决方案[快速入门]
  17. 线性代数笔记-线性空间和矩阵复习
  18. Grafana变量介绍
  19. Csapp 第三章阅读以及思考
  20. 计算机应用能力考试有几科,全国专业技术人员计算机应用能力考试科目(模块)设置有哪些?...

热门文章

  1. 便利店收银系统多少钱一套
  2. 计算机运行命令jar,jar文件打开教程
  3. [前端代码] 3月2日更新-近期200+热门微信小程序demo源码下载汇总
  4. java jdbc sqlerver_SQLServer2000的JDBC驱动
  5. java 使用的钩子_Java 钩子程序
  6. 2010年的读书计划
  7. 使用Pytorch来拟合函数
  8. 最新投影圣经投影赞美诗歌圣经诗歌2020
  9. 计算机专业有关电路的书,计算机专业电路基础试题.doc
  10. java 学习资料总结