x86保護模式筆記

2021-06-23 09:21:05 字數 2243 閱讀 6001

以下為自己的總結的x86保護模式知識

x86虛擬位址空間64tb,通過分段/分頁對映到物理記憶體。而linux 實際上只是有限的使用了分段機制(比如使用了段的特權級保護),並沒有利用分段機制實現虛擬化,所以linux下每個程序的虛擬空間,或者說程式設計空間只有4gb,而不是64tb。  假設現在我們要利用x86的分段機制實現虛擬化,將虛擬空間變成64tb,那麼與分頁機制實現的虛擬化相比,有什麼不同的地方呢?討論如下:

在分頁機制下,每個頁大小為4kb,對於x86來說,乙個頁表項一旦建立,4kb的物理記憶體就已經被 「 使用 」了,即使實際上你只使用了乙個位元組。。因此,系統內能同時存在的頁表項的個數x4kb,不能大於實際物理記憶體,其餘的頁表項必須標識為不存在。那麼在分段機制上,段的大小是不固定的,但是一旦在段描述符中確定大小後(假設為n個位元組),與分頁機制一樣,即使你只用了乙個位元組,對x86來說,n個位元組已經被 「 使用 」了。。因此,系統內能同時存在的段的個數是不固定的,但他們的大小之和不能大於系統物理記憶體。

x86有32位位址線,對於linux來說 由於沒有利用分段機制實現虛擬化,虛擬位址的選擇子都是作業系統填的,程式設計師只需要關注偏移位址,不管選擇子是多少,段描述符中基位址都為0,也就是虛擬位址統一對映到偏移位址,這樣一來,16位選擇子不參與位址映**,16+32位位址等於變成了32位位址,64tb虛擬空間被壓縮到了4gb線性空間(也就是說linux下虛擬位址的偏移部分等於線性位址),再由分頁對這4gb空間進行虛擬化。。 假設我們要讓16位位址參與對映,實現64tb虛擬空間,就要注意線性位址不能 「 衝突 」 (在linux中,實際上線性位址是「 衝突 」 的,比如選擇子為1,偏移為0xffff,和選擇子為2,偏移為0xffff,都對映到乙個線性位址0xffff),具體來說就是 線性位址由選擇子和偏移位址共同唯一確定,但畢竟只有32位位址線,對映完4gb線性位址後,多出來的64tb-4gb的虛擬位址如何表示呢,答案是無法表示,那麼會有問題嗎,不會!因為這部分位址所在段的存在位一定是0(見前面第二段)。分頁機制總的虛擬空間只有4gb,正好夠32位數來表示,所以整個虛擬空間都能用線性位址表示出來,而在分段機制中,(64tb-4gb)大小的虛擬位址無法表示(這不一定是4gb~64tb這段位址,而是64tb虛擬位址對映4gb線性位址後,剩下的那塊64tb-4gb大小的位址),但反正也不存在,所以對虛擬化實現沒有影響,要用時,釋放掉之前使用的一些線性位址,把相同大小的虛擬位址對映過去就行了(總之最多對映4gb),總之,64tb虛擬空間中,能表示為線性位址的就4gb,其餘的就無法表示且存在位一定為0。

到此為止。

程式流的轉移:

x86程式流的轉移主要有以下幾種方式: 子程式呼叫,中斷和任務切換。對於x86,只要當前tss段沒有切換,那麼x86就認為任務沒有切換,因此,段間子程式呼叫、非任務門的中斷、呼叫門(儘管linux沒有呼叫門)這些轉移對於x86來說都是「 任務內轉移 」 ,從這個角度劃分,我把程式流的轉移分為下面幾種。

首先大類別上分為任務內轉移與任務間轉移,任務間轉移就是任務切換,這裡不談(參考x86任務切換),所以現在主要討論任務內轉移;任務內轉移又分為段內轉移與段間轉移,段內轉移很簡單,其實就是call或者jump進行短跳轉,指令運算元只給出偏移,預設在當前段內跳轉。如果是call指令,cpu壓入eip,執行ret時返回到原程式。。段間轉移又分為特權級切換的段間轉移和特權級不變的段間轉移,對於特權級不變的段間轉移,一般就是call,jump長跳轉,或者是呼叫門,如果是直接call或者call呼叫門,cpu壓入cs,eip,執行retf遠返回到原程式。對於需要改變特權級的段間轉移,就需要切換到對應特權級的堆疊上,這裡提一下,x86中,**分為一致性**和非一致性**,程式可以轉移到特權級相等或更高的一致性**段(cpl不變),卻只能轉移到相同特權級的非一致性**段中(除非用call呼叫門或者中斷/異常的方式,可以轉移到特權級更高的非一致性**段中,此時cpl變為目標**段的dpl)。因此,對於會改變特權級的段間轉移,只有一種可能,就是低特權級段轉向另乙個高特權級段。這時,需要切換到高特權級堆疊,這個堆疊儲存在任務的tss段中,x86檢測到發生特權級上公升的時候,會從那裡拿到新的高特權級對應的堆疊,載入這個堆疊到ss,esp中,並將原來的堆疊壓入這個新棧,如果是call呼叫門的方式引起的轉移,還會壓入指定個引數(個數在呼叫門描述符中指定)到新堆疊(這些引數也在原堆疊上),最後壓入返回位址cs,eip。

那麼如果是中斷引起的特權級公升高的段間轉移呢?首先從tss段拿到對應新堆疊,載入到ss,esp中,並將原堆疊值壓入新堆疊,這和之前通過call呼叫門轉移到高特權級段是一樣的,但是中斷不傳遞引數,所以沒有引數入棧,另外中斷與普通程式不同,需要儲存標誌暫存器(因為中斷的隨機性),所以eflags入棧,最後cs,eip入棧。。

再說一下,以上轉移在x86眼中都是同乙個任務內的轉移哦。。

X86保護模式程式設計總結(1)

系統設計的步驟 1,初始化相關硬體.並裝入系統.2,取得並測試相應硬體的引數.並初始化如x387等硬體.3,載入gdt到gdtr 第乙個描述符必須為0,至少需要乙個 段和乙個資料段 4,載入idt到idtr 必須先關中斷,載入完後可開啟 5,設定cr0中pe 1 也可和pg位一起設,並用jmp大跳 ...

X86保護模式程式設計總結(4)

cpu標識 eflage標誌位 8086cpu 第12 15位始終置位 intel286cpu 在實模式下,12 15位始終清除 32位cpu 在實模式下,第15位始終清除,第12 14位具有最後被裝入的值.在保護模式下,第14位具有最後被裝入的值,第15位被清除.第18位 intel486和pen...

X86保護模式程式設計總結(6)

中斷和異常 中斷 可遮蔽中斷,在cpu的intr引腳接收的中斷請求,if 1時才允許發生可遮蔽中斷 不可遮蔽中斷,在cpu的nmi輸入腳上接收到,cpu無法關閉不可遮蔽中斷.異常 cpu檢測的異常被分為3種 故障,是在已被檢測到異常的指令之前的指令邊界上報告的異常.故障在恢復到允許指令重新啟動狀態時...