清华大学操作系统课程lab2实验报告

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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的页表项索引

相关文档
最新文档