文章目录
Part1 Physical Page Management
Exercise1
boot_alloc()
result = nextfree;
if (n > 0) {
nextfree = ROUNDUP((char *) (nextfree + n), PGSIZE);
}
return result;
mem_init()
pages = (struct PageInfo*) boot_alloc(sizeof(struct PageInfo) * npages);
memset(pages, 0, sizeof(struct PageInfo) * npages)
page_init()
#define MARK_FREE(_i) \
({ \
pages[_i].pp_ref = 0; \
pages[_i].pp_link = page_free_list; \
page_free_list = &pages[_i]; \
})
#define MARK_USE(_i) \
({ \
pages[_i].pp_ref = 0; \
pages[_i].pp_link = NULL; \
})
page_free_list = NULL;
physaddr_t kern_pgdir_end = PADDR(boot_alloc(0));
size_t i;
// 1)
MARK_USE(0);
// 2)
for (i = 1; i < npages_basemem; i++) {
MARK_FREE(i);
}
// 3)
for (i = IOPHYSMEM / PGSIZE; i < EXTPHYSMEM / PGSIZE; i++) {
MARK_USE(i);
}
// 4)
for (i = EXTPHYSMEM / PGSIZE; i < kern_pgdir_end / PGSIZE; i++) {
MARK_USE(i);
}
for (i = kern_pgdir_end / PGSIZE; i < npages; i++) {
MARK_FREE(i);
}
#undef MARK_FREE
#undef MARK_USE
page_alloc()
if (!page_free_list) {
return NULL;
}
struct PageInfo* alloc_page = page_free_list;
page_free_list = page_free_list->pp_link;
alloc_page->pp_link = NULL;
alloc_page->pp_ref = 0;
if (alloc_flags & ALLOC_ZERO) {
memset(page2kva(alloc_page), 0, PGSIZE);
}
return alloc_page;
page_free()
if (pp->pp_ref != 0 || pp->pp_link != NULL) {
panic("page_free");
}
pp->pp_link = page_free_list;
page_free_list = pp;
Part2 Virtual Memory
Exercise 2. Look at chapters 5 and 6 of the Intel 80386 Reference Manual, if you haven’t done so already. Read the sections about page translation and page-based protection closely (5.2 and 6.4). We recommend that you also skim the sections about segmentation; while JOS uses the paging hardware for virtual memory and protection, segment translation and segment-based protection cannot be disabled on the x86, so you will need a basic understanding of it.
Virtual, Linear, and Physical Addresses
Exercise3
C Type | Address Type |
---|---|
T* | Virtual |
uintptr_t | Virtual |
physaddr_t | Physical |
Question1
uintptr_t
Reference counting
Page Table Management
Exercise4
pgdir_walk()
pde_t *pde;
pte_t *pgtab;
pde = &pgdir[PDX(va)];
if (*pde & PTE_P) {
pgtab = (pte_t*)KADDR(PTE_ADDR(*pde));
} else {
struct PageInfo *pp = page_alloc(ALLOC_ZERO);
if (!create || !page)
return NULL;
pp->pp_ref += 1;
pgtab = (pte_t*)KADDR(page2pa(pp));
memset(pgtab, 0, PGSIZE);
*pde = PADDR(pgtab) | PTE_P | PTE_W | PTE_U;
}
return &pgtab[PTX(va)];
boot_map_region
char *a, *last;
pte_t* pte;
a = (char*)va;
last = (char*)(va + size - 1);
while(1) {
if((pte = pgdir_walk(pgdir, a, 1)) == NULL)
return -1;
if(*pte & PTE_P)
panic("remap");
*pte = pa | perm | PTE_P;
if (a == last)
break;
a += PGSIZE;
pa += PGSIZE;
}
page_lookup()
pte_t *pte = pgdir_walk(pgdir, va, 0);
if (!pte || !(*pte & PTE_P)) {
return NULL;
}
if (pte_store) {
*pte_store = pte;
}
return pa2page(PTE_ADDR(*pte));
page_remove()
struct PageInfo *pp;
pte_t *pte;
if (pp = page_lookup(pgdir, va, &pte)) {
page_decref(pp);
memset(pte, 0, sizeof(pte_t));
tlb_invalidate(pgdir, va);
}
page_insert()
pte_t *pte;
if (!(pte = pgdir_walk(pgdir, va, 1))) {
return -E_NO_MEM;
}
pp->pp_ref++;
page_remove(pgdir, va)
*pte = page2pa(pp) | perm | PTE_P;
return 0;
Part3 Kernel Address Space
内核和用户环境空间以ULIM
为分割线,ULIM
以上为内核空间,以下为用户环境空间
Permissions and Fault Isolation
用户环境无法访问ULIM
以上的空间,内核和用户环境都可以读取[UTOP,ULIM)
之间的空间,UTOP
以下的空间为用户环境空间,可以设置相应的权限
Initializing the Kernel Address Space
Exercise5
mem_init()
boot_map_region(kern_pgdir, UPAGES, PTSIZE, PADDR(pages), PTE_U);
boot_map_region(kern_pgdir, KSTACKTOP - KSTKSIZE, KSTKSIZE, PADDR(bootstacktop), PTE_W);
boot_map_region(kern_pgdir, KERNBASE, ~(uint32_t)0 - KERNBASE + 1, 0, PTE_W);
Question2:
3BD号页目录项,指向的是kern_pgdir
3BC号页目录项,指向的是pages数组
3BF号页目录项,指向的是bootstack
3C0~3FF号页目录项,指向的是kernel
Question3:
因为用户空间和内核空间的页表项中的PTE_U位不同。本质上是x86处理器的MMU通过CS寄存器的特权级结合页表项的PTE_U位来判断当前代码是否有访问特定地址的权限
Question4:
由于这个操作系统利用一个大小为4MB的空间UPAGES来存放所有的页的PageInfo结构体信息,每个结构体的大小为8B,所以一共可以存放512K个PageInfo结构体,所以一共可以出现512K个物理页,每个物理页大小为4KB,自然总的物理内存占2GB。
Question5:
管理内存的开销为1个一级页表与1024个二级页表,再加上4MB的PAGES,即 1025 * 4KB + 4MB = 6100KB
Question6:
在执行指令jmp *%eax
时,会重新设置EIP的值,使其大于KERNBASE。EIP处于低地址仍然可以运行,是因为entry_pgdir
包含了虚拟内存0~4MB到物理内存0~4MB的映射,目的是兼容从物理访存到虚拟访存
Address Space Layout Alternatives
进程的虚拟地址空间布局不唯一
Reference
操作系统实验报告_MIT 6.828 JOS Lab2 实验报告
MIT-6.828 Lab 2: Memory Management实验报告