OSDI 4

ss
11 min readSep 23, 2018

--

Lab4主要是要設定memory中page的機制,我們需要將virtual address 對應到physical address , 在這之中需要去做許多管理以及對應的配置,

切記!!!! 可以參考,但是照抄真的很沒有意義,學不到東西也無法讓你帶著走

我們在main.c的檔案中看到這次新增的項目mem_init 而這個function 放在mem.c 裡,這次所有的設定也幾乎都在這個檔案內完成。所以我們接著進去看這個function寫了什麼東西。

我們先看到的是i386_detect_memory,可以看到我的註解,主要是去看記憶體中有多少空間是我們可以使用的以及不可以使用的,那這定義在哪呢?看下面的圖

由於第一代PC處理器是16bit的8088處理器,這只能訪問1MB的空間,及0x00000000–0x000FFFFF的大小,但這1MB也不是每個人都利用的到的,只有640KB(0–0x000A0000)是可以使用的,如圖所示,從0x000A0000到1MB的空間都是有其他用途的,故我們在之後分配時,不會去動用這塊,所以總結一下,
0x00000000–0x000A0000是basemem,可用
0x000A00000–0x00010000是IO hole 不可用
0x100000-~是extmem可用
其中npage記錄整個memory的頁數,npage_basemem紀錄basemem的頁數,npage_extmem紀錄extmem的頁數

好接下去我們往下看到

Kern_pgdir為一個pde_t的指標,它是OS的page directory的指標,我們之後都會透過這個目錄去做virtual address的轉換,所以我們要先分配一個page大小給他,如果不懂這個目錄,請看下面的圖,linear address第一個需要轉換所對的目錄就是這個

所以我們必須看這個boot_alloc這個function,

這個function主要的目的是那個nextfree這個值,它幫助我們紀錄下一個可用空間的位址,如果n為0就會回傳當前nextfree指向的地方,如果有要求大小它會找到最接近的位置(並且能夠整除一個PAGESIZE,ROUNDUP函數去幫我們做到這件事的,至於如何做到我就沒有詳細去看了)並且回傳位址,結果就會向下圖所示

