MIT 6.828 JOS學習筆記16. Lab 2.2


Part 3 Kernel Address Space

JOS把32位線性地址虛擬空間划分成兩個部分。其中用戶環境(進程運行環境)通常占據低地址的那部分,叫用戶地址空間。而操作系統內核總是占據高地址的部分,叫內核地址空間。這兩個部分的分界線是定義在memlayout.h文件中的一個宏 ULIM。JOS為內核保留了接近256MB的虛擬地址空間。這就可以理解了,為什么在實驗1中要給操作系統設計一個高地址的地址空間。如果不這樣做,用戶環境的地址空間就不夠了。

Permission and Fault Isolation

由於內核和用戶進程只能訪問各自的地址空間,所以我們必須在x86頁表中使用訪問權限位(Permission Bits)來使用戶進程的代碼只能訪問用戶地址空間,而不是內核地址空間。否則用戶代碼中的一些錯誤可能會覆寫內核中的數據,最終導致內核的崩潰。

處在用戶地址空間中的代碼不能訪問高於ULIM的地址空間,但是內核可以讀寫這部分空間。而內核和用戶對於地址范圍[UTOP, ULIM]有着相同的訪問權限,那就是可以讀取但是不可以寫入。這一個部分的地址空間通常被用於把一些只讀的內核數據結構暴露給用戶地址空間的代碼。在UTOP之下的地址范圍是給用戶進程使用的,用戶進程可以訪問,修改這部分地址空間的內容。

Initializing the Kernel Address Space

現在我們要設置一下UTOP之上的地址空間:這也是整個虛擬地址空間中的內核地址空間部分。inc/memlayout.h文件中已經向你展示了這部分地址空間的布局。你可以使用你剛剛編寫的函數來設置這些地址的布局。


 Exercise 5

  繼續完善mem_init()函數,你的程序現在必須能夠通過check_kern_pgdir()和check_page_installed_pgdir()函數的檢測。

 答:

  剩下的工作就是要完善mem_init()函數,現在要完善的功能就是把關於操作系統的一些重要的地址范圍映射到現在的新頁目錄項上kern_pgdir上。這里我們可以利用前面定義過的boot_map_region函數。

  首先我們要映射的范圍是把pages數組映射到線性地址UPAGES,大小為一個PTSIZE。

  所以我們添加的代碼是:

boot_map_region(kern_pgdir, UPAGES, PTSIZE, PADDR(pages), PTE_U);

  其中perm變量之所以設置為PTE_U,是因為這部分空間是kernel space和user space中的代碼都能訪問的,所以要設置PTE_U。

  

  然后映射內核的堆棧區域,把由bootstack變量所標記的物理地址范圍映射給內核的堆棧。內核堆棧的虛擬地址范圍是[KSTACKTOP-PTSIZE, KSTACKTOP),不過要把這個范圍划分成兩部分:

    * [KSTACKTOP-KSTKSIZE, KSTACKTOP) 這部分映射關系加入的頁表中。

    * [KSTACKTOP-PTSIZE, KSTACKTOP-KSTKSIZE) 這部分不進行映射。

  對這部分地址的訪問權限是,kernel space 可以讀寫,user space 無權訪問,所以代碼如下:

boot_map_region(kern_pgdir, KSTACKTOP - KSTKSIZE, KSTKSIZE, PADDR(bootstack), PTE_W)

   

  最后映射整個操作系統內核,虛擬地址范圍是[KERNBASE, 2^32],物理地址范圍是[0,2^32 - KERNBASE]。

  訪問權限是,kernel space 可以讀寫,user space 無權訪問,所以代碼如下:

boot_map_region(kern_pgdir, KERNBASE, 0xffffffff - KERNBASE, 0, PTE_W);

  至此,Exercise 5已經全部完成。


 

 Question:

  2. 到目前為止頁目錄表中已經包含多少有效頁目錄項?他們都映射到哪里?

    3BD號頁目錄項,指向的是kern_pgdir

    3BC號頁目錄項,指向的是pages數組

    3BF號頁目錄項,指向的是bootstack

    3C0~3FF號頁目錄項,指向的是kernel

  3. 如果我們把kernel和user environment放在一個相同的地址空間中。為什么用戶程序不同讀取,寫入內核的內存空間?用什么機制保護內核的地址范圍。

    用戶程序不能去隨意修改內核中的代碼,數據,否則可能會破壞內核,造成程序崩潰。

    正常的操作系統通常采用兩個部件來完成對內核地址的保護,一個是通過段機制來實現的,但是JOS中的分段功能並沒有實現。二就是通過分頁機制來實現,通過把頁表項中的 Supervisor/User位置0,那么用戶態的代碼就不能訪問內存中的這個頁。

  4. 這個操作系統的可以支持的最大數量的物理內存是多大?

       由於這個操作系統利用一個大小為4MB的空間UPAGES來存放所有的頁的PageInfo結構體信息,每個結構體的大小為8B,所以一共可以存放512K個PageInfo結構體,所以一共可以出現512K個物理頁,每個物理頁大小為4KB,自然總的物理內存占2GB。

  5. 如果現在的物理內存頁達到最大個數,那么管理這些內存所需要的額外空間開銷有多少?  

    這里不太明白,參考別的答案是,首先需要存放所有的PageInfo,需要4MB,需要存放頁目錄表,kern_pgdir,4KB,還需要存放當前的頁表,大小為2MB。所以總的開銷就是6MB + 4KB。

  6. 回顧entry.S文件中,當分頁機制開啟時,寄存器EIP的值仍舊是一個小的值。在哪個位置代碼才開始運行在高於KERNBASE的虛擬地址空間中的?當程序位於開啟分頁之后到運行在KERNBASE之上這之間的時候,EIP的值是小的值,怎么保證可以把這個值轉換為真實物理地址的?

    在entry.S文件中有一個指令 jmp *%eax,這個指令要完成跳轉,就會重新設置EIP的值,把它設置為寄存器eax中的值,而這個值是大於KERNBASE的,所以就完成了EIP從小的值到大於KERNBASE的值的轉換。

    在entry_pgdir這個頁表中,也把虛擬地址空間[0, 4MB)映射到物理地址空間[0, 4MB)上,所以當訪問位於[0, 4MB)之間的虛擬地址時,可以把它們轉換為物理地址。

Address Space Layout Alternatives

  進程的虛擬地址空間的布局不是只有我們討論的這種唯一的情況,我們也可以把內核映射到低地址處。但是JOS之所以要這么做,是為了保證x86的向后兼容性。

  只要我們能夠仔細設計,雖然很難,但是我們也能設計出來一種內核的布局方式,使得進程的地址空間就是從0到4GB,無需為內核預留一部分空間,但是仍然能夠保證,用戶進程不會破壞操作系統的指令,數據。

 

至此,lab 2已經全部完成~歡迎大家的意見與問題

  zzqwf12345@163.com

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM