ucore lab3

主要姓名:冯成 学号:19021221183 学院:电子工程学院

lab3 延续1和2。实现了配套的虚拟机制。主要是包括缺页异常处理。

相较于lab2已有代码的改变:

struct Page *
alloc_pages(size_t n) {
    struct Page *page=NULL;
    bool intr_flag;
    while (1)
    {
         local_intr_save(intr_flag);
         {
              page = pmm_manager->alloc_pages(n);
         }
         local_intr_restore(intr_flag);

        //      为什么N不能大于1
         if (page != NULL || n > 1 || swap_init_ok == 0) break;
         
         extern struct mm_struct *check_mm_struct;
         //cprintf("page %x, call swap_out in alloc_pages %d\n",page, n);
         
         // 在分配页时,如果没有可用的物理内存(在空闲链表上查找),就将一部分内存换出到磁盘。
         swap_out(check_mm_struct, n, 0);

    }
    //cprintf("n %d,get page %x, No %d in alloc_pages\n",n,page,(page-pages));
    return page;
}

struct Page {
    int ref;                        // page frame's reference counter
    uint32_t flags;                 // array of flags that describe the status of the page frame
    unsigned int property;          // the num of free block, used in first fit pm manager
    list_entry_t page_link;         // free list link
    list_entry_t pra_page_link;     // used for pra (page replace algorithm)  虚拟地址的链表,每次缺页时,会加载一个页,并将该页放到这个中。根据这个链表前后顺序可以达到需要换出的物理页面。
    uintptr_t pra_vaddr;            // used for pra (page replace algorithm)  虚拟地址
};

// 

同时在trap.c中加入了缺页异常的处理程序。init.c 中也加入了对磁盘的初始化。本实验中主要是为了理解操作系统的实现。所以我们将对磁盘的操作看成一个api即可。以
swapfs_write为例。
swapfs_write(swap_entry_t entry, struct Page *page) 表示将page空间的内存写入到entry位置的磁盘中。为了实现这个lab,在理解完整个流程后就要明确check_swap函数。

首先了解有关虚拟内存的数据结构

// mm_struct和vma_struct都是现代linux内核中重要的东西。
// 首先每个程序只有一个mm_struct结构体,表示这个进程的内存管理器。
// 这个进程又有多个内存区域,对应于只读区,静态区,代码区等等(这些区域分别对应一个vma_struct)。
struct mm_struct {
    list_entry_t mmap_list;        // linear list link which sorted by start addr of vma
    struct vma_struct *mmap_cache; // current accessed vma, used for speed purpose
    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
};

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

检测程序.

// 引用了部分代码
static void check_swap(void)
{
     pde_t *pgdir = mm->pgdir = boot_pgdir;
     assert(pgdir[0] == 0);
     
     // 0x1000-0x6000, 这里实际上就是0x1000-0x5999可用。一共5页。(虚拟页)
     struct vma_struct *vma = vma_create(BEING_CHECK_VALID_VADDR, CHECK_VALID_VADDR, VM_WRITE | VM_READ);
     assert(vma != NULL);

     insert_vma_struct(mm, vma);

     for (i = 0; i < CHECK_VALID_PHY_PAGE_NUM; i++)
     {
          check_rp[i] = alloc_page();
     }
     list_entry_t free_list_store = free_list;
     list_init(&free_list);
     assert(list_empty(&free_list));

    // 此时空闲链表中没有数据,再通过下面释放四页。总共有四页可用
     unsigned int nr_free_store = nr_free;
     nr_free = 0;
     for (i = 0; i < CHECK_VALID_PHY_PAGE_NUM; i++)
     {
          free_pages(check_rp[i], 1);
     }
     // 中间将空闲链表清空后,然后释放4页。
     
     assert(nr_free == CHECK_VALID_PHY_PAGE_NUM);

     // 总结:现在就是一共4个物理空闲页,虚拟空间一共5页。
     // 那么一定的,对其中一个页的访问需要借助磁盘了。
     pgfault_num = 0;

     check_content_set();

     // 此时0x1000-0x4999一共四个页都分配了物理地址

     ret = check_content_access();

}


static inline void
check_content_set(void)
{
     // 这里的缺页函数都会进入到do_pgfault的pgdir_alloc_page中,而且此时是不需要换出的。
     // 在执行这前,这些内存值都没有被访问,所以每第一次访问会出现异常。
     // 第二次可以正常访问,所以缺页总数第一次访问时都是加1的。第二次是相等的

     *(unsigned char *)0x1000 = 0x0a;
     assert(pgfault_num == 1);
     *(unsigned char *)0x1010 = 0x0a;
     assert(pgfault_num == 1);
     *(unsigned char *)0x2000 = 0x0b;
     assert(pgfault_num == 2);
     *(unsigned char *)0x2010 = 0x0b;
     assert(pgfault_num == 2);
     *(unsigned char *)0x3000 = 0x0c;
     assert(pgfault_num == 3);
     *(unsigned char *)0x3010 = 0x0c;
     assert(pgfault_num == 3);
     *(unsigned char *)0x4000 = 0x0d;
     assert(pgfault_num == 4);
     *(unsigned char *)0x4010 = 0x0d;
     assert(pgfault_num == 4);
}

