MIT 6.S081 Lab traps

Compulsory exercises

Preparation

  • reading
  • To start the lab, switch to the trap branch
1
2
3
git fetch
git checkout traps
make clean

RISC-V assembly (easy)

  • Which registers contain arguments to functions? For example, which register holds 13 in main’s call to printf?
    • a0-a1 a2-a7; a2
  • 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.)
    • f in printf 0x34 , g in f 0x14
  • At what address is the function printf located?
    • 0x630
  • What value is in the register ra just after the jalr to printf in main?
    • 0x38
  • Run the following code.
1
2
unsigned int i = 0x00646c72;
printf("H%x Wo%s", 57616, &i);
  • What is the output?
    • 注意字节序是小端序
    • He110 World
  • 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?
    • i = 0x72646c00 -> “ord\0”
    • no
  • In the following code, what is going to be printed after ‘y=’? (note: the answer is not a specific value.) Why does this happen?
1
printf("x=%d y=%d", 3);
  • x=3 y=寄存器a2的十进制值,因为在printf没有传入第三个参数,a2没有被更新,因此直接把原来a2的值传入

Backtrace (moderate)

  • 该任务是打印出错堆栈前的所有返回地址ra

  • Implement a backtrace() function in kernel/printf.c

  • 添加定义和内联函数(内核中)

defs.h //printf.c
1
void            backtrace(void);
riscv.h
1
2
3
4
5
6
7
8
// store frame pointer
static inline uint64
r_fp()
{
uint64 x;
asm volatile("mv %0, s0" : "=r" (x) );
return x;
}
  • 注意ra在fp-8处,上一个fp在fp-16处

  • 使用riscv中的宏定义PGROUNDDOWN(fp)和PGROUNDUP(fp)确定循环终止条件

  • 实现backtrace()

kernel/printf.c
1
2
3
4
5
6
7
8
9
10
11
12
13
void backtrace(void)
{
printf("backtrace:\n");
uint64 fp = r_fp();
uint64 start = PGROUNDDOWN(fp);
uint64 end = PGROUNDUP(fp);

while (start <= fp && fp <= end) {
uint64 ra = *(uint64*)(fp - 8);
fp = *(uint64*)(fp - 16);
printf("%p\n", ra);
}
}
  • 添加至sys_sleep()和panic()

sysproc.c
1
backtrace();
kernel/printf.c panic()
1
backtrace();

Alarm (hard)

  • 添加系统调用在计时器中断时打印alarm

  • test0: invoke handler

  • 修改proc.h

proc.h struct proc
1
2
3
int ticks;
uint64 handler;
int gonetick;
  • 需要完成sigalarm系统调用,并且添加sigreturn系统调用(空)

sysproc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
uint64
sys_sigalarm(void)
{
int ticks;
uint64 handler;
if (argint(0, &ticks) < 0)
return -1;
if (argaddr(1, &handler) < 0)
return -1;

struct proc* p = myproc();
p->ticks = ticks;
p->handler = handler;

return 0;
}

uint64
sys_sigreturn(void)
{
//test0
return 0;
}
  • 修改usertrap()

trap.c usertrap()
1
2
3
4
5
6
7
8
//test0
if(which_dev == 2) {
p->gonetick += 1;
if (p->ticks_pass % p->ticks == 0) {
p->trapframe->epc = p->handler;
}
yield();
}
  • test1/test2(): resume interrupted code

  • test0尚未完成返回,因此程序在alarm后崩溃,需要补全sigreturn

  • 修改proc.h用于保存alarm时的寄存器信息,inhandler防止函数被多次调用

  • 需要初始化的参数可以通过allocproc()初始化

proc.h struct proc >folded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
int ticks;
uint64 handler;
int gonetick;
int inhandler;

/* 40 */ uint64 ra;
/* 48 */ uint64 sp;
/* 56 */ uint64 gp;
/* 64 */ uint64 tp;
/* 72 */ uint64 t0;
/* 80 */ uint64 t1;
/* 88 */ uint64 t2;
/* 96 */ uint64 s0;
/* 104 */ uint64 s1;
/* 112 */ uint64 a0;
/* 120 */ uint64 a1;
/* 128 */ uint64 a2;
/* 136 */ uint64 a3;
/* 144 */ uint64 a4;
/* 152 */ uint64 a5;
/* 160 */ uint64 a6;
/* 168 */ uint64 a7;
/* 176 */ uint64 s2;
/* 184 */ uint64 s3;
/* 192 */ uint64 s4;
/* 200 */ uint64 s5;
/* 208 */ uint64 s6;
/* 216 */ uint64 s7;
/* 224 */ uint64 s8;
/* 232 */ uint64 s9;
/* 240 */ uint64 s10;
/* 248 */ uint64 s11;
/* 256 */ uint64 t3;
/* 264 */ uint64 t4;
/* 272 */ uint64 t5;
/* 280 */ uint64 t6;

