操作系统实验:Lab3 虚拟内存管理

清华大学操作系统Lab3实验报告
课程主页:http://os.cs.tsinghua.edu.cn/oscourse/OS2018spring
实验指导书:https://chyyuu.gitbooks.io/ucore_os_docs/content/
github:https://github.com/chyyuu/ucore_os_lab

实验目的

  • 了解虚拟内存的Page Fault异常处理实现
  • 了解页替换算法在操作系统中的实现

实验内容

本次实验是在实验二的基础上,借助于页表机制和实验一中涉及的中断异常处理机制,完成Page Fault异常处理和FIFO页替换算法的实现,结合磁盘提供的缓存空间,从而能够支持虚存管理,提供一个比实际物理内存空间“更大”的虚拟内存空间给系统使用。这个实验与实际操作系统中的实现比较起来要简单,不过需要了解实验一和实验二的具体实现。实际操作系统系统中的虚拟内存管理设计与实现是相当复杂的,涉及到与进程管理系统、文件系统等的交叉访问。

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

kern/mm/vmm.c中,(解释见注释)

//(1) try to find a pte, if pte's PT(Page Table) isn't existed, then create a 
//    PT.
    ptep = get_pte(mm -> pgdir, addr, 1);              
    if (*ptep == 0) {
//(2) if the phy addr isn't exist, then alloc a page & map the phy addr 
//    with logical addr
        pgdir_alloc_page(mm -> pgdir, addr, perm);

    }
    else { ... }
请描述页目录项(Page Director Entry)和页表(Page Table Entry)中组成部分对ucore实现页替换算法的潜在用处。

页目录项(Page Director Entry):使用双向链表存储了目前所有的页的物理地址和逻辑地址的对应,即在物理内存中的所有页。替换算法中被换出的页从pgdir中选出。

页表(Page Table Entry)存储了替换算法中被换入的页的信息,替换后会将其映射到一物理地址。页表项中的dirty bit和访问位可以帮助实现一些页替换算法(比如extended clock)。

如果ucore的缺页服务例程在执行过程中访问内存,出现了页访问异常,请问硬件要做哪些事情?
  • 发生异常,将产生异常的地址保存在CR2寄存器中,同时还要将EFLAGS,CS,EIP,ErrorCode等保存在内核栈上。ErrorCode设为页访问异常的编码,即0xE
  • CPU将页访问异常的中断服务例程的地址加载到CS和EIP中,并开始执行中断服务程序。
  • OS:OS首先将寄存器保存在内核栈中,接下来按照trap--> trap_dispatch-->pgfault_handler-->do_pgfault的调用关系来执行中断服务程序。
  • OS:在do_pgfault里,OS可以获得ErrorCode,并根据ErrorCode为页访问异常,OS将执行上面补充的代码段,并完成中断服务例程。

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

kern/mm/vmm.c中,补全*ptep != 0分支后的内容。

        if(swap_init_ok) {
            struct Page *page=NULL;
            //swap_in(mm, addr, &page);           
//(1)According to the mm AND addr, try to load the content of right .
//    disk page into the memory which page managed.     
//(2) According to the mm, addr AND page, setup the map of phy addr. 
//    <---> logical addr   
            if (!swap_in(mm, addr, &page) && !page_insert(mm -> pgdir, page, addr, perm)) {
//(3) make the page swappable.
                swap_map_swappable(mm, addr, page, 0);
                page -> pra_vaddr = addr;
            }                       
        }
        else {
            cprintf("no swap_init_ok but ptep is %x, failed\n",*ptep);
            goto failed;
        }

kern/mm/swap_fifo.c中,补全_fifo_map_swappable_fifo_swap_out_victim两个函数。

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: 2015011346*/
    //(1)link the most recent arrival page at the back of the pra_list_head qeueue.
    list_add(head -> prev, entry);
    return 0;
}

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: 2015011346*/
     //(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
     list_entry_t *p = list_next(head);
     *ptr_page = le2page(p, pra_page_link);
     list_del(p);
     return 0;
}
如果要在ucore上实现"extended clock页替换算法"请给你的设计方案,现有的swap_manager框架是否足以支持在ucore中实现此算法?如果是,请给你的设计方案。如果不是,请给出你的新的扩展和基此扩展的设计方案。并需要回答如下问题

