您的位置:首页 > 其它

操作系统ucore lab3实验报告

2017-04-25 00:47 387 查看

练习0

填写已有实验

  本实验依赖实验1和实验2.请把要做的实验1的代码填入本实验中代码有lab1、lab2的注释相应部分

首先利用meld工具比较两个文件的差异





发现缺失的是
kdebug.c、trap.c、default_pmm.c、pmm.c
四个文件的相关代码,补全后进行下一练习

练习1

给未被映射的地址映射上物理页(需要编程)

  完成
do_pgfault(mm/vmm.c)
函数,给未被映射的地址映射上物理页。设置访问权限的时候需要参考页面所在VMA的权限,同时需要注意映射物理页时需要操作内存控制结构所制定的页表,而不是内核的页表。

原理分析

  在程序的执行过程中由于某种原因(页框不存在/写只读页等)而是CPU无法最终访问到相应的物理内存单元,即无法完成从虚拟地址到物理地址的映射是,CPU会产生一次页错误异常,从而需要进行相应的页错误异常服务例程。当相关处理完成后,将返回产生异常的指令处重新执行,使得软件正常运行。

[b]产生页面异常的只要原因如下:[/b]

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

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

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

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

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


  因此此函数是完成页错误异常处理的主要函数,他根据从CPU的控制寄存器CR2中获取的页错误异常的虚拟地址,以及根据error code的错误类型来查找次虚拟地址是否在某个VMA的地址范围内,并且是否满足正确的读写权限,如果在此范围内并且权限也正确,就认为这是一次合法访问,但没有建立虚实对应关系,所以需要分配一个空闲的内存页,并修改页表完成虚地址到物理地址的映射,刷新TLB,然后调用iret中断,返回并重新执行。如果该虚地址不在某VMA范围内,这认为是一个非法访问

这里把vma_struct结构的变量简称为VMA变量。

vma_struct

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
指向用来链接记录页访问情况的链表头

结构关系



代码补充

do_pgfault

首先看下注释

/*LAB3 EXERCISE 1: YOUR CODE
* Maybe you want help comment, BELOW comments can help you finish the code
*
* Some Useful MACROs and DEFINEs, you can use them in below implementation.
* MACROs or Functions:
*   get_pte : get an pte and return the kernel virtual address of this pte for la
*             if the PT contians this pte didn't exist, alloc a page for PT (notice the 3th parameter '1')
*   pgdir_alloc_page : call alloc_page & page_insert functions to allocate a page size memory & setup
*             an addr map pa<--->la with linear address la and the PDT pgdir
* DEFINES:
*   VM_WRITE  : If vma->vm_flags & VM_WRITE == 1/0, then the vma is writable/non writable
*   PTE_W           0x002                   // page table/directory entry flags bit : Writeable
*   PTE_U           0x004                   // page table/directory entry flags bit : User can access
* VARIABLES:
*   mm->pgdir : the PDT of these vma
*
*/
(1) try to find a pte, if pte's PT(Page Table) isn't existed, then create a PT.
(2) if the phy addr isn't exist, then alloc a page & map the phy addr with logical addr


相关定义







根据注释修改代码

if (ptep == NULL)
{
cprintf("get_pte in do_pgfault failed\n");
goto failed;
}
// if the phy addr isn't exist, then alloc a page & map the phy addr with logical addr
//页表不存在
if (*ptep == 0)
{ //尝试分配一空闲页,匹配物理地址与逻辑地址,建立对应关系
if (pgdir_alloc_page(mm->pgdir, addr, perm) == NULL) {//失败内存不够退出
cprintf("pgdir_alloc_page in do_pgfault failed\n");
goto failed;
}
}


练习2

补充完成基于
FIFO
的页面替换算法(需要编程)

  完成
vmm.c
中的
do_pgfault
函数,并且在实现
FIFO
算法的
swap_fifo.c
中完成
map_swappable
swap_out_victim
函数。通过对swap的测试

