Lab5: Copy-on-Write Fork for xv6

riscv.h

#define PTE_V (1L << 0) // valid
#define PTE_R (1L << 1)
#define PTE_W (1L << 2)
#define PTE_X (1L << 3)
#define PTE_U (1L << 4) // user can access
#define PTE_RSW (1L << 8)

kalloc.c

#define INDEX(pa) (((uint64)pa) / PGSIZE)

int ref_cnt[PHYSTOP / PGSIZE];

void addref(uint64 pa)
{
	acquire(&kmem.lock);
	ref_cnt[INDEX(pa)]++;
	release(&kmem.lock);
}

int getref(uint64 pa)
{
	return ref_cnt[INDEX(pa)];
}
void * kalloc(void)
{
	struct run *r;

	acquire(&kmem.lock);
	r = kmem.freelist;
	if (r)
		kmem.freelist = r->next;
	release(&kmem.lock);

	if (r)
	{
		memset((char *)r, 5, PGSIZE); // fill with junk
		ref_cnt[INDEX(r)] = 1;
	}

	return (void *)r;
}
void kfree(void *pa)
{
	struct run *r;

	if (((uint64)pa % PGSIZE) != 0 || (char *)pa < end || (uint64)pa >= PHYSTOP)
		panic("kfree");

	acquire(&kmem.lock);
  	int remain = --ref_cnt[INDEX(pa)];
  	release(&kmem.lock);

	if (remain > 0)
	{
		return;
	}
	
	memset(pa, 1, PGSIZE);

	r = (struct run *)pa;

	acquire(&kmem.lock);
	r->next = kmem.freelist;
	kmem.freelist = r;
	release(&kmem.lock);
}
void freerange(void *pa_start, void *pa_end)
{
	char *p;
	p = (char *)PGROUNDUP((uint64)pa_start);
	for (; p + PGSIZE <= (char *)pa_end; p += PGSIZE)
	{
		ref_cnt[INDEX(p)] = 1;
		kfree(p);
	}
}

vm.c 

int uvmcopy(pagetable_t old, pagetable_t new, uint64 sz)
{
	pte_t *pte;
	uint64 pa, i;
	uint flags;

	for (i = 0; i < sz; i += PGSIZE)
	{
		if ((pte = walk(old, i, 0)) == 0)
			panic("uvmcopy: pte should exist");
		if ((*pte & PTE_V) == 0)
			panic("uvmcopy: page not present");
		pa = PTE2PA(*pte);
		if (*pte & PTE_W)
		{
			*pte &= ~PTE_W;
			*pte |= PTE_RSW;
		}
		flags = PTE_FLAGS(*pte);
		if (mappages(new, i, PGSIZE, pa, flags) != 0)
		{
			goto err;
		}
		addref(pa);
	}
	return 0;

err:
	uvmunmap(new, 0, i / PGSIZE, 1);
	return -1;
}
int copyout(pagetable_t pagetable, uint64 dstva, char *src, uint64 len)
{
	uint64 n, va0, pa0;
	pte_t *pte;

	while (len > 0)
	{
		va0 = PGROUNDDOWN(dstva);
		if (va0 >= MAXVA)
			return -1;
		pte = walk(pagetable, va0, 0);
		if (pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
			return -1;
		if ((*pte & PTE_W) == 0)
		{
			if (cowalloc(pagetable, va0) < 0)
			{
				return -1;
			}
		}
		pa0 = PTE2PA(*pte);
		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;
}
int cowalloc(pagetable_t pagetable, uint64 va)
{
	char* mem;
	pte_t* pte;
	uint64 pa, flags;
	int ref;

	if (va >= MAXVA)
	{
		return -1;
	}

	pte = walk(pagetable, va, 0);
	if (pte == 0 || (*pte & PTE_V) == 0 || (*pte & PTE_U) == 0)
	{
		return -1;
	}
	if ((*pte & PTE_W) == 0 && (*pte & PTE_RSW) == 0)
	{
		return -1;
	}
	
	va = PGROUNDDOWN(va);
	pa = PTE2PA(*pte);
	*pte |= PTE_W;
	*pte &= ~PTE_RSW;
	flags = PTE_FLAGS(*pte);

	ref = getref(pa);

	if (ref == 1)
	{
		return 0;
	}
	else if (ref > 1)
	{
		if ((mem = kalloc()) == 0)
		{
			return -1;
		}

		memmove(mem, (char *)pa, PGSIZE);
		uvmunmap(pagetable, va, 1, 1);
		if (mappages(pagetable, va, PGSIZE, (uint64)mem, flags) != 0)
		{
			kfree(mem);
			return -1;
		}
		return 0;
	}
	else
	{
		return -1;
	}
}

 trap.c

void usertrap(void)
{
    
    ......

	else if (r_scause() == 15)
	{
		if (cowalloc(p->pagetable, r_stval()) < 0)
		{
			p->killed = 1;
		}
	}
	
	......
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值