(來源:http://www.cnblogs.com/bdhmwz/p/4960034.html)

這行目的主要說明我們必須先定義到此目錄的配置(virtual to physcial)必須將首先我們先了解UVPT

此為一段virtual address,這是kern_pgdir(phy addr)要對到的位置,PDX為page directory的index(offset)

PADDR(kern_pgdir)主要是表示對應到的實體記憶體位置,後面則是說明對這個entry存取的權限flag

接著我們看到下面要我們實驗的東西,我們必須去配置所有剛剛確定可以分配npage數量的physical page所以這邊就是用到boot_alloc去分配大小為

這邊我們可以注意一下這個pageinfo的結構

pp_link是用來做link list 用的,透過這個我們可以將所以沒有用到的page串成一塊,等到別人需要時可以方便分配,要退回時也可以方便的退還,而ref主要是說明有幾個vaddr對應到這個page,故如果都沒有就是0
接下來我們一樣初始化這些page
好再來就是第一階段重頭戲,看到這四個

後面的三個check主要就是用來幫助我們檢查之後的功課是否正確,所以我們就往page_init看,

提示主要說明著,那些是可以用的那些是不行的,至於詳情都在上面已經介紹完了,至於可以用的有,第0個page,0-npages_basemem,npages_extmem這些空間
故我們將可以用的串成一個link list其實不能用的只有io hole與被kernel code占走那兩塊,所以不要去動那兩塊地page

這樣就確保我們不會動到不能用的記憶體了
只後會通過check-page-free(1)去檢查是否正確,至於這邊這參數為何是1我就沒有先研究了,在這邊先讓我偷懶一下。
接著我們回到mem_init繼續往下看,check_page_alloc這個page是用來檢查你接下來的兩個function,page_alloc,page_free

我們先看到page_alloc()

這個function主要是說明先判斷page_free_list這個list還有沒有可配置的page若無救回傳null若有就將這page移出此list並看參數(alloc_flags&ALLOC_ZERO)為true的話將此page set 成’/0’ page2kva 記得這個 因為目前kernel看不懂physical address 根據提示可以用這個幫助我們去轉換成virtual address在memset

至於page_free就很間單的將這個page加回page_free_list,
Physical memory的配置部分就先到這邊

接著我們繼續往下看check_page()
這個函數一次檢查很多東西,page_lookup,page_insert,page_remove,pgdir_walk
這四個function,我們一向一項去完成
首先我們先看到pgdir_walk(因為其他項都需要這個函數的操作,先完成它,我覺得這個也是最不好做的)

提示中提到,給一個page directory 跟一個virtual address,我們去檢查此virtual address 是否有存在一個對應的page table,若無,create引數是用來幫助我們決定要不要建立,建立的話回傳此page table entry的pointer,若有,回傳此指向此 page 的pointer(就是回傳此page的address),

我們用PDX找到這個va的page_dir_offset,用PTX找到va的page_table_offset,
並直接看pgdir[offset]裡面是否有值,無的話我們看一下是否要create,拿到page記得先將ref++,之後將pgdir更新,並在後面賦予權限,記得要先轉成physcial address存入,填好之後我們將回傳,此table的addr用PTE_ADDR來取出physcial addr, 但別忘了 kernel只看得懂virtual addr 記得要透過KADDR轉成va,最後,回傳此page的address,就完成了
我們接著看page_lookup

這邊不會寫很可能不是你不懂,是不會指標XD,我們看到提示像我們說明它
根據輸入一個va,需要回傳一個page,若pte_store不為0,則將page address存進這個store裡
首先我們先判定是否存在這個page
令pte 為一個指向pte_t struct的指標,利用剛剛的pgdir_walk(提示說要用的,不然我還真的沒想到這個),把指標給指過去,如下方程式碼所示,記的不用create,若pte為0,則回傳NULL接著再判斷store,如果有值就把它的指向給pte(把原本只到別的地方的指標換成指向pte的指標),這邊的話不懂請去參考指標的指標(主要是因為要傳一個struct的指標變數,如果更模糊的話可以忽略XD),至於中間那個檢查她的present我一開始根本沒想到= = ,這邊好像真的蠻重要的很多地方都會沒有注意到,這邊如果沒有加的話就不能work,

再來下一個是page_insert

其實函數名稱就大概猜得出這個要做什麼了,將physical page映射到va
如果有其他page映射到va,我們將此page刪除,一樣首先我們先令一個*pte =pgdir_walk(),檢查pte是否有值,無的話根據pgdir_walk的定義,代表除了目錄查不到之外也不能重新新增一個,根據要求回傳-E_NO_MEM
成功的話將pp->ref++,先用PTE_P檢查是否有人在用,有的話移除,再將page設好(映射到page2pa(pp)),包括權限,如下圖,這樣就行了

最後page_remove就如函數名稱一樣,一樣先看提示

給一個pgdir跟va 去刪除在這上面的page並記得使用hint的東西去做,TLB感覺應該是要將在TLB上的資料清空,一樣,這邊不懂的話很可能是你指標的指標不熟,記得去注意一下,現在我有時候也會有點搞不清楚,把此page table entry清空掉之後就不會有人只到這個page了page_decref我就不多說了 直接去看他的function我想你們應該就會明白了

最後我們看到boot_map_region這個函數

提示的第一句話其實把這函數要做的事情說得非常清楚,我們想要將一段va直接對到一段pa,大小為page的倍數,這邊我們用for迴圈去跑總共要幾個page,記得這邊的size數要除pgsize,不然就會像筆者一樣卡在這邊很久,最後用gdb追進去才抓到卡在這邊……………..然後根據提示用pgdir_walk去map,將pa配置進pte,然後pa跟va都加一個pagesize,跑完for迴圈之後就能結束這個function

到這邊再跑時,應該可以將check_page成功的提示給印出來了 接下來我們去配置最後kernel 的相關配置,

根據提示可以知道,將kernel stack map 到bookstack,我們用剛剛完成的boot_map_region,它的起始位置為KSTACKTOP — KSTKSIZE 因為stack是從高處往低處加的,perm為PTE_W (可讀寫),這樣kernel stack 就配置完成了

下一個提示說明將kernel的va對映到pa 0的地方,提是說明大小為2²³-1-KERNBASE

最後一個page fault 並且印出記憶體位置,這邊我有點偷吃步,再把trap設好後(詳情再LAB3),我發現有一個print_trapframe,就試著print出這個trapframe,發現rcr2貌似是用來存記憶體位置的,所以就拿來用了,而此次lab就到這邊做一個段落,如果我觀念上有錯誤或者有錯字都能直接留言給我或私訊我

謝謝大家的收看

--

--

ss
ss

No responses yet