【淺談】x86記憶體管理的分段分頁機制
最近一直在接著作業系統的課程,著手跟著os.dev上的大神的文件寫一個小型的核心,然後前期的東西自己一直在看也沒時間寫Blog,最近做到了記憶體管理這裡,看了Jamesmolloy的文件還有一些os.dev.org上的關於memorymanage的東西,總覺的還是寫點東西吧,雖是贅述,但對自己而言定是有用的。
我不想說太多關於早期8086分段的原因,只是簡單說一下這種概念。我們知道x86架構下的分段+分頁機制共同實現了我們OS的記憶體管理邏輯,當然現在很多除x86架構的CPU已經完全不需要分段(段地址+偏移地址)這種機制,因為分頁完全可以滿足我們對於記憶體的對映管理與定址。Intel只是因為早期
雖然80386
我們知道在多使用者多工環境下,記憶體尋地工作不再是簡單地取得32位的記憶體地址就可以直接不假思索地放到地址總線上去讀寫記憶體了,此刻必須先要對需訪問的地址進行合法性檢查,看看訪問者是不是有權利去訪問它要求的地址。如果發現有非法訪問企圖,則立刻阻止
GDT中23位G是粒度(Granularity)位,用於解釋段界限的含義。當G位是“0”時,段界限以位元組為單位。此時,段的擴充套件範圍是從1位元組到1兆位元組(1B~1MB),因為描述符中的界限值是20位的。相反,如果該位是“1”,那麼,段界限是以4KB為單位的。這樣,段的擴充套件範圍是從4KB到4GB。S位用於指定描述符的型別(DescriptorType)。當該位是“0”時,表示是一個系統段;為“1”時,表示是一個程式碼段或者資料段(堆疊段也是特殊的資料段)。DPL表示描述符的特權級(DescriptorPrivilege Level,DPL)。這兩位用於指定段的特權級。共有4種處理器支援的特權級別,分別是0、1、2、3,其中0是最高特權級別,3是最低特權級別。剛進入保護模式時執行的程式碼具有最高特權級0(可以看成是從處理器那裡繼承來的),這些程式碼通常都是作業系統程式碼,因此它的特權級別最高。每當作業系統載入一個使用者程式時,它通常都會指定一個稍低的特權級,比如3特權級。不同特權級別的程式是互相隔離的,其互訪是嚴格限制的,而且有些處理器指令(特權指令)只能由0特權級的程式來執行,為的就是安全。
為了跟蹤全域性描述符表,處理器內部有一個48位的暫存器,稱為全域性描述符表暫存器(GDTR,下圖所示),該暫存器分為兩部分,分別是32位的線性地址和16位的邊界。32位的處理器具有32根地址線,可以訪問的地址範圍是0x00000000到0xFFFFFFFF,即4GB記憶體。所以,GDTR的32位線性基地址部分儲存的是全域性描述符表在記憶體中的起始線性地址,16位邊界部分儲存的是全域性描述符表的邊界(界限),其在數值上等於表的大小(總位元組數)減一。
描述符中指定了32位的段起始地址,以及20位的段邊界。在真實模式下,段地址並非真實的實體地址,在計算實體地址時,還要左移4位(乘以16)。和真實模式不同,在32位保護模式下,段地址是32位的線性地址,如果未開啟分頁功能,該線性地址就是實體地址。在進入保護模式之後,處理器立即要按新的記憶體訪問模式工作,所以,必須在進入保護模式之前定義GDT。但是,由於在真實模式下只能訪問1MB的記憶體,故GDT通常都定義在1MB以下的記憶體範圍中。
ok,GDT就說到這,下面我們開始啟動記憶體分頁的東西。其實也是我們所謂的真實模式和保護模式的分界。在此之前,我們必須知道CPU的一些控制暫存器。CR0,CR1,CR2,CR3,CR4。。。。。,CR0是32位的暫存器,包含了一系列用於控制處理器操作模式和執行狀態的標誌位。所示,它的第1位(位0)是保護模式允許位(ProtectionEnable,PE,是開啟保護模式大門的門把手,如果把該位置“1”,則處理器進入保護模式,按保護模式的規則開始執行。32位處理器下的6個段暫存器分為兩部分,前16位和8086相同,在真實模式下,它們用於按傳統的方式定址1MB記憶體,使用方法也沒有變化。在保護模式下訪問一個段時,傳送到段選擇器的是段選擇子(上圖)。它由三部分組成,第一部分是描述符的索引號,用來在描述符表中選擇一個段描述符。TI是描述符表指示器 (TableIndicator),TI=0時,表示描述符在GDT中;TI=1時,描述符在LDT中。LDT的知識將在後面進行介紹,它也是一個描述符表,和GDT類似。上圖中的RPL是請求特權級,表示給出當前選擇子的那個程式的特權級別,正是該程式要求訪問