Part1
Exercise 1:
boot_alloc:
if(!n){
result=nextfree;
return result;
}
else{
uint32_t remainingPages=npages-((uint32_t)nextfree-(uint32_t)KERNBASE)/PGSIZE;
if(n<remainingPages*PGSIZE){
result=nextfree;
nextfree=ROUNDUP(nextfree+n,PGSIZE);
return result;
}else{
panic("The memory has been used up\n");
}
}
return NULL;
mem_init:
pages=(struct PageInfo *)boot_alloc(npages*sizeof(struct PageInfo));
memset(pages,0,npages*sizeof(struct PageInfo));
Page_init:
size_t i;
uint32_t j=((uint32_t)boot_alloc(0)-KERNBASE)/PGSIZE;
uint32_t j2=IOPHYSMEM/PGSIZE;
for (i = npages-1; i>=1; i--) {
//the physical memory pages that has been used by pages and kernel
//cprintf("rrrrrrrrrrrrrrrrr");
if(!((i>=j2&&i<j)||i==0)){
pages[i].pp_ref = 0;
pages[i].pp_link = page_free_list;
page_free_list = &pages[i];
}
}
Page_alloc:
if(page_free_list==NULL) return 0;
struct PageInfo *result=page_free_list;
page_free_list=page_free_list->pp_link;
//set '\0'
if(alloc_flags&ALLOC_ZERO){
void * resultKVA=page2kva(result);
memset(resultKVA,0,PGSIZE);
}
//cprintf("page_alloc va is %08x\n",page2kva(result));
return result;
Page_free:
if(pp->pp_ref!=0) return;
pp->pp_link=page_free_list;
page_free_list=pp;
Part2
Exercise 3:
ctrl+a c进入qemu调试
qemu下调试: xp/Nx physical address与GDB调试的x/Nxw virtual address,查看内存的内容
info pg和info mem显示内存映射的情况
Question1: 虚拟地址。2013.7.17
Exercise 4:
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
// Fill this function in
pte_t ptet=pgdir[PDX(va)];
//cprintf("cprintf_walk, the pgdir is %08x\n",ptet);
if((ptet&PTE_P)==0){
if(create==false)return NULL;
struct PageInfo *pageinfo=page_alloc(1);
if(!pageinfo) return NULL;
pageinfo->pp_ref++;
pgdir[PDX(va)]=page2pa(pageinfo)| PTE_U | PTE_P|PTE_W;
// cprintf("pgdir_walk, the physical is %08x va is %08x %08x\n",PTX(va),va,page2kva(pageinfo)+PTX(va));
return (pte_t*)page2kva(pageinfo)+PTX(va);
}
pte_t * ptet_va=KADDR(PTE_ADDR(ptet));
//cprintf("pdgidr_walk page table item is %08x\n",ptet_va[PTX(va)]);
return ptet_va+PTX(va);
}
static void
boot_map_region(pde_t *pgdir, uintptr_t va, size_t size, physaddr_t pa, int perm)
{
// Fill this function in
// i think the va and pa must be a multiple of PGSIZE also Author:ryz
// if size is more than 4M, one pte can't contain so may datas???!!!!!
// use walk every va address, there is no any problem
if(size&0xFFF) panic("boot_map_region: va is not a multiple of PGSIZE %08x\n",size);
uintptr_t i;
for(i=0;i<size;i+=PGSIZE){
pte_t * ptet=pgdir_walk(pgdir,(void *)va,true);
*ptet=pa|PTE_P|perm;
pa+=PGSIZE;
va+=PGSIZE;
}
}
struct PageInfo *
page_lookup(pde_t *pgdir, void *va, pte_t **pte_store)
{
// Fill this function in
pte_t * ptet=pgdir_walk(pgdir,va,false);
if(*pte_store!=NULL)*pte_store=ptet;
if((ptet==NULL)||((*ptet&PTE_P)==0)) return NULL;
//cprintf("page_lookup linear address is %08x\n",(uint32_t)va);
//cprintf("11111111111111\n");
//cprintf("%08x\n",*ptet);
return pa2page(PTE_ADDR(*ptet));
//cprintf("22222222222222222\n");
}
void
page_remove(pde_t *pgdir, void *va)
{
// Fill this function in
//cprintf("page_remove entry\n");
pte_t *ptet;
struct PageInfo *pageinfo=page_lookup(pgdir,va,&ptet);
//cprintf("333333333333");
if (pageinfo==NULL) return;
page_decref(pageinfo);
*ptet=0;
tlb_invalidate(pgdir,va);
}
int
page_insert(pde_t *pgdir, struct PageInfo *pp, void *va, int perm)
{
// Fill this function in
//cprintf("page_insert entry\n");
//cprintf("page_insert the va is %08x\n",(uint32_t)va);
pte_t * ptet=pgdir_walk(pgdir,va,true);
if(ptet==NULL) return -E_NO_MEM;
if(*ptet&PTE_P){
if(PTE_ADDR(*ptet)==page2pa(pp)){
*ptet=page2pa(pp)|perm|PTE_P;
tlb_invalidate(pgdir, va);
//cprintf("page_insert linear address is %08x, the physical is %08x\n",(uint32_t)va,*ptet);
return 0;
}else{
page_remove(pgdir,va);
*ptet=page2pa(pp)|perm|PTE_P;
//cprintf("page_insert linear address is %08x, the physical is %08x\n",(uint32_t)va,*ptet);
pp->pp_ref++;
return 0;
}
}else{
*ptet=page2pa(pp)|perm|PTE_P;
//cprintf("page_insert linear address is %08x, the physical is %08x\n",(uint32_t)va,*ptet);
pp->pp_ref++;
}
//cprintf("page_insert out\n");
return 0;
}
pgdir_walk() : 用来查找对应线性地址的页表itemboot_map_region() : 进行地址映射,就是把当前的地址空间的分布,映射到新的页目录页表下的地址空间。注意PTE_Wpage_lookup():查找某个线性地址的页表item是否存在,返回对应的物理地址的pageinfo信息. 当需要pageinfo信息时,才调用这个函数 page_remove(): page_insert(): 将某个物理页映射到某个线性地址。
Part3
Exercise5:
boot_map_region(kern_pgdir,UPAGES,ROUNDUP(npages*sizeof(struct PageInfo),PGSIZE),PADDR(pages), PTE_U | PTE_P);
boot_map_region(kern_pgdir,KSTACKTOP-KSTKSIZE,KSTKSIZE,PADDR(bootstack),PTE_W|PTE_P);
boot_map_region(kern_pgdir,KERNBASE,1<<28,0,PTE_W|PTE_P);
注意:PTE_W,否则即使
check_kern_pgdir()
通过,页目录切换lrc3时也会出错!!!!
我根据赵炯的书上,这本书上说,当特权用户时,PTE_W不起作用,但是仿佛不是如此!
后来又查了查intel user mannual, 发现赵炯说的是对的,那为什么这里必须要设置PTE_W, 不清楚!!!
Question 2:
Question 3:使用PTE_U这个page drectory/page table选项。
Question 4:因为一开始内存只映射了4M, kernel用去一部分,剩下的全部用于管理内存的话,假设有A byte, 则可以管理的内存为(A/sizeof(struct Pageinfo))*4K
Question 5: 没明白overhead是啥意思!
Question 6: mov $relocated, %eax
jmp *%eax 这里的跳转指令跳转到0xfxxxxxxx的线性地址。因为这时的页机制,将线性地址0xf0000000+4M和0x00000000+4M都映射到了物理地址的0-4M之间。
Challenge 1: 4M也模式,映射变化了,需要重新编写我们的映射函数。
Challenge 2: 这个比较简单,调用我们编写的那几个函数就可以实现了。
Challenge 3:这个超级麻烦!如果user process单独使用4G线性地址空间,kernel如何访问user process地址空间呢? 就不能访问了吧? 只能在user proces和kernel process之间 传递数据了吧??
Callenge 4:linux kernel使用buddy来实现连续物理地址的大内存的申请!!很复杂,看看kernel的书籍吧!!
其他:1. mem_init中映射pages和栈,啥时候用呢? 现在没用吧!!!
学习心得:原来底层编程这么回事,真的比较复杂。学习这个实验,对于我理解计算机体系结构真的帮助很大,对于编程的理解更加的深入了。
这些都可以研究明白,而且许多的牛人在研究这个方面,计算机行业,真的很庞大,许多需要学习呀!!!
2013.7.14-2013.7.21