// 但是当执行
static int
_fifo_check_swap(void) {
    
    // 0x1000-0x4999一共四个页都分配了物理地址
    cprintf("write Virt Page c in fifo_check_swap\n");
    *(unsigned char *)0x3000 = 0x0c;
    
    assert(pgfault_num==4);
    cprintf("write Virt Page a in fifo_check_swap\n");
    *(unsigned char *)0x1000 = 0x0a;
    
    assert(pgfault_num==4);
    cprintf("write Virt Page d in fifo_check_swap\n");
    *(unsigned char *)0x4000 = 0x0d;
    
    assert(pgfault_num==4);
    cprintf("write Virt Page b in fifo_check_swap\n");
    *(unsigned char *)0x2000 = 0x0b;
    
    assert(pgfault_num==4);

    // 这里一定会出现缺页。在check_swap中将空闲物理页设置为4个了,当访问0x5000时,就需要加载新的页,但是此时的空闲物理页已经用完,所以需要换出。
    cprintf("write Virt Page e in fifo_check_swap\n");
    *(unsigned char *)0x5000 = 0x0e;
    
    assert(pgfault_num==5);
    cprintf("write Virt Page b in fifo_check_swap\n");
    *(unsigned char *)0x2000 = 0x0b;
    
    assert(pgfault_num==5);
    cprintf("write Virt Page a in fifo_check_swap\n");
    *(unsigned char *)0x1000 = 0x0a;
   
    assert(pgfault_num==6);
    cprintf("write Virt Page b in fifo_check_swap\n");
    *(unsigned char *)0x2000 = 0x0b;
    
    assert(pgfault_num==7);
    cprintf("write Virt Page c in fifo_check_swap\n");
    *(unsigned char *)0x3000 = 0x0c;
    
    assert(pgfault_num==8);
    cprintf("write Virt Page d in fifo_check_swap\n");
    *(unsigned char *)0x4000 = 0x0d;
    
    assert(pgfault_num==9);
    cprintf("write Virt Page e in fifo_check_swap\n");


    *(unsigned char *)0x5000 = 0x0e;
    
    assert(pgfault_num==10);
    cprintf("write Virt Page a in fifo_check_swap\n");
    
    assert(*(unsigned char *)0x1000 == 0x0a);

    *(unsigned char *)0x1000 = 0x0a;
    assert(pgfault_num==11);
    return 0;
}


int do_pgfault(struct mm_struct *mm, uint32_t error_code, uintptr_t addr)
{
    int ret = -E_INVAL;
    // try to find a vma which include addr
    struct vma_struct *vma = find_vma(mm, addr);

    pgfault_num++;
    // If the addr is in the range of a mm's vma?
    if (vma == NULL || vma->vm_start > addr)
    {
        cprintf("not valid addr %x, and  can not find it in vma\n", addr);
        goto failed;
    }
    // check the error_code
    // 当发生缺页异常时,硬件将会对error_code压栈,并且将出错的地址写入cr2寄存器中。
    switch (error_code & 3)
    {
    default:
        /* error code flag : default is 3 ( W/R=1, P=1): write, present */
    case 2: /* error code flag : (W/R=1, P=0): write, not present */
        if (!(vma->vm_flags & VM_WRITE))
        {
            cprintf("do_pgfault failed: error code flag = write AND not present, but the addr's vma cannot write\n");
            goto failed;
        }
        break;
    case 1: /* error code flag : (W/R=0, P=1): read, present */
        cprintf("do_pgfault failed: error code flag = read AND present\n");
        goto failed;
    case 0: /* error code flag : (W/R=0, P=0): read, not present */
        if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
        {
            cprintf("do_pgfault failed: error code flag = read AND not present, but the addr's vma cannot read or exec\n");
            goto failed;
        }
    }

    uint32_t perm = PTE_U;
    if (vma->vm_flags & VM_WRITE)
    {
        perm |= PTE_W;
    }
    addr = ROUNDDOWN(addr, PGSIZE);

    ret = -E_NO_MEM;

    pte_t *ptep = NULL;

#if 1
    ptep = get_pte(mm->pgdir, addr, 1);
    struct Page *page;
    /*LAB3 EXERCISE 1: YOUR CODE*/
    //(1) try to find a pte, if pte's PT(Page Table) isn't existed, then create a PT.
    if (*ptep == 0)
    {
        //(2) if the phy addr isn't exist, then alloc a page & map the phy addr with logical addr
        page = pgdir_alloc_page(mm->pgdir, addr, perm);
    }
    else
    { // 执行到这里只有一种情况就是,pte表示的是磁盘中的位置。不可能是正常的物理地址,因为正常的物理地址不会走异常中断的

        cprintf("****** need swap\n");

        if (swap_init_ok)
        {
            struct Page *page = NULL;
            swap_in(mm, addr, &page);
            page->pra_vaddr =addr;    
            page_insert(mm->pgdir, page, addr, perm);
            swap_map_swappable(mm, addr, page, 1);
            //(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
            //(3) make the page swappable.
        }
        else
        {
            cprintf("no swap_init_ok but ptep is %x, failed\n", *ptep);
            goto failed;
        }
    }

#endif

    ret = 0;
failed:
    return ret;
}


访问一个内存时,如果异常,却地址范围和权限都是正确的,就会进入异常处理程序。如果这个地址对应的页没有映射,就给他分配一个页。在分配一个页的过程中,如果没有可用物理地址就将最早缺页异常的空间换出到磁盘空间。此时这个地址对应的pte是磁盘中的位置。当下一次访问这个地址的时候一定出现缺页异常。只是这个地址对应的pte是有值的,这个值是可磁盘中的位置是有关联的,所以可以将磁盘中的数据加载到这个虚拟内存(缺页异常地址)对应的页中。

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

推荐阅读更多精彩内容