设计方案见challenge部分的实现。用现有的swap_manager框架可以支持ucore实现extended clock页替换算法(用dirty bit作为该算法的访问标记)。

  • 需要被换出的页的特征是什么?
    extended clock算法可以看成一种改进的LRU算法,它避免了LRU中在访问页或找替换页时必须对所有页进行扫描。因此被换出的页基本满足最久未被访问的特征。
  • 在ucore中如何判断具有这样特征的页?
    指针扫描到的第一个dirty bit为0的页。
  • 何时进行换入和换出操作?
    当需要调入的页不在页表中,且页表已满时,进行换入换出操作。
练习1、2测试结果

扩展练习 Challenge:实现识别dirty bit的 extended clock页替换算法

模仿kern/mm/swap_fifo.hkern/mm/swap_fifo.c,写出针对extended clock算法的kern/mm/swap_clock.hkern/mm/swap_clock.c。代码和解释如下:

#include <defs.h>
#include <x86.h>
#include <stdio.h>
#include <string.h>
#include <swap.h>
#include <swap_clock.h>
#include <list.h>

list_entry_t pra_list_head;

/*
 * (2) _clock_init_mm: init pra_list_head and let  mm->sm_priv point to the addr of pra_list_head.
 *              Now, From the memory control struct mm_struct, we can access extend clock PRA
 */
static int
_clock_init_mm(struct mm_struct *mm)
{
     list_init(&pra_list_head);
     mm->sm_priv = &pra_list_head;
     //cprintf(" mm->sm_priv %x in clock_init_mm\n",mm->sm_priv);
     return 0;
}

/*
 * (3)_clock_map_swappable: 按照课件的说法,应该将换入页插入到被换出页的位置。
*    实际操作中,换入页的在链表中的位置并不影响,因此将其插入到链表最末端。
 */
static int
_clock_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 -> prev, entry);
// 新插入的页dirty bit标记为0.
    struct Page *ptr = le2page(entry, pra_page_link);
    pte_t *pte = get_pte(mm -> pgdir, ptr -> pra_vaddr, 0);
    *pte &= ~PTE_D;
    return 0;
}
/*
 *  (4)_clock_swap_out_victim: 找到换出页,仿佛是指针沿链表扫描。
 *   如果扫描到的页dirty bit为1,则改为0;如果为0,则标记为换出页。
 */
static int
_clock_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 *p = head;
     while (1) {
         p = list_next(p);
         if (p == head) {
             p = list_next(p);
         }
         struct Page *ptr = le2page(p, pra_page_link);
         pte_t *pte = get_pte(mm -> pgdir, ptr -> pra_vaddr, 0);
// 如果dirty bit为1,改为0
         if ((*pte & PTE_D) == 1) {
             *pte &= ~PTE_D;
         } else {
// 如果dirty bit为0,则标记为换出页
             *ptr_page = ptr;
             list_del(p);
             break;
         }
     }
     return 0;
}

static int
_clock_check_swap(void) {
    cprintf("write Virt Page c in clock_check_swap\n");
    *(unsigned char *)0x3000 = 0x0c;
    assert(pgfault_num==4);
    cprintf("write Virt Page a in clock_check_swap\n");
    *(unsigned char *)0x1000 = 0x0a;
    assert(pgfault_num==4);
    cprintf("write Virt Page d in clock_check_swap\n");
    *(unsigned char *)0x4000 = 0x0d;
    assert(pgfault_num==4);
    cprintf("write Virt Page b in clock_check_swap\n");
    *(unsigned char *)0x2000 = 0x0b;
    assert(pgfault_num==4);
    cprintf("write Virt Page e in clock_check_swap\n");
    *(unsigned char *)0x5000 = 0x0e;
    assert(pgfault_num==5);
    cprintf("write Virt Page b in clock_check_swap\n");
    *(unsigned char *)0x2000 = 0x0b;
    assert(pgfault_num==5);
    cprintf("write Virt Page a in clock_check_swap\n");
    *(unsigned char *)0x1000 = 0x0a;
    assert(pgfault_num==6);
    cprintf("write Virt Page b in clock_check_swap\n");
    *(unsigned char *)0x2000 = 0x0b;
    assert(pgfault_num==7);
    cprintf("write Virt Page c in clock_check_swap\n");
    *(unsigned char *)0x3000 = 0x0c;
    assert(pgfault_num==8);
    cprintf("write Virt Page d in clock_check_swap\n");
    *(unsigned char *)0x4000 = 0x0d;
    assert(pgfault_num==9);
    cprintf("write Virt Page e in clock_check_swap\n");
    *(unsigned char *)0x5000 = 0x0e;
    assert(pgfault_num==10);
    cprintf("write Virt Page a in clock_check_swap\n");
    assert(*(unsigned char *)0x1000 == 0x0a);
    *(unsigned char *)0x1000 = 0x0a;
    assert(pgfault_num==11);
    return 0;
}


