操作系统ucore lab3实验报告

练习0

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

首先利用meld工具比较两个文件的差异
操作系统ucore lab3实验报告_第1张图片

操作系统ucore lab3实验报告_第2张图片

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

练习1

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

原理分析

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

产生页面异常的只要原因如下:
  • 目标页面不存在(页表项全为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_startvm_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指向用来链接记录页访问情况的链表头

结构关系

操作系统ucore lab3实验报告_第3张图片

代码补充

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

相关定义

这里写图片描述

这里写图片描述

操作系统ucore lab3实验报告_第4张图片

根据注释修改代码

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_swappableswap_out_victim函数。通过对swap的测试

分析

  根据练习1,当页错误异常发生时,有可能是因为页面保存在swap区或者磁盘文件上造成的,所以我们需要利用页面替换算法解决这个问题。
  页面替换主要分为两个方面,页面换出和页面换入。
- 页面换入主要在上述的do_pgfault()函数实现;
- 页面换出主要在swap_out_vistim()函数实现。

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

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

相关定义

这里写图片描述

这里写图片描述

操作系统ucore lab3实验报告_第5张图片

这里写图片描述

代码

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;
}

运行结果

操作系统ucore lab3实验报告_第6张图片

运行成功

收获

  通过本次实验,我了解物理内存管理中的连续空间分配算法的具体实现,熟悉掌握Page Fault异常处理和FIFO页替换算法的实现。对页面替换机制有了一个大题的了解,在试验中学习,收获较多。但还是对执行流程较为模糊,对页替换算法还是掌握不牢,需要进一步的巩固学习.

你可能感兴趣的:(操作系统)