操作系统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!
所以实验成功
相关文章推荐
- 【持久化框架】SpringMVC+Spring4+Mybatis3 集成,开发简单Web项目+源码下载
- hdu 5701(区间查询思路题)
- c语言的基本类型
- LeetCode 62. Unique Paths
- 第十六周--用文件保存的学生名单
- poj之旅——2155
- Sublime text 3安装Emmet插件
- SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
- elasticsearch web界面查询
- github注册,使用方法
- 拼图响应式前端框架版响应式后台
- 对于解析txt 格式的的文件
- Hibernate(四)
- No space left on device
- 操作系统ucore lab2实验报告
- 闭包概述的例子
- Java设计模式其一【单例设计模式】
- ios学习路线—iOS高级(UDP)
- 数据库复习⑥
- 操作系统ucore lab1实验报告