static int
_clock_init(void)
{
    return 0;
}

static int
_clock_set_unswappable(struct mm_struct *mm, uintptr_t addr)
{
    return 0;
}

static int
_clock_tick_event(struct mm_struct *mm)
{ return 0; }


struct swap_manager swap_manager_clock =
{
     .name            = "extend_clock swap manager",
     .init            = &_clock_init,
     .init_mm         = &_clock_init_mm,
     .tick_event      = &_clock_tick_event,
     .map_swappable   = &_clock_map_swappable,
     .set_unswappable = &_clock_set_unswappable,
     .swap_out_victim = &_clock_swap_out_victim,
     .check_swap      = &_clock_check_swap,
};

为了使用extended clock算法,将swap.c中swap_init函数的

sm = &swap_manager_fifo;

改为

sm = &swap_manager_clock;

测试结果如下:

extended clock页替换算法

覆盖的知识点

  • Page Fault异常处理
  • 页面置换机制

与参考答案的区别

  • 练习1:自己完成的。但是实现中没有加入对各种异常情况的处理(即goto fault),参考答案后补充上去了。
  • 练习2:自己完成的,差别是我的链表按照插入时间从早到晚排列,而答案的链表按照插入时间由晚到早排列。在阅读答案后,发现找到链表最后一个元素并不需要遍历一边,而是通过哨兵的prev指针就能找到,这样能够加速插入过程,遂按照答案的方法改正。
  • Challenge:自己完成。

总结

在经过了两个Lab的磕磕绊绊之后,终于意识到在开始实验之前应该认真观看Mooc并认真阅读实验指导书(特别是基本原理概述部分)。
虽然代码不到十行,却出现了三个bug。特别是最后一个,我发现lab1时的challenge实现已经不足以支持这次实验的页面替换了,所以一直在报一个奇怪的缺页错误。最后多亏多次make qemu了lab3_answer发现它没有输出set user mode才发现了这个这个问题。看来我对user mode和kernel mode的转换还缺乏了解。在发现无法借助Mooc的原理部分解决现有的问题后,我决定认真阅读一下Intel Manual来加深对操作系统的理解。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,454评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,553评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,921评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,648评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,770评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,950评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,090评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,817评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,275评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,592评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,724评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,409评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,052评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,815评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,043评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,503评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,627评论 2 350

推荐阅读更多精彩内容

  • 实验三:虚拟内存管理 专业班级: 学号: 姓名: 上课老师: 一、实验目的 1.了解虚拟内存的Page Fault...
    北北南北阅读 1,998评论 0 2
  • 清华大学操作系统Lab1实验报告课程主页:http://os.cs.tsinghua.edu.cn/oscours...
    wenj1997阅读 3,392评论 0 0
  • 操作系统对内存的管理 没有内存抽象的年代 在早些的操作系统中,并没有引入内存抽象的概念。程序直接访问和操作的都是物...
    Mr槑阅读 16,677评论 3 24
  • 我一直很想写武侠小说。 我觉得至今没有人写出我心中的江湖,除了一个人。 他说春风得意马蹄疾, 一日看尽长安花。 江...
    MorishimaC阅读 244评论 1 0
  • 名字:明天 职业:教职员工 描述绘画顺序:房子一路一花草一右侧树一左侧树一云朵一小鸟一人物(我,女儿,老公)本来画...
    Du紫藤阅读 227评论 0 0