第一部分 RISC-V assembly 阅读汇编

相关的C代码:

#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"int g(int x) {return x+3;
}int f(int x) {return g(x);
}void main(void) {printf("%d %d\n", f(8)+1, 13);exit(0);
}

相关的汇编代码:

0000000000000000 <g>:
#include "kernel/param.h"
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"int g(int x) {0:    1141                    addi    sp,sp,-162: e422                    sd  s0,8(sp)4:  0800                    addi    s0,sp,16return x+3;
}6: 250d                    addiw   a0,a0,38:   6422                    ld  s0,8(sp)a:  0141                    addi    sp,sp,16c:  8082                    ret000000000000000e <f>:int f(int x) {e:  1141                    addi    sp,sp,-1610:    e422                    sd  s0,8(sp)12: 0800                    addi    s0,sp,16return g(x);
}14:    250d                    addiw   a0,a0,316:  6422                    ld  s0,8(sp)18: 0141                    addi    sp,sp,161a: 8082                    ret000000000000001c <main>:void main(void) {1c:   1141                    addi    sp,sp,-161e:    e406                    sd  ra,8(sp)20: e022                    sd  s0,0(sp)22: 0800                    addi    s0,sp,16printf("%d %d\n", f(8)+1, 13);24:    4635                    li  a2,1326:    45b1                    li  a1,1228:    00000517            auipc   a0,0x02c:   7b050513            addi    a0,a0,1968 # 7d8 <malloc+0xea>30:    00000097            auipc   ra,0x034:   600080e7            jalr    1536(ra) # 630 <printf>exit(0);38:    4501                    li  a0,03a: 00000097            auipc   ra,0x03e:   27e080e7            jalr    638(ra) # 2b8 <exit>

问题:

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

24: 4635 li a2,13可以看出来13存储在a2寄存器,相应地,前两个参数分别寄存在a0和a1。

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.)

编译器把函数优化成inline的,主函数中对f的调用直接被优化成了li a1,12

At what address is the function printf located?

jalr 1536(ra) # 630 <printf>0000000000000630 <printf>:

Run the following code.
What is the output? Here’s an ASCII table that maps bytes to characters.

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

57616的16进制是e110

ascii码对照:

2进制 10进制 16进制 字符
0111 0010 114 72 r
0110 1100 108 6c l
0110 0100 100 64 d

综上,打印结果为He110 World

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);

%d的取值取决于a2寄存器的值,如果没有设置,该值可能是随机的。


第二部分 Backtrace 回溯

大概意思是回溯打印函数调用栈中的返回地址(即发生函数调用的地址)

Implement a backtrace() function in kernel/printf.c. Insert a call to this function in sys_sleep, and then run bttest, which calls sys_sleep. Your output should be as follows:

backtrace:
0x0000000080002cda
0x0000000080002bb6
0x0000000080002898

After bttest exit qemu. In your terminal: the addresses may be slightly different but if you run addr2line -e kernel/kernel (or riscv64-unknown-elf-addr2line -e kernel/kernel) and cut-and-paste the above addresses as follows:

$ addr2line -e kernel/kernel
0x0000000080002de2
0x0000000080002f4a
0x0000000080002bfc
Ctrl-D

You should see something like this:

kernel/sysproc.c:74
kernel/syscall.c:224
kernel/trap.c:85

上代码,首先在risv.h中添加从寄存器中读取当前fp指针的函数

static inline uint64
r_fp()
{uint64 x;asm volatile("mv %0, s0" : "=r" (x) );return x;
}

printf.c中添加backtrace函数

void backtrace(void)
{uint64 fp = r_fp();uint64 upbound = PGROUNDUP(fp);while (fp < upbound) {printf("%p\n", *(uint64*)(fp - 8));fp = *(uint64*)(fp - 16);}}

之后在defs.h添加函数声明。最后在sys_sleep函数(sysproc.c)中调用backtrace函数。即可编译运行测试。

hart 1 starting
hart 2 starting
init: starting sh
$ bttest
0x00000000800020cc
0x0000000080001fa6
0x0000000080001c90

第三部分 Alarm (hard)

