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终止循环是有帮助的。

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;

Last updated