Lab 4 traps

RISC-V assembly

1.哪些寄存器保存函数的参数?例如,在mainprintf的调用中,哪个寄存器保存13?

  1. 寄存器a0~a7保存函数的参数,寄存器a2保存13

2.main的汇编代码中对函数f的调用在哪里?对g的调用在哪里?

编译器将函数内联了,直接得出结果12存入寄存器a1。

3.printf函数位于哪个位置?

0x630。

4.在main函数中printfjalr之后的寄存器ra中有什么值?

执行`jalr`指令后,PC+4,所以寄存器`ra`中存储0x38。

5.程序的输出是:He110 World,改成大端存储不需要修改57616

在`printf("x=%d y=%d", 3)`中,因为没有给第二个参数,所以y会打印寄存器a2中上一次保存的值。

Backtrace

该函数的功能在题目中显示很清楚,,通过课程中的栈帧布局图我们可以知道返回地址在帧指针偏移地址-8的位置,保存的帧指针位于偏移地址-16的位置,此外,一旦帧指针超出栈页面顶部和底部的范围,停止该函数。

void
backtrace(void)
{
  uint64 fp, r_add, top, bottom;
  printf("backtrace:\n");
  fp = r_fp();
  top = PGROUNDUP(fp);
  bottom = PGROUNDDOWN(fp);
  while((fp < top) && (fp > bottom))
  {
    r_add = *(uint64*)(fp - 8);
    printf("%p\n", r_add);
    fp = *(uint64*)(fp - 16);
  }
}

然后在sys_sleeppanic中调用该函数。

Alarm

首先,我们按照题目的提示,在一些文件里增加sigalarmsigreturn的声明和相关的定义,这步工作与之前的lab的相同工作无异。

接着,我们需要在struct proc里增加一些新的字段,我们需要用到他们。

  // alarm
  int ticks;                   // The number of ticks
  uint64 handler;             // Pointer to the handler
  int interval;                // Interval of alarm
  int flag_handler;

  // save registers
  uint64 save_epc;
  uint64 save_ra;
  uint64 save_sp;
  uint64 save_gp;
  uint64 save_tp;
  uint64 save_t0;
  uint64 save_t1;
  uint64 save_t2;
  uint64 save_t3;
  uint64 save_t4;
  uint64 save_t5;
  uint64 save_t6;
  uint64 save_a0;
  uint64 save_a1;
  uint64 save_a2;
  uint64 save_a3;
  uint64 save_a4;
  uint64 save_a5;
  uint64 save_a6;
  uint64 save_a7;
  uint64 save_s0;
  uint64 save_s1;
  uint64 save_s2;
  uint64 save_s3;
  uint64 save_s4;
  uint64 save_s5;
  uint64 save_s6;
  uint64 save_s7;
  uint64 save_s8;
  uint64 save_s9;
  uint64 save_s10;
  uint64 save_s11;

前半部分变量是跟sigalarm有关的,这包括了ticks的数量、周期还有指向函数的指针;后半部分是用来存储寄存器的变量,在系统调用中我们需要存储之前的寄存器。

根据题意我们知道,在产生了计时器中断这种情况时,会操纵进程报警,产生ticks,于是根据提示我们在相应部分填入代码。

  // give up the CPU if this is a timer interrupt.
  if((which_dev == 2) && (p->flag_handler == 0))
  {
    p->ticks += 1;
    if((p->ticks > 0) && (p->ticks == p->interval))
    {
      p->flag_handler = 1;
      p->ticks = 0;

      // save needed registers
      p->save_epc = p->trapframe->epc;
      p->save_ra = p->trapframe->ra;
      p->save_sp = p->trapframe->sp;
      p->save_gp = p->trapframe->gp;
      p->save_tp = p->trapframe->tp;
      p->save_t0 = p->trapframe->t0;
      p->save_t1 = p->trapframe->t1;
      p->save_t2 = p->trapframe->t2;
      p->save_t3 = p->trapframe->t3;
      p->save_t4 = p->trapframe->t4;
      p->save_t5 = p->trapframe->t5;
      p->save_t6 = p->trapframe->t6;
      p->save_a0 = p->trapframe->a0;
      p->save_a1 = p->trapframe->a1;
      p->save_a2 = p->trapframe->a2;
      p->save_a3 = p->trapframe->a3;
      p->save_a4 = p->trapframe->a4;
      p->save_a5 = p->trapframe->a5;
      p->save_a6 = p->trapframe->a6;
      p->save_a7 = p->trapframe->a7;
      p->save_s0 = p->trapframe->s0;
      p->save_s1 = p->trapframe->s1;
      p->save_s2 = p->trapframe->s2;
      p->save_s3 = p->trapframe->s3;
      p->save_s4 = p->trapframe->s4;
      p->save_s5 = p->trapframe->s5;
      p->save_s6 = p->trapframe->s6;
      p->save_s7 = p->trapframe->s7;
      p->save_s8 = p->trapframe->s8;
      p->save_s9 = p->trapframe->s9;
      p->save_s10 = p->trapframe->s10;
      p->save_s11 = p->trapframe->s11;

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

我们使用一个flag的标志来决定是否进入handler,在这里,我们设置该标志为0时,我们选择进入。而且我们知道,很多寄存器在此前的trap操作中是存入trapframe的,所以我们将其存入我们设置的保存寄存器的变量中。

接下来是sigalarm系统调用的具体实现:

uint
sys_sigalarm(void)
{
  struct proc *p = myproc();
  if(argint(0, &(p->interval)) < 0)
    return -1;
  if(argaddr(1, &(p->handler)) < 0)
    return -1;
  return 0;
}

我们需要判断第一个参数n和第二个指针参数,若无效返回-1。

然后我们还需要使用sigreturn来恢复被中断的代码,该实现我们只需要恢复此前存储的寄存器,然后重新设置flag,恢复后可以进行下一次handler。

uint 
sys_sigreturn(void)
{
  struct proc *p = myproc();
  p->trapframe->epc = p->save_epc; 
  p->trapframe->ra = p->save_ra; 
  p->trapframe->sp = p->save_sp; 
  p->trapframe->gp = p->save_gp; 
  p->trapframe->tp = p->save_tp; 
  p->trapframe->a0 = p->save_a0; 
  p->trapframe->a1 = p->save_a1; 
  p->trapframe->a2 = p->save_a2; 
  p->trapframe->a3 = p->save_a3; 
  p->trapframe->a4 = p->save_a4; 
  p->trapframe->a5 = p->save_a5; 
  p->trapframe->a6 = p->save_a6; 
  p->trapframe->a7 = p->save_a7; 
  p->trapframe->t0 = p->save_t0; 
  p->trapframe->t1 = p->save_t1; 
  p->trapframe->t2 = p->save_t2; 
  p->trapframe->t3 = p->save_t3; 
  p->trapframe->t4 = p->save_t4; 
  p->trapframe->t5 = p->save_t5; 
  p->trapframe->t6 = p->save_t6;
  p->trapframe->s0 = p->save_s0;
  p->trapframe->s1 = p->save_s1;
  p->trapframe->s2 = p->save_s2;
  p->trapframe->s3 = p->save_s3;
  p->trapframe->s4 = p->save_s4;
  p->trapframe->s5 = p->save_s5;
  p->trapframe->s6 = p->save_s6;
  p->trapframe->s7 = p->save_s7;
  p->trapframe->s8 = p->save_s8;
  p->trapframe->s9 = p->save_s9;
  p->trapframe->s10 = p->save_s10;
  p->trapframe->s11 = p->save_s11;

  p->flag_handler = 0;
  return 0;
}