分析

  根据练习1,当页错误异常发生时,有可能是因为页面保存在swap区或者磁盘文件上造成的,所以我们需要利用页面替换算法解决这个问题。

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

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

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

  在换入时,需要先检查产生访问异常的地址是否属于某个VMA表示的合法虚拟地址,并且保存在硬盘的swap文件中(即对应的PTE的高24位不为0,而最低位为0),则是执行页换入的时机,将调用swap_in函数完成页面换入。

  在换出时,采取的是消极的换出策略,是在调用alloc_pages函数获取空闲页时,此函数如果发现无法从物理内存页分配器(比如First Fit)获得空闲页,就会进一步调用swap_out函数 换出某页,实现一种消极的换出策略

相关定义









代码

do_pgfault

查看注释

/*LAB3 EXERCISE 2: YOUR CODE
* Now we think this pte is a  swap entry, we should load data from disk to a page with phy addr,
* and map the phy addr with logical addr, trigger swap manager to record the access situation of this page.
*
*  Some Useful MACROs and DEFINEs, you can use them in below implementation.
*  MACROs or Functions:
*    swap_in(mm, addr, &page) : alloc a memory page, then according to the swap entry in PTE for addr,
*                               find the addr of disk page, read the content of disk page into this memroy page
*    page_insert : build the map of phy addr of an Page with the linear addr la
*    swap_map_swappable : set the page swappable
*/


根据注释补充代码

else
{ // if this pte is a swap entry, then load data from disk to a page with phy addr
// and call page_insert to map the phy addr with logical addr
if(swap_init_ok)
{//页表项非空,根据mm结构和addr地址,尝试将硬盘中的内容换入page中
struct Page *page=NULL;
ret = swap_in(mm, addr, &page);
if (ret != 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;
}
}


_fifo_map_swappable()

  首先是
_fifo_map_swappable
,可用于建立页访问属性和关系,比如访问时间的先后顺序。

首先看下注释

//record the page access situlation
/*LAB3 EXERCISE 2: YOUR CODE*/
//(1)link the most recent arrival page at the back of the pra_list_head qeueue.


根据注释写代码

/*
* (3)_fifo_map_swappable: According FIFO PRA, we should link the most recent arrival page at the back of pra_list_head qeueue
*/
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);
//record the page access situlation /*LAB3 EXERCISE 2: YOUR CODE*/ //(1)link the most recent arrival page at the back of the pra_list_head qeueue.//将最近用到的页面添加到次序的队尾
list_add(head, entry);
return 0;
}


_fifo_swap_out_victim()

  然后是
_fifo_swap_out_victim
,可用于实现挑选出要换出的页。

查看下注释

/* Select the victim */
/*LAB3 EXERCISE 2: YOUR CODE*/
//(1)  unlink the  earliest arrival page in front of pra_list_head qeueue
//(2)  set the addr of addr of this page to ptr_page


根据注释写代码

/*
*  (4)_fifo_swap_out_victim: According FIFO PRA, we should unlink the  earliest arrival page in front of pra_list_head qeueue,
*                            then set the addr of addr of this page to ptr_page.
*/
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);
/* Select the victim */
/*LAB3 EXERCISE 2: YOUR CODE*/
//(1)  unlink the  earliest arrival page in front of pra_list_head qeueue
//(2)  set the addr of addr of this page to ptr_page
/* Select the tail */
//指出需要被换出的页
list_entry_t *le = head->prev;
assert(head != le);
//le2page 宏可以根据链表元素,获得对应page的指针
struct Page *p = le2page(le, pra_page_link);
//将进来最早的页面从队列中删除
list_del(le);
assert(p != NULL);
//将这一页的地址存储在ptr_page中
*ptr_page = p;
return 0;
}


运行结果



运行成功

收获

  通过本次实验,我了解物理内存管理中的连续空间分配算法的具体实现,熟悉掌握Page Fault异常处理和FIFO页替换算法的实现。对页面替换机制有了一个大题的了解,在试验中学习,收获较多。但还是对执行流程较为模糊,对页替换算法还是掌握不牢,需要进一步的巩固学习.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  操作系统