# Lab4

### RISC-V assembly

> li a2, ARCHI\_FC\_CID//将ARCHI\_FC\_CID的低6位取出写入到a2中
>
> sd : 存储指令

```
1.
(1)s0
(2)a2
2.
li a1,12 函数内联
3.
0x630
4.
0x630
5.
HE110 World
i改为0x726c6400，still 57616
6.
y的结果取决于之前a2中保存的数据
```

### Backtrace(moderate)

* 注意返回地址位于栈帧帧指针（fp）的固定偏移(-8)位置，并且保存的帧指针位于帧指针的固定偏移(-16)位置
* XV6在内核中以页面对齐的地址为每个栈分配一个页面。你可以通过`PGROUNDDOWN(fp)`和`PGROUNDUP(fp)`（参见\***kernel/riscv.h\***）来计算栈页面的顶部和底部地址。这些数字对于`backtrace`终止循环是有帮助的。

![](https://1752334052-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FIIqxByMmYzpNlPdXE8Oy%2Fuploads%2F76RUPHDyyVQz0jIVdkAk%2Flab4_1.png?alt=media\&token=d2c6399a-28df-4fe7-b809-38aeecc54b5a)

```
void 
backtrace() 
{
  printf("backtrace:\n");
  uint64 fp = r_fp(),top = PGROUNDUP(fp);
  // 因为risc-v中栈是向下增长的，所以上一个Frame肯定在这一个Frame的上面
  // 所以以top为边界增长，取出 To Prev.Frame，然后获取 fp-8 中存的返回地址。
  for(;fp < top;fp=*(uint64*)(fp-16)) {
    uint64 ret = *(uint64*)(fp-8);
    printf("%p\n",ret);
  }
}
```

### Alarm(Hard)

添加系统调用参照Hint2或者lab2.

在 proc.h中添加：

```
  int interval; // 时间间隔
  void (*handler)(); // 处理函数
  int counts; // 滴答时长
  int doing; // 防止对处理程序的重复调用——如果处理程序还没有返回，内核就不应该再次调用它。test2测试这个。
  struct trapframe *alarm_trapframe; // 用来保存寄存器，方便再 sigreturn 中恢复
```

因为在ecall指令中，PC（程序计数器）会保存到SEPC寄存器中，通过usertrap：p->trapframe->epc = r\_sepc(); 可以看到 spec 寄存器的值存在 epc中。

修改usertrap() ： 这里将 epc的值保存为在sys\_sigalarm中取到的第二个参数，也就是处理函数的地址。因为后续要将epc的值重新存入spec寄存器，而这里会覆盖掉函数的返回地址，所以会导致出错。

```
if(which_dev == 2){
    if (++p->counts == p->interval && p->doing == 0) {
        p->doing = 1;
        memmove(p->alarm_trapframe,p->trapframe,sizeof(struct trapframe));
        p->trapframe->epc = (uint64) p->handler;
        p->counts = 0;
    }
    yield();
}
```

在sysproc.c 中添加：

```
uint64
sys_sigalarm(void)
{
    // a0 是第一个参数的寄存器，a1是第二个参数的寄存器
  if (argint(0,&myproc()->interval) < 0 || argaddr(1,(uint64 *)&myproc()->handler) < 0)
  {
    return -1;
  }
  return 0;
}

uint64
sys_sigreturn(void)
{
    // 恢复寄存器状态
  memmove(myproc()->trapframe,myproc()->alarm_trapframe,sizeof(struct trapframe));
  myproc()->doing = 0;
  return 0;
}
```

在allocproc（）添加：

```
p->interval = 0;
p->handler = 0;
p->counts = 0;
p->doing = 0;
if((p->alarm_trapframe = (struct trapframe *)kalloc()) == 0) {
    release(&p->lock);
    return 0;
}
```

在freeproc() 添加：

```
if(p->alarm_trapframe)
    kfree((void*)p->alarm_trapframe);
p->doing = 0;
p->handler = 0;
p->interval = 0;
p->counts = 0;
```

\\
