1、pgdir_walk(),返回指向为线性地址va分配的页表入口地址。如果相关页表没有在页目录中,那么做如下工作:
如果create为0,那么返回NULL。否则,pgdir_walk()用page_alloc()分配一个新页,将pp_ref设置为1
===============================code=====================================
pte_t *
pgdir_walk(pde_t *pgdir, const void *va, int create)
{
// Fill this function in
//
// +--------10------+-------10-------+---------12----------+
// | Page Directory | Page Table | Offset within Page |
// | Index | Index | |
// +----------------+----------------+---------------------+
// \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/
// \----------- PPN(la) -----------/
struct Page* p;
pte_t *pt;
pgdir = (pde_t *)&pgdir[PDX(va)];
//whether the page table exist or not
//it isn't exist~
if(0 == (*pgdir& PTE_P)){
if(0 == create)return NULL;
//allocate a page
if(page_alloc(&p) < 0)return NULL;
//p points to an entry in the pages table and set pp_ref to 1
p->pp_ref = 1;
//set the page clear
memset(KADDR(page2pa(p)), 0, PGSIZE);
//make the page directory point to that page (contains pt)
*pgdir = page2pa(p) | PTE_U |PTE_W | PTE_P;
}
pt = (pte_t*) KADDR(PTE_ADDR(*pgdir));
// Page table exists, return the VA of the page table entry
return &pt[PTX(va)];
}
================================end=====================================
2、boot_map_segment(),将[la, la+size)的线性地址映射到[pa, pa+size)的物理地址上:
===============================code=====================================
static void
boot_map_segment(pde_t *pgdir, uintptr_t la, size_t size, physaddr_t pa, int perm)
{
// Fill this function in
uintptr_t i;
pte_t *p;
//1)Size is a multiple of PGSIZE and la must be a multiple of PGSIZE
size = ROUNDUP(size, PGSIZE);
assert (0 == la % PGSIZE); //assert va is a multiple of BY2PG.
//2)size is multiple of PGSIZE,so we should creat pages no less 1
for(i = 0; i < size; i+=PGSIZE){
p = pgdir_walk(pgdir, (void*)la + i, 1);
assert(p != NULL);
*p = (pa +i) |perm |PTE_P;
}//end for
}
================================end=====================================
3、page_lookup(),返回在虚拟地址va处分配的页面。
===============================code=====================================
struct Page *
page_lookup(pde_t *pgdir, void *va, pte_t **pte_store)
{
// Fill this function in
//pte is the pointer to the page table entry for va
pte_t *pte = pgdir_walk(pgdir, va, 0);
if(NULL == pte)
return NULL;
// If pte_store is not zero, then we store in it the address
// of the pte for that page
if(pte_store != NULL)
*pte_store = pte;
return pa2page(*pte);
}
================================end=====================================
4、page_remove():
===============================code=====================================
void
page_remove(pde_t *pgdir, void *va)
{
// Fill this function in
pte_t *pte = NULL;
struct Page *p;
p = page_lookup(pgdir, va, &pte);
if(NULL == p) return;
//The ref count on the physical page should decrement
page_decref(p);
// Set the respective page table entry to 0
if(pte != NULL)
*pte = 0;
//Set the TLB invalid
tlb_invalidate(pgdir, va);
}
================================end=====================================
5、page_insert()
===============================code=====================================
int
page_insert(pde_t *pgdir, struct Page *pp, void *va, int perm)
{
// Fill this function in
pte_t *pte;
pte = pgdir_walk(pgdir, va, 1);
if(NULL == pte)
return -E_NO_MEM;
// First increase the reference count so the page doesn't get
// removed in the next step if we try to repeat a mapping
pp->pp_ref++;
// If there is something mapped there, page remove it
if( (*pte & PTE_P) != 0)
page_remove(pgdir, va);
*pte = page2pa(pp) |PTE_P |perm;
return 0;
}
================================end=====================================
6、补全i386_vm_init()
===============================code=====================================
......
//////////////////////////////////////////////////////////////////////
// Map 'pages' read-only by the user at linear address UPAGES
// (ie. perm = PTE_U | PTE_P)
// Permissions:
// - pages -- kernel RW, user NONE
// - the read-only version mapped at -- kernel R, user R
// Your code goes here:
n = ROUNDUP(npage*sizeof(struct Page), PGSIZE);
assert(n < 4 *1024 * 1024);
boot_map_segment(pgdir, UPAGES, n,
PADDR(pages),PTE_W |PTE_U);
//////////////////////////////////////////////////////////////////////
// Map the kernel stack (symbol name "bootstack"). The complete VA
// range of the stack, [KSTACKTOP-PTSIZE, KSTACKTOP), breaks into two
// pieces:
// * [KSTACKTOP-KSTKSIZE, KSTACKTOP) -- backed by physical memory
// * [KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) -- not backed => faults
// Permissions: kernel RW, user NONE
// Your code goes here:
boot_map_segment(pgdir, KSTACKTOP-KSTKSIZE, KSTKSIZE,
PADDR(bootstack), PTE_W |PTE_P)
boot_map_segment(pgdir, KSTACKTOP-PTSIZE, PTSIZE-KSTKSIZE, 0, 0);
//////////////////////////////////////////////////////////////////////
// Map all of physical memory at KERNBASE.
// Ie. the VA range [KERNBASE, 2^32) should map to
// the PA range [0, 2^32 - KERNBASE)
// We might not have 2^32 - KERNBASE bytes of physical memory, but
// we just set up the amapping anyway.
// Permissions: kernel RW, user NONE
// Your code goes here:
boot_map_segment(pgdir, KERNBASE, ~KERNBASE+1,0, PTE_W|PTE_P);
......
}
================================end=====================================
阅读(4412) | 评论(0) | 转发(0) |