ucore lab3

主要姓名:馮成 學號:19021221183 學院:電子工程學院

lab3 延續(xù)1和2橄杨。實現(xiàn)了配套的虛擬機制账嚎。主要是包括缺頁異常處理今缚。

相較于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);
         
         // 在分配頁時察皇,如果沒有可用的物理內(nèi)存(在空閑鏈表上查找)蕉堰,就將一部分內(nèi)存換出到磁盤若锁。
         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)  虛擬地址的鏈表搁骑,每次缺頁時,會加載一個頁又固,并將該頁放到這個中仲器。根據(jù)這個鏈表前后順序可以達到需要換出的物理頁面。
    uintptr_t pra_vaddr;            // used for pra (page replace algorithm)  虛擬地址
};

// 

同時在trap.c中加入了缺頁異常的處理程序仰冠。init.c 中也加入了對磁盤的初始化乏冀。本實驗中主要是為了理解操作系統(tǒng)的實現(xiàn)。所以我們將對磁盤的操作看成一個api即可洋只。以
swapfs_write為例辆沦。
swapfs_write(swap_entry_t entry, struct Page *page) 表示將page空間的內(nèi)存寫入到entry位置的磁盤中昼捍。為了實現(xiàn)這個lab,在理解完整個流程后就要明確check_swap函數(shù)众辨。

首先了解有關虛擬內(nèi)存的數(shù)據(jù)結構

// mm_struct和vma_struct都是現(xiàn)代linux內(nèi)核中重要的東西端三。
// 首先每個程序只有一個mm_struct結構體,表示這個進程的內(nèi)存管理器鹃彻。
// 這個進程又有多個內(nèi)存區(qū)域郊闯,對應于只讀區(qū),靜態(tài)區(qū)蛛株,代碼區(qū)等等(這些區(qū)域分別對應一個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));

    // 此時空閑鏈表中沒有數(shù)據(jù)欢摄,再通過下面釋放四頁∷袼冢總共有四頁可用
     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);

     // 總結:現(xiàn)在就是一共4個物理空閑頁害捕,虛擬空間一共5頁绿淋。
     // 那么一定的,對其中一個頁的訪問需要借助磁盤了尝盼。
     pgfault_num = 0;

     check_content_set();

     // 此時0x1000-0x4999一共四個頁都分配了物理地址

     ret = check_content_access();

}


static inline void
check_content_set(void)
{
     // 這里的缺頁函數(shù)都會進入到do_pgfault的pgdir_alloc_page中吞滞,而且此時是不需要換出的。
     // 在執(zhí)行這前盾沫,這些內(nèi)存值都沒有被訪問裁赠,所以每第一次訪問會出現(xiàn)異常。
     // 第二次可以正常訪問赴精,所以缺頁總數(shù)第一次訪問時都是加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);
}

// 但是當執(zhí)行
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);

    // 這里一定會出現(xiàn)缺頁。在check_swap中將空閑物理頁設置為4個了蕾哟,當訪問0x5000時失尖,就需要加載新的頁,但是此時的空閑物理頁已經(jīng)用完渐苏,所以需要換出掀潮。
    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
    // 當發(fā)生缺頁異常時,硬件將會對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
    { // 執(zhí)行到這里只有一種情況就是,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;
}


訪問一個內(nèi)存時择诈,如果異常,卻地址范圍和權限都是正確的出皇,就會進入異常處理程序羞芍。如果這個地址對應的頁沒有映射,就給他分配一個頁郊艘。在分配一個頁的過程中荷科,如果沒有可用物理地址就將最早缺頁異常的空間換出到磁盤空間。此時這個地址對應的pte是磁盤中的位置纱注。當下一次訪問這個地址的時候一定出現(xiàn)缺頁異常畏浆。只是這個地址對應的pte是有值的,這個值是可磁盤中的位置是有關聯(lián)的狞贱,所以可以將磁盤中的數(shù)據(jù)加載到這個虛擬內(nèi)存(缺頁異常地址)對應的頁中刻获。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市瞎嬉,隨后出現(xiàn)的幾起案子蝎毡,更是在濱河造成了極大的恐慌,老刑警劉巖氧枣,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沐兵,死亡現(xiàn)場離奇詭異,居然都是意外死亡挑胸,警方通過查閱死者的電腦和手機痒筒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進店門宰闰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來茬贵,“玉大人,你說我怎么就攤上這事移袍〗庠澹” “怎么了?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵葡盗,是天一觀的道長螟左。 經(jīng)常有香客問我,道長觅够,這世上最難降的妖魔是什么胶背? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮喘先,結果婚禮上钳吟,老公的妹妹穿的比我還像新娘。我一直安慰自己窘拯,他們只是感情好红且,可當我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布坝茎。 她就那樣靜靜地躺著,像睡著了一般暇番。 火紅的嫁衣襯著肌膚如雪嗤放。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天壁酬,我揣著相機與錄音次酌,去河邊找鬼。 笑死厨喂,一個胖子當著我的面吹牛和措,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蜕煌,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼派阱,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了斜纪?” 一聲冷哼從身側響起贫母,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎盒刚,沒想到半個月后腺劣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡因块,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年橘原,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涡上。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡趾断,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吩愧,到底是詐尸還是另有隱情芋酌,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布雁佳,位于F島的核電站脐帝,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏糖权。R本人自食惡果不足惜堵腹,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望星澳。 院中可真熱鬧疚顷,春花似錦、人聲如沸募判。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至释液,卻和暖如春全释,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背误债。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工浸船, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人寝蹈。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓李命,卻偏偏與公主長得像,于是被迫代替她去往敵國和親箫老。 傳聞我的和親對象是個殘疾皇子封字,可洞房花燭夜當晚...
    茶點故事閱讀 44,933評論 2 355

推薦閱讀更多精彩內(nèi)容