LAB2 PART2 Virtual Memory

Exercise 2

阅读手册有关于虚拟内存的部分。主要是这张图。主要理解分页部分,(各大教材都有,这里就不赘述了)也就是线性地址转换成物理地址的部分。需要注意的是:这是一个二级页表。

 Exercise 3

       通过GDB,我们只能通过虚拟地址来查看内存所存放的内容,但是如果我们能够访问物理内存的话,肯定会更有帮助的。我们可以看一下QEMU中的一些常用指令,特别是xp指令,可以允许我们去访问物理内存地址。

    在当前终端执行make qemu-gdb指令,打开qemu。另开一个终端(第二终端),执行make gdb指令,开启gdb调试。在gdb中执行c命令,使得程序开始编译,按键ctrl+c使得程序终止。然后键入命令x/16xw 0xf0100000:查看内存。再执行c命令。

    回到第一终端,键入ctrl+a c命令,出现qemu终端,然后键入xp/16xw 0x00100000查看内存。

    两次查看内存的结果如图,发现内存内容一样,说明0xf0100000虚拟地址成功映射到了0x00100000物理地址上。

QUESTIION

假设下述JOS内核代码是正确的,那么变量x应该是uintptr_t类型呢,还是physaddr_t呢? 

Assuming that the following JOS kernel code is correct, what type should variable x have, uintptr_t or physaddr_t?

	mystery_t x;
	char* value = return_a_pointer();
	*value = 10;
	x = (mystery_t) value;

官网知识点总结如下:

变量x应该是uintptr_t类型。 因为代码第三句直接对*value进行了赋值,所以value肯定 是一个虚拟地址。

Exercise 4

在文件kern/pmap.c中,实现以下几个函数:pgdir_walk(), boot_map_region() ,page_lookup() ,page_remove() ,page_insert().

check_page函数会测试页表管理器,需要确保它报告成功的信息。

pgdir_walk函数

这个函数的作用是查找一个虚拟地址对应的页表项的物理地址,如果没有可以创建映射。这里要注意的是进行操作的话都需要把物理地址转换成虚拟地址,返回的也是虚拟地址。

pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
        // Fill this function in
        uint32_t pdx = PDX(va);               //页目录项索引
        uint32_t ptx = PTX(va);               //页表项索引
        pte_t *page_dir_entry = pgdir + pdx;  //页目录项指针(段内基址+偏移地址)
        pte_t *page_table_entry;              //页表指针
        Struct PageInfo *pp;
        if(*page_dir_entry& PTE_P){
          //二级页表Exist 
          page_table_entry = KADDR(PTE_ADDR(*page_dir_entry));
        }else{
          //Not Exist
         if(!create) return NULL;
         pp = page_alloc(1);
         if(!pp) return NULL;
         page_table_entry = (pte_t*)page2kva(pp);
         pp->pp_ref++;
         *page_dir_entry = PADDR(page_table_entry)|PTE_P|PTE_W|PTE_U;
        }

        return page_table_entry+ptx;
        //return &page_table_entry[ptx];
}
/*代码逻辑就是照着注释来的*/

 boot_map_region函数

这个函数的作用是把一块指定虚拟也映射到指定物理页,可以直接利用pgdir_walk函数,pgdir_walk函数提供了映射功能。

static void
boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm)
{
        // Fill this function in
        size_t numpage = size/PGSIZE;
        int  i;
        if(size % PGSIZE !=0) numpage++;

        for(i=0;i<numpage;i++){
          pte_t *pte = pgdir_walk(pgdir,(void *)va,1);
          if(!pte) panic("boot_map_region:out ouf memory!\n");
          *pte = pa|PTE_P|perm;
          pa+=PGSIZE;
          va+=PGSIZE;
        }
}

page_lookup函数

 作用:查找虚拟地址对应的物理地址描述。

page_lookup(pde_t *pgdir, void *va, pte_t **pte_store)
{
	// Fill this function in
	pte_t *pt = pgdir_walk(pgdir,va,0);
	if(!pt) return NULL;
	if(pte_store)
		*pte_store = pt;
	return pa2page(PTE_ADDR(*pt));
}

page_remove函数

 移除一个虚拟地址对物理地址的映射。

page_remove(pde_t *pgdir, void *va)
{
	// Fill this function in
	pte_t *pt;
	struct PageInfo* pageinfo = page_lookup(pgdir,va,&pt);
        if(!pageinfo) return;
	page_decref(pageinfo);
	*pt = 0;
	tlb_invalidate(pgdir,va);
        
}

page_insert函数

 建立物理内存页pp和虚拟地址va的映射关系。需要注意一种情况就是映射到与之前相同的页。

page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm)
{
	// Fill this function in
	pte_t *pt=pgdir_walk(pgdir,va,1);
	if(!pt) return -E_NO_MEM;

	pp->pp_ref++;
	if(*pt & PTE_P) page_remove(pgdir,va);
	*pt = page2pa(pp)|perm|PTE_P;
	return 0;
        
}

实验结果

make grade

part2完成。

猜你喜欢

转载自blog.csdn.net/qq_43012789/article/details/107686630