MIT6.s081 lab lazy allocation
LAB:xv6 lazy page allocation
1.实验概述
本节的实验内容是给xv6加上一个延迟分配内存的功能,具体内容为,在用户态调用系统调用sys_bark
时,只设置进程控制块中内存大小,不进行具体分配,等待用户需要使用上次调用的内存时,会产生一个pagefault
,此时在中断处理程序中进行具体分配并返回重新执行指令
2.重点代码
uint64
sys_sbrk(void)
{
int addr;
int n;
struct proc *p = myproc();
addr = p->sz;
if(argint(0, &n) < 0)
return -1;
if (n < 0) {
uint64 sz = p->sz;
p->sz = uvmdealloc(p->pagetable, sz, sz + n);
} else {
(p->sz) += n;
}
return addr;
}
// usertrap
else if(r_scause() == 15 || r_scause() == 13){
uint64 falut_addr = r_stval();
if (falut_addr >= p->sz || falut_addr < p->trapframe->sp) {
p->killed = 1;
} else {
falut_addr = PGROUNDDOWN(falut_addr);
uint64 ka = (uint64)kalloc();
if(ka == 0) {
p->killed = 1;
} else {
memset((void *)ka, 0, PGSIZE);
if (mappages(p->pagetable, falut_addr, PGSIZE, ka, PTE_W | PTE_U | PTE_R) != 0) {
kfree((void*)ka);
p->killed = 1;
}
}
}
}
此时你还需要处理一种情况:当进程的内存未被分配就需要释放时,uvmunmap
在去除pagetable
上的ptes
时,可能查找不到那块尚未分配的内存的pte
,且上面的PTE_V
不存在,所以我们需要处理一下uvmunmap
// uvmunmap
void
uvmunmap(pagetable_t pagetable, uint64 va, uint64 npages, int do_free)
{
uint64 a;
pte_t *pte;
if((va % PGSIZE) != 0)
panic("uvmunmap: not aligned");
for(a = va; a < va + npages*PGSIZE; a += PGSIZE){
if((pte = walk(pagetable, a, 0)) == 0)
continue;
if((*pte & PTE_V) == 0)
continue;
if(PTE_FLAGS(*pte) == PTE_V)
panic("uvmunmap: not a leaf");
if(do_free){
uint64 pa = PTE2PA(*pte);
kfree((void*)pa);
}
*pte = 0;
}
}
此时可以正常调用echo hi
了,但想要完美通过lazytests
和usertests
,需要处理这种情况:当用户态调用系统调用write
和read
时,可能会访问到未被分配的内存块,但此时是从内核态进入中断的,usertrap
并不会处理,所以我们需要处理一下copyin
和copyout
函数,这两个函数被write
调用
int
copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
{
uint64 n, va0, pa0;
struct proc *p = myproc();
while(len > 0){
va0 = PGROUNDDOWN(srcva);
pa0 = walkaddr(pagetable, va0);
if(pa0 == 0) {
if (va0 >= p->sz || va0 < p->trapframe->sp) {
return -1;
}
pa0 = (uint64)kalloc();
if (pa0 == 0) {
p->killed = 1;
} else {
memset((void *)pa0, 0, PGSIZE);
if (mappages(p->pagetable, va0, PGSIZE, pa0, PTE_W | PTE_U | PTE_R) != 0) {
kfree((void*)pa0);
p->killed = 1;
}
}
}
n = PGSIZE - (srcva - va0);
if(n > len)
n = len;
memmove(dst, (void *)(pa0 + (srcva - va0)), n);
len -= n;
dst += n;
srcva = va0 + PGSIZE;
}
return 0;
}
int
copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
{
uint64 n, va0, pa0;
struct proc *p = myproc();
while(len > 0){
va0 = PGROUNDDOWN(dstva);
pa0 = walkaddr(pagetable, va0);
if(pa0 == 0) {
if (va0 >= p->sz || va0 < p->trapframe->sp)
return -1;
pa0 = (uint64)kalloc();
if (pa0 == 0) {
p->killed = 1;
} else {
memset((void *)pa0, 0, PGSIZE);
if (mappages(p->pagetable, va0, PGSIZE, pa0, PTE_W | PTE_U | PTE_R) != 0) {
kfree((void*)pa0);
p->killed = 1;
}
}
}
n = PGSIZE - (dstva - va0);
if(n > len)
n = len;
memmove((void *)(pa0 + (dstva - va0)), src, n);
len -= n;
src += n;
dstva = va0 + PGSIZE;
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通