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中保存的数据
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);
}
}
添加系统调用参照Hint2或者lab2.
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();
}
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;
}
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;
}
if(p->alarm_trapframe)
kfree((void*)p->alarm_trapframe);
p->doing = 0;
p->handler = 0;
p->interval = 0;
p->counts = 0;