LAB2_Part 1 Physical Page Management
前言
记录一下自己的学习过程
实验内容翻译:
https://gitee.com/cherrydance/mit6.828
该翻译仅供参考
首先备份lab1。然后如下图所示执行,得到lab2
练习1
在文件 kern/pmap.c 中,您需要按照给定的顺序实现以下函数的代码。
boot_alloc()
mem_init()(仅限到调用 check_page_free_list(1) 的部分)
page_init()
page_alloc()
page_free()
check_page_free_list() 和 check_page_alloc() 用于测试您的物理页面分配器。您应该启动 JOS 并查看 check_page_alloc() 是否报告成功。修改您的代码,使其通过测试。您可以添加自己的 assert() 来验证您的假设是否正确。
首先我们在init.c中找到i386_init()函数,里面调用了mem_init(),进入此函数发现它先调用了boot_alloc()函数来创造一个初始页目录。该函数也是要求我们补全的第一个函数。
先看给出的注释和提示告诉我们要实现什么功能。
// Allocate a chunk large enough to hold 'n' bytes, then update
// nextfree. Make sure nextfree is kept aligned
// to a multiple of PGSIZE.
//分配足够大以容纳'n'字节的块,然后更新nextfree。
//确保将nextfree保持对PGSIZE的倍数对齐。
实现代码如下
result = nextfree;
nextfree = ROUNDUP(nextfree + n, PGSIZE);
if((uint32_t)nextfree - KERNBASE > (npages * PGSIZE)){
panic("out of memory!\n");
}
return result;
在memlayout.h和pamp.c的开头给出了一些关键信息,所有物理内存映射到KERNBASE地址上。
//pmap.c
size_t npages; // Amount of physical memory (in pages)
//memlayout.h
// All physical memory mapped at this address
#define KERNBASE 0xF0000000
在mem_init函数中继续往下看,
// Allocate an array of npages 'struct PageInfo's and store it in 'pages'.
// The kernel uses this array to keep track of physical pages: for
// each physical page, there is a corresponding struct PageInfo in this
// array. 'npages' is the number of physical pages in memory. Use memset
// to initialize all fields of each struct PageInfo to 0.
意思是让我们分配一块内存存放一个PageInfo的结构体数组将其存储在pages中。这块内存的大小为npages * sizeof(struct PageInfo),并将所有内存初始化为0。
实现代码如下:
pages = (struct PageInfo*) boot_alloc(npages * sizeof(struct PageInfo));
memset(pages, 0, npages * sizeof(struct PageInfo));
接下来是page_init()函数。其要求如下:
// 1) Mark physical page 0 as in use.
// This way we preserve the real-mode IDT and BIOS structures
// in case we ever need them. (Currently we don't, but...)
// 2) The rest of base memory, [PGSIZE, npages_basemem * PGSIZE)
// is free.
// 3) Then comes the IO hole [IOPHYSMEM, EXTPHYSMEM), which must
// never be allocated.
// 4) Then extended memory [EXTPHYSMEM, ...).
// Some of it is in use, some is free. Where is the kernel
// in physical memory? Which pages are already in use for
// page tables and other data structures?
总结就是pages[0]默认占用,[IOPHYSMEM, EXTPHYSMEM)占用,在boot_alloc中已经分配的占用,剩下的全是空闲的。实现代码:
size_t i;
size_t io_pagenum = (EXTPHYSMEM - IOPHYSMEM) / PGSIZE;
size_t allo_pagenum = ((uint32_t)boot_alloc(0) - KERNBASE) / PGSIZE;
for (i = 0; i < npages; i++) {
if(i == 0){
//条件1
pages[i].pp_ref = 1;
}else if(i >= npages_basemem && i <(npages_basemem + io_pagenum + allo_pagenum)){
//条件3和条件4
pages[i].pp_ref = 1;
}else{
pages[i].pp_ref = 0;
pages[i].pp_link = page_free_list;
page_free_list = &pages[i];
}
}
接下来是实现page_alloc()函数,同样的我们先看给出的提示:
// Allocates a physical page. If (alloc_flags & ALLOC_ZERO), fills the entire
// returned physical page with '\0' bytes. Does NOT increment the reference
// count of the page - the caller must do these if necessary (either explicitly
// or via page_insert).
//
// Be sure to set the pp_link field of the allocated page to NULL so
// page_free can check for double-free bugs.
//
// Returns NULL if out of free memory.
//
// Hint: use page2kva and memset
分配一个物理页,如果(alloc_flags & ALLOC_ZERO),怎将整个页面填充为0。
不增加页面的引用计数且将pp_link设置为NULL。如果超出空闲内存返回NULL。
提示的page2kav函数接收一个页面地址,将其转化为内核虚拟地址。
实现代码如下:
struct PageInfo *
page_alloc(int alloc_flags)
{
// Fill this function in
struct PageInfo *temp;
if(page_free_list == NULL){
//没有可分配的页面
return NULL;
}
temp = page_free_list;
page_free_list = temp->pp_link;
temp->pp_link = NULL;
//从free链表中取出第一个节点的操作
if(alloc_flags & ALLOC_ZERO){
memset(page2kva(temp), 0, PGSIZE);
}
return temp;
}
最后一个函数是page_free函数。
// Return a page to the free list.
// (This function should only be called when pp->pp_ref reaches 0.)
这个函数的作用就是将一个使用完成的页面进行回收,将其重新放回page_free_list链表中。其代码如下:
if(pp->pp_ref != 0 || pp->pp_link != NULL){
panic("page_free error!\n");
}
pp->pp_link = page_free_list;
page_free_list = pp;
将mem_init函数中panic注释,make qemu查看结果:
可以看到check_page_free_list和check_page_alloc成功。
总结
lab2的part1完成。总的来说倒是不难,根据注释写代码,注意细节。
有问题欢迎大家指出。