您的位置:首页 > 其它

操作系统ucore lab3实验报告

2016-06-18 20:08 357 查看

操作系统lab3实验报告

本次实验主要完成ucore内核对虚拟内存的管理工作。其总体设计思路还是比较简单,即首先完成初始化虚拟内存管理机制,即需要设置好哪些页需要放在物理内存中,哪些页不需要放在物理内存中,而是可被换出到硬盘上,并涉及完善建立页表映射、页错误异常处理操作等函数实现。然后就执行一组访存测试,看看我们建立的页表项是否能够正确完成虚实地址映射,是否正确描述了虚拟内存页在物理内存中还是在硬盘上,是否能够正确把虚拟内存页在物理内存和硬盘之间进行传递,是否正确实现了页面替换算法等。

练习0 填写已有实验

同样与lab2类似,我使用了名为
meld
的一款文件比对工具,直接比对
lab2
lab3
两个文件夹,它就能把其中不相同的部分列举出来,然后比对进行修改即可。大致截图如下:



比对修改之后,大致罗列一下有以下文件需要我们进行修改:

default_pmm.c
pmm.c
trap.c


练习0主要要让我们修改补充的就是上述四个文件。直接在
meld
里面对比复制就行了。也没有什么技术含量。

练习1 给未被映射的地址映射上物理页

本实验要求完成
do_pgfault
函数,作用给未被映射的地址映射上物理页。

具体而言,当启动分页机制以后,如果一条指令或数据的虚拟地址所对应的物理页框不在内

存中或者访问的类型有错误(比如写一个只读页或用户态程序访问内核态的数据等),就会发生

页错误异常。产生页面异常的原因主要有:

目标页面不存在(页表项全为0,即该线性地址与物理地址尚未建立映射或者已经撤销);

相应的物理页面不在内存中(页表项非空,但Present标志位=0,比如在swap分区或磁盘文件上)

访问权限不符合(此时页表项P标志=1,比如企图写只读页面).

当出现上面情况之一,那么就会产生页面
page fault(#PF)
异常。产生异常的线性地址存储在

CR2中,并且将是
page fault
的产生类型保存在 error code 中

那么我们的这个
do_pgfault
函数的思路就明显了。
do_pgfault()
函数从CR2寄存器中获取页错误异常的虚拟地址,根据
error code
来查找这个虚拟地址是否在某一个VMA的地址范围内,那么就给它分配一个物理页。

这里的VMA是描述应用程序对虚拟内存“需求”的变量,如下:

struct vma_struct {
// the set of vma using the same PDT
struct mm_struct *vm_mm;
uintptr_t vm_start;      // start addr of vma
uintptr_t vm_end;      // end addr of vma
uint32_t vm_flags;     // flags of vma
//linear list link which sorted by start addr of vma
list_entry_t list_link;
};


vm_start
vm_end
描述的是一个合理的地址空间范围(即严格确保 vm_start < vm_end的关系);

list_link
是一个双向链表,按照从小到大的顺序把一系列用
vma_struct
表示的虚拟内存空间链接起来,并且还要求这些链起来的
vma_struct
应该是不相交的,即vma之间的地址空间无交集;

vm_flags
表示了这个虚拟内存空间的属性,目前的属性包括

> #define VM_READ 0x00000001   //只读
#define VM_WRITE 0x00000002  //可读写
#define VM_EXEC 0x00000004   //可执行


vm_mm
是一个指针,指向一个比
vma_struct
更高的抽象层次的数据结构
mm_struct


而这
mm_struct
包含所有虚拟内存空间的共同属性,如下:

struct mm_struct {
// linear list link which sorted by start addr of vma
list_entry_t mmap_list;
// current accessed vma, used for speed purpose
struct vma_struct *mmap_cache;
pde_t *pgdir; // the PDT of these vma
int map_count; // the count of these vma
void *sm_priv; // the private data for swap manager
};


mmap_list
是双向链表头,链接了所有属于同一页目录表的虚拟内存空间

mmap_cache
是指向当前正在使用的虚拟内存空间

pgdir
所指向的就是
mm_struct
数据结构所维护的页表

map_count
记录
mmap_list
里面链接的
vma_struct
的个数

sm_priv
指向用来链接记录页访问情况的链表头

最后具体的实现如下:(这里只摘录了我填写的部分)

if ((ptep = get_pte(mm->pgdir, addr, 1)) == NULL) { //目标页面不存在,失败
cprintf("get_pte in do_pgfault failed\n");
goto failed;
}

if (*ptep == 0) {   //权限不够,也是失败!
if (pgdir_alloc_page(mm->pgdir, addr, perm) == NULL) {
cprintf("pgdir_alloc_page in do_pgfault failed\n");
goto failed;
}
}
else {   //页表项非空,可以尝试换入页面
if(swap_init_ok) {
struct Page *page=NULL;//根据mm结构和addr地址,尝试将硬盘中的内容换入至page中
if ((ret = swap_in(mm, addr, &page)) != 0) {
cprintf("swap_in in do_pgfault failed\n");
goto failed;
}
page_insert(mm->pgdir, page, addr, perm);//建立虚拟地址和物理地址之间的对应关系
swap_map_swappable(mm, addr, page, 1);//将此页面设置为可交换的
page->pra_vaddr = addr;
}
else {
cprintf("no swap_init_ok but ptep is %x, failed\n",*ptep);
goto failed;
}
}


练习2 补充完成基于
FIFO()
的页面替换算法

页错误异常发生时,有可能是因为页面保存在swap区或者磁盘文件上造成的,所以我们需要通过页面分配解决这个问题。

页面替换主要分为两个方面,页面换出和页面换入。

页面换入主要在上述的
do_pgfault()
函数实现;

页面换出主要在
swap_out_vistim()
函数实现。

这里换入在练习1已经完成了,这里就主要介绍换出。

FIFO
替换算法会维护一个队列,队列按照页面调用的次序排列,越早被加载到内存的页面会越早被换出。

具体实现的函数如下:

首先是
_fifo_map_swappable()
,它的主要作用是将最近被用到的页面添加到算法所维护的次序队列。

static int _fifo_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in) {
list_entry_t *head=(list_entry_t*) mm->sm_priv;
list_entry_t *entry=&(page->pra_page_link);
assert(entry != NULL && head != NULL);
list_add(head, entry); //将最近用到的页面添加到次序队尾
return 0;
}


然后是
_fifo_swap_out_victim()
函数是用来查询哪个页面需要被换出,它的主要作用是用来查询哪个页面需要被换出。

static int
_fifo_swap_out_victim(struct mm_struct *mm, struct Page ** ptr_page, int in_tick) {
list_entry_t *head=(list_entry_t*) mm->sm_priv;
assert(head != NULL);
assert(in_tick==0);
list_entry_t *le = head->prev;  //用le指示需要被换出的页
assert(head!=le);
struct Page *p = le2page(le, pra_page_link);//le2page宏可以根据链表元素获得对应的Page指针p
list_del(le);      //将进来最早的页面从队列中删除
assert(p !=NULL);
*ptr_page = p; //将这一页的地址存储在ptr_page中
return 0;
}


结果截图

由于在虚拟机内部,而且滚屏稍快,所以这里截图如下:



这里可以看到如下部分:

........
check_vma_struct() succeeded!
page fault at 0x00000100: K/W [no page found].
check_pgfault() succeeded!
check_vmm() succeeded.
........


然后是下图:



可以看到这个

check_swap() succeeded!


所以实验成功
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: