作業系統實驗報告 lab3
目錄:
-
- 作業系統實驗報告 lab3
- 練習0 填寫已有實驗
- 練習1 給未被映射的位址映射上實體頁
- 問題分析
- 結構體分析
- vma_struct
- mm_struct
- 管理結構關系
- 實作代碼
- 練習2 補充完成基于FIFO的頁面替換算法
- 問題分析
- 函數分析
- 實作代碼
- 實驗截圖
- 總結
本次實驗主要完成ucore核心對虛拟記憶體的管理工作。首先完成初始化虛拟記憶體管理機制,即需要設定好哪些頁需要放在實體記憶體中,哪些頁不需要放在實體記憶體中,而是可被換出到硬碟上,并涉及完善建立頁表映射、頁錯誤異常處理操作等函數實作。最後測試編寫的代碼有沒有達到預期的效果。整體的實驗不難,但需要掌握一些資料結構之間的關系,這樣對了解虛拟記憶體管理有很大的幫助。
練習0 填寫已有實驗
将實驗二代碼補全至實驗三
在這裡了仍然采用meld工具直接進行比較,截圖如下

圖1 檔案夾對比
總共需要修改的檔案有三個
default_pmm.c
pmm.c
trap.c
将代碼直接從
lab2
複制至
lab3
,修改完之後進入下面的實驗
練習1 給未被映射的位址映射上實體頁
完成 do_pgfault函數,給未被映射的位址映射上實體頁。設定通路權限的時候要參考所在頁面的VMA權限,同時需要注意映射實體頁時需要操作記憶體控制結構指定的頁表,而不是核心頁表
1 問題分析:
當啟動分頁機制以後,如果一條指令或資料的虛拟位址所對應的實體頁不在記憶體中,或者通路權限不夠,那麼就會産生頁錯誤異常。其具體原因有以下三點:
- 頁表項全為0——虛拟位址與實體位址未建立映射關系或已被撤銷。
- 實體頁面不在記憶體中——需要進行換頁機制。
- 通路權限不夠——應當報錯。
當出現上面情況之一,那麼就會産生頁面page fault(#PF)異常。産生異常的線性位址存儲在
CR2中,并且将是page fault的産生類型儲存在 error code 中
2 結構體分析
vma_struct
每個程序隻有一個
mm_struct
結構,在每個程序的
task_struct
結構體中,有一個指向該程序的結構。可以說,
mm_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;
};
1.vm_start和vm_end描述的是一個合理的位址空間範圍(即嚴格確定 vm_start < vm_end的關系);
2.list_link是一個雙向連結清單,按照從小到大的順序把一系列用vma_struct表示的虛拟記憶體空間連結起來,并且還要求這些鍊起來的vma_struct應該是不相交的,即vma之間的位址空間無交集;
3.vm_flags表示了這個虛拟記憶體空間的屬性,目前的屬性包括
#define VM_READ 0x00000001 //隻讀
#define VM_WRITE 0x00000002 //可讀寫
#define VM_EXEC 0x00000004 //可執行
4.vm_mm是一個指針,指向一個比vma_struct更高的抽象層次的資料結構mm_struct
mm_struct
較高層次的結構
vm_area_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
};
1.mmap_list是雙向連結清單頭,連結了所有屬于同一頁目錄表的虛拟記憶體空間
2.mmap_cache是指向目前正在使用的虛拟記憶體空間
3.pgdir所指向的就是 mm_struct資料結構所維護的頁表
4.map_count記錄mmap_list裡面連結的vma_struct的個數
5.sm_priv指向用來連結記錄頁通路情況的連結清單頭
3 管理結構關系
在程序的
task_struct
結構中包含一個指向
mm_struct
結構的指針,
mm_strcut
用來描述一個程序的虛拟位址空間。
程序的
mm_struct
則包含裝入的可執行映像資訊以及程序的頁目錄指針
pgd
。該結構還包含有指向
vm_area_struct
結構的幾個指針.
每個
vm_area_struct
代表程序的一個虛拟位址區間。
vm_area_struct
結構含有指向
vm_operations_struct
結構的一個指針,
vm_operations_struct
描述了在這個區間的操作。
vm_operations
結構中包含的是函數指針;其中,
open
、
close
分别用于虛拟區間的打開、關閉,而
nopage
用于當虛存頁面不在實體記憶體而引起的“缺頁異常”時所應該調用的函數,當 Linux 處理這一缺頁異常時(請頁機制),就可以為新的虛拟記憶體區配置設定實際的實體記憶體。
圖2 管理結構圖
圖3 關系圖
實作代碼
1.目标頁面不存在(頁表項全為0,即該線性位址與實體位址尚未建立映射或者已經撤銷);
2.相應的實體頁面不在記憶體中(頁表項非空,但Present标志位=0,比如在swap分區或磁盤檔案上)
3.通路權限不符合(此時頁表項P标志=1,比如企圖寫隻讀頁面).
int do_pgfault(struct mm_struct *mm,uint32_t error_code,uintptr addr)
{
pte_t *ptep=NULL;//頁目錄
if ((ptep = get_pte(mm->pgdir, addr, )) == NULL) { //查找頁目錄 如果不存在則失敗
cprintf("get_pte in do_pgfault failed\n");
goto failed;
}
if (*ptep == ) { //如果實體位址不存在,那麼配置設定一個實體頁 并且與虛拟記憶體建立對應關系
if (pgdir_alloc_page(mm->pgdir, addr, perm) == NULL) {
cprintf("pgdir_alloc_page in do_pgfault failed\n");
goto failed;
}
}
else { //頁表項非空,可以嘗試換入頁面
if(swap_init_ok) {
struct Page *page=NULL;//建立記憶體頁指針
if ((ret = swap_in(mm, addr, &page)) != ) {//根據mm結構和addr位址,嘗試将硬碟中的内容換入至page中
cprintf("swap_in in do_pgfault failed\n");
goto failed;
}
page_insert(mm->pgdir, page, addr, perm);//建立虛拟位址和實體位址之間的對應關系
swap_map_swappable(mm, addr, page, );//将此頁面設定為可交換的
page->pra_vaddr = addr;
}
else {
cprintf("no swap_init_ok but ptep is %x, failed\n",*ptep);
goto failed;
}
}
ret =
failed:
return ret;
}
練習2 補充完成基于FIFO()的頁面替換算法
完成vmm.c中的do_pgfault函數,并且在實作FIFO算法的swap_fifo.c中完成map_swappable和swap_out_vistim函數。通過對swap的測試。
問題分析
根據練習1,當頁錯誤異常發生時,有可能是因為頁面儲存在swap區或者磁盤檔案上造成的,練習2需要利用頁面替換算法解決這個問題。
函數分析
map_swappable()
主要解決的問題是将最近被用到的頁面添加到算法所維護的次序隊列。
連結清單是由
list_entry_t
指針串起來的
mm_struct
結構體的
sm_priv
元素是交換管理的私有資料 是一串連結清單 滿足
FIFO
先進先出
_fifo_swap_out_victim()
函數是用來查詢哪個頁面需要被換出,它的主要作用是用來查詢哪個頁面需要被換出。
實作代碼
_fifo_map_swappable()
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);
list_add(head, entry); //将最近用到的頁面添加到次序隊尾
return ;
}
_fifo_swap_out_victim()
static int
ifo_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==);
list_entry_t *le = head->prev; //用le訓示需要被換出的頁,最先進入隊列的元素head的另一端
assert(head!=le);
struct Page *p = le2page(le, pra_page_link);//le2page宏可以根據連結清單元素獲得對應的Page指針p 這裡是實體頁屬性
list_del(le); //将進來最早的頁面從隊列中删除
assert(p !=NULL);
*ptr_page = p; //将這一頁的位址存儲在ptr_page中
return ;
}
實驗截圖
圖4 實驗效果圖
check_vma_struct() succeeded!
page fault at x00000100: K/W [no page found].
check_pgfault() succeeded!
check_vmm() succeeded.
圖5 實驗效果圖
check_swap() succeeded!
實驗運作成功!
總結
1.整個實驗下來感覺自己收獲很多,通過上網查找資料,自己深刻學習了虛拟記憶體管理的機制,通過實驗更是加深了印象。
2.實驗中遇到了很多的問題,比如程序虛拟記憶體的管理涉及到的一些結構體的關系,由于種類比較多很容易混亂,通過列圖梳理了他們之間的關系。
3.作業系統這門課程比較基礎,涉及到的内容比較多。有時學起來會比較吃力,但這門課程非常重要,是以後專業課的基石,希望在以後自己留給更多的時間在做實驗上,進而更加深入的了解、掌握作業系統