5.3.6 虚拟地址、线性地址和物理地址之间的关系
內核代碼和數據的地址
對于linux 0.11內核代碼和數據來說,在head.s程序的初始化操作中已經把內核代碼段和數據段都設置成長度為16M的段。在線性地址空間中這兩個段的范圍重疊,都是從線性地址0開始到地址0XFFFFFF共16M地址范圍。在該范圍中含有內核所有的代碼、內核段表(GDT,IDT,TSS)、頁目錄表和內核的二級頁表、內核局部數據和內核臨時堆棧(將被用作第一個任務即任務0的用戶堆棧)。其頁目錄表和二級頁表已設置成把0-16M的線性地址空間一一對應到物理地址上,占用了4個目錄項即4個二級頁表。因此對于內核代碼和數據來說,我們可以直接把它看作是物理內存中的地址。如下圖:
因此,默認情況下Linux 0.11內核最多可管理16MB的物理內存,共有4096個物理頁面,每個頁面4KB。通過上述分析可以看出:
1.內核代碼段和數據段區域在線性地址空間和物理地址空間中是一樣的,這樣設置可以大大簡化內核的初始化操作
2.GDT和IDT在內核數據段中,因此他們的線性地址也同樣等同于他們的物理地址。在實模式下setup.s程序初始化操作中,我們曾經設置過臨時的GDT和IDT,這是進入保護模式之前必須設置的。由于這兩個表當時處于物理內存大約0x90200處,而進入保護模式之后內核系統模塊處于物理內存0開始位置,并且0x90200處的空間也被挪作他用(用于高速緩沖),因此在進入保護模式后,在運行的第一個程序head.s中要重新設置這兩個表。即設置GDTR和IDTR指向新的GDT和IDT,描述符也需要重新加載。由于開啟分頁機制時這兩個表的位置沒有變動,因此無需再重新建立或移動表位置。
3.除任務0以外,所有其他任務所需要的物理頁面與線性地址中不同或部分不同,因此內核需要動態的在主內存區中為他們作映射操作,動態的建立頁目錄項和頁表項。雖然任務的代碼和數據也在內核中,但由于它需要另行分配獲得內存,因此也需要自己的映射表項。
任務0的地址對應關系
任務0是系統中第一個人工啟動的任務。他的代碼段和數據段長度被設置為640kb。該任務的代碼和數據直接包含在內核代碼和數據中,是從地址0開始的640KB的內容,因此它可以直接使用內核代碼已經設置好的頁目錄和頁表進行分頁地址變換,同樣,它的代碼和數據在線性地址空間也是重疊的,對應的任務狀態段TSS0也是手工預設值好的,并且位于任務0數據結構中,參見sched.h第113行開始的內容。TSS0段位于內核sched.c程序的代碼中,長度為104字節,具體位置參加圖5-23中"任務0結構信息"所示。三個位置的對應關系如圖5-15所示:
?
由于任務0直接包含在內核中,不再需要為其重新分配內存頁,它運行時需要的內核態堆棧和用戶態堆棧空間也都在內核代碼區中,并且由于在內核初始化時(head.s)這些內核頁面在頁表項中的屬性都已經被設置成了0b111,即對應頁面用戶可讀寫且存在,因此用戶堆棧user_stack[]空間雖然在內核空間中,但任務0仍能對其進行讀寫操作。
任務1的地址對應關系
與任務0類似,任務1也是一個特殊任務。它的代碼也在內核代碼區域中。與任務0不同的是在線性地址空間中系統在使用fork()創建任務1(init進程)時為存放任務1的二級頁表而在內存中申請了一頁內存區域來存放,并復制了父進程的頁目錄和二級頁表項。因此任務1擁有自己的頁目錄和頁表表項,它把任務1占用的線性空間范圍64M-128M(實際上是64M-64M+640KB)也同樣映射到物理地址0-640KB處。此時任務1的長度也是640KB,并且其代碼段和數據段相重疊,只占用一個頁目錄項和一個二級頁表。另外,系統還會為任務1在主內存區域中申請一頁內存來存放它的任務數據結構和用作任務1的內核堆棧空間。任務數據結構中包括任務1的TSS段結構信息,如下圖:
任務1的用戶態堆棧空間將直接共享使用處于內核代碼和數據區域(線性地址0-640KB)中任務0的用戶態堆棧空間user_stack[](參見kernek/sched.c,第67-72行),因此這個堆棧需要在任務1實際使用時保持“干凈”,以確保被復制用于任務1的堆棧不含有無用數據,在剛開始創建任務1時,任務0的用戶態堆棧user_stack[]與任務1共享使用,但當任務1 開始運行時,由于任務1映射到user_stack[]處的頁表被設置成只讀,使得任務1在執行堆棧操作時將會引起寫頁面異常,從而由內核另行分配主內存區頁面作為堆棧空間使用。
其他任務的地址對應關系
對于被創建的從任務2開始的其他任務,它們的父進程都是init(任務1)進程,我們已經知道,在linux 0.11系統中共可以有64個進程同時存在,下面以任務2為例來說明其他任何任務隊地址空間的使用情況。
從任務2開始如果任務號以nr表示,那么任務nr在線性地址空間中的起始位置被設定在nr*64M處,例如任務2的開始位置=nr*64M=2*64M=128M。任務代碼段和數據段的最大長度被設置為64M,因此任務2占有的線性地址空間范圍是128M-192M,共占用64M/4M=16個頁目錄項,虛擬空間中任務代碼段和數據段都被映射到線性地址空間中相同的范圍,因此它們也會完全重疊。圖5-17顯示出了任務2的代碼段和數據段在三種地址空間中的對應關系。
在任務2被創建出來之后,將在其中運行execve()函數來執行shell程序,當內核通過復制任務1剛創建任務2時,除了占用線性地址空間范圍不同以外(128M-128M+640K),此時任務2的代碼和數據在三種地址空間中的對應關系和任務1的類似。當任務2的代碼(init())調用execve()系統調用開始加載并執行shell()程序時,該系統調用會釋放掉從任務1復制的頁目錄和頁表表項及相應的內存頁面,然后為新的執行程序shell重新設置頁目錄和頁表表項。在執行execve()函數時,系統雖然為任務2分配了64M的空間范圍,但是內核并不會立刻為其分配和映射物理頁面,只有當任務2開始執行時由于發生缺頁而引起異常時才會由內存管理程序為其在主內存區中分配并映射一頁物理內存到其線性地址空間中,這種分配和映射物理內存的方法稱為需求加載(load on demand).
?
?
?
轉載于:https://www.cnblogs.com/coderCaoyu/p/3618854.html
總結
以上是生活随笔為你收集整理的5.3.6 虚拟地址、线性地址和物理地址之间的关系的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java对象引用与对象的区别
- 下一篇: 旅行1:丽江