2020 mit6.s081 os Lab: xv6 traps
文章目录
- 实验链接
- 实验
- 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
a0-a7,13保存在a2里
函数f和g直接被内联优化了,即printf的第2个参数直接是12(f(8)+1的结果).
0x640
ra保存的是函数调用后返回的地址,由下图可以看出为0x38
He110 World(本人的机器是小端的,所以是这个输入,如果是大端的,输出则不一样)
unsigned int i = 0x00646c72; printf("H%x Wo%s", 57616, &i);
y的输出结果为0,保存的是a2寄存器中的值。
printf("x=%d y=%d", 3);
Backtrace
该题的主要目的是打印当前进程的调用链,为实现该函数,我们首先需要了解栈的分布情况,如下图所示:
stack
地址从高到低进行增长;sp
: 指向栈的最底端;fp
: 当前栈帧的顶端;return address
是地址是fp-8
prev frame fp
保存地址是fp-16
按照实验提示进行代码更改:
kernel/defs.h,添加头文件。
// printf.c void printf(char*, ...); void panic(char*) __attribute__((noreturn)); void printfinit(void); // begin++++ void backtrace(void); // end------
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; }
kernel/riscv.h文件中,添加如下函数,该函数的主要作用是从
s0
寄存器读取数值。(gcc编译器将当前正在执行函数的栈帧指针保存在s0寄存器中)static inline uint64 r_fp() {uint64 x;asm volatile("mv %0, s0" : "=r" (x) );return x; }
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));} }
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(;;); }
运行结果:
Alarm
该题的主要目的是让我们增加一个系统调用,该系统调用会在指定时间间隔后调用用户态的函数,因此需要我们对内核态的相关状态进行保存。按照实验提示一步一步来即可。涉及修改的文件如何所示:
Makefile文件,增加如下代码:
+ $U/_alarmtest\
文件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+++++++ }
文件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++++++ }
文件Kernel/proc.c,在函数freeproc中增加如下内容:
// begin++++ if(p->alarmtrapframe)kfree((void*)p->alarmtrapframe);p->alarmtrapframe=0;// end+++++
在文件kernel/syscall.h中,增加如下内容
// begin++++ #define SYS_sigalarm 22 #define SYS_sigreturn 23 // end++++
在文件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+++++
在文件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; }
在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();}}
在文件user/user.h中,添加如下内容:
int sigalarm(int ticks, void (*handler)()); int sigreturn(void);
在文件user/usys.pl中,添加如下内容:
entry("sigalarm"); entry("sigreturn");
查看结果
提交结果
$ git commit -m "lab page tabls"
$ make handin
查看结果
登录网站https://6828.scripts.mit.edu/2020/handin.py/student
,可以看到提交的结果。
课程涉及知识汇总
寄存器
- RISC-V有32个用户寄存器,用户可以使用全部的寄存器。
- 通过系统调用从用户态转到内核态时,相关系统调用的参数,可以通过a0至a7寄存器进行传递。通过调试我们发现:
- a7一般用来保存系统调用函数的编号;
- a0-a6可用来保存用户传递给系统调用的参数;
- a0也用来保存系统调用之后的返回结果;
- STVEC:在内核态的时候,指向的是内核的trap代码位置,在用户态的时候,应该指向用户的trap代码位置;
- SEPC: 内核的程序计算器
- 任何需要进行编译的语言(例如C语言),都不能修改用户寄存器。因此,用户寄存器必须在汇编代码中保存。
- SSTATUS:控制寄存器,本次课程中用到了其中的两个bit
- SPP:代表sret指令的行为,为0表示我们要进入用户态,为1表示我们要进入特权态();
- SPIE:代表是否打开中断,为0表示关闭,为1表示打开
page table
- trapframe page和trampoline page这两个页的
PTE_U
都为0,表示用户不能访问,只有进入supervisor mode才能访问;
指令
- ecall:该命令会将控制权由用户转到内核。执行该指令时,并不会切换page table
GDB
tui enable
可以打开对应的C语言代码;
Trapline
- 由内核映射在各个进程和内核空间的的代码;
- 该代码涉及到的功能有
- 将用户寄存器的值保存至trapframe对应字段;
Trapframe
- 保存用户态和内核态切换时的上下文信息,主要包含相关寄存器的值以及内核
page table
,内核stack
的顶部指针,usertrap
代码位置,程序计数器等相关信息,具体可参考文件的kernel/proc.h
中的trapframe
结构体。
常用命令
ctrl + a c
,进入qemu的console页面;- 在console页面,输入
info mem
,可以打印当前的page table。
- 在console页面,输入
参考链接
Github
https://github.com/aerfalwl/mit-xv6-labs-2020.git
2020 mit6.s081 os Lab: xv6 traps相关推荐
- 2020 MIT6.s081 os Lab: page tables
文章目录 实验链接 Print a page table A kernel page table per process Simplify 实验结果 提交实验 查看结果 参考链接 github地址 友 ...
- OS Lab 【Traps】
一.实验内容: Part A RISC-V assembly 见问题回答 Part B Backtrace Add the prototype for your backtrace() to kern ...
- 2020 MIT6.s081 XV6操作系统调试
文章目录 环境准备 启动调试 调试步骤 gdb layout GDB调试常用命令 参考链接 友情链接:全部实验哟 环境准备 操作系统:本人采用的操作系统版本为Ubuntu 20.04.2 LTS # ...
- MIT6.S081学习总结-lab4:traps
lab4 是traps相关 Backtrace 添加一个backtrace函数,sys_sleep调用这个函数后可以打印出函数调用栈 实现: kernel/riscv.h里添加函数来获取frame p ...
- 操作系统MIT6.S081:[xv6参考手册第4章]->Trap与系统调用
本系列文章为MIT6.S081的学习笔记,包含了参考手册.课程.实验三部分的内容,前面的系列文章链接如下 操作系统MIT6.S081:[xv6参考手册第1章]->操作系统接口 操作系统MIT6. ...
- 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 ...
- Mit6.S081学习记录
Mit6.S081学习记录 前言 一.课程简述 二.课程资源 1,课程主页 2,参考书 3,实验环境 三.学习过程 Mit6.S081-实验环境搭建 Mit6.S081-GDB使用 Mit6.S081 ...
- MIT6.S081 2021
MIT6.S081 2021 环境配置 Xv6 and Unix utilities vscode格式化头文件排序问题 以地址空间的视角看待变量 其他 代码参考 system calls trace ...
- 操作系统MIT6.S081:P7->Interrupts
本系列文章为MIT6.S081的学习笔记,包含了参考手册.课程.实验三部分的内容,前面的系列文章链接如下 操作系统MIT6.S081:[xv6参考手册第1章]->操作系统接口 操作系统MIT6. ...
- 操作系统MIT6.S081:Lab4->Trap
本系列文章为MIT6.S081的学习笔记,包含了参考手册.课程.实验三部分的内容,前面的系列文章链接如下 操作系统MIT6.S081:[xv6参考手册第1章]->操作系统接口 操作系统MIT6. ...
最新文章
- 这些HTML、CSS知识点,面试和平时开发都需要 No10-No11
- Windows CE 程序设计 (3rd 版)
- 四则运算APP最后阶段
- 数字图像处理:第九章 线性系统、卷积、傅立叶变换
- Find First and Last Position of Element in Sorted Array
- OpenShift 4 - 通过Maven镜像加速Java应用构建速度
- 安装python扩展库时只能使用pip_使用pip安装Python扩展库的方法
- 德鲁伊 oltp oltp_内存中OLTP –更快变得更简单!
- 用tbody解决div在table标签里无法隐藏某些行
- 述职答辩提问环节一般可以问些什么_陕西省高级职称评审,90%的人都“死”在答辩上?...
- linux安装python3环境_linux安装python3环境并配置虚拟环境
- P3110 [USACO14DEC]驮运Piggy Back
- PPT超链接字体颜色修改方法
- 软件工程文档——步骤流程图
- 一文道尽JavaScript 20年的发展史
- SEO网站优化基础解决方案[快速入门]
- 线性代数笔记-线性空间和矩阵复习
- Grafana变量介绍
- Csapp 第三章阅读以及思考
- 计算机应用能力考试有几科,全国专业技术人员计算机应用能力考试科目(模块)设置有哪些?...