uint64 epc;
  • 完成sigreturn系统调用

sysproc.c >folded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
uint64
sys_sigalarm(void)
{
int ticks;
uint64 handler;
if (argint(0, &ticks) < 0)
return -1;
if (argaddr(1, &handler) < 0)
return -1;

struct proc* p = myproc();
p->ticks = ticks;
p->handler = handler;

return 0;
}

uint64
sys_sigreturn(void)
{
//test12
struct proc* p = myproc();
p->trapframe->ra = p->ra;
p->trapframe->sp = p->sp;
p->trapframe->gp = p->gp;
p->trapframe->tp = p->tp;
p->trapframe->t0 = p->t0;
p->trapframe->t1 = p->t1;
p->trapframe->t2 = p->t2;
p->trapframe->s0 = p->s0;
p->trapframe->s1 = p->s1;
p->trapframe->a0 = p->a0;
p->trapframe->a1 = p->a1;
p->trapframe->a2 = p->a2;
p->trapframe->a3 = p->a3;
p->trapframe->a4 = p->a4;
p->trapframe->a5 = p->a5;
p->trapframe->a6 = p->a6;
p->trapframe->a7 = p->a7;
p->trapframe->s2 = p->s2;
p->trapframe->s3 = p->s3;
p->trapframe->s4 = p->s4;
p->trapframe->s5 = p->s5;
p->trapframe->s6 = p->s6;
p->trapframe->s7 = p->s7;
p->trapframe->s8 = p->s8;
p->trapframe->s9 = p->s9;
p->trapframe->s10 = p->s10;
p->trapframe->s11 = p->s11;
p->trapframe->t3 = p->t3;
p->trapframe->t4 = p->t4;
p->trapframe->t5 = p->t5;
p->trapframe->t6 = p->t6;

p->trapframe->epc = p->epc;
p->inhandler = 0;
return 0;
}
  • 修改usertrap()

trap.c usertrap() >folded
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//test12
if(which_dev == 2 && p->inhandler == 0) {
p->gonetick += 1;
if (p->ticks && p->gonetick == p->ticks) {
p->gonetick = 0;
p->inhandler = 1;

p->ra = p->trapframe->ra;
p->sp = p->trapframe->sp;
p->gp = p->trapframe->gp;
p->tp = p->trapframe->tp;
p->t0 = p->trapframe->t0;
p->t1 = p->trapframe->t1;
p->t2 = p->trapframe->t2;
p->s0 = p->trapframe->s0;
p->s1 = p->trapframe->s1;
p->a0 = p->trapframe->a0;
p->a1 = p->trapframe->a1;
p->a2 = p->trapframe->a2;
p->a3 = p->trapframe->a3;
p->a4 = p->trapframe->a4;
p->a5 = p->trapframe->a5;
p->a6 = p->trapframe->a6;
p->a7 = p->trapframe->a7;
p->s2 = p->trapframe->s2;
p->s3 = p->trapframe->s3;
p->s4 = p->trapframe->s4;
p->s5 = p->trapframe->s5;
p->s6 = p->trapframe->s6;
p->s7 = p->trapframe->s7;
p->s8 = p->trapframe->s8;
p->s9 = p->trapframe->s9;
p->s10 = p->trapframe->s10;
p->s11 = p->trapframe->s11;
p->t3 = p->trapframe->t3;
p->t4 = p->trapframe->t4;
p->t5 = p->trapframe->t5;
p->t6 = p->trapframe->t6;

p->epc = p->trapframe->epc;

p->trapframe->epc = p->handler;
}
yield();
}

Optional challenge exercises

  • Print the names of the functions and line numbers in backtrace() instead of numerical addresses (hard).

作者

huayi

发布于

2023-04-13

更新于

2023-04-23

许可协议