In this exercise you’ll add a feature to xv6 that periodically alerts a process as it uses CPU time. This might be useful for compute-bound processes that want to limit how much CPU time they chew up, or for processes that want to compute but also want to take some periodic action. More generally, you’ll be implementing a primitive form of user-level interrupt/fault handlers; you could use something similar to handle page faults in the application, for example. Your solution is correct if it passes alarmtest and usertests.

首先编写系统调用

uint64 sys_sigalarm(void) {int interval;if (argint(0, &interval) < 0) {return -1;}void (*fn) (void);if (argaddr(1, (uint64*)&fn) < 0) {return -1;}struct proc *p = myproc();// 如果传入两个0,清空if (interval == 0 && fn == 0) {p->interval = -1;p->tiktok = 0;return 0;}// 保存间隔时间,保存函数指针,计时为0p->interval = interval;p->fn = fn;p->tiktok = 0;return 0;
}// 恢复系统调用,恢复之前保存下来的寄存器(在trap.c中保存的)
uint64 sys_sigreturn(void) {struct proc *p = myproc();p->trapframe->epc = p->pc2;p->trapframe->s0 = p->s0_2;p->trapframe->ra = p->ra;p->trapframe->sp = p->sp;p->flag = 0; // 清空flag,指示当前可以重入handler函数p->trapframe->a0 = p->a0;p->trapframe->a1 = p->a1;p->trapframe->a2 = p->a2;p->trapframe->a3 = p->a3;···// printf("%p\n", p->trapframe->epc);return 0;
};

修改proc.h中的结构体定义

// Per-process state
struct proc {struct spinlock lock;// p->lock must be held when using these:enum procstate state;        // Process statevoid *chan;                  // If non-zero, sleeping on chanint killed;                  // If non-zero, have been killedint xstate;                  // Exit status to be returned to parent's waitint pid;                     // Process ID// wait_lock must be held when using this:struct proc *parent;         // Parent process// these are private to the process, so p->lock need not be held.uint64 kstack;               // Virtual address of kernel stackuint64 sz;                   // Size of process memory (bytes)pagetable_t pagetable;       // User page tablestruct trapframe *trapframe; // data page for trampoline.Sstruct context context;      // swtch() here to run processstruct file *ofile[NOFILE];  // Open filesstruct inode *cwd;           // Current directorychar name[16];               // Process name (debugging)// 需要保持的寄存器int interval;int tiktok;uint64 pc2;uint64 s0_2;uint64 sp;uint64 ra;uint64 a0;uint64 a1;uint64 a2;uint64 a3;···// 需要新增的字段int flag; // 是否正在处理handler函数void (*fn)(void); // handler函数指针
};

修改trap.c

void
usertrap(void)
{···// give up the CPU if this is a timer interrupt. 如果是tick中断if(which_dev == 2) {if (p->interval != -1) { // 如果计时器激活p->tiktok += 1; // 计时加1}yield();}usertrapret();
}//
// return to user space
//
void
usertrapret(void)
{struct proc *p = myproc();···// set S Exception Program Counter to the saved user pc.// 如果计时器到时,且flag为0(flag指示当时是否在handler过程中)if (p->tiktok == p->interval && p->flag != 1) {// printf("%p %p\n", p->fn, p->trapframe->ra);// printf("%p %p\n", p->trapframe->epc, p->trapframe->ra);// 保存寄存器p->pc2 = p->trapframe->epc;p->s0_2 = p->trapframe->s0;p->ra = p->trapframe->ra;p->sp = p->trapframe->sp;p->a0 = p->trapframe->a0;p->a1 = p->trapframe->a1;p->a2 = p->trapframe->a2;p->a3 = p->trapframe->a3;···p->flag = 1;// printf("%p\n", p->trapframe->epc);// printf("%p\n", p->pc2);// 将epc指向fn函数的起始地址p->trapframe->epc = (uint64)(p->fn);// tiktok置零p->tiktok = 0;}w_sepc(p->trapframe->epc);// tell trampoline.S the user page table to switch to.uint64 satp = MAKE_SATP(p->pagetable);// jump to trampoline.S at the top of memory, which // switches to the user page table, restores user registers,// and switches to user mode with sret.uint64 fn = TRAMPOLINE + (userret - trampoline);((void (*)(uint64,uint64))fn)(TRAPFRAME, satp);
}

测试结果,全部通过

