清华大学操作系统课程lab2实验报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
物理内存管理实验报告
练习0:合并lab1和lab2
书上提示使用“diff/merge”工具来合并lab1和lab2的代码,可是没有找到这款工具,但是被推荐使用meld工具,也能很方便地将不同目录的文件异同比较出来,可以一一手动合并,删除,增加代码,避免了不必要的错误。
这部分主要合并的文件有kdebug.c、trap.c。
练习1:实现firstfit连续物理内存分配算法。
完成合并代码的工作之后,make qemu执行lab2,结果出现错误提示:
提示default_pmm.c的第283行出现错误,打开文件看,发现这句话出现在函数static void default_check(void) 中,这是一个检查函数,并且提示不要修改。
当然,为了调试工作,在检查函数中加一些代码还是可以的。例如通过cprintf输出一些调试信息,除此之外,还发现check函数中使用大量assert函数,大概作用是当参数条件不为1的时候就弹出debug minitor。也可以用来调试作用。
起初,我仔细看了basic_check函数,它的作用只是做了一些简单的分配释放的操作,并且也没出错,后面看了default_check函数之后也没找到问题所在。再然后是重点分析default_alloc_pages和default_free_pages函数,结合list_add函数看了许久才发现它的空闲块插入顺序有问题:每次插入都是从free_list的头部插入,事实上,应该保持free_list 的顺序,地址小的空闲块应该放在前面,地址大的空闲块应该放在后面,以便firstfit算法的从头快速查找。
找到问题后大致明白了这个exercise的目标:这个练习主要就是完善
default_alloc_pages和default_free_pages。
关键变量:
#define free_list (free_area.free_list)//空闲块的链表,但是不指向具体页
#define nr_free (free_area.nr_free)//空闲块的个数
关键函数:
list_init(&free_list);//初始化空闲块链表
SetPageProperty(base);
ClearPageProperty(base);
关键宏:
le2page(le, page_link);//由链表指针得到对应页的地址
(一)Alloc pages:用firstfit算法寻找空闲块
list_entry_t *le = &free_list;
while ((le = list_next(le)) != &free_list) {
struct Page *p = le2page(le, page_link);
if (p->property >= n) {
page = p;
break;
}
}
(二)Alloc pages:删除空闲块,若有剩余则把剩余的部分插入空闲块链表
if (page != NULL)
{
list_del(&(page->page_link));
if (page->property > n) {
struct Page *p = page + n;
p->property = page->property - n;
//list_add(&free_list, &(p->page_link));
//Excise 1 :My Code
list_add(page->page_link.prev, &(p->page_link));/////////应该要插在链表合适的位置
}
nr_free -= n;
ClearPageProperty(page);
}
(三)Free pages:删除指定块相邻的空闲块,合并成大空闲块
while (le != &free_list) {
p = le2page(le, page_link);
le = list_next(le);
if (base + base->property == p) {
base->property += p->property;
ClearPageProperty(p);
list_del(&(p->page_link));
}
else if (p + p->property == base) {
p->property += base->property;
ClearPageProperty(base);
base = p;
list_del(&(p->page_link));
}
}
(四)Free pages:把大空闲块假如空闲块链表
//Excise 1:My Code 把新的大空闲块插入free_list
le=list_next(&free_list);
if(le==&free_list)//假如之前的删除操作刚好把空闲块链表清空
list_add(&free_list,&(base->page_link));
else
{//找合适的位置把大空闲块入free_list
while(le!=&free_list)
{
p=le2page(le,page_link);
if (p>base)
{
list_add_before(&(p->page_link),&(base->page_link));
break;
}
le=list_next(le);
}
if(le==&free_list)//假如找不到比base序号大的页,则放在链表尾部
list_add_after(free_list.prev,&(base->page_link));
}
}
练习2、实现寻找虚拟地址对应的页表项
关键的函数以及宏函数:
* PDX(la) = 返回虚拟地址la的页目录索引
* KADDR(pa) : 返回物理地址pa相关的内核虚拟地址
* set_page_ref(page,1) : 设置此页被引用了一次
* page2pa(page): 得到page管理的那一页的物理地址
* struct Page * alloc_page() : 分配一页出来
* memset(void *s, char c, size_t n) : 设置s指向地址的前面n个字节为字节‘c’.
pde_t *pdep = &pgdir[PDX(la)];//得到页目录项
if (!(*pdep & PTE_P)) {//假如页目录项不存在
struct Page *page;
if (!create || (page = alloc_page()) == NULL) {//假如不需要分配页或者分配页失败
return NULL;
}
set_page_ref(page, 1);//设置该页被引用了一次
uintptr_t pa = page2pa(page);//得到该页物理地址
memset(KADDR(pa), 0, PGSIZE);//物理地址转虚拟地址,然后把该页初始化
*pdep = pa | PTE_U | PTE_W | PTE_P;//设置可读,可写,存在位
}
return &((pte_t *)KADDR(PDE_ADDR(*pdep)))[PTX(la)];
//KADDR(PDE_ADDR(*pdep)):这部分是由页目录项地址得到关联的页表物理地址,再转成虚拟地址
//PTX(la):返回虚拟地址la的页表项索引