Part One: Eliminate allocation from sbrk()
任务
将 sbrk(n) 系统调用实现中的分配 page 部分删除,在 sysproc.c 中的 sys_sbrk() 中。在删除之后,新的 sbrk(n) 应该仅仅将进程的内存大小的指示符 (myproc()->sz) 增加 n,但不实际分配内存。
代码修改情况:
int
sys_sbrk(void)
{
int addr;
int n;
if(argint(0, &n) < 0)
return -1;
addr = myproc()->sz;
myproc()->sz += n;
// if(growproc(n) < 0)
// return -1;
return addr;
}
修改后重新编译,引发异常
$ echo hi
pid 3 sh: trap 14 err 6 on cpu 0 eip 0x1220 addr 0x4004--kill proc
Part Two: Lazy allocation
任务
修改 trap.c 的代码使在处理缺页异常时,将一个新分配的页返回到用户空间。
根据题目的提示,在输出错误信息的 cprintf 语句前添加代码,模仿 vm.c 中的 allocuvm 函数分配空间,修改后的 trap 函数如下:
注意:
- 要根据提示将 mappages 函数在前面进行一次声明,并将 vm.c 中函数定义前面的 static 删去。
- 观察 proc.c 中对 allocuvm 的调用,sys_sbrk() 返回值即 oldsz 存在 %eax 中,即 myproc()->tf->eax。
int mappages(pde_t *pgdir, void *va, uint size, uint pa, int perm);
void trap(struct trapframe *tf)
{
if (tf->trapno == T_SYSCALL)
{
if (myproc()->killed)
exit();
myproc()->tf = tf;
syscall();
if (myproc()->killed)
exit();
return;
}
switch (tf->trapno)
{
case T_IRQ0 + IRQ_TIMER:
if (cpuid() == 0)
{
acquire(&tickslock);
ticks++;
wakeup(&ticks);
release(&tickslock);
}
lapiceoi();
break;
case T_IRQ0 + IRQ_IDE:
ideintr();
lapiceoi();
break;
case T_IRQ0 + IRQ_IDE + 1:
// Bochs generates spurious IDE1 interrupts.
break;
case T_IRQ0 + IRQ_KBD:
kbdintr();
lapiceoi();
break;
case T_IRQ0 + IRQ_COM1:
uartintr();
lapiceoi();
break;
case T_IRQ0 + 7:
case T_IRQ0 + IRQ_SPURIOUS:
cprintf("cpu%d: spurious interrupt at %x:%x\n",
cpuid(), tf->cs, tf->eip);
lapiceoi();
break;
// PAGEBREAK: 13
default:
if (myproc() == 0 || (tf->cs & 3) == 0)
{
// In kernel, it must be our mistake.
cprintf("unexpected trap %d from cpu %d eip %x (cr2=0x%x)\n",
tf->trapno, cpuid(), tf->eip, rcr2());
panic("trap");
}
char *mem = kalloc();
uint a = PGROUNDDOWN(rcr2());
if (mem != 0)
{
memset(mem, 0, PGSIZE);
if (mem == 0)
{
cprintf("allocuvm out of memory\n");
// sys_sbrk() 返回值即 oldsz 存在 %eax 中,即 myproc()->tf->eax
deallocuvm(myproc()->pgdir, myproc()->sz, myproc()->tf->eax);
return;
}
extern int mappages(pde_t * pgdir, void *a, uint size, uint pa, int perm);
if (mappages(myproc()->pgdir, (void *)a, PGSIZE, V2P(mem), PTE_W | PTE_U) >= 0)
{
break;
}
else
{
cprintf("allocuvm out of memory (2)\n");
deallocuvm(myproc()->pgdir, myproc()->sz, myproc()->tf->eax);
kfree(mem);
return;
}
}
// In user space, assume process misbehaved.
cprintf("pid %d %s: trap %d err %d on cpu %d "
"eip 0x%x addr 0x%x--kill proc\n",
myproc()->pid, myproc()->name, tf->trapno,
tf->err, cpuid(), tf->eip, rcr2());
myproc()->killed = 1;
}
// Force process exit if it has been killed and is in user space.
// (If it is still executing in the kernel, let it keep running
// until it gets to the regular system call return.)
if (myproc() && myproc()->killed && (tf->cs & 3) == DPL_USER)
exit();
// Force process to give up CPU on clock tick.
// If interrupts were on while locks held, would need to check nlock.
if (myproc() && myproc()->state == RUNNING &&
tf->trapno == T_IRQ0 + IRQ_TIMER)
yield();
// Check if the process has been killed since we yielded
if (myproc() && myproc()->killed && (tf->cs & 3) == DPL_USER)
exit();
}
编译后 echo hi 能够正确运行:
$ echo hi
hi
标签:case,break,lazy,myproc,IRQ0,Xv6,allocation,tf,return
From: https://www.cnblogs.com/tea-in-the-snow/p/16990019.html