概述
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完成。
最后
以上就是欢呼心锁为你收集整理的LAB2 PART2 Virtual MemoryExercise 2 Exercise 3Exercise 4的全部内容,希望文章能够帮你解决LAB2 PART2 Virtual MemoryExercise 2 Exercise 3Exercise 4所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复