MIT_6.828_lab2_总结

简而言之,使用pageinfo结构体映射物理页,使用pages数组保存页结构体,pagefreelist保存空闲页结构体,使用pa2page和page2pa实现物理页和页结构体的转换,使用二级页表机制进行物理地址与虚拟地址的转换,使用PDX、PTX等宏(其实就是简单的移位操作)实现虚拟地址查页表,各级页表的页表项结构相同,都是前20位物理页索引,后12位标志位。

更详细的页表项、结构说明等,参见lab2_exercise1讲解。

手动实现了10个函数

  1. boot_alloc()
static void *
boot_alloc(uint32_t n)
{
	static char *nextfree;	// virtual address of next byte of free memory
	char *result;
	if (!nextfree) {
		extern char end[];
		nextfree = ROUNDUP((char *) end, PGSIZE);
	}
	if (n == 0)	return nextfree;
	else if (n > 0)	{
		result = nextfree;
		nextfree += ROUNDUP(n, PGSIZE);	//如果n大于零,就这么搞。注意这里res和nex的用法,nex始终指向
		return result;					//被分配出来的空白空间的开头,而nex始终指向被分配空间的结尾
	}									//就象这里,可以对指针直接加整型数,来表示指针的移动和分配空间
	else	return NULL;
}

**在运行虚拟内存系统之前暂时分配页。**实际是使用一个指针,保存一个uint_32_t类型的值,直接将这个值作为指针(地址)。将n向上取整为PGSIZE的倍数后,nextfree后移。

  1. mem_int()1
	pages = (struct PageInfo*) boot_alloc(sizeof(struct PageInfo) * npages);
	memset(pages, 0, sizeof(struct PageInfo) * npages);

**初始化页表结构体数组pages,pages中的每一项对应一个物理页,pages用来保存页表结构体。**通过页表结构体,就能索引到页表,以及当前页的其他信息。

  1. page_init()
void
page_init(void)
{
	size_t i;
	for (i = 1; i< npages_basemem; i++)	{
		pages[i].pp_ref = 0;
		pages[i].pp_link = page_free_list;
		page_free_list = &pages[i];
	}
	for (i = PGNUM(PADDR(boot_alloc(0))); i < npages; i++) {
		pages[i].pp_ref = 0;
		pages[i].pp_link = page_free_list;
		page_free_list = &pages[i];
	}
}

**初始化页表结构,包括结构体赋初值和空闲页表维护。**使用单链表连接空页。用物理内存的高位来映射在pages中的页号。

  1. page_alloc()
struct PageInfo *
page_alloc(int alloc_flags)
{
	if (page_free_list == NULL)	return NULL;
	struct PageInfo* res = page_free_list;
	page_free_list = page_free_list->pp_link;
	res->pp_link = NULL;
	if (alloc_flags & ALLOC_ZERO)
		memset(page2kva(res), '\0', PGSIZE);
	return res;
}

分配出一个空闲页,返回这个页的结构体。

  1. page_free()
void
page_free(struct PageInfo *pp)
{
	if (pp->pp_ref || pp->pp_link)	panic("Page isn't empty!\n");
	pp->pp_link = page_free_list;
	page_free_list = pp;
}

**删除一个空闲页。**只有当这个页是空时才能删除。将这个页重新挂在pagefreelist单链表上。

  1. pgdir_walk()
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
	pde_t* tpde = &pgdir[PDX(va)];	//PDX(va)是含va的二级页表在一级页表的索引,即指向va的一级页表项。pgdir是一个页表目录,就是一级页表的初址
	pte_t* tpte=NULL;				//保存包含va的二级页表首地址
	if (*tpde & PTE_P)	{	//如果一级页表中有含va的一级页表项,且这个二级页表页可以分配,
		tpte = (pte_t*) KADDR(PTE_ADDR(*tpde));	//就将tpte指向这个二级页表
	}
	else	{	//如果一级页表中对应项没有已分配的二级页表页
		if (!create)	return NULL;	//如果不可创建,返回空
		else {	//如果可以创建
			struct PageInfo * newpage = page_alloc(true);	//创建一个二级页表页
			if (!newpage)	return NULL;	//如果创建失败
			newpage->pp_ref++;
			*tpde = page2pa(newpage) | PTE_P | PTE_U | PTE_W;	//创建之后,将这个对应的创建的页标志位设为present、user、write
			tpte = page2kva(newpage);	//tpte指向新创建的二级页表页
		}
	}
	return &tpte[PTX(va)];	//PTX得到va在二级页表页内的偏移,以tpte初址寻址后,得到含va的二级页表项,取地址,得到指向va所在的二级页表项的指针。
}

返回指向一个虚拟地址va的二级页表项的指针(没有这个项则按create决定是否创建)。

tpte无论哪种情况,都要转化成虚拟地址,因为此时页表机制已经启动,地址都会通过页表机制进行转化,这样最后才能通过数组索引,找到对应项取地址。

  1. boot_map_region()
static void
boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm)
{
	for(size_t i = 0; i < size; i += PGSIZE){
		pte_t* pte = pgdir_walk(pgdir, (const void *)va + i, 1);
		*pte = (pa + i) | PTE_P | perm;
	}
}

**将虚拟地址va处的size字节,映射到物理地址pa处。**由于已经对齐了,所以这里直接调函数赋值就行了。

  1. page_insert()
int
page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm)
{
	pte_t * tpte = pgdir_walk(pgdir, va, true);
	if (!tpte)	return -E_NO_MEM;
	pp->pp_ref++;
	if (*tpte & PTE_P)	page_remove(pgdir, va);
	*tpte = page2pa(pp)	| perm | PTE_P;
	return 0;
}

**将虚拟地址va插入页结构体pp对应页中。**比较好理解,只需要找到va对应的二级页表项,将这一项赋值为pp对应页的物理地址,再设置权限位即可。

  1. page_lookup()
struct PageInfo *
page_lookup(pde_t *pgdir, void *va, pte_t **pte_store)
{
	pte_t* ppte = pgdir_walk(pgdir, va, 0);
	if (!ppte)	return NULL;
	pte_t idx = *ppte>>PTXSHIFT<<PTXSHIFT;
	if (pte_store != 0)	*pte_store = ppte;
	return pa2page(idx);
}

**查找到va对应页的页结构体。**详细解释在exercise4讲解中。

  1. page_remove()
void
page_remove(pde_t *pgdir, void *va)
{
	pte_t * ppp;
	struct PageInfo * pg1 = page_lookup(pgdir, va, &ppp);
	if (!pg1)	return;
	*ppp = 0;
	pg1->pp_ref--;
	if (pg1->pp_ref == 0)	page_free(pg1);
	tlb_invalidate(pgdir, va);
}

删除va与现在它所在的页表的映射。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值