1. 程式人生 > >作業系統課設實驗七---Nachos記憶體地址擴充套件

作業系統課設實驗七---Nachos記憶體地址擴充套件

這次我們實驗要求是一直做到實驗七為止,但是比較難受的就是按照實驗七的要求記憶體地址空間擴充套件部分即使做完了也沒法驗證,因為如果想驗證就需要等到實驗八做完才能驗證,這裡為了通過增加部分程式碼的方式來對實驗七進行了驗證,很多實現也參考了寫完實驗八的那位學長的部落格。
山東大學作業系統課設實驗nachos系統(6)系統呼叫Exec()和Exit()

一、實驗要求重述

擴充套件地址空間,使其能夠執行多個使用者程式。

通過檢視實驗指導書中的Things to Do,可以知道在本次試驗中,我們需要擴充套件地址空間使其能夠執行多個使用者程式,此外就是通過對Exec函式的處理,使得我們能夠觀察到擴充套件地址空間之後的結果。

二、地址空間擴充套件部分

首先我們來處理地址空間的擴充套件,通過對相關程式碼的分析,我們知道與空間分配有關的程式碼均在AddrSpace這個類中,在修改之前虛擬地址頁到實體地址幀之間的對映是一對一的,這樣也無法執行多個使用者程序,所以我們需要對其進行修改,根據提示,我們知道這裡在分配實體地址單位的時候可以用到bitmap這個資料結構,而這個資料結構可能在整個系統執行過程中都需要,因此我們可以把它設定為一個靜態變數,這裡我寫到了addrspace.h中,如圖:
bitmap的新增
我們曾經在檔案系統的擴充套件中用過這個資料結構,那時將其寫到磁碟上的時候只佔了一個扇區,通過計算可以知道其最多儲存128個專案,這裡我們沿襲傳統,也設為128,如果需要的話也可以設定的更大。
有了分配使用的資料結構,我們可以來實際的進行實體記憶體的分配,這裡可以看到AddrSpace的建構函式中之前的設定是實體記憶體與虛擬記憶體一一對應,為了讓一個虛擬記憶體號對應多個實體記憶體號,我們在這裡使用BitMap來為其分配一個空閒的物理幀。
find


之後我們看到建構函式中呼叫了一個bzero函式,這個函式會將主存清空,即置為0,這裡我們並不需要它去清空主存,所以把這句話註釋掉。按照註釋說明是應該註釋掉這句話的,不過有同學說沒有註釋似乎也能執行。。
bzero
最後在建構函式中的程式碼段和初始化資料的讀取用到的是之前的虛擬記憶體頁號,因為之前虛擬記憶體等同於實體記憶體,既然我們這裡修改了原來一一對映的關係,這裡我們也要進行處理,處理方法就是通過虛擬記憶體計算出實際記憶體來,具體演算法就是首先通過虛擬記憶體和頁大小計算出所在頁,然後得出所在頁對應的物理幀,最後加上頁內偏移量即可。這裡首先計算程式碼段的實體地址:
實體地址

這裡通過程式碼上下文的閱讀我們知道程式的程式碼段是寫在物理幀的起始位置,所以不需要加偏移量也可以找到具體內容,所以這裡省去了偏移量的計算。接下來還有初始資料的讀取:
初始資料


這裡的初始化資料段未必寫在頁的起始位置,因此我們需要計算出偏移量並在最後計算實體地址時加上偏移量。
到這裡我們分配實體記憶體的部分就算完成了,但是如果不對分配的記憶體進行釋放,最後也會導致系統出錯,所以我們需要在解構函式中釋放掉BitMap中分配的實體記憶體,程式碼如下:
free

至此,擴充套件記憶體的部分就全部完成了。

三、擴充套件結果檢驗部分

首先我們知道Exec函式屬於一個系統呼叫,因此會在exception.cc檔案中的ExceptionHandler函式中進行處理,因此我們需要增加一個else if語句來對其進行處理,否則會直接調到else語句中,無法實現功能。

在這個else if語句中,我們需要做到3件事,拿到Exec函式的引數、開啟一個新的執行緒去執行新的程式檔案、將暫存器的值增加防止其卡死在這裡。

首先來說拿引數的部分,通過對註釋的閱讀,我們知道第一個引數儲存在4號暫存器中,所以我們可以從4號暫存器中讀取出所需的字串引數,而這裡我們取出的是一個虛擬記憶體,因此我們可以使用Machine::ReadMem函式來讀取出與其對應的實體記憶體中儲存的內容,這裡由於是一個長度未知的字串,因此在讀取時需要逐字元處理,一直讀,直到讀到’\0’為止,並將讀到的字元拼接成字串。程式碼如下:
讀引數

接下來則是新建執行緒,這裡我們可以參考實驗一的程序切換與progtest.cc中的StartProcess方法來實現執行緒的新建。

這裡首先說一下StartProcess方法,他的作用就是傳進去一個檔名字串,然後它根據這個檔名開啟並執行對應的程序,然而我們將要使用的Thread的Fork方法卻支援的是int型別引數,所以我們需要將StartProcess的引數改為int型別,並在內部將其轉換為char *型別,再去執行原來的邏輯,程式碼如下:
startProcess
最後則是fork一個執行緒去執行StartProcess方法,這裡仿照實驗一中的內容來實現:
fork

這裡傳入時取到filename字串的起始地址,轉換成int型別再傳入。
最後則是暫存器的推移,這裡可以參照mipssim.cc中相關程式碼來實現:
暫存器推移
至此,測試的程式碼也修改完了,最後則是完成並編譯測試程式碼。

四、編寫測試程式碼並執行

在test目錄下新建bar.c和exec.c,並寫入實驗指導書給出的測試程式碼:
測試檔案
為了編譯這兩個新檔案,我們需要修改test目錄下的Makefile檔案,在target那一行後面新增上bar和exec:
makefile

然後首先在test下面執行make命令來編譯這兩個新檔案,再去userprog下執行修改完並編譯過的nachos,並加上執行引數來執行bar.noff程式,得到如圖的效果:
result
即擴充套件空間成功,並且exec命令得到執行。