共计 2131 个字符,预计需要花费 6 分钟才能阅读完成。
前言
- 本篇是对于 MIT 6.S081-2020-Lab4 的实现;
- 如果内容上发现有什么问题请不要悭吝您的键盘。
Backtrace
试验领导书上给出了 RISC-V 栈帧布局:
基本上只有看懂这幅图就能够过关了:
/* kernel/printf.c */
void
backtrace()
{uint64 *fp = (uint64*)r_fp(), *ra;
while ((uint64)fp != PGROUNDUP((uint64)fp) && (uint64)fp != PGROUNDUP((uint64)fp)) {ra = (uint64*)(*(fp - 1));
fp = (uint64*)(*(fp - 2));
printf("%p\n", ra);
}
}
Alarm
尽管是 hard
,但认真地看清楚并了解要求的话还是可能收掉的。
先依照提醒给 struct proc
增加几个必要的字段进去:
// Per-process state
struct proc {
...
int ticks; // alarm interval
void (*handler)(); // the pointer to the handler function
int ticks_passed;
};
test0: invoke handler
/* kernel/sysfile.c */
uint64
sys_sigalarm(void)
{
int ticks;
void (*handler)();
if (argint(0, &ticks) < 0)
return -1;
if (argaddr(1, (uint64*)&handler) < 0)
return -1;
struct proc *p = myproc();
p->ticks = ticks;
p->handler = handler;
return 0;
}
/* kernel/trap.c */
void
usertrap(void)
{
...
// give up the CPU if this is a timer interrupt.
if(which_dev == 2) {if (p->ticks != 0 && p->ticks == ++p->ticks_passed) {p->trapframe->epc = (uint64)p->handler;
}
yield();}
...
}
test1/test2(): resume interrupted code
如果要保留中断的现场,kernel 的做法是将它们放进 trapframe
当中。
在这里,咱们也做相似的操作。
不过因为 trapframe
被占用了,咱们再给 struct proc
增加一个字段 struct trapframe *utrapframe;
。
因为这是个指针变量,在 allocproc()
的时候还得给它 kalloc()
一页内存,回头 freeproc()
的时候还得 kfree()
掉它,要不然 usertest 过不去。
/* kernel/proc.c */
static struct proc*
allocproc(void)
{
...
// Allocate a trapframe page.
if((p->trapframe = (struct trapframe *)kalloc()) == 0){release(&p->lock);
return 0;
}
if((p->utrapframe = (struct trapframe *)kalloc()) == 0){release(&p->lock);
return 0;
}
...
}
/* kernel/proc.c */
static void
freeproc(struct proc *p)
{
...
if(p->trapframe)
kfree((void*)p->trapframe);
p->trapframe = 0;
if(p->utrapframe)
kfree((void*)p->utrapframe);
p->utrapframe = 0;
...
}
咱们要在适当的机会去拿 trapframe
里的内容去初始化 utrapframe
:
/* kernel/trap.c */
void
usertrap(void)
{
...
// give up the CPU if this is a timer interrupt.
if(which_dev == 2) {if (p->ticks != 0 && p->ticks == ++p->ticks_passed) {memmove(p->utrapframe, p->trapframe, sizeof(*(p->trapframe)));
p->trapframe->epc = (uint64)p->handler;
}
yield();}
...
}
最初别忘了还要返回现场:
/* kernel/sysfile.c */
uint64
sys_sigreturn(void)
{struct proc *p = myproc();
p->ticks_passed = 0;
memmove(p->trapframe, p->utrapframe, sizeof(*(p->trapframe)));
usertrapret();
return 0;
}
后记
Lab4 比 Lab3 相比切实顺畅很多。
因为做 Lab3 的时候把 xv6 book 的第四章也一起看了,所以本人一个人从头到做到尾不到半天工夫。
Lab3 跟 Lab4 相比,次要还是要想的货色太多,出异常中断了也不好排错……
正文完