(base) zhaokanglun@GANBADEI:~/s081/xv6-labs-2021$ make qemu
qemu-system-riscv64 -machine virt -bios none -kernel kernel/kernel -m 128M -smp 3 -nographic -drive file=fs.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0xv6 kernel is bootinghart 1 starting
hart 2 starting
init: starting sh
$ alarmtest
test0 start
.....................................alarm!
test0 passed
test1 start
......alarm!
.....alarm!
......alarm!
.....alarm!
....alarm!
.....alarm!
........alarm!
......alarm!
......alarm!
.....alarm!
.test1 passed
test2 start
..................................................................alarm!
test2 passed
$

6.S081 Lab4 Traps相关推荐

  1. MIT 6.S081 Lab4 traps

    #Lab4: traps #Source #My Code #Motivation #Backtrace (moderate) #Motivation #Solution #S0 - RISC-V 栈 ...

  2. 6.S081 lab4: traps

    1. 写在前面   感觉这个lab给我最大的收获就是:不加参数的cat,用ctrl+D退出(笑).之前用cat的时候忘了写参数然后就陷入cat的循环里去了,不知道怎么退出,就只好强行关掉shell.另 ...

  3. xv6 6.S081 Lab4: lazy

    xv6 6.S081 Lab4: lazy 写在前面 实验介绍 开始! 打印页表 实现Lazy Allocation 修改sbrk() 实现Lazy Allocation 完善Lazy Allocat ...

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

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

  5. MIT6.S081 2021

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

  6. xv6---Lab4 traps

    参考: Lab: Traps 关于寄存器s0和堆栈 https://pdos.csail.mit.edu/6.828/2020/lec/l-riscv-slides.pdf RISC-V assemb ...

  7. mit 6.s081

    简介 xv6-book chapter1 Operating system interfaces chapter2 Operating system organization Code:startin ...

  8. XV6实验(2020)

    XV6实验记录(2020) 环境搭建 参考连接 Lab guidance (mit.edu) 6.S081 / Fall 2020 (mit.edu) xv6 book中文版 Lab1:Xv6 and ...

  9. 6.S081-6缺页异常 - lazy allocation - Page Fault

    6.S081-6缺页异常Page Fault 这一节课,可以帮我们完成2个实验: 题目要求链接:Lab: xv6 lazy page allocation 对应做法链接:6.S081 Lab4 Laz ...

最新文章

  1. Android特色开发之Google MAP
  2. java 服务器发布_我如何在java中发布到服务器?
  3. 撤回的微信消息真的看不到?78行Python代码帮你看穿一切!
  4. 极简静态 Web 服务器
  5. 最新信恒第四方支付系统源码+服务器直接打包
  6. 免费领,单片机入门到高级进阶学习攻略(附教程+工具)
  7. 28Python库分析科比生涯数据
  8. 奥拉星插件flash下载手机版下载安装_flash插件
  9. java中的terminated_解决maven build 无反应,直接terminated的问题
  10. VUE3 响应式 API 之 toRef 与 toRefs
  11. Accuracy and precision 意义
  12. 前端国密加解密使用方法SM2、SM3、SM4
  13. Pytorch中rand,randn, random以及normal的区别
  14. 关闭xshell6提示音
  15. 5G的工业应用场景梳理
  16. 广播(broadcast)的简单解析与实例运用
  17. ym——Andorid-15k+的面试题。
  18. DELL EqualLogic PS4000服务器硬盘坏道修复过程
  19. 5款免费在线软件行为分析(在线沙盘)
  20. 小米路由器青春版中继模式后登陆

热门文章

  1. uboot start.S分析
  2. 数据分析——泰坦尼克号预测
  3. 联想t450进入bios设置按哪个键_ThinkPad笔记本电脑如何设置Fn热键切换功能
  4. 通信工程专业就业方向
  5. 重庆邮电大学计算机科学与技术调剂,重庆邮电大学接收硕士生预调剂
  6. 【mxGraph】源码学习:(5)mxGraph
  7. 世界标准时间yyyy-MM-dd‘T‘HH:mm:ss.SSSXXX详解
  8. 【MATLAB】数值计算:计算黄金分割比的N种方法
  9. 相机的 高清到底是一个什么东西
  10. 对IDEA中断点Suspend 属性理解