Lab 4 traps
RISC-V assembly
1.哪些寄存器保存函数的参数?例如,在main对printf的调用中,哪个寄存器保存13?
寄存器a0~a7保存函数的参数,寄存器a2保存13。
2.main的汇编代码中对函数f的调用在哪里?对g的调用在哪里?
编译器将函数内联了,直接得出结果12存入寄存器a1。
3.printf函数位于哪个位置?
0x630。
4.在main函数中printf和jalr之后的寄存器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_sleep和panic中调用该函数。
Alarm
首先,我们按照题目的提示,在一些文件里增加sigalarm和sigreturn的声明和相关的定义,这步工作与之前的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;
}
