藉由Intel VT-x與AMD-V新增特權層級,讓x86指令集勉強符合「波佩克與戈德堡虛擬化需求」,但災難尚未結束,x86指令集2種不同的記憶體保護方式,提供了不同的保護層級,替早期純軟體虛擬化方案帶來了天大的麻煩。
80386之前的「節區」記憶體管理
在80386提供分頁表(Paging)虛擬記憶體之前, 記憶體保護是採用「節區(Segmentation)」定址記憶體管理模式,作業系統需不時改變節區暫存器的內容,以存取實際上散亂在記憶體各處的資料,基本上屬於「記憶體容量像黃金一樣珍貴,必須錙銖必較」的歷史產物,在今天也沒什麼好批評的。
80386之後,近代x86作業系統基於效能考量以及「程式設計者不需要在配置記憶體這件事上傷腦筋」,全面採用「平面記憶體定址模型(Flat Memory Model,又稱為「0:32」)」,「虛級化」節區暫存器,將其基底值通通都設為0,毋須改變其內容,只靠1個來自32位元暫存器的偏移值(Offset)即可標定4GB虛擬定址空間的任何一處(雖然有PAE/PSE-36這種邁向64位元前的過渡期特例)。
新技術問世前的實作方式
這也讓x86處理器廠商紛紛放棄改善節區定址模式的執行效率,僅維持相容性即可,依循「Make The Common Case Fast」的大原則,把電晶體預算砸到最常用到功能的刀口上,64位元x86指令集更全面揚棄節區記憶體,強制實現平面記憶體模型。當年Pentium Pro所謂的「16位元效能不佳」就是因為動到資料節區暫存器(Data Segment)的指令,在Pentium Pro無法被非循序預測執行,會讓後面的指令大塞車。
麻煩的是,在Intel VT-x與AMD-V問世前,在x86處理器上面實作虛擬化,必須將腦袋動到「只有節區記憶體才提供的4層權限」,經常被用來舉例的POPF,在特權模式(Ring 0)和使用者模式(Ring 1-3)會有不一樣的執行結果,POPF在使用者模式並不會啟動EFLAGS暫存器的IF(Interrupt Enable)欄位,卻也不會製造例外(Exception)。
假使採用壓縮權限(Ring Compression)方式,將原本在Ring 0執行的作業系統轉移到Ring 1,POPF將會有錯誤的執行結果,而被迫使用節區記憶體定址,也降低整體效能。好笑的是,x86的節區記憶體定址定義了4層權限,但歷史上除了微軟曾經將驅動程式放在Ring 1外,根本少人去動用Ring 1和Ring 2,後來的分頁表只有2層就是最好的反證。
就算有了Intel VT-x和AMD-V,「記憶體虛擬化」也並非高枕無憂,需透過軟體手段「遮蔽(Shadow)」作業系統可以看到的記憶體位址空間,不准直接存取,也就是軟體模擬出1個「影子分頁表(Shadow Page Table)」給虛擬機上執行的作業系統,至於實體位址與虛擬位址的轉換也是莫大的負擔,加上x86指令集因長期缺乏資料暫存器,而讓應用程式的行為變得非常的「Memory Intensive(記憶體存取密集)」,相信各位科科光用想的就會覺得這樣效率一定不太好,同時執行的作業系統越多勢必更加嚴重,所以「硬體輔助的記憶體虛擬化」技術就要浮上檯面了。未完待